// Section tracking and navigation highlighting document.addEventListener("DOMContentLoaded", function () { const sections = document.querySelectorAll("section[id]"); const navLinks = document.querySelectorAll(".nav-links a"); // Configuration const offset = 100; // Offset for when section becomes "active" (accounts for fixed nav) let isScrolling = false; function getCurrentSection() { let currentSection = ""; const scrollPosition = window.scrollY + offset; // Find which section we're currently in sections.forEach((section) => { const sectionTop = section.offsetTop; const sectionHeight = section.offsetHeight; const sectionId = section.getAttribute("id"); if ( scrollPosition >= sectionTop && scrollPosition < sectionTop + sectionHeight ) { currentSection = sectionId; } }); // Special case: if we're at the very top, activate the first section if (window.scrollY < 100) { currentSection = sections[0]?.getAttribute("id") || ""; } return currentSection; } function updateActiveNavLink() { const currentSection = getCurrentSection(); navLinks.forEach((link) => { const href = link.getAttribute("href"); // Remove active class from all links link.classList.remove("active"); // Add active class to matching link if (href === `#${currentSection}`) { link.classList.add("active"); } }); } // Throttle scroll events for better performance function handleScroll() { if (!isScrolling) { window.requestAnimationFrame(() => { updateActiveNavLink(); isScrolling = false; }); isScrolling = true; } } // Listen for scroll events window.addEventListener("scroll", handleScroll); // Update on page load updateActiveNavLink(); // Also update when clicking nav links (for smooth scroll) navLinks.forEach((link) => { link.addEventListener("click", function (e) { // Remove active from all navLinks.forEach((l) => l.classList.remove("active")); // Add active to clicked link this.classList.add("active"); // Let the scroll handler update it properly after scroll completes setTimeout(updateActiveNavLink, 100); }); }); // Handle hash changes (browser back/forward) window.addEventListener("hashchange", function () { setTimeout(updateActiveNavLink, 100); }); // Intersection Observer for more precise tracking (progressive enhancement) if ("IntersectionObserver" in window) { const observerOptions = { rootMargin: "-20% 0px -70% 0px", // Trigger when section is roughly in the middle of viewport threshold: 0, }; const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const sectionId = entry.target.getAttribute("id"); navLinks.forEach((link) => { link.classList.remove("active"); if (link.getAttribute("href") === `#${sectionId}`) { link.classList.add("active"); } }); } }); }, observerOptions); // Observe all sections sections.forEach((section) => observer.observe(section)); } });