Files
shop/composables/useProductContent.ts
Michael Czechowski 44107c0734
Some checks failed
Build and publish / build (push) Failing after 19s
feat: extract shop from mp/shop — initial libreshop/shop
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.
2026-04-29 17:48:56 +02:00

370 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Product content keyed by cover type
// This content is displayed on product detail pages as storytelling modules
export type CoverType = "Hardcover" | "Softcover" | "Heft" | "Spiralbindung";
export interface FeatureModule {
eyebrow?: string;
headline: string;
subtitle?: string;
body: string;
image?: string;
imageRight?: boolean;
}
export interface UseCase {
icon: "pen" | "palette" | "clipboard" | "briefcase";
title: string;
description: string;
}
// =============================================================================
// FEATURE MODULES - Storytelling sections per cover type
// =============================================================================
export const FEATURE_MODULES: Record<CoverType, FeatureModule[]> = {
Hardcover: [
{
eyebrow: "Handarbeit",
headline: "Klassische Fadenheftung",
subtitle: "Strapazierfähig bei intensivem Gebrauch",
body: `Jedes Heft wird mit Singer-Stich-Heftung von Hand gebunden.
Das Ergebnis: Ein Notizbuch, das sich vollständig flach öffnen
lässt und auch nach Jahren intensiver Nutzung nicht auseinanderfällt.
Der rote Vorsatzbogen setzt einen dezenten Farbakzent
Deine erste Begegnung beim Öffnen.`,
image: "/images/features/hardcover/binding-closeup.jpg",
imageRight: false,
},
{
eyebrow: "100% Recycling",
headline: "VIVUS 89 Papier",
subtitle: "Außergewöhnliche Schreibqualität",
body: `VIVUS 89 ist nicht irgendein Recyclingpapier.
Die matte, ungestrichene Oberfläche mit feiner Textur verhindert
Durchschlagen selbst bei Füllfederhaltern und Aquarellfarben.
Mit 120g/qm und 1,2-fachem Volumen fühlt sich jede Seite
substanziell an, ohne starr zu wirken.`,
image: "/images/features/hardcover/paper-texture.jpg",
imageRight: true,
},
{
headline: "160 Seiten für Deine Ideen",
subtitle: "Raum für 3-6 Monate intensive Arbeit",
body: `160 Seiten bedeuten genug Platz für ein abgeschlossenes Projekt,
eine komplette Reise, oder ein Quartal Deines Bullet Journals.
Blanko-Seiten geben Dir absolute Freiheit: Skizzieren, Schreiben,
Collagieren ohne Raster, das Deine Kreativität einschränkt.`,
image: "/images/features/hardcover/lifestyle-desk.jpg",
imageRight: false,
},
{
headline: "Kein Heft gleicht dem anderen",
subtitle: "13 einzigartige Mustervarianten",
body: `Jeder Einband wird individuell mit variierenden geometrischen
Mustern bedruckt. Die Kombination aus mattem Schwarz (300g/qm Karton)
und den Mustern macht Dein Heft unverwechselbar.`,
image: "/images/features/hardcover/cover-pattern.jpg",
imageRight: true,
},
{
eyebrow: "Made in Stuttgart",
headline: "Transparente Lieferkette",
subtitle: "Messbare Nachhaltigkeit",
body: `<strong>100% Recyclingpapier</strong> (FSC® C018175)<br>
<strong>CO₂-neutral</strong> produziert<br>
<strong>Blauer Engel + EU Ecolabel</strong> zertifiziert<br>
<strong>Hergestellt in Stuttgart</strong>, Deutschland<br><br>
Keine langen Transportwege, keine Ausbeutung, kein Greenwashing.
Nur ehrliches Handwerk mit messbaren Umweltstandards.`,
image: "/images/production/04.png",
imageRight: false,
},
],
Softcover: [
{
eyebrow: "Leicht & Flexibel",
headline: "Der tägliche Begleiter",
subtitle: "Passt in jede Tasche",
body: `Das Softcover ist Dein unkomplizierter Alltagsbegleiter.
Leicht, flexibel und robust perfekt für unterwegs.
Die weiche Hülle schmiegt sich an und übersteht jeden Rucksack.`,
image: "/images/features/softcover/flexible-cover.jpg",
imageRight: false,
},
{
eyebrow: "100% Recycling",
headline: "VIVUS 89 Papier",
subtitle: "Dieselbe Qualität, leichteres Format",
body: `Auch im Softcover kommt unser bewährtes VIVUS 89 Recyclingpapier
zum Einsatz. 120g/qm für optimale Schreibqualität ohne Durchschlagen.
Perfekt für Füllfederhalter, Fineliner und Aquarellstifte.`,
image: "/images/features/softcover/paper-writing.jpg",
imageRight: true,
},
{
headline: "Praktische Steppstich-Bindung",
subtitle: "Liegt flach, bleibt offen",
body: `Die Steppstich-Bindung ermöglicht ein vollständiges Aufklappen.
Ideal zum Schreiben, Zeichnen und für alle, die beide Seiten
gleichzeitig nutzen möchten.`,
image: "/images/features/softcover/binding-detail.jpg",
imageRight: false,
},
{
eyebrow: "Made in Stuttgart",
headline: "Nachhaltig produziert",
subtitle: "Lokale Fertigung, globale Standards",
body: `<strong>FSC® zertifiziert</strong><br>
<strong>Blauer Engel</strong> Umweltzeichen<br>
<strong>CO₂-neutral</strong> hergestellt<br><br>
Kurze Wege, faire Produktion, messbare Nachhaltigkeit.`,
image: "/images/features/softcover/workshop.png",
imageRight: true,
},
],
Heft: [
{
eyebrow: "Kompakt & Praktisch",
headline: "Das klassische Notizheft",
subtitle: "Für schnelle Notizen und Ideen",
body: `Manchmal braucht man kein dickes Notizbuch sondern ein
handliches Heft für den Moment. Perfekt für Meeting-Notizen,
Einkaufslisten oder spontane Skizzen.`,
image: "/images/features/heft/compact-size.jpg",
imageRight: false,
},
{
eyebrow: "100% Recycling",
headline: "Qualität im Kleinformat",
subtitle: "VIVUS 89 auch im Heft",
body: `Unser Recyclingpapier macht auch im kleinen Format keine
Kompromisse. Die gleiche Schreibqualität, die Du von unseren
größeren Notizbüchern kennst.`,
image: "/images/features/heft/paper-quality.jpg",
imageRight: true,
},
{
headline: "Ruckzuck-Heftung",
subtitle: "Einfach, aber solide",
body: `Die klassische Rückstich-Heftung hält Dein Heft zusammen
und ermöglicht ein flaches Aufklappen. Bewährt seit Generationen,
nachhaltig für die Zukunft.`,
image: "/images/features/heft/binding.jpg",
imageRight: false,
},
],
Spiralbindung: [
{
eyebrow: "360° Flexibilität",
headline: "Wire-O-Bindung",
subtitle: "Komplett umklappbar",
body: `Die Spiralbindung lässt sich vollständig umklappen
ideal für beengte Arbeitsflächen. Schreibe auf einer Seite,
während die andere flach auf dem Tisch liegt.`,
image: "/images/features/spiral/360-flip.jpg",
imageRight: false,
},
{
eyebrow: "100% Recycling",
headline: "VIVUS 89 Papier",
subtitle: "Premium-Qualität, flexibles Format",
body: `Unser bewährtes Recyclingpapier in der praktischen
Spiralbindung. 120g/qm verhindern Durchschlagen
auch bei intensiver Nutzung mit verschiedenen Stiften.`,
image: "/images/features/spiral/paper-texture.jpg",
imageRight: true,
},
{
headline: "Seiten heraustrennbar",
subtitle: "Perforation für sauberes Abtrennen",
body: `Jede Seite lässt sich sauber heraustrennen perfekt,
wenn Du Notizen weitergeben oder Skizzen verschenken möchtest.
Die Mikroperforation sorgt für glatte Kanten.`,
image: "/images/features/spiral/tear-out.jpg",
imageRight: false,
},
{
eyebrow: "Made in Stuttgart",
headline: "Nachhaltig & Praktisch",
subtitle: "Das Beste aus beiden Welten",
body: `<strong>Recycling-Drahtbindung</strong><br>
<strong>FSC® zertifiziertes Papier</strong><br>
<strong>CO₂-neutral</strong> produziert<br><br>
Funktionalität trifft Nachhaltigkeit.`,
image: "/images/features/spiral/workshop.jpg",
imageRight: true,
},
],
};
// =============================================================================
// TECHNICAL SPECS - Collapsible details per cover type
// =============================================================================
export const TECHNICAL_SPECS: Record<CoverType, Record<string, string>> = {
Hardcover: {
Format: "150 × 210 mm (A5)",
Seitenanzahl: "160 Seiten (80 Blatt)",
Papier: "VIVUS 89, 120g/qm, 100% Recycling",
Einband: "300g/qm Recyclingkarton",
Bindung: "Klassische Fadenheftung (Singer-Stich)",
Vorsatzpapier: "Rot durchgefärbt",
Zertifizierung: "FSC® C018175, Blauer Engel, EU Ecolabel",
Herstellung: "Stuttgart, Deutschland",
},
Softcover: {
Format: "150 × 210 mm (A5)",
Seitenanzahl: "96 Seiten (48 Blatt)",
Papier: "VIVUS 89, 120g/qm, 100% Recycling",
Einband: "250g/qm Recyclingkarton, flexibel",
Bindung: "Steppstich-Heftung",
Zertifizierung: "FSC® C018175, Blauer Engel, EU Ecolabel",
Herstellung: "Stuttgart, Deutschland",
},
Heft: {
Format: "148 × 210 mm (A5)",
Seitenanzahl: "20, 40 oder 60 Seiten",
Papier: "VIVUS 89, 120g/qm, 100% Recycling",
Einband: "200g/qm Recyclingkarton",
Bindung: "Rückstich-Heftung",
Zertifizierung: "FSC® C018175, Blauer Engel",
Herstellung: "Stuttgart, Deutschland",
},
Spiralbindung: {
Format: "150 × 210 mm (A5)",
Seitenanzahl: "120 Seiten (60 Blatt)",
Papier: "VIVUS 89, 120g/qm, 100% Recycling",
Einband: "300g/qm Recyclingkarton",
Bindung: "Wire-O-Bindung (Doppeldraht)",
Perforation: "Mikroperforation zum Heraustrennen",
Zertifizierung: "FSC® C018175, Blauer Engel, EU Ecolabel",
Herstellung: "Stuttgart, Deutschland",
},
};
// =============================================================================
// USE CASES - Same for all products
// =============================================================================
export const USE_CASES: UseCase[] = [
{
icon: "pen",
title: "Schreibprojekte",
description: "Romane, Tagebuch, Morning Pages",
},
{
icon: "palette",
title: "Mixed-Media",
description: "Aquarell, Collage, Skizzen",
},
{
icon: "clipboard",
title: "Sketchbook",
description: "Layouts ohne Raster",
},
{
icon: "briefcase",
title: "Arbeit & Studium",
description: "Meetings, Forschung, Konzepte",
},
];
// =============================================================================
// HELPER: Get cover type from product.cover.name
// =============================================================================
export function getCoverType(coverName?: string): CoverType {
if (!coverName) return "Hardcover";
const name = coverName.toLowerCase();
if (name.includes("heft")) return "Heft";
if (name.includes("hardcover")) return "Hardcover";
if (name.includes("softcover")) return "Softcover";
if (name.includes("spiral") || name.includes("wire")) return "Spiralbindung";
return "Hardcover"; // fallback
}
// =============================================================================
// COMPOSABLE
// =============================================================================
import type { Product } from "~/types";
export function useProductContent(
coverName: Ref<string | undefined> | ComputedRef<string | undefined>,
product?: Ref<Product | null> | ComputedRef<Product | null>
) {
const coverType = computed(() => getCoverType(coverName.value));
const featureModules = computed(() => FEATURE_MODULES[coverType.value] ?? []);
// Derive technical specs from product data when available
const technicalSpecs = computed(() => {
const baseSpecs = TECHNICAL_SPECS[coverType.value] ?? {};
const prod = product?.value;
if (!prod) return baseSpecs;
const derivedSpecs: Record<string, string> = {};
// Format from copyText
if (prod.cover?.copyText?.format) {
derivedSpecs["Format"] = prod.cover.copyText.format;
}
// Seitenanzahl from pages
if (prod.pages?.name) {
derivedSpecs["Seitenanzahl"] = prod.pages.name;
} else if (prod.pages?.count) {
const sheets = Math.floor(prod.pages.count / 2);
derivedSpecs["Seitenanzahl"] = `${prod.pages.count} Seiten (${sheets} Blatt)`;
}
// Parse paper string: "VIVUS 89: 100% Recyclingpapier, ... Inhalt: 120g/qm, Einband: 300g/qm. Zertifizierung: ..."
if (prod.cover?.copyText?.paper) {
const paperText = prod.cover.copyText.paper;
// Extract paper name and description (before "Inhalt:")
const inhaltMatch = paperText.match(/^(.+?)(?:\s*Inhalt:|$)/);
if (inhaltMatch) {
derivedSpecs["Papier"] = inhaltMatch[1].trim().replace(/,\s*$/, "");
}
// Extract Inhalt (paper weight)
const inhaltWeightMatch = paperText.match(/Inhalt:\s*([^,]+)/);
if (inhaltWeightMatch) {
derivedSpecs["Papiergewicht"] = inhaltWeightMatch[1].trim();
}
// Extract Einband (cover weight)
const einbandMatch = paperText.match(/Einband:\s*([^.]+)/);
if (einbandMatch) {
derivedSpecs["Einband"] = einbandMatch[1].trim();
}
// Extract Zertifizierung
const zertMatch = paperText.match(/Zertifizierung:\s*(.+)$/);
if (zertMatch) {
derivedSpecs["Zertifizierung"] = zertMatch[1].trim();
}
}
// Bindung from cover binding
if (prod.cover?.binding) {
derivedSpecs["Bindung"] = prod.cover.binding;
}
// Merge: product data overrides base specs
return { ...baseSpecs, ...derivedSpecs };
});
return {
coverType,
featureModules,
technicalSpecs,
useCases: USE_CASES,
};
}