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.
177 lines
5.8 KiB
Vue
177 lines
5.8 KiB
Vue
<template>
|
||
<main>
|
||
<!-- Hero Section -->
|
||
<section class="bg-gray-900 text-white py-16 lg:py-24">
|
||
<div class="container mx-auto px-6 text-center">
|
||
<p class="text-sm uppercase tracking-widest opacity-60 mb-4">Unsere Kollektion</p>
|
||
<h1 class="text-4xl lg:text-5xl font-bebas mb-4">Alle Notizbücher</h1>
|
||
<p class="text-lg opacity-80 max-w-2xl mx-auto">
|
||
Handgefertigte Notizbücher aus Stuttgart – mit 100% Recyclingpapier und traditioneller Fadenheftung.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Category Navigation -->
|
||
<section class="py-8 border-b border-gray-200">
|
||
<div class="container mx-auto px-6">
|
||
<div class="flex flex-wrap justify-center gap-3">
|
||
<NuxtLink
|
||
to="/notebooks"
|
||
class="px-4 py-2 rounded-full text-sm font-medium transition-colors bg-gray-900 text-white"
|
||
>
|
||
Alle
|
||
</NuxtLink>
|
||
<NuxtLink
|
||
v-for="cover in covers"
|
||
:key="cover.id"
|
||
:to="`/notebooks/${cover.slug}`"
|
||
class="px-4 py-2 rounded-full text-sm font-medium transition-colors bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||
>
|
||
{{ cover.name }}
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Products Grid -->
|
||
<section class="py-12 lg:py-16">
|
||
<div class="container mx-auto px-6">
|
||
<!-- Section Header -->
|
||
<div class="flex justify-between items-center mb-8">
|
||
<div>
|
||
<h2 class="text-xl font-semibold">{{ pagination?.total ?? 0 }} Notizbücher</h2>
|
||
<p class="text-sm text-gray-500">Seite {{ currentPage }} von {{ pagination?.pageCount ?? 1 }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Loading State -->
|
||
<div v-if="pending" class="text-center py-12">
|
||
<LoadingSpinner />
|
||
<p class="mt-4 text-gray-500">Produkte werden geladen...</p>
|
||
</div>
|
||
|
||
<!-- Error State -->
|
||
<div v-else-if="error" class="text-center py-12 text-red-600">
|
||
<p>Fehler beim Laden der Produkte</p>
|
||
</div>
|
||
|
||
<!-- Products Grid -->
|
||
<div v-else class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
|
||
<ProductCard v-for="product in products" :key="product.id" :product="normalizeProduct(product)" />
|
||
</div>
|
||
|
||
<!-- Pagination -->
|
||
<div v-if="pagination && pagination.pageCount > 1" class="mt-12 flex justify-center gap-2">
|
||
<NuxtLink
|
||
v-for="pageNum in pagination.pageCount"
|
||
:key="pageNum"
|
||
:to="pageNum === 1 ? '/notebooks' : `/notebooks?page=${pageNum}`"
|
||
class="px-4 py-2 rounded-full text-sm font-medium transition-colors"
|
||
:class="pageNum === currentPage ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'"
|
||
>
|
||
{{ pageNum }}
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Footer CTA -->
|
||
<section class="py-16 bg-gray-50 border-t border-gray-200">
|
||
<div class="container mx-auto px-6 text-center">
|
||
<h3 class="text-2xl font-bold mb-3">Fragen zu unseren Produkten?</h3>
|
||
<p class="text-gray-600 max-w-xl mx-auto mb-6">
|
||
Jedes Notizbuch wird in unserer Stuttgarter Werkstatt von Hand gebunden.
|
||
</p>
|
||
<NuxtLink
|
||
to="/about"
|
||
class="inline-block px-6 py-3 rounded-full font-medium bg-gray-900 text-white hover:bg-gray-700 transition-colors"
|
||
>
|
||
Mehr über uns
|
||
</NuxtLink>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { Product } from "~/types";
|
||
import { slugify } from "~/utils/slugify";
|
||
import { trackEvent } from "~/utils/trackEvent";
|
||
|
||
const route = useRoute();
|
||
const currentPage = computed(() => parseInt(route.query.page as string) || 1);
|
||
|
||
const shopApi = useShopApi();
|
||
|
||
// Fetch products (cheapest variant per cover+pattern)
|
||
const { data, pending, error } = await useAsyncData(
|
||
() => `products-all-page-${currentPage.value}`,
|
||
() => shopApi.getCheapestProducts(undefined, currentPage.value, 20),
|
||
{ watch: [currentPage] }
|
||
);
|
||
|
||
// Fetch covers for category navigation
|
||
const { data: coversData } = await useAsyncData("covers-nav", async () => {
|
||
try {
|
||
const { data } = await shopApi.getProductCovers();
|
||
return data
|
||
.map((cover: any) => ({
|
||
id: cover.id,
|
||
name: cover.attributes?.name,
|
||
slug: slugify(cover.attributes?.name ?? ""),
|
||
sort: cover.attributes?.sort ?? 0
|
||
}))
|
||
.sort((a: any, b: any) => a.sort - b.sort);
|
||
} catch {
|
||
return [];
|
||
}
|
||
});
|
||
|
||
const covers = computed(() => coversData.value ?? []);
|
||
const products = computed(() => data.value?.data ?? []);
|
||
const pagination = computed(() => data.value?.meta?.pagination);
|
||
|
||
// Normalize Strapi response to Product type
|
||
function normalizeProduct(item: any): Product {
|
||
const attrs = item.attributes ?? item;
|
||
return {
|
||
id: item.id,
|
||
name: attrs.name,
|
||
slug: attrs.slug,
|
||
totalProductPrice: attrs.totalProductPrice ?? attrs.price,
|
||
pattern: attrs.pattern?.data ? { id: attrs.pattern.data.id, name: attrs.pattern.data.attributes?.name } : attrs.pattern,
|
||
cover: attrs.cover?.data ? { id: attrs.cover.data.id, name: attrs.cover.data.attributes?.name } : attrs.cover,
|
||
ruling: attrs.ruling?.data ? { id: attrs.ruling.data.id, name: attrs.ruling.data.attributes?.name } : attrs.ruling,
|
||
pages: attrs.pages?.data ? { id: attrs.pages.data.id, name: attrs.pages.data.attributes?.name } : attrs.pages,
|
||
images: attrs.images
|
||
};
|
||
}
|
||
|
||
// SEO
|
||
useSeoMeta({
|
||
title: "Alle Notizbücher | MUELLERPRINTS",
|
||
description: "Entdecken Sie unsere handgefertigten Notizbücher aus Stuttgart mit 100% Recyclingpapier.",
|
||
ogTitle: "Alle Notizbücher | MUELLERPRINTS",
|
||
ogDescription: "Entdecken Sie unsere handgefertigten Notizbücher aus Stuttgart mit 100% Recyclingpapier."
|
||
});
|
||
|
||
// Track category view on mount
|
||
onMounted(() => {
|
||
trackEvent("category-viewed", {
|
||
category: "all",
|
||
page: currentPage.value,
|
||
totalProducts: pagination.value?.total ?? 0
|
||
});
|
||
});
|
||
|
||
// Track pagination clicks
|
||
watch(currentPage, (newPage, oldPage) => {
|
||
if (newPage !== oldPage) {
|
||
trackEvent("category-pagination-clicked", {
|
||
category: "all",
|
||
page: newPage
|
||
});
|
||
}
|
||
});
|
||
</script>
|