44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { ChevronDown } from 'lucide-react';
|
||
|
|
import { useEffect, useState } from 'react';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Scroll cue — a fixed pill anchored to the bottom of the viewport that
|
||
|
|
* points the visitor down to the flow video below the hero. Fades out
|
||
|
|
* once the user has scrolled past the loadscreen so it doesn't follow
|
||
|
|
* them around the page.
|
||
|
|
*
|
||
|
|
* Lives at z-30 so it sits above the hero content but below modals.
|
||
|
|
* The frosted pill (backdrop-blur + border) reads clearly against the
|
||
|
|
* particle background without stealing focus from the H1.
|
||
|
|
*/
|
||
|
|
export function ScrollCue({ targetId }: { targetId: string }) {
|
||
|
|
const [visible, setVisible] = useState(true);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
function onScroll() {
|
||
|
|
setVisible(window.scrollY < 80);
|
||
|
|
}
|
||
|
|
onScroll();
|
||
|
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||
|
|
return () => window.removeEventListener('scroll', onScroll);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<a
|
||
|
|
href={`#${targetId}`}
|
||
|
|
aria-label="See the flow in action"
|
||
|
|
className={`fixed inset-x-0 bottom-5 z-30 mx-auto flex w-fit items-center gap-1.5 rounded-full border border-[--color-border] px-3 py-1.5 text-[10.5px] uppercase tracking-[0.18em] text-[--color-fg-subtle] backdrop-blur transition-opacity duration-500 hover:text-[--color-fg] ${
|
||
|
|
visible ? 'opacity-100' : 'pointer-events-none opacity-0'
|
||
|
|
}`}
|
||
|
|
style={{
|
||
|
|
backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 75%, transparent)',
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<span>see it run</span>
|
||
|
|
<ChevronDown size={12} className="animate-bounce" />
|
||
|
|
</a>
|
||
|
|
);
|
||
|
|
}
|