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:
199
pages/index.vue
Normal file
199
pages/index.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<main class="pt-0">
|
||||
<h1 class="sr-only">MUELLERPRINTS — Handgefertigte Notizbücher aus Stuttgart</h1>
|
||||
<Hero />
|
||||
|
||||
<!-- First cover section -->
|
||||
<section v-if="covers[0]" class="my-20 lg:container mx-auto px-6">
|
||||
<Heading v-if="covers[0]?.name" :level="2" html-tag="h2">{{ covers[0].name }}</Heading>
|
||||
<p v-if="covers[0]?.copyText?.details" class="leading-6 tracking-tight xl:w-2/3" v-html="covers[0].copyText.details" />
|
||||
<div class="mt-8">
|
||||
<ClientOnly>
|
||||
<LazyCarousel>
|
||||
<Slide v-for="(item, j) in covers[0]?.products" :key="j">
|
||||
<ProductCard :product="item" />
|
||||
</Slide>
|
||||
</LazyCarousel>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Storytelling: Handwerk aus Stuttgart -->
|
||||
<FeatureModule
|
||||
eyebrow="Handwerk aus Stuttgart"
|
||||
headline="Jedes Notizbuch ein Unikat"
|
||||
subtitle="Tradition trifft Nachhaltigkeit"
|
||||
:body="`
|
||||
In unserer Werkstatt verbinden wir <strong>traditionelle Buchbindekunst</strong> mit modernem Design.
|
||||
Jedes Notizbuch wird von Hand gebunden – mit Fadenheftung, die ein flaches Aufschlagen ermöglicht.
|
||||
Wir verwenden ausschließlich <strong>100% Recyclingpapier</strong> aus deutscher Produktion.
|
||||
`"
|
||||
:image="productionImage01"
|
||||
class="bg-gray-50"
|
||||
/>
|
||||
|
||||
<!-- Remaining cover sections with alternating backgrounds -->
|
||||
<template v-for="(coverData, i) in covers.slice(1)" :key="i">
|
||||
<section :class="['my-20 lg:container mx-auto px-6']">
|
||||
<Heading v-if="coverData?.name" :level="2" html-tag="h2">{{ coverData.name }}</Heading>
|
||||
<p v-if="coverData?.copyText?.details" class="leading-6 tracking-tight xl:w-2/3" v-html="coverData.copyText.details" />
|
||||
<div class="mt-8">
|
||||
<ClientOnly>
|
||||
<LazyCarousel>
|
||||
<Slide v-for="(item, j) in coverData?.products" :key="j">
|
||||
<ProductCard :product="item" />
|
||||
</Slide>
|
||||
</LazyCarousel>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="py-16 bg-gray-900 text-white">
|
||||
<div class="container mx-auto px-6 text-center">
|
||||
<h3 class="text-3xl lg:text-4xl font-bebas mb-4">Premium Notizbücher für kreative Köpfe</h3>
|
||||
<p class="text-lg opacity-80 max-w-2xl mx-auto mb-8">
|
||||
Erfahre wie unsere handgefertigten Notizbücher aus recyceltem Papier hergestellt werden
|
||||
</p>
|
||||
<NuxtLink
|
||||
to="/notebooks"
|
||||
class="inline-block px-8 py-3 rounded-full font-medium bg-white text-gray-900 hover:bg-gray-200 transition-all duration-200"
|
||||
@click="trackEvent('start-page-cta-clicked')"
|
||||
>
|
||||
Jetzt entdecken
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Testimonials (hidden for now)
|
||||
<section v-if="testimonials?.length > 0" class="px-6 lg:container mx-auto mt-20 mb-32">
|
||||
<div class="text-center mb-10">
|
||||
<h3 class="text-2xl font-bold mb-3">Was unsere Kunden sagen</h3>
|
||||
<p class="text-gray-600 max-w-2xl mx-auto">Erfahrungen und Bewertungen von zufriedenen Kunden</p>
|
||||
</div>
|
||||
<LazyTestimonial
|
||||
:testimonials="testimonials"
|
||||
:show-title="false"
|
||||
:show-rating="true"
|
||||
:show-avatar="false"
|
||||
:show-quote-icon="true"
|
||||
primary-color="#374151"
|
||||
star-color="#374151"
|
||||
/>
|
||||
</section>
|
||||
-->
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Slide } from "vue3-carousel";
|
||||
import productionImage01 from "~/assets/production/01.png";
|
||||
import { trackEvent } from "~/utils/trackEvent";
|
||||
import { scrollProgress } from "~/utils/scrollProgress";
|
||||
import type { Testimonial } from "~/types";
|
||||
|
||||
const shopApi = useShopApi();
|
||||
|
||||
// Fetch covers with their products
|
||||
const { data: coversData } = await useAsyncData("landing-covers", async () => {
|
||||
try {
|
||||
const { data } = await shopApi.getProductCovers();
|
||||
const covers = await Promise.all(
|
||||
data.map(async (cover: any) => {
|
||||
const productsResponse = await shopApi.getCheapestProducts(cover.id, 1, 10);
|
||||
return {
|
||||
id: cover.id,
|
||||
name: cover.attributes?.name,
|
||||
sort: cover.attributes?.sort ?? 0,
|
||||
copyText: cover.attributes?.copyText,
|
||||
products: productsResponse?.data ?? []
|
||||
};
|
||||
})
|
||||
);
|
||||
return covers
|
||||
.filter((c) => c.products.length > 0)
|
||||
.sort((a, b) => a.sort - b.sort);
|
||||
} catch (error) {
|
||||
console.error("Error fetching covers:", error);
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const covers = computed(() => coversData.value ?? []);
|
||||
|
||||
// Testimonials
|
||||
const testimonials: Testimonial[] = [
|
||||
{
|
||||
name: "Maria S.",
|
||||
purpose: "Skizzenbuch",
|
||||
comment: "Endlich ein Papier, das meine Aquarellstifte aushält. Kein Durchdrücken, nichts wellt sich. Hab schon das dritte bestellt.",
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: "Thomas W.",
|
||||
purpose: "Tagebuch",
|
||||
comment: "Schreibe seit Jahren Tagebuch und das hier ist mit Abstand das beste Notizbuch, das ich hatte. Liegt super in der Hand.",
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: "Julia B.",
|
||||
purpose: "Studium",
|
||||
comment: "Benutze es für Vorlesungsmitschriften. Das Papier ist top, mein Füller schmiert nicht.",
|
||||
rating: 4
|
||||
},
|
||||
{
|
||||
name: "Sophia K.",
|
||||
purpose: "Bullet Journal",
|
||||
comment: "Die Bindung ist echt gut, das Buch bleibt flach liegen beim Schreiben. Und ich mag, dass es in Deutschland hergestellt wird.",
|
||||
rating: 5
|
||||
}
|
||||
];
|
||||
|
||||
// Scroll tracking
|
||||
const hasScrolled50 = ref(false);
|
||||
const hasScrolled100 = ref(false);
|
||||
|
||||
function trackScrolling() {
|
||||
if (hasScrolled100.value) return;
|
||||
|
||||
const progress = scrollProgress();
|
||||
|
||||
if (progress >= 50 && !hasScrolled50.value) {
|
||||
trackEvent("start-page-scrolled-50");
|
||||
hasScrolled50.value = true;
|
||||
}
|
||||
|
||||
if (progress === 100) {
|
||||
trackEvent("start-page-scrolled-100");
|
||||
hasScrolled100.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle dark mode for hero section
|
||||
const toggleDarkMode = inject<(value: boolean) => void>("toggleDarkMode");
|
||||
|
||||
onMounted(() => {
|
||||
toggleDarkMode?.(true);
|
||||
window.addEventListener("scroll", trackScrolling);
|
||||
|
||||
// Track start page view
|
||||
trackEvent("start-page-viewed", {
|
||||
coverCount: covers.value.length
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
toggleDarkMode?.(false);
|
||||
window.removeEventListener("scroll", trackScrolling);
|
||||
});
|
||||
|
||||
// SEO Meta
|
||||
useSeoMeta({
|
||||
title: "MUELLERPRINTS - Handgefertigte Notizbücher aus Stuttgart",
|
||||
description: "Handgefertigte Notizbücher mit 100% Recyclingpapier, traditioneller Fadenheftung und einzigartigen Einbanddesigns. Made in Stuttgart.",
|
||||
ogTitle: "MUELLERPRINTS - Handgefertigte Notizbücher",
|
||||
ogDescription: "Handgefertigte Notizbücher mit 100% Recyclingpapier, traditioneller Fadenheftung und einzigartigen Einbanddesigns.",
|
||||
ogType: "website"
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user