Files
pivoine.art/layouts/partials/nav.html
T
2026-04-11 17:51:21 +02:00

133 lines
5.9 KiB
HTML

<header
x-data="{ scrolled: false }"
x-init="window.addEventListener('htmx:pushedIntoHistory', () => { $store.nav.path = window.location.pathname; $store.nav.open = false })"
@scroll.window="scrolled = window.scrollY > 80"
class="fixed top-0 inset-x-0 z-50"
>
<!-- Top bar -->
<div
class="gutter-x flex items-center justify-between py-4 transition-all duration-500"
:class="$store.nav.open || scrolled ? 'bg-ink/95 backdrop-blur-md shadow-[0_1px_0_var(--color-zinc)]' : ''"
>
<!-- Logotype -->
<a href="/" class="logo-glitch flex items-center gap-3 hover:opacity-90 transition-opacity" aria-label="{{ .Site.Params.logoText }} Home">
{{- partial "logo.html" (dict "id" "nav" "class" "h-8 w-auto flex-shrink-0") -}}
<span class="font-display text-2xl md:text-3xl leading-none tracking-wide">
{{- .Site.Params.logoText -}}
</span>
</a>
<!-- Desktop navigation -->
<nav class="hidden md:flex items-center gap-8" aria-label="Primary navigation">
{{- range .Site.Menus.main -}}
{{- $href := .URL -}}
<a
href="{{ $href }}"
class="label relative transition-colors"
:class="($store.nav.path === '{{ $href }}' || ('{{ $href }}' !== '/' && $store.nav.path.startsWith('{{ $href }}'))) ? 'text-heat' : 'text-fog hover:text-chalk'"
>
{{ .Name }}
<span
class="absolute -bottom-0.5 left-0 h-px bg-heat transition-all duration-300 ease-out"
:style="($store.nav.path === '{{ $href }}' || ('{{ $href }}' !== '/' && $store.nav.path.startsWith('{{ $href }}'))) ? 'width: 100%' : 'width: 0'"
style="width: 0"
></span>
</a>
{{- end -}}
</nav>
<!-- Mobile toggle — animated hamburger → X -->
<button
class="md:hidden w-10 h-10 flex flex-col items-center justify-center gap-[6px] text-fog hover:text-chalk transition-colors"
:class="$store.nav.open ? 'text-heat' : ''"
@click="$store.nav.open = !$store.nav.open"
:aria-expanded="$store.nav.open.toString()"
aria-controls="mobile-menu"
aria-label="Toggle navigation"
>
<span class="block h-px w-6 bg-current transition-all duration-300 origin-center"
:class="$store.nav.open ? 'rotate-45 translate-y-[7px]' : ''"></span>
<span class="block h-px w-4 bg-current transition-all duration-200"
:class="$store.nav.open ? 'opacity-0' : 'opacity-100'"></span>
<span class="block h-px w-6 bg-current transition-all duration-300 origin-center"
:class="$store.nav.open ? '-rotate-45 -translate-y-[7px]' : ''"></span>
</button>
</div>
<!-- Fullscreen overlay — teleported to <body> to escape header's stacking context -->
<template x-teleport="body">
<div
id="mobile-menu"
x-show="$store.nav.open"
x-cloak
x-transition:enter="transition duration-300 ease-out"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition duration-200 ease-in"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 z-40 flex flex-col bg-void speed-lines overflow-hidden"
>
<!-- Top spacer (nav bar height) -->
<div class="flex-none h-[65px]"></div>
<div class="gradient-line flex-none"></div>
<!-- Decorative background text -->
<div class="graffiti-tag absolute -bottom-4 -right-4 select-none pointer-events-none"
style="-webkit-text-stroke-color: rgba(155,0,255,0.07);" aria-hidden="true">MENU</div>
<!-- Main nav links -->
<nav class="flex-1 flex flex-col justify-center gutter-x py-10" aria-label="Mobile navigation">
<div class="flex flex-col gap-0">
{{- $i := 0 -}}
{{- range .Site.Menus.main -}}
{{- $href := .URL -}}
<a
href="{{ $href }}"
class="group relative leading-none py-3 overflow-hidden"
style="font-family: var(--font-display); font-size: clamp(2.8rem, 11vw, 6.5rem); animation: mob-link-in 0.5s var(--ease-out-expo) {{ mul $i 70 }}ms both"
@click="$store.nav.open = false"
>
<!-- Hover sweep -->
<span class="absolute inset-y-0 left-0 w-0 group-hover:w-full transition-all duration-300 ease-out"
style="background: linear-gradient(90deg, rgba(255,26,140,0.07), transparent);"></span>
<!-- Link text -->
<span class="relative transition-colors duration-200 text-paper group-hover:text-heat uppercase"
:class="($store.nav.path === '{{ $href }}' || ('{{ $href }}' !== '/' && $store.nav.path.startsWith('{{ $href }}'))) ? 'text-gradient' : ''"
>{{ .Name }}</span>
<!-- Index number -->
<span class="absolute right-0 top-1/2 -translate-y-1/2 label text-smoke group-hover:text-heat transition-colors duration-200"
style="animation: mob-link-in 0.4s var(--ease-out-expo) {{ add (mul $i 70) 100 }}ms both"
>0{{ add $i 1 }}</span>
</a>
{{- $i = add $i 1 -}}
{{- end -}}
</div>
<div class="gradient-line my-8"
style="animation: mob-link-in 0.4s ease {{ mul $i 70 }}ms both"></div>
<div class="flex flex-wrap gap-x-8 gap-y-3"
style="animation: mob-link-in 0.4s ease {{ add (mul $i 70) 40 }}ms both">
{{- range .Site.Menus.footer -}}
<a href="{{ .URL }}" class="label text-fog hover:text-heat transition-colors" @click="$store.nav.open = false">{{ .Name }}</a>
{{- end -}}
</div>
</nav>
<!-- Bottom bar -->
<div class="flex-none gutter-x pb-8 pt-4 border-t border-zinc"
style="animation: mob-link-in 0.4s ease 420ms both">
<p class="label text-smoke">{{ .Site.Params.tagline }}</p>
</div>
</div>
</template>
</header>
<style>
@keyframes mob-link-in {
from { opacity: 0; transform: translateY(14px); }
to { opacity: 1; transform: translateY(0); }
}
</style>