nicholai-work-2026/src/components/Navigation.astro
Nicholai 2ca66ccc6d Update theme variable usage and add ThemeToggle component
- Refactor component styles to use CSS custom properties for colors and backgrounds.
- Replace hard‑coded Tailwind classes with theme variables across BlogCard, BlogFilters, Footer, GridOverlay, Navigation, PostNavigation, ReadingProgress, RelatedPosts, TableOfContents, ThemeToggle, sections, layouts, pages, and global.css.
- Add ThemeToggle component for user‑controlled theme switching.
- Update global styles to define new theme variables.
- Ensure all components respect theme changes and maintain accessibility.

Hubert The Eunuch
2025-12-18 17:08:52 -07:00

169 lines
7.2 KiB
Plaintext

---
import ThemeToggle from './ThemeToggle.astro';
---
<nav class="fixed top-0 left-0 w-full z-50 px-6 lg:px-12 py-6 lg:py-8 flex justify-between items-center backdrop-blur-md bg-[var(--theme-overlay)] border-b border-[var(--theme-border-secondary)]">
<!-- Left side - branding and theme toggle -->
<div class="flex items-center gap-6">
<a href="/" class="text-[10px] font-mono text-[var(--theme-text-muted)] tracking-widest uppercase hover:text-brand-accent transition-colors duration-300">NV / 2026</a>
<div class="hidden md:block">
<ThemeToggle />
</div>
</div>
<!-- Right side navigation -->
<div class="flex items-center gap-6 lg:gap-10 ml-auto">
<div class="hidden md:flex items-center gap-10 lg:gap-12">
<a href="/"
class:list={[
"relative text-xs font-semibold uppercase tracking-[0.15em] transition-all duration-300 py-2 group",
Astro.url.pathname === '/' ? "text-[var(--theme-text-primary)]" : "text-[var(--theme-text-muted)] hover:text-[var(--theme-text-primary)]"
]}>
<span class="relative z-10">Home</span>
<span class:list={[
"absolute bottom-0 left-0 h-[1px] bg-brand-accent transition-all duration-300 ease-out",
Astro.url.pathname === '/' ? "w-full" : "w-0 group-hover:w-full"
]}></span>
</a>
<a href="/blog"
class:list={[
"relative text-xs font-semibold uppercase tracking-[0.15em] transition-all duration-300 py-2 group",
Astro.url.pathname.startsWith('/blog') ? "text-[var(--theme-text-primary)]" : "text-[var(--theme-text-muted)] hover:text-[var(--theme-text-primary)]"
]}>
<span class="relative z-10">Blog</span>
<span class:list={[
"absolute bottom-0 left-0 h-[1px] bg-brand-accent transition-all duration-300 ease-out",
Astro.url.pathname.startsWith('/blog') ? "w-full" : "w-0 group-hover:w-full"
]}></span>
</a>
</div>
<a href="/contact"
class:list={[
"hidden md:block border px-5 lg:px-6 py-2.5 lg:py-3 text-xs font-bold uppercase tracking-[0.15em] transition-all duration-300",
Astro.url.pathname.startsWith('/contact')
? "border-brand-accent bg-brand-accent text-brand-dark"
: "border-[var(--theme-border-strong)] text-[var(--theme-text-primary)] hover:border-brand-accent hover:bg-brand-accent hover:text-brand-dark"
]}>
Let's Talk
</a>
</div>
<!-- Mobile menu button -->
<div class="md:hidden flex items-center">
<button
id="mobile-menu-toggle"
class="p-2 text-[var(--theme-text-muted)] hover:text-[var(--theme-text-primary)] transition-colors z-[60]"
aria-label="Toggle menu"
aria-expanded="false"
>
<!-- Hamburger icon -->
<svg id="menu-icon-open" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Close icon (hidden by default) -->
<svg id="menu-icon-close" class="w-6 h-6 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
</nav>
<!-- Mobile Menu Overlay -->
<div
id="mobile-menu"
class="fixed inset-0 z-40 bg-[var(--theme-overlay-heavy)] backdrop-blur-xl transform translate-x-full transition-transform duration-300 ease-out md:hidden"
>
<!-- Menu Content -->
<div class="flex flex-col justify-center items-center h-full px-8">
<!-- Navigation Links -->
<nav class="flex flex-col items-center gap-8 mb-12">
<a
href="/"
class="mobile-nav-link text-3xl font-bold uppercase tracking-wider text-[var(--theme-text-primary)] hover:text-brand-accent transition-colors duration-300"
>
Home
</a>
<a
href="/blog"
class="mobile-nav-link text-3xl font-bold uppercase tracking-wider text-[var(--theme-text-primary)] hover:text-brand-accent transition-colors duration-300"
>
Blog
</a>
<a
href="/contact"
class="mobile-nav-link text-3xl font-bold uppercase tracking-wider text-[var(--theme-text-primary)] hover:text-brand-accent transition-colors duration-300"
>
Contact
</a>
</nav>
<!-- CTA Button -->
<a
href="/contact"
class="border border-brand-accent px-8 py-4 text-sm font-bold uppercase tracking-[0.2em] text-brand-accent hover:bg-brand-accent hover:text-brand-dark transition-all duration-300 mb-8"
>
Let's Talk
</a>
<!-- Decorative Elements -->
<div class="absolute bottom-12 left-8 right-8 flex justify-between items-center">
<div class="flex flex-col gap-2">
<div class="text-[10px] font-mono text-[var(--theme-text-muted)] uppercase tracking-widest">
NV / 2026
</div>
<ThemeToggle />
</div>
<div class="text-[10px] font-mono text-[var(--theme-text-muted)] uppercase tracking-widest self-end">
Menu
</div>
</div>
</div>
</div>
<script>
const toggle = document.getElementById('mobile-menu-toggle');
const menu = document.getElementById('mobile-menu');
const iconOpen = document.getElementById('menu-icon-open');
const iconClose = document.getElementById('menu-icon-close');
const mobileNavLinks = document.querySelectorAll('.mobile-nav-link');
let isOpen = false;
function toggleMenu() {
isOpen = !isOpen;
if (isOpen) {
menu?.classList.remove('translate-x-full');
menu?.classList.add('translate-x-0');
iconOpen?.classList.add('hidden');
iconClose?.classList.remove('hidden');
document.body.style.overflow = 'hidden';
toggle?.setAttribute('aria-expanded', 'true');
} else {
menu?.classList.add('translate-x-full');
menu?.classList.remove('translate-x-0');
iconOpen?.classList.remove('hidden');
iconClose?.classList.add('hidden');
document.body.style.overflow = '';
toggle?.setAttribute('aria-expanded', 'false');
}
}
toggle?.addEventListener('click', toggleMenu);
// Close menu when clicking a link
mobileNavLinks.forEach(link => {
link.addEventListener('click', () => {
if (isOpen) toggleMenu();
});
});
// Close menu on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && isOpen) {
toggleMenu();
}
});
</script>