"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; type NavItem = { label: string; href: string; }; type NavLinksProps = { items: NavItem[]; alignEnd: boolean; }; function getHashId(href: string) { return href.split("#")[1] ?? ""; } export function NavLinks({ items, alignEnd }: NavLinksProps) { const [activeId, setActiveId] = useState(""); useEffect(() => { const sectionIds = items.map((item) => getHashId(item.href)).filter(Boolean); const sections = sectionIds .map((id) => document.getElementById(id)) .filter((section): section is HTMLElement => Boolean(section)); if (sections.length === 0) { setActiveId(""); return; } function syncFromHash() { const nextId = window.location.hash.replace("#", ""); if (sectionIds.includes(nextId)) { setActiveId(nextId); } } syncFromHash(); const observer = new IntersectionObserver( (entries) => { const visible = entries .filter((entry) => entry.isIntersecting) .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]; if (visible?.target.id) { setActiveId(visible.target.id); } }, { rootMargin: "-28% 0px -58% 0px", threshold: [0.12, 0.24, 0.36] } ); sections.forEach((section) => observer.observe(section)); window.addEventListener("hashchange", syncFromHash); return () => { observer.disconnect(); window.removeEventListener("hashchange", syncFromHash); }; }, [items]); return ( ); }