"use client"; import Image from "next/image"; import { useRef, type ReactNode } from "react"; import { motion, useMotionTemplate, useReducedMotion, useScroll, useSpring, useTransform, } from "motion/react"; import { Lock, TrendingUp, Users } from "lucide-react"; /* ------------------------------------------------------------------ * * Browser chrome — glass bar over the screenshot * ------------------------------------------------------------------ */ export function BrowserFrame({ children, url = "app.kumasy.de", className = "", }: { children: ReactNode; url?: string; className?: string; }) { return (
{url}
{children}
); } /* ------------------------------------------------------------------ * * Floating stat chip * * Deliberately opaque, unlike the rest of the glass family. These chips * sit directly on top of the dashboard screenshot, so a translucent * surface lets the sidebar labels and the chart line read straight * through the chip's own text — backdrop-blur cannot fix that, because * what is behind is small sharp type rather than a soft wash. Same call * the app makes for dialogs: darken behind, never blur, so the content * in front stays legible. * ------------------------------------------------------------------ */ function GlassStat({ Icon, label, value, tone, }: { Icon: typeof Users; label: string; value: string; tone: "mint" | "amber"; }) { return (
{label}

{value}

); } /* ------------------------------------------------------------------ * * ParallaxLayer * ------------------------------------------------------------------ */ export function ParallaxLayer({ children, depth = 60, className = "", }: { children: ReactNode; depth?: number; className?: string; }) { const ref = useRef(null); const reduced = useReducedMotion(); const { scrollYProgress } = useScroll({ target: ref, offset: ["start end", "end start"], }); const y = useSpring(useTransform(scrollYProgress, [0, 1], [depth, -depth]), { stiffness: 120, damping: 28, mass: 0.4, }); return ( {children} ); } /* ------------------------------------------------------------------ * * ShowcaseStage — one product shot, presented cleanly * ------------------------------------------------------------------ */ export function ShowcaseStage() { const ref = useRef(null); const reduced = useReducedMotion(); const { scrollYProgress } = useScroll({ target: ref, offset: ["start 0.95", "end 0.2"], }); // The window tips up from a shallow angle and settles flat, as if being // set down on the pedestal. One gesture, not five competing ones. const rotateX = useSpring(useTransform(scrollYProgress, [0, 0.6], [12, 0]), { stiffness: 90, damping: 26, }); const scale = useSpring(useTransform(scrollYProgress, [0, 0.6], [0.94, 1]), { stiffness: 90, damping: 26, }); const lift = useTransform(scrollYProgress, [0, 0.6], [50, 0]); const glowY = useTransform(scrollYProgress, [0, 1], [40, -40]); const chipY = useTransform(scrollYProgress, [0, 1], [-46, 46]); const transform = useMotionTemplate`perspective(1600px) rotateX(${rotateX}deg) scale(${scale})`; return (
{/* Pedestal: a warm plinth the window stands on, so it reads as placed rather than pasted onto the page. */}
{/* The product shot. Full opacity, nothing covering it. */} Kumasy Dashboard mit Umsatzverlauf über zwölf Monate und Kurs-Kennzahlen {/* Two chips, clear of the window on either side. They annotate the product; they never sit on top of the UI they point at. */}
); }