- Neues Rabatt-System: Prozent-/Betrag-Rabatt mit optionalem Ablaufdatum, Mengenrabatt-Staffel pro Produkt, sowie site-weite Gutscheincodes. Wird live im Warenkorb/Checkout berechnet (src/data/rabatt.ts, src/data/gutscheine.ts, cart.ts) und ist im Adminbereich direkt unter dem Preis bearbeitbar (config.yml: "Rabatte" + neue Collection "Gutscheincodes"). Effektiver Preis + Rabatt-Badge auf Produktkarten und Produktseite sichtbar. - Mengen-Stepper auf der Produktseite vergrößert (bereits vorbereitet, jetzt mit Build/Test verifiziert). - Zahlungsart im Checkout auf Platz 1, mit markenfarbigen, fertig gestalteten Buttons (PayPal/Klarna/Banküberweisung). - Unterkategorie-Seiten zeigen jetzt VanVans eigene Produktbeschreibung und das echte Fotos des Produkts statt Platzhaltertext, mit kleinem Link zur HasiDog-Universum-Seite statt großem Button. Verifiziert per Puppeteer-Funktionstest gegen den echten Production-Build (Rabatt-Berechnung, Mengenrabatt, Gutschein-Einlösung, Checkout-Summary, keine Konsolenfehler).
256 lines
11 KiB
YAML
256 lines
11 KiB
YAML
backend:
|
||
name: github
|
||
repo: vans-diy-bastelbedarf/website
|
||
branch: main
|
||
base_url: https://vans-diy-bastelbedarf-cms-auth.dogfather1608.workers.dev
|
||
|
||
logo:
|
||
src: /logo.png
|
||
|
||
app_title: "Van's Shop – Adminbereich"
|
||
|
||
# Bilder, die VanVan hier hochlädt, landen automatisch hier im Projekt und sind danach
|
||
# unter /img/products/<dateiname> auf der Website erreichbar.
|
||
media_folder: "public/img/products"
|
||
public_folder: "/img/products"
|
||
|
||
collections:
|
||
- name: products
|
||
label: Produkte
|
||
label_singular: Produkt
|
||
icon: shopping_bag
|
||
folder: src/content/products
|
||
create: true
|
||
delete: true
|
||
slug: "{{fields.slug}}"
|
||
identifier_field: slug
|
||
extension: json
|
||
format: json
|
||
summary: "{{name.de}} — {{preis}} €"
|
||
fields:
|
||
- label: "📷 Fotos"
|
||
name: bilder
|
||
widget: list
|
||
required: false
|
||
hint: "Hier Fotos hochladen oder per Drag & Drop reinziehen. Das erste Foto ist das Hauptbild, das überall zuerst angezeigt wird."
|
||
field: { label: Foto, name: bild, widget: image }
|
||
- label: Name
|
||
name: name
|
||
widget: object
|
||
fields:
|
||
- { label: Deutsch, name: de, widget: string }
|
||
- { label: Englisch, name: en, widget: string }
|
||
- { label: "Schweizerdeutsch", name: ch, widget: string }
|
||
- { label: Französisch, name: fr, widget: string }
|
||
- label: Beschreibung
|
||
name: beschreibung
|
||
widget: object
|
||
fields:
|
||
- { label: Deutsch, name: de, widget: text }
|
||
- { label: Englisch, name: en, widget: text }
|
||
- { label: "Schweizerdeutsch", name: ch, widget: text }
|
||
- { label: Französisch, name: fr, widget: text }
|
||
- label: "Preis (€)"
|
||
name: preis
|
||
widget: number
|
||
value_type: float
|
||
step: 0.01
|
||
hint: "Der ganz normale Verkaufspreis, z.B. 19.99"
|
||
- label: "Reduzierter Preis? (nur ausfüllen, wenn im Sale)"
|
||
name: preisAlt
|
||
widget: number
|
||
value_type: float
|
||
step: 0.01
|
||
required: false
|
||
hint: "Hier den ALTEN, höheren Preis eintragen — er wird dann durchgestrichen neben dem neuen Preis angezeigt. Leer lassen, wenn kein Sale."
|
||
- label: "🏷️ Rabatte (optional — alles leer lassen, wenn kein automatischer Rabatt gelten soll)"
|
||
name: rabatt
|
||
widget: object
|
||
required: false
|
||
hint: "Zusätzlich zum 'Reduzierten Preis' oben kannst du hier einen automatischen Rabatt einrichten, der von selbst wieder abläuft, sowie einen Mengenrabatt (z.B. ab 3 Stück günstiger)."
|
||
fields:
|
||
- { label: "Rabatt in Prozent (z.B. 20 für 20%)", name: prozent, widget: number, value_type: int, required: false, hint: "Nur ausfüllen ODER den Betrag unten — nicht beides." }
|
||
- { label: "ODER: Rabatt als fester Betrag (€)", name: betrag, widget: number, value_type: float, step: 0.01, required: false }
|
||
- { label: "Rabatt gültig bis (leer = läuft nicht automatisch ab)", name: bis, widget: date, format: "YYYY-MM-DD", required: false, hint: "Nach diesem Datum verschwindet der Rabatt automatisch — ohne dass du etwas tun musst." }
|
||
- label: "Mengenrabatt-Staffel (z.B. ab 3 Stück 10% Rabatt)"
|
||
name: mengenrabatt
|
||
widget: list
|
||
required: false
|
||
summary: "ab {{fields.abMenge}} Stück → -{{fields.prozent}}%"
|
||
hint: "Gilt automatisch im Warenkorb, wenn jemand mehrere Stück dieses Produkts kauft."
|
||
fields:
|
||
- { label: "Ab wie vielen Stück", name: abMenge, widget: number, value_type: int }
|
||
- { label: "Rabatt in Prozent", name: prozent, widget: number, value_type: int }
|
||
- label: "Auf Lager"
|
||
name: bestand
|
||
widget: number
|
||
value_type: int
|
||
hint: "Wie viele Stück hast du vorrätig? 0 = ausverkauft (Artikel bleibt trotzdem sichtbar)."
|
||
- label: Kategorie
|
||
name: kategorie
|
||
widget: relation
|
||
collection: categories
|
||
search_fields: ["name.de"]
|
||
value_field: "slug"
|
||
display_fields: ["name.de"]
|
||
- label: "Unterkategorie (optional)"
|
||
name: unterkategorie
|
||
widget: string
|
||
required: false
|
||
hint: "Interner Code der Unterkategorie eintragen, z.B. kuh-frieda (siehe Bereich Kategorien)"
|
||
- label: Auszeichnungen
|
||
name: badges
|
||
widget: select
|
||
multiple: true
|
||
required: false
|
||
hint: "Erscheinen als kleine Sticker auf dem Produktbild"
|
||
options:
|
||
- { label: "✨ Neu", value: neu }
|
||
- { label: "🔥 Bestseller", value: bestseller }
|
||
- { label: "🏷️ Im Sale", value: sale }
|
||
- { label: "🧶 Handgemacht", value: handgemacht }
|
||
- { label: Artikelnummer, name: artikelnummer, widget: string, required: false }
|
||
- { label: Material, name: material, widget: string, required: false }
|
||
- { label: "Größe / Maße", name: groesse, widget: string, required: false }
|
||
- label: Farben
|
||
name: farben
|
||
widget: list
|
||
required: false
|
||
hint: "Eine Farbe pro Zeile, z.B. Lavendel"
|
||
- { label: Lieferumfang, name: lieferumfang, widget: string, required: false }
|
||
- { label: Pflegehinweise, name: pflegehinweise, widget: string, required: false }
|
||
- { label: Lieferzeit, name: lieferzeit, widget: string, required: false }
|
||
- label: "🚚 Eigene Versandkosten (nur für Einzelkauf dieses Produkts)"
|
||
name: versand
|
||
widget: object
|
||
required: false
|
||
hint: "Gilt NUR, wenn jemand genau 1 Stück von genau diesem Produkt kauft. Bei mehreren Produkten/Stück im Warenkorb gilt automatisch die allgemeine Versandkosten-Staffel (siehe Bereich 'Versandkosten-Staffel'). Leer lassen = Staffel gilt auch beim Einzelkauf."
|
||
fields:
|
||
- { label: "Deutschland (€)", name: de, widget: number, value_type: float, step: 0.01, required: false }
|
||
- { label: "Österreich (€)", name: at, widget: number, value_type: float, step: 0.01, required: false }
|
||
- { label: "Schweiz (€)", name: ch, widget: number, value_type: float, step: 0.01, required: false }
|
||
- { label: "Luxemburg (€)", name: lu, widget: number, value_type: float, step: 0.01, required: false }
|
||
- label: "Interner Code (URL) — nach Veröffentlichung nicht mehr ändern!"
|
||
name: slug
|
||
widget: string
|
||
hint: "Nur Kleinbuchstaben, Zahlen und Bindestriche, z.B. wolke-plushie-lavendel"
|
||
|
||
- name: categories
|
||
label: Kategorien
|
||
label_singular: Kategorie
|
||
icon: category
|
||
folder: src/content/categories
|
||
create: true
|
||
delete: false
|
||
slug: "{{fields.slug}}"
|
||
identifier_field: slug
|
||
extension: json
|
||
format: json
|
||
summary: "{{name.de}}"
|
||
fields:
|
||
- label: "Icon (Emoji)"
|
||
name: icon
|
||
widget: string
|
||
hint: "z.B. 🧸"
|
||
- label: Name
|
||
name: name
|
||
widget: object
|
||
fields:
|
||
- { label: Deutsch, name: de, widget: string }
|
||
- { label: Englisch, name: en, widget: string }
|
||
- { label: "Schweizerdeutsch", name: ch, widget: string }
|
||
- { label: Französisch, name: fr, widget: string }
|
||
- label: Beschreibung
|
||
name: description
|
||
widget: object
|
||
fields:
|
||
- { label: Deutsch, name: de, widget: text }
|
||
- { label: Englisch, name: en, widget: text }
|
||
- { label: "Schweizerdeutsch", name: ch, widget: text }
|
||
- { label: Französisch, name: fr, widget: text }
|
||
- label: Unterkategorien
|
||
name: subcategories
|
||
widget: list
|
||
required: false
|
||
summary: "{{fields.name.de}}"
|
||
fields:
|
||
- { label: "Interner Code (URL)", name: slug, widget: string }
|
||
- label: Name
|
||
name: name
|
||
widget: object
|
||
fields:
|
||
- { label: Deutsch, name: de, widget: string }
|
||
- { label: Englisch, name: en, widget: string }
|
||
- { label: "Schweizerdeutsch", name: ch, widget: string }
|
||
- { label: Französisch, name: fr, widget: string }
|
||
- label: "Reihenfolge (0 = zuerst)"
|
||
name: order
|
||
widget: number
|
||
value_type: int
|
||
- label: "Interner Code (URL) — nach Veröffentlichung nicht mehr ändern!"
|
||
name: slug
|
||
widget: string
|
||
|
||
- name: versandkosten
|
||
label: "🚚 Versandkosten-Staffel"
|
||
icon: local_shipping
|
||
files:
|
||
- name: staffel
|
||
label: "Versandkosten-Staffel nach Warenwert"
|
||
file: src/content/versandstaffel.json
|
||
description: >
|
||
Gilt automatisch im Warenkorb/an der Kasse, sobald jemand mehrere Produkte oder
|
||
mehrere Stück kauft (bei genau 1 Stück von 1 Produkt gilt stattdessen der eigene
|
||
Versandpreis am Produkt, falls dort einer eingetragen ist). Ab 75 € Warenwert ist der
|
||
Versand immer kostenlos, unabhängig von dieser Tabelle.
|
||
fields:
|
||
- label: Deutschland
|
||
name: de
|
||
widget: list
|
||
summary: "ab {{fields.abWarenwert}} € → {{fields.kosten}} €"
|
||
fields:
|
||
- { label: "Ab Warenwert (€)", name: abWarenwert, widget: number, value_type: float, step: 0.01 }
|
||
- { label: "Versandkosten (€)", name: kosten, widget: number, value_type: float, step: 0.01 }
|
||
- label: Österreich
|
||
name: at
|
||
widget: list
|
||
summary: "ab {{fields.abWarenwert}} € → {{fields.kosten}} €"
|
||
fields:
|
||
- { label: "Ab Warenwert (€)", name: abWarenwert, widget: number, value_type: float, step: 0.01 }
|
||
- { label: "Versandkosten (€)", name: kosten, widget: number, value_type: float, step: 0.01 }
|
||
- label: Schweiz
|
||
name: ch
|
||
widget: list
|
||
summary: "ab {{fields.abWarenwert}} € → {{fields.kosten}} €"
|
||
fields:
|
||
- { label: "Ab Warenwert (€)", name: abWarenwert, widget: number, value_type: float, step: 0.01 }
|
||
- { label: "Versandkosten (€)", name: kosten, widget: number, value_type: float, step: 0.01 }
|
||
- label: Luxemburg
|
||
name: lu
|
||
widget: list
|
||
summary: "ab {{fields.abWarenwert}} € → {{fields.kosten}} €"
|
||
fields:
|
||
- { label: "Ab Warenwert (€)", name: abWarenwert, widget: number, value_type: float, step: 0.01 }
|
||
- { label: "Versandkosten (€)", name: kosten, widget: number, value_type: float, step: 0.01 }
|
||
|
||
- name: gutscheine
|
||
label: "🎟️ Gutscheincodes"
|
||
icon: local_offer
|
||
files:
|
||
- name: codes
|
||
label: "Gutscheincodes"
|
||
file: src/content/gutscheine.json
|
||
description: >
|
||
Codes, die Kund:innen im Warenkorb/an der Kasse eingeben können, um Rabatt auf den
|
||
gesamten Warenwert zu bekommen (z.B. für Aktionen, Newsletter, Stammkund:innen).
|
||
fields:
|
||
- label: Gutscheincodes
|
||
name: codes
|
||
widget: list
|
||
summary: "{{fields.code}}"
|
||
fields:
|
||
- { label: "Code (z.B. WILLKOMMEN10)", name: code, widget: string, hint: "Groß-/Kleinschreibung ist egal — wird automatisch angepasst." }
|
||
- { label: "Rabatt in Prozent (z.B. 10 für 10%)", name: prozent, widget: number, value_type: int, required: false }
|
||
- { label: "ODER: Rabatt als fester Betrag (€)", name: betrag, widget: number, value_type: float, step: 0.01, required: false }
|
||
- { label: "Gültig bis (leer = unbegrenzt)", name: bis, widget: date, format: "YYYY-MM-DD", required: false }
|