feat: enhance header and mobile navigation with smooth scrolling and active link highlighting

This commit is contained in:
TerryM
2026-05-12 22:39:36 +08:00
parent dbaad19d0b
commit a6bd0ca864
4 changed files with 134 additions and 19 deletions

View File

@@ -16,9 +16,49 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
<title>{title}</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body class="bg-surface font-sans overflow-x-hidden">
<slot />
<script>
(() => {
const header = document.getElementById('site-header');
const getOffset = () => header ? header.offsetHeight : 0;
// Smooth scroll with header offset
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', e => {
const href = link.getAttribute('href');
if (!href || href === '#') return;
const target = document.querySelector(href);
if (!target) return;
e.preventDefault();
const top = target.getBoundingClientRect().top + window.scrollY - getOffset();
window.scrollTo({ top, behavior: 'smooth' });
});
});
// Active nav highlighting via IntersectionObserver
const navLinks = document.querySelectorAll('[data-nav-link]');
const sections = Array.from(navLinks)
.map(l => document.querySelector(l.getAttribute('href') ?? ''))
.filter(Boolean) as Element[];
if ('IntersectionObserver' in window && sections.length) {
const observer = new IntersectionObserver(entries => {
const visible = entries
.filter(e => e.isIntersecting)
.sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
if (!visible) return;
navLinks.forEach(link => {
const active = link.getAttribute('href') === `#${visible.target.id}`;
link.classList.toggle('!text-[#f28a4b]', active);
link.classList.toggle('text-[#7a726d]', !active);
});
}, { rootMargin: '-30% 0px -60% 0px', threshold: 0 });
sections.forEach(s => observer.observe(s));
}
})();
</script>
</body>
</html>