diff --git a/app/page.tsx b/app/page.tsx index 9420766..44450e8 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,9 +1,11 @@ import Header from "@/components/Header"; import Hero from "@/components/Hero"; import TaglineBanner from "@/components/TaglineBanner"; +import StatsBar from "@/components/StatsBar"; import Services from "@/components/Services"; import Technologies from "@/components/Technologies"; import DataSovereignty from "@/components/DataSovereignty"; +import PaperlessSection from "@/components/PaperlessSection"; import About from "@/components/About"; import Contact from "@/components/Contact"; import Footer from "@/components/Footer"; @@ -14,11 +16,13 @@ export default function Home() { + - + + diff --git a/components/StatsBar.tsx b/components/StatsBar.tsx new file mode 100644 index 0000000..788ada7 --- /dev/null +++ b/components/StatsBar.tsx @@ -0,0 +1,72 @@ +// components/StatsBar.tsx +"use client"; + +import { useEffect, useRef, useState } from "react"; + +const stats = [ + { value: 30, suffix: "+", label: "Jahre IT-Erfahrung", accent: "orange" }, + { value: 99, suffix: "%", label: "Server-Uptime", accent: "blue" }, + { value: 50, suffix: "+", label: "Abgeschlossene Projekte", accent: "orange" }, + { value: 24, suffix: "h", label: "Support-Reaktionszeit", accent: "blue" }, +]; + +function Counter({ value, suffix, accent }: { value: number; suffix: string; accent: string }) { + const [count, setCount] = useState(0); + const ref = useRef(null); + const started = useRef(false); + + useEffect(() => { + const el = ref.current; + if (!el) return; + + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !started.current) { + started.current = true; + const duration = 1500; + const start = performance.now(); + + const tick = (now: number) => { + const progress = Math.min((now - start) / duration, 1); + const eased = 1 - Math.pow(1 - progress, 3); + setCount(Math.floor(eased * value)); + if (progress < 1) requestAnimationFrame(tick); + }; + + requestAnimationFrame(tick); + observer.disconnect(); + } + }, + { threshold: 0.3 } + ); + + observer.observe(el); + return () => observer.disconnect(); + }, [value]); + + const color = accent === "orange" ? "text-orange-400" : "text-blue-400"; + + return ( + + {count}{suffix} + + ); +} + +export default function StatsBar() { + return ( + + + + + {stats.map((stat) => ( + + + {stat.label} + + ))} + + + + ); +}
{stat.label}