feat: extract shop from mp/shop — initial libreshop/shop
Some checks failed
Build and publish / build (push) Failing after 19s
Some checks failed
Build and publish / build (push) Failing after 19s
Source moved verbatim from mp/shop/ on 2026-04-29; mp was the first concrete adapter consuming the libreshop toolkit. Builds and publishes git.librete.ch/libreshop/shop on every main / v* push via the standard .gitea/workflows/build.yml shared across libreshop components.
This commit is contained in:
104
components/Header.vue
Normal file
104
components/Header.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<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 })"
|
||||
/>
|
||||
<HeaderNavLink
|
||||
label="Über uns"
|
||||
description="Über MUELLERPRINTS"
|
||||
path="/about"
|
||||
@click="trackEvent('header-item-clicked', { label: 'Über uns' })"
|
||||
/>
|
||||
</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>
|
||||
Reference in New Issue
Block a user