'use client'; import { useEffect, useState, useRef, useCallback } from 'react'; import { cn } from '@/lib/utils'; export interface SectionNavItem { id: string; label: string; } interface SectionNavProps { sections: SectionNavItem[]; } function useScrollSpy(sections: SectionNavItem[]) { const [activeId, setActiveId] = useState(null); const observerRef = useRef(null); useEffect(() => { if (sections.length < 3) return; const handleIntersect = (entries: IntersectionObserverEntry[]) => { const visible = entries .filter((e) => e.isIntersecting) .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top); const first = visible[0]; if (first) { setActiveId(first.target.id); } }; observerRef.current = new IntersectionObserver(handleIntersect, { rootMargin: '-80px 0px -60% 0px', threshold: 0, }); for (const section of sections) { const el = document.getElementById(section.id); if (el) observerRef.current.observe(el); } return () => { observerRef.current?.disconnect(); }; }, [sections]); return activeId; } export function SectionNav({ sections }: SectionNavProps) { const activeId = useScrollSpy(sections); const handleClick = useCallback((id: string) => { const el = document.getElementById(id); if (el) { el.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, []); if (sections.length < 3) return null; return ( <> {/* Desktop: left sidebar — positioned by parent flex container */} {/* Mobile: horizontal pill bar */} ); }