From fdab68efe545d252c751b1ad3f68af00b9bbf43d Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 30 Jun 2026 22:24:02 +0000 Subject: [PATCH] fix(Navbar): replace IntersectionObserver with scroll-based active section --- app/components/Navbar.tsx | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/app/components/Navbar.tsx b/app/components/Navbar.tsx index 284e96b..d72d4af 100644 --- a/app/components/Navbar.tsx +++ b/app/components/Navbar.tsx @@ -48,30 +48,22 @@ export function Navbar() { }, []); useEffect(() => { - const visible = new Set(); - - const updateActive = () => { + const onScroll = () => { + // trigger line = 1/3 from top of viewport (= 2/3 from bottom) + const triggerY = window.scrollY + NAVBAR_HEIGHT + (window.innerHeight - NAVBAR_HEIGHT) / 3; + let current = ""; for (const id of anchorIds) { - if (visible.has(id)) { setActiveSection(id); return; } + const el = document.getElementById(id); + if (!el) continue; + const top = el.getBoundingClientRect().top + window.scrollY; + if (top <= triggerY) current = id; } - setActiveSection(""); + setActiveSection(current); }; - const observers = anchorIds.map((id) => { - const el = document.getElementById(id); - if (!el) return null; - const obs = new IntersectionObserver( - ([entry]) => { - entry.isIntersecting ? visible.add(id) : visible.delete(id); - updateActive(); - }, - { rootMargin: "-100px 0px -67% 0px" } - ); - obs.observe(el); - return obs; - }); - - return () => observers.forEach((o) => o?.disconnect()); + onScroll(); + window.addEventListener("scroll", onScroll, { passive: true }); + return () => window.removeEventListener("scroll", onScroll); }, []); return (