62 lines
2.3 KiB
TypeScript
62 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { motion, useScroll, useSpring } from 'framer-motion';
|
|
import { usePrefersReducedMotion } from '@/lib/motion';
|
|
|
|
// The gold spine of the page: one continuous line down the vertical centre,
|
|
// drawing itself as the reader scrolls. It is what turns ten sections into a
|
|
// single route — *claridad · dirección · crecimiento* made visible, per the
|
|
// Manual de Identidad Visual.
|
|
//
|
|
// Centred, never in a side gutter: the brand's through-line belongs in the
|
|
// middle, on every breakpoint. It sits ABOVE the section backgrounds (z-10)
|
|
// but BELOW the text, which `Container` lifts to z-20 — so the thread reads
|
|
// as a faint watermark spine behind the reading, never crossing it.
|
|
//
|
|
// Page-level useScroll() with no target ref on purpose: no element measuring,
|
|
// no "container has a static position" warnings, one listener for the page.
|
|
|
|
const TRAZO =
|
|
'M50 0 C 42 200, 58 400, 50 600 C 42 800, 58 1000, 50 1200';
|
|
|
|
export function HiloConductor({ className = '' }: { className?: string }) {
|
|
const reduced = usePrefersReducedMotion();
|
|
const { scrollYProgress } = useScroll();
|
|
const avance = useSpring(scrollYProgress, { stiffness: 90, damping: 30, restDelta: 0.001 });
|
|
|
|
const wrapper = `pointer-events-none absolute inset-0 z-10 ${className}`;
|
|
|
|
// Plain <path> for reduced motion: motion.path applies dash scaffolding even
|
|
// without initial/animate and would leave the thread invisible.
|
|
const trazo = reduced ? (
|
|
<path d={TRAZO} fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" />
|
|
) : (
|
|
<motion.path
|
|
d={TRAZO}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth={1.5}
|
|
strokeLinecap="round"
|
|
style={{ pathLength: avance }}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<div className={wrapper}>
|
|
{/* Mirrors Container's own centring (`mx-auto max-w-content`) so the
|
|
thread is measured from the real column edge and stays centred in it. */}
|
|
<div className="relative mx-auto h-full w-full max-w-content">
|
|
<svg
|
|
className="absolute inset-y-0 left-1/2 h-full w-14 -translate-x-1/2 text-dorado/25"
|
|
viewBox="0 0 100 1200"
|
|
preserveAspectRatio="none"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
{trazo}
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|