Files
Webklar.com/components/ui/timeline.tsx
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

111 lines
3.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useScroll, useTransform, motion } from "motion/react";
import React, { useEffect, useRef, useState } from "react";
import { colors } from "@/lib/colors";
interface TimelineEntry {
title: string;
content: React.ReactNode;
}
export const Timeline = ({ data }: { data: TimelineEntry[] }) => {
const ref = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(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 (
<div
className="w-full font-sans md:px-10"
ref={containerRef}
style={{ backgroundColor: colors.background }}
>
<div className="max-w-7xl mx-auto py-20 px-4 md:px-8 lg:px-10">
<h2
className="text-lg md:text-4xl mb-4 max-w-4xl"
style={{ color: colors.primary }}
>
Unser Projektfahrplan im Überblick
</h2>
<p
className="text-sm md:text-base max-w-sm"
style={{ color: colors.secondary }}
>
Schritt für Schritt zur erfolgreichen Website transparent,
strukturiert und begleitet von unserem Team.
</p>
</div>
<div ref={ref} className="relative max-w-7xl mx-auto pb-20">
{data.map((item, index) => (
<div
key={index}
className="flex justify-start pt-10 md:pt-40 md:gap-10 min-h-[320px]"
>
<div className="sticky flex flex-col md:flex-row z-40 items-center top-40 self-start max-w-xs lg:max-w-sm md:w-full">
<div
className="h-10 absolute left-3 md:left-3 w-10 rounded-full flex items-center justify-center"
style={{ backgroundColor: colors.background }}
>
<div
className="h-4 w-4 rounded-full border"
style={{
backgroundColor: `${colors.secondary}4D`,
borderColor: `${colors.secondary}66`,
}}
/>
</div>
<h3
className="hidden md:block text-xl md:pl-20 md:text-5xl font-bold"
style={{ color: colors.primary }}
>
{item.title}
</h3>
</div>
<div className="relative pl-20 pr-4 md:pl-4 w-full">
<h3
className="md:hidden block text-2xl mb-4 text-left font-bold"
style={{ color: colors.primary }}
>
{item.title}
</h3>
{item.content}{" "}
</div>
</div>
))}
<div
style={{
height: height + "px",
}}
className="absolute md:left-8 left-8 top-0 overflow-hidden w-[2px] bg-[linear-gradient(to_bottom,var(--tw-gradient-stops))] from-transparent from-[0%] via-neutral-200 dark:via-neutral-700 to-transparent to-[99%] [mask-image:linear-gradient(to_bottom,transparent_0%,black_10%,black_90%,transparent_100%)] "
>
<motion.div
style={{
height: heightTransform,
opacity: opacityTransform,
}}
className="absolute inset-x-0 top-0 w-[2px] bg-gradient-to-t from-purple-500 via-blue-500 to-transparent from-[0%] via-[10%] rounded-full"
/>
</div>
</div>
</div>
);
};