Files
shop/components/Header.vue
T
libretech 61a74e649b
build / build (push) Successful in 1m38s
feat(selection): lock single-option boxes, drop the about link
Recovered work in progress that sat uncommitted since 2026-05: a
SelectionBox renders as a plain div instead of a NuxtLink when locked,
so a variant with only one choice reads as decided rather than
clickable, and it reports aria-checked in that state. useProductContent
gained the content lookups the details and index pages now use, the
cookie banner says Schließen instead of Akzeptieren, the Über uns
header entry is gone, and ProductCard's hover shadow no longer relies
on a short-circuit that could yield a non-array.
2026-09-23 22:09:52 +02:00

99 lines
3.6 KiB
Vue

<template>
<header class="text-gray-900 z-50" :class="{ 'bg-white bg-opacity-95 absolute shadow-xl top-0 left-0 right-0 z-[99999]': isDarkMode }">
<div class="xl:container mx-auto lg:text-lg">
<div class="flex flex-col lg:flex-row lg:gap-12 relative">
<div class="flex lg:w-1/4 justify-between">
<NuxtLink to="/" class="max-sm:sticky max-sm:top-0 p-6 py-6 lg:py-7 hover:text-red-600" @click="trackEvent('header-logo-clicked')">
<span class="tracking-wide text-3xl font-bebas leading-none block">
<span class="!text-black">MUELLERPRINTS</span>.<br />Paperwork
</span>
</NuxtLink>
<button @click="toggleMobileMenu()" class="p-6 py-6 lg:py-7 lg:hidden" :class="{ 'bg-white': !isDarkMode }" aria-label="Menü öffnen" :aria-expanded="isMobileMenuOpen">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
</button>
</div>
<div
v-if="route.name"
role="navigation"
class="grow lg:w-3/4 p-6 py-6 lg:py-7 hidden lg:block bg-transparent"
:class="{ '!block bg-white': isMobileMenuOpen, 'text-gray-900': isMobileMenuOpen && isDarkMode }"
>
<nav class="flex justify-end" v-if="isCheckoutRoute" aria-label="Navigation">
<HeaderNavLink v-if="!isPaymentRoute" label="Zurück zum Warenkorb" path="/cart" @click="trackEvent('header-back-to-cart-clicked')" />
</nav>
<nav
class="flex flex-col lg:flex-row justify-between gap-4 lg:gap-28 lg:h-full"
v-else
aria-label="Navigation"
@click="closeMobileMenu()"
>
<div class="flex flex-col lg:flex-row gap-4 lg:gap-2">
<HeaderNavLink
label="Shop"
description="Alle Notizbücher"
path="/notebooks"
@click="trackEvent('header-item-clicked', { label: 'Shop' })"
/>
<HeaderNavLink
v-for="item in sortedCovers"
:key="item.id"
:label="item.label"
:description="item.description"
:path="`/notebooks/${item.slug}`"
@click="trackEvent('header-item-clicked', { label: item.label })"
/>
</div>
<NuxtLink
to="/cart"
class="px-4 py-0.5 rounded-full font-medium text-lg text-black transition-all duration-200 flex items-center gap-2 hover:bg-gray-900 hover:text-white"
active-class="!bg-gray-900 !text-white"
title="Warenkorb"
@click="trackEvent('header-cart-clicked')"
>
Warenkorb
<span
v-if="productsCount > 0"
class="inline-flex items-center justify-center w-5 h-5 text-xs font-semibold rounded-full bg-gray-900 text-white group-hover:bg-white group-hover:text-gray-900"
:class="{ '!bg-white !text-gray-900': $route.path === '/cart' }"
>
{{ productsCount }}
</span>
</NuxtLink>
</nav>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import type { CoverNavItem } from "~/types";
const props = defineProps<{
covers: CoverNavItem[];
isDarkMode?: boolean;
}>();
const route = useRoute();
const { productsCount } = useCart();
const isMobileMenuOpen = ref(false);
const sortedCovers = computed(() => [...props.covers].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)));
const isCheckoutRoute = computed(() => String(route.name).startsWith("checkout-"));
const isPaymentRoute = computed(() => route.name === "checkout-3");
function toggleMobileMenu() {
isMobileMenuOpen.value = !isMobileMenuOpen.value;
}
function closeMobileMenu() {
isMobileMenuOpen.value = false;
}
</script>