// HpUI — small ambient UI components used across the homepage. // Exports: HpScrollProgress, HpScrollToTop, HpLiveBadge. // --- Scroll progress bar (fixed coral line at the very top) --------- function HpScrollProgress() { const [pct, setPct] = React.useState(0); React.useEffect(() => { let rafId = null; const onScroll = () => { if (rafId) return; rafId = window.requestAnimationFrame(() => { const doc = document.documentElement; const scrollable = (doc.scrollHeight - window.innerHeight) || 1; const p = Math.min(100, Math.max(0, (window.scrollY / scrollable) * 100)); setPct(p); rafId = null; }); }; onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll); return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); if (rafId) window.cancelAnimationFrame(rafId); }; }, []); return (
); } window.HpScrollProgress = HpScrollProgress; // --- Floating back-to-top button ------------------------------------ function HpScrollToTop() { const [visible, setVisible] = React.useState(false); React.useEffect(() => { const onScroll = () => setVisible(window.scrollY > 720); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); const onClick = () => { window.scrollTo({ top: 0, behavior: "smooth" }); }; return ( ); } window.HpScrollToTop = HpScrollToTop; // --- LIVE badge (pulsing dot + caption) ----------------------------- function HpLiveBadge({ children }) { return ( {children} ); } window.HpLiveBadge = HpLiveBadge;