"use client"; import { useMotionValueEvent, useScroll, useTransform, motion } from "framer-motion"; import React, { useEffect, useRef, useState } from "react"; import { Rocket, Database, Sparkles, Palette, Calendar, Layout, Users, Smartphone, FileText, Brain, Tags, Target, HelpCircle, Zap, Eye } from "lucide-react"; // Icon mapping const iconMap = { Rocket, Database, Sparkles, Palette, Calendar, Layout, Users, Smartphone, FileText, Brain, Tags, Target, HelpCircle, Zap, Eye, }; interface Feature { title: string; description: string; time?: string; traditional?: string; icon: keyof typeof iconMap; } interface WeekData { weekNumber: number; title: string; status: "completed" | "in_progress" | "planned"; description: string; features: Feature[]; metrics: { hours: string; cost: string; linesOfCode: string; }; achievements: string[]; } interface TimelineData { heading: string; description: string; weeks: WeekData[]; } interface BuildTimelineProps { data: TimelineData; } const StatusBadge = ({ status }: { status: WeekData["status"] }) => { const styles = { completed: "bg-teal-100 text-teal-700 border-teal-200", in_progress: "bg-amber-100 text-amber-700 border-amber-200", planned: "bg-slate-100 text-slate-600 border-slate-200", }; const labels = { completed: "Voltooid", in_progress: "Bezig", planned: "Gepland", }; return ( {labels[status]} ); }; const FeatureCard = ({ feature }: { feature: Feature }) => { const Icon = iconMap[feature.icon]; return (

{feature.title}

{feature.description}

{feature.time && feature.traditional && (
Met AI: {feature.time}
Traditioneel: {feature.traditional}
)}
); }; export const BuildTimeline = ({ data }: BuildTimelineProps) => { const ref = useRef(null); const containerRef = useRef(null); const [height, setHeight] = useState(0); useEffect(() => { if (ref.current) { const rect = ref.current.getBoundingClientRect(); setHeight(rect.height); } }, [ref]); const { scrollYProgress } = useScroll({ target: containerRef, offset: ["start 10%", "end 50%"], }); const heightTransform = useTransform(scrollYProgress, [0, 1], [0, height]); const opacityTransform = useTransform(scrollYProgress, [0, 0.1], [0, 1]); return (
{/* Header */}

{data.heading}

{data.description}

{/* Timeline */}
{data.weeks.map((week, index) => (
{/* Left side - Week title (sticky) */}
{/* Timeline dot */}
{/* Week title - hidden on mobile */}

{week.title}

{/* Right side - Content */}
{/* Week title - mobile only */}

{week.title}

{/* Description */}

{week.description}

{/* Features */} {week.features.length > 0 && (

Features

{week.features.map((feature, fIndex) => ( ))}
)} {/* Metrics */}

Metrics

{week.metrics.hours}
Development
{week.metrics.cost}
Infrastructure
{week.metrics.linesOfCode}
Lines of Code
{/* Achievements */} {week.achievements.length > 0 && (

Achievements

    {week.achievements.map((achievement, aIndex) => (
  • {achievement}
  • ))}
)} {/* Link to detailed documentation */} Bekijk uitgebreide documentatie
))} {/* Animated timeline line */}
); };