d8a79ccbe3
- Huemint Magazine tokens for light/dark themes with AA-safe accent variants - FOUC-free theme init + toggle (localStorage, follows OS until chosen) - Seo component (canonical, OG, Twitter, WebSite/Person JSON-LD) - Header with popover mobile menu, 4-column footer with social links - Container, GridLines, SectionHeading, Button, Badge, Card, ExternalLink - site.json / social.json validated with zod - dev-only /styleguide preview Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
2.9 KiB
Plaintext
89 lines
2.9 KiB
Plaintext
---
|
|
import { Icon } from 'astro-icon/components';
|
|
import { site } from '../lib/data';
|
|
import Container from './Container.astro';
|
|
import ThemeToggle from './ThemeToggle.astro';
|
|
|
|
const path = Astro.url.pathname;
|
|
const isActive = (href: string) => (href === '/' ? path === '/' : path.startsWith(href));
|
|
---
|
|
|
|
<header class="border-line relative z-20 border-b">
|
|
<Container class="flex h-16 items-center justify-between gap-6 md:h-20">
|
|
<a
|
|
href="/"
|
|
class="font-display text-2xl font-black tracking-tight uppercase"
|
|
aria-label={`${site.name} — ${site.ui.home}`}
|
|
>
|
|
{site.name}
|
|
</a>
|
|
|
|
<div class="flex items-center gap-2 md:gap-6">
|
|
<nav aria-label={site.ui.mainNav} class="hidden md:block">
|
|
<ul class="flex items-center gap-6">
|
|
{site.nav.map((item) => (
|
|
<li>
|
|
<a
|
|
href={item.href}
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
|
class="font-display hover:border-accent aria-[current=page]:border-accent block border-b-3 border-transparent py-1 text-sm font-bold tracking-wide uppercase transition-colors"
|
|
>
|
|
{item.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
|
|
<ThemeToggle />
|
|
|
|
<button
|
|
type="button"
|
|
popovertarget="mobile-nav"
|
|
aria-label={site.ui.menuOpen}
|
|
class="text-fg hover:text-accent inline-flex size-10 cursor-pointer items-center justify-center md:hidden"
|
|
>
|
|
<Icon name="tabler:menu-2" class="size-7" aria-hidden="true" />
|
|
</button>
|
|
</div>
|
|
</Container>
|
|
|
|
<!-- Native popover: Escape / light-dismiss / focus handling without custom JS. -->
|
|
<nav
|
|
id="mobile-nav"
|
|
popover
|
|
aria-label={site.ui.mainNav}
|
|
class="bg-bg-alt text-fg fixed inset-0 m-0 h-dvh max-h-none w-full max-w-none p-0 md:hidden"
|
|
>
|
|
<Container class="flex h-16 items-center justify-between">
|
|
<span class="font-display text-2xl font-black tracking-tight uppercase" aria-hidden="true">
|
|
{site.name}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
popovertarget="mobile-nav"
|
|
popovertargetaction="hide"
|
|
aria-label={site.ui.menuClose}
|
|
class="hover:text-accent inline-flex size-10 cursor-pointer items-center justify-center"
|
|
>
|
|
<Icon name="tabler:x" class="size-7" aria-hidden="true" />
|
|
</button>
|
|
</Container>
|
|
<Container>
|
|
<ul class="mt-8 flex flex-col gap-2">
|
|
{site.nav.map((item) => (
|
|
<li>
|
|
<a
|
|
href={item.href}
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
|
class="headline aria-[current=page]:decoration-accent block py-2 text-4xl decoration-4 underline-offset-8 aria-[current=page]:underline"
|
|
>
|
|
{item.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</Container>
|
|
</nav>
|
|
</header>
|