diff --git a/public/admin/config.yml b/public/admin/config.yml index 762aaab..6cbbb6c 100644 --- a/public/admin/config.yml +++ b/public/admin/config.yml @@ -45,6 +45,11 @@ collections: 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 Kategorien-Bereich)" - { label: "Preis (in Euro)", name: preis, widget: number, value_type: float, step: 0.01 } - label: "Alter Preis (nur ausfüllen, wenn im Sale)" name: preisAlt diff --git a/src/content/categories/diy-plushies.json b/src/content/categories/diy-plushies.json index f4a6962..fb8e685 100644 --- a/src/content/categories/diy-plushies.json +++ b/src/content/categories/diy-plushies.json @@ -8,10 +8,10 @@ "fr": "Peluches DIY" }, "description": { - "de": "Handgenähte Kuscheltiere und Plüschfiguren – jedes Stück ein Unikat.", - "en": "Hand-sewn stuffed animals and plush figures – every piece a one-of-a-kind.", - "ch": "Vo Hang gnähti Kuscheltier und Plüschfigure – jedes Sächeli es Unikat.", - "fr": "Peluches et figurines cousues à la main – chaque pièce est unique." + "de": "Handgefertigte Kuscheltiere und Plüschfiguren – jedes Stück ein Unikat.", + "en": "Handcrafted stuffed animals and plush figures – every piece a one-of-a-kind.", + "ch": "Vo Hang gmachti Kuscheltier und Plüschfigure – jedes Sächeli es Unikat.", + "fr": "Peluches et figurines fabriquées à la main – chaque pièce est unique." }, "icon": "🧸", "subcategories": [ @@ -22,6 +22,12 @@ "en": "Cow \"Frieda\"", "ch": "Kuh „Frieda”", "fr": "Vache « Frieda »" + }, + "vorstellung": { + "de": "Hallo, ich bin Frieda.\nIch liebe blühende Wiesen und sammle jeden Tag die schönsten Glücksmomente. Mit meinem sanften Herzen erinnere ich dich daran, dass die schönsten Dinge oft ganz leise entstehen.", + "en": "Hello, I'm Frieda.\nI love blooming meadows and collect the sweetest little moments of happiness every day. With my gentle heart, I remind you that the most beautiful things often happen quietly.", + "ch": "Hoi, ig bi d'Frieda.\nIg liebe blüehendi Wise und sammle jede Tag die schönste Glücksmomänt. Mit mim sanfte Härz erinner ig di dra, dass die schönschte Sache oft ganz leis entstöh.", + "fr": "Bonjour, je suis Frieda.\nJ'aime les prairies fleuries et je récolte chaque jour les plus beaux instants de bonheur. Avec mon cœur tendre, je te rappelle que les plus belles choses naissent souvent tout en douceur." } }, { @@ -31,7 +37,14 @@ "en": "Bunny \"HasiDog\"", "ch": "Hase „HasiDog”", "fr": "Lapin « HasiDog »" - } + }, + "vorstellung": { + "de": "Hallo, ich bin HasiDog.\nIch bin klein, knuffig, wuschelig und verspielt, aber auch ein großer, frecher Abenteurer.", + "en": "Hello, I'm HasiDog.\nI'm small, cuddly, fluffy and playful — but also a big, cheeky adventurer.", + "ch": "Hoi, ig bi dr HasiDog.\nIg bi chli, härzig, wuschelig und verspielt, aber o en grosse, freche Abentürer.", + "fr": "Bonjour, je suis HasiDog.\nJe suis petit, tout doux, ébouriffé et joueur — mais aussi un grand aventurier un brin coquin." + }, + "mehrLink": "/hasidog/" }, { "slug": "wal-sam", @@ -40,6 +53,12 @@ "en": "Whale \"Sam\"", "ch": "Wal „Sam”", "fr": "Baleine « Sam »" + }, + "vorstellung": { + "de": "Hallo, ich bin Sam.\nIch träume von großen Abenteuern im tiefblauen Meer und trage dabei unzählige Geschichten in meinem Herzen. Egal wohin die Reise geht – ich schwimme als treuer Freund immer an deiner Seite.", + "en": "Hello, I'm Sam.\nI dream of great adventures in the deep blue sea, carrying countless stories in my heart. Wherever the journey leads, I'll always be swimming loyally by your side.", + "ch": "Hoi, ig bi dr Sam.\nIg treume vo grosse Abentür im tiefblaue Meer und trage derbi zahllosi Gschichte i mim Härz. Wo o immer d'Reis higoht – ig schwimme als treue Fründ immer a dinere Site.", + "fr": "Bonjour, je suis Sam.\nJe rêve de grandes aventures dans les profondeurs bleues de l'océan, portant d'innombrables histoires dans mon cœur. Où que le voyage te mène, je nage toujours fidèlement à tes côtés." } }, { @@ -49,6 +68,12 @@ "en": "Octopus \"Siggi\"", "ch": "Oktopus „Siggi”", "fr": "Poulpe « Siggi »" + }, + "vorstellung": { + "de": "Hallo, ich bin Siggi.\nIch habe immer alle Arme voll zu tun, finde aber trotzdem Zeit für eine liebevolle Umarmung. Mit meiner fröhlichen Art zaubere ich dir selbst an grauen Tagen ein Lächeln ins Gesicht.", + "en": "Hello, I'm Siggi.\nMy arms are always full, but I still find time for a loving hug. With my cheerful nature, I can bring a smile to your face even on grey days.", + "ch": "Hoi, ig bi dr Siggi.\nIg ha immer alli Arm voll z'tue, find aber trotzdäm Zit für e liebevolli Umarmig. Mit minere fröhleche Art zauberi der sogar a graue Täg es Lächle is Gsicht.", + "fr": "Bonjour, je suis Siggi.\nJ'ai toujours les bras occupés, mais je trouve quand même le temps pour un câlin plein de tendresse. Avec ma bonne humeur, je fais naître un sourire même les jours gris." } }, { @@ -58,6 +83,12 @@ "en": "Turtle \"Gaby\"", "ch": "Schildchröte „Gaby”", "fr": "Tortue « Gaby »" + }, + "vorstellung": { + "de": "Hallo, ich bin Gaby.\nIch zeige, dass man nichts überstürzen muss, denn jedes Ziel erreicht man Schritt für Schritt. Mit meiner ruhigen Art schenke ich Geborgenheit und Gelassenheit.", + "en": "Hello, I'm Gaby.\nI show that there's no need to rush — every goal is reached step by step. With my calm nature, I bring comfort and ease.", + "ch": "Hoi, ig bi d'Gaby.\nIg zeig, dass me nüt überstürze muess, wills jedes Ziel Schritt für Schritt erreicht wird. Mit minere ruhige Art schänke ig Gborgeheit und Gelassehei.", + "fr": "Bonjour, je suis Gaby.\nJe montre qu'il ne faut rien précipiter, car chaque but s'atteint pas à pas. Avec mon calme, j'apporte réconfort et sérénité." } }, { @@ -67,6 +98,12 @@ "en": "Penguin \"Pingi\"", "ch": "Pinguin „Pingi”", "fr": "Pingouin « Pingi »" + }, + "vorstellung": { + "de": "Hallo, ich bin Pingi.\nIch liebe Schnee, Eis und warme Umarmungen gleichermaßen. Ich beweise jeden Tag, dass ein großes Herz auch im kältesten Winter für Wärme sorgen kann.", + "en": "Hello, I'm Pingi.\nI love snow, ice, and warm hugs in equal measure. Every day I prove that a big heart can bring warmth, even in the coldest winter.", + "ch": "Hoi, ig bi dr Pingi.\nIg lieb Schnee, Eis und warmi Umarmige glich gärn. Ig bewis jede Tag, dass es grosses Härz o im chalteschte Winter für Wärmi sorge cha.", + "fr": "Bonjour, je suis Pingi.\nJ'aime autant la neige et la glace que les câlins tout doux. Chaque jour, je prouve qu'un grand cœur peut réchauffer même l'hiver le plus froid." } } ] diff --git a/src/content/categories/haekelzubehoer.json b/src/content/categories/haekelzubehoer.json index 82c0f4d..893958c 100644 --- a/src/content/categories/haekelzubehoer.json +++ b/src/content/categories/haekelzubehoer.json @@ -8,10 +8,10 @@ "fr": "Fournitures de crochet" }, "description": { - "de": "Nadeln, Garne und alles, was dein nächstes Häkelprojekt braucht.", - "en": "Hooks, yarn and everything your next crochet project needs.", - "ch": "Nadle, Garn und alles, wo's für dis nächschte Häkelprojekt bruucht.", - "fr": "Crochets, fils et tout ce qu'il faut pour votre prochain projet." + "de": "Maschenmarkierer und vieles, was dein nächstes Häkelprojekt benötigt.", + "en": "Stitch markers and everything else your next crochet project needs.", + "ch": "Masche-Markierer und viel, wo's für dis nächschte Häkelprojekt bruucht.", + "fr": "Marqueurs de mailles et tout ce qu'il faut pour votre prochain projet au crochet." }, "icon": "🪡", "subcategories": [ diff --git a/src/data/categories.ts b/src/data/categories.ts index 2048953..a43c47e 100644 --- a/src/data/categories.ts +++ b/src/data/categories.ts @@ -11,6 +11,11 @@ type LocalizedText = Record; export interface Subcategory { slug: string; name: LocalizedText; + // Persönliche Vorstellung des Charakters (z.B. bei DIY-Plushies-Unterkategorien) — optional, + // wird auf der Unterkategorie-Seite als eigene Box unter der Überschrift angezeigt. + vorstellung?: LocalizedText; + // Optionales Ziel für einen "Mehr über ..."-Button (z.B. HasiDog hat eine eigene Seite). + mehrLink?: string; } export interface Category { diff --git a/src/data/products.ts b/src/data/products.ts index 9a10cc6..96f8607 100644 --- a/src/data/products.ts +++ b/src/data/products.ts @@ -16,6 +16,7 @@ export interface Product { name: LocalizedText; artikelnummer?: string; kategorie: string; // slug aus categories.ts + unterkategorie?: string; // optionaler Unterkategorie-Slug aus categories.ts preis: number; // in Euro preisAlt?: number; // falls Sale bestand: number; // 0 = ausverkauft, bleibt trotzdem sichtbar diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts index b5cd344..9ef997b 100644 --- a/src/i18n/ui.ts +++ b/src/i18n/ui.ts @@ -41,7 +41,7 @@ export const ui = { sortNew: "Neu", sortBestseller: "Bestseller", sortPriceAsc: "Preis aufsteigend", sortPriceDesc: "Preis absteigend", resultCount: (n: number) => `${n} Produkt${n === 1 ? "" : "e"}`, noResults: "Keine Produkte gefunden – bitte Filter anpassen.", breadcrumbShop: "Shop", categoryEmpty: "In dieser Kategorie sind aktuell noch keine Produkte hinterlegt – schau bald wieder vorbei.", - categoryLabel: "Kategorie", productSingular: "Produkt", productPlural: "Produkte", sortLabel: "Sortierung", subcategoriesLabel: "Unterkategorien", subcategoryEmpty: "Für diesen Bereich stellt VanVan bald die ersten Produkte ein – schau bald wieder vorbei.", + categoryLabel: "Kategorie", productSingular: "Produkt", productPlural: "Produkte", sortLabel: "Sortierung", subcategoriesLabel: "Unterkategorien", subcategoryEmpty: "Für diesen Bereich stellt VanVan bald die ersten Produkte ein – schau bald wieder vorbei.", moreAbout: "Mehr über", }, sale: { eyebrow: "% Sale", title: "Aktuelle Angebote", lead: "Zeitlich begrenzte Rabatte auf ausgewählte handgemachte Stücke.", @@ -210,7 +210,7 @@ export const ui = { sortNew: "New", sortBestseller: "Bestseller", sortPriceAsc: "Price: low to high", sortPriceDesc: "Price: high to low", resultCount: (n: number) => `${n} product${n === 1 ? "" : "s"}`, noResults: "No products found – please adjust your filters.", breadcrumbShop: "Shop", categoryEmpty: "No products in this category yet – check back soon.", - categoryLabel: "Category", productSingular: "product", productPlural: "products", sortLabel: "Sort by", subcategoriesLabel: "Subcategories", subcategoryEmpty: "VanVan will be adding the first products here soon – check back shortly.", + categoryLabel: "Category", productSingular: "product", productPlural: "products", sortLabel: "Sort by", subcategoriesLabel: "Subcategories", subcategoryEmpty: "VanVan will be adding the first products here soon – check back shortly.", moreAbout: "More about", }, sale: { eyebrow: "% Sale", title: "Current offers", lead: "Time-limited discounts on selected handmade pieces.", @@ -379,7 +379,7 @@ export const ui = { sortNew: "Neu", sortBestseller: "Bestseller", sortPriceAsc: "Pris ufsteigend", sortPriceDesc: "Pris absteigend", resultCount: (n: number) => `${n} Produkt`, noResults: "Kei Produkt gfunde – bitte Filter apasse.", breadcrumbShop: "Shop", categoryEmpty: "In däre Kategorie sind grad no kei Produkt hinterlegt – lueg spöter nomal verbi.", - categoryLabel: "Kategorie", productSingular: "Produkt", productPlural: "Produkt", sortLabel: "Sortiere", subcategoriesLabel: "Unterkategorie", subcategoryEmpty: "Für das da stellt VanVan bald die erschte Produkt i – lueg bald wieder verbi.", + categoryLabel: "Kategorie", productSingular: "Produkt", productPlural: "Produkt", sortLabel: "Sortiere", subcategoriesLabel: "Unterkategorie", subcategoryEmpty: "Für das da stellt VanVan bald die erschte Produkt i – lueg bald wieder verbi.", moreAbout: "Meh über", }, sale: { eyebrow: "% Aktion", title: "Aktuelli Aktion", lead: "Zytlich begrenzti Rabatt uf uswählti, vo Hang gmachti Sächeli.", @@ -548,7 +548,7 @@ export const ui = { sortNew: "Nouveautés", sortBestseller: "Best-sellers", sortPriceAsc: "Prix croissant", sortPriceDesc: "Prix décroissant", resultCount: (n: number) => `${n} produit${n === 1 ? "" : "s"}`, noResults: "Aucun produit trouvé – veuillez ajuster les filtres.", breadcrumbShop: "Boutique", categoryEmpty: "Aucun produit dans cette catégorie pour le moment – repassez bientôt.", - categoryLabel: "Catégorie", productSingular: "produit", productPlural: "produits", sortLabel: "Trier par", subcategoriesLabel: "Sous-catégories", subcategoryEmpty: "VanVan ajoutera bientôt les premiers produits ici – repassez bientôt.", + categoryLabel: "Catégorie", productSingular: "produit", productPlural: "produits", sortLabel: "Trier par", subcategoriesLabel: "Sous-catégories", subcategoryEmpty: "VanVan ajoutera bientôt les premiers produits ici – repassez bientôt.", moreAbout: "En savoir plus sur", }, sale: { eyebrow: "% Soldes", title: "Offres actuelles", lead: "Réductions limitées dans le temps sur une sélection de pièces faites main.", diff --git a/src/pages/ch/hasidog/index.astro b/src/pages/ch/hasidog/index.astro new file mode 100644 index 0000000..52ae484 --- /dev/null +++ b/src/pages/ch/hasidog/index.astro @@ -0,0 +1,34 @@ +--- +import Layout from "../../../layouts/Layout.astro"; +import { getCategory, getSubcategory } from "../../../data/categories"; +import type { Locale } from "../../../i18n/config"; +import { useTranslations } from "../../../i18n/ui"; + +const lang: Locale = "ch"; +const t = useTranslations(lang); +const category = getCategory("diy-plushies")!; +const sub = getSubcategory("diy-plushies", "hase-hasidog")!; +--- + +
+
+
+ Ghäklets Hase-Plushie HasiDog i blaue Latzhose, im Gras + {t.common.handmadeBadge} +
+
+ {category.icon} {category.name[lang]} +

{sub.name[lang]}

+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )} + +
+
+
+
diff --git a/src/pages/ch/shop/[kategorie].astro b/src/pages/ch/shop/[kategorie].astro index dd006c5..4d705cd 100644 --- a/src/pages/ch/shop/[kategorie].astro +++ b/src/pages/ch/shop/[kategorie].astro @@ -17,14 +17,16 @@ const category = getCategory(kategorie!)!; const items = productsByCategory(category.slug); --- -
-
- - -

{category.name[lang]}

-

{category.description[lang]}

-
-
+
+ +
+
+ +

{category.name[lang]}

+

{category.description[lang]}

+
+
+
diff --git a/src/pages/ch/shop/[kategorie]/[unterkategorie].astro b/src/pages/ch/shop/[kategorie]/[unterkategorie].astro index fd6e441..6f0b6b0 100644 --- a/src/pages/ch/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/ch/shop/[kategorie]/[unterkategorie].astro @@ -17,22 +17,30 @@ const category = getCategory(kategorie!)!; const sub = getSubcategory(kategorie!, unterkategorie!)!; --- -
-
- - -

{sub.name[lang]}

-
-
+
+ +
+
+ +

{sub.name[lang]}

+
+
+
+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )}

{t.shop.subcategoryEmpty}

diff --git a/src/pages/ch/shop/index.astro b/src/pages/ch/shop/index.astro index 2bac425..91f5053 100644 --- a/src/pages/ch/shop/index.astro +++ b/src/pages/ch/shop/index.astro @@ -28,7 +28,16 @@ const t = useTranslations(lang);
@@ -58,6 +67,7 @@ const t = useTranslations(lang);
{ - const matchKat = !kat || slot.dataset.kategorie === kat; + const matchKat = !kat + ? true + : kat.startsWith("sub:") + ? slot.dataset.unterkategorie === kat.slice(4) + : slot.dataset.kategorie === kat; const matchPreis = Number(slot.dataset.preis) <= maxPreis; const matchVerfuegbar = !nurVerfuegbar || Number(slot.dataset.bestand) > 0; const show = matchKat && matchPreis && matchVerfuegbar; diff --git a/src/pages/en/hasidog/index.astro b/src/pages/en/hasidog/index.astro new file mode 100644 index 0000000..1e5c2c6 --- /dev/null +++ b/src/pages/en/hasidog/index.astro @@ -0,0 +1,34 @@ +--- +import Layout from "../../../layouts/Layout.astro"; +import { getCategory, getSubcategory } from "../../../data/categories"; +import type { Locale } from "../../../i18n/config"; +import { useTranslations } from "../../../i18n/ui"; + +const lang: Locale = "en"; +const t = useTranslations(lang); +const category = getCategory("diy-plushies")!; +const sub = getSubcategory("diy-plushies", "hase-hasidog")!; +--- + +
+
+
+ Crocheted bunny plushie HasiDog in blue overalls, in the grass + {t.common.handmadeBadge} +
+
+ {category.icon} {category.name[lang]} +

{sub.name[lang]}

+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )} + +
+
+
+
diff --git a/src/pages/en/shop/[kategorie].astro b/src/pages/en/shop/[kategorie].astro index 11d3b73..2c93d2d 100644 --- a/src/pages/en/shop/[kategorie].astro +++ b/src/pages/en/shop/[kategorie].astro @@ -17,14 +17,16 @@ const category = getCategory(kategorie!)!; const items = productsByCategory(category.slug); --- -
-
- - -

{category.name[lang]}

-

{category.description[lang]}

-
-
+
+ +
+
+ +

{category.name[lang]}

+

{category.description[lang]}

+
+
+
diff --git a/src/pages/en/shop/[kategorie]/[unterkategorie].astro b/src/pages/en/shop/[kategorie]/[unterkategorie].astro index 0f6e3b9..21356ad 100644 --- a/src/pages/en/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/en/shop/[kategorie]/[unterkategorie].astro @@ -17,22 +17,30 @@ const category = getCategory(kategorie!)!; const sub = getSubcategory(kategorie!, unterkategorie!)!; --- -
-
- - -

{sub.name[lang]}

-
-
+
+ +
+
+ +

{sub.name[lang]}

+
+
+
+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )}

{t.shop.subcategoryEmpty}

diff --git a/src/pages/en/shop/index.astro b/src/pages/en/shop/index.astro index d28f84f..5715c47 100644 --- a/src/pages/en/shop/index.astro +++ b/src/pages/en/shop/index.astro @@ -28,7 +28,16 @@ const t = useTranslations(lang);
@@ -58,6 +67,7 @@ const t = useTranslations(lang);
{ - const matchKat = !kat || slot.dataset.kategorie === kat; + const matchKat = !kat + ? true + : kat.startsWith("sub:") + ? slot.dataset.unterkategorie === kat.slice(4) + : slot.dataset.kategorie === kat; const matchPreis = Number(slot.dataset.preis) <= maxPreis; const matchVerfuegbar = !nurVerfuegbar || Number(slot.dataset.bestand) > 0; const show = matchKat && matchPreis && matchVerfuegbar; diff --git a/src/pages/fr/hasidog/index.astro b/src/pages/fr/hasidog/index.astro new file mode 100644 index 0000000..dcfe04f --- /dev/null +++ b/src/pages/fr/hasidog/index.astro @@ -0,0 +1,34 @@ +--- +import Layout from "../../../layouts/Layout.astro"; +import { getCategory, getSubcategory } from "../../../data/categories"; +import type { Locale } from "../../../i18n/config"; +import { useTranslations } from "../../../i18n/ui"; + +const lang: Locale = "fr"; +const t = useTranslations(lang); +const category = getCategory("diy-plushies")!; +const sub = getSubcategory("diy-plushies", "hase-hasidog")!; +--- + +
+
+
+ Peluche lapin au crochet HasiDog en salopette bleue, dans l'herbe + {t.common.handmadeBadge} +
+
+ {category.icon} {category.name[lang]} +

{sub.name[lang]}

+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )} + +
+
+
+
diff --git a/src/pages/fr/shop/[kategorie].astro b/src/pages/fr/shop/[kategorie].astro index 7586385..f3a1fcb 100644 --- a/src/pages/fr/shop/[kategorie].astro +++ b/src/pages/fr/shop/[kategorie].astro @@ -17,14 +17,16 @@ const category = getCategory(kategorie!)!; const items = productsByCategory(category.slug); --- -
-
- - -

{category.name[lang]}

-

{category.description[lang]}

-
-
+
+ +
+
+ +

{category.name[lang]}

+

{category.description[lang]}

+
+
+
diff --git a/src/pages/fr/shop/[kategorie]/[unterkategorie].astro b/src/pages/fr/shop/[kategorie]/[unterkategorie].astro index 2b40810..dfaf881 100644 --- a/src/pages/fr/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/fr/shop/[kategorie]/[unterkategorie].astro @@ -17,22 +17,30 @@ const category = getCategory(kategorie!)!; const sub = getSubcategory(kategorie!, unterkategorie!)!; --- -
-
- - -

{sub.name[lang]}

-
-
+
+ +
+
+ +

{sub.name[lang]}

+
+
+
+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )}

{t.shop.subcategoryEmpty}

diff --git a/src/pages/fr/shop/index.astro b/src/pages/fr/shop/index.astro index 7bbd364..2b8595c 100644 --- a/src/pages/fr/shop/index.astro +++ b/src/pages/fr/shop/index.astro @@ -28,7 +28,16 @@ const t = useTranslations(lang);
@@ -58,6 +67,7 @@ const t = useTranslations(lang);
{ - const matchKat = !kat || slot.dataset.kategorie === kat; + const matchKat = !kat + ? true + : kat.startsWith("sub:") + ? slot.dataset.unterkategorie === kat.slice(4) + : slot.dataset.kategorie === kat; const matchPreis = Number(slot.dataset.preis) <= maxPreis; const matchVerfuegbar = !nurVerfuegbar || Number(slot.dataset.bestand) > 0; const show = matchKat && matchPreis && matchVerfuegbar; diff --git a/src/pages/hasidog/index.astro b/src/pages/hasidog/index.astro new file mode 100644 index 0000000..3f34a9c --- /dev/null +++ b/src/pages/hasidog/index.astro @@ -0,0 +1,34 @@ +--- +import Layout from "../../layouts/Layout.astro"; +import { getCategory, getSubcategory } from "../../data/categories"; +import type { Locale } from "../../i18n/config"; +import { useTranslations } from "../../i18n/ui"; + +const lang: Locale = "de"; +const t = useTranslations(lang); +const category = getCategory("diy-plushies")!; +const sub = getSubcategory("diy-plushies", "hase-hasidog")!; +--- + +
+
+
+ Gehäkeltes Hasen-Plushie HasiDog in blauer Latzhose, im Gras + {t.common.handmadeBadge} +
+
+ {category.icon} {category.name[lang]} +

{sub.name[lang]}

+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )} + +
+
+
+
diff --git a/src/pages/shop/[kategorie].astro b/src/pages/shop/[kategorie].astro index 2918f12..fe0b10e 100644 --- a/src/pages/shop/[kategorie].astro +++ b/src/pages/shop/[kategorie].astro @@ -17,14 +17,16 @@ const category = getCategory(kategorie!)!; const items = productsByCategory(category.slug); --- -
-
- - -

{category.name[lang]}

-

{category.description[lang]}

-
-
+
+ +
+
+ +

{category.name[lang]}

+

{category.description[lang]}

+
+
+
diff --git a/src/pages/shop/[kategorie]/[unterkategorie].astro b/src/pages/shop/[kategorie]/[unterkategorie].astro index a3eb901..2b75d33 100644 --- a/src/pages/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/shop/[kategorie]/[unterkategorie].astro @@ -17,22 +17,30 @@ const category = getCategory(kategorie!)!; const sub = getSubcategory(kategorie!, unterkategorie!)!; --- -
-
- - -

{sub.name[lang]}

-
-
+
+ +
+
+ +

{sub.name[lang]}

+
+
+
+ {sub.vorstellung && ( +
+ {sub.vorstellung[lang].split("\n").map((line) =>

{line}

)} +
+ )}

{t.shop.subcategoryEmpty}

diff --git a/src/pages/shop/index.astro b/src/pages/shop/index.astro index 5eb2490..b60517a 100644 --- a/src/pages/shop/index.astro +++ b/src/pages/shop/index.astro @@ -28,7 +28,16 @@ const t = useTranslations(lang);
@@ -58,6 +67,7 @@ const t = useTranslations(lang);
{ - const matchKat = !kat || slot.dataset.kategorie === kat; + const matchKat = !kat + ? true + : kat.startsWith("sub:") + ? slot.dataset.unterkategorie === kat.slice(4) + : slot.dataset.kategorie === kat; const matchPreis = Number(slot.dataset.preis) <= maxPreis; const matchVerfuegbar = !nurVerfuegbar || Number(slot.dataset.bestand) > 0; const show = matchKat && matchPreis && matchVerfuegbar; diff --git a/src/styles/global.css b/src/styles/global.css index f71203b..149630e 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -647,6 +647,20 @@ a:focus-visible, button:focus-visible { } .subcategory-chip:hover { color: var(--c-accent); border-color: color-mix(in srgb, var(--c-accent) 55%, transparent); background: color-mix(in srgb, var(--c-accent) 8%, var(--c-anthracite)); } +/* Persönliche Vorstellung eines Plushie-Charakters auf seiner Unterkategorie-Seite (z.B. + "Hallo, ich bin Frieda ..."). Dezente Box im Kartenstil des Shops, kein neues Designelement. */ +.character-intro { + max-width: 640px; + margin: 1.6rem 0 2rem; + padding: 1.4rem 1.6rem; + border-radius: var(--radius-l); + background: var(--c-anthracite); + border: 1px solid rgba(244, 241, 247, 0.1); + border-left: 3px solid var(--c-accent); +} +.character-intro p { margin: 0; white-space: pre-line; } +.character-intro p:first-child { font-family: var(--font-head); font-weight: 600; color: var(--c-text); margin-bottom: 0.5em; } + /* Seiten-Banner (Shop, Sale, ...): echtes Foto/Grafik als Kopfbild mit Verlauf-Überblendung unten, damit Titel/Text darauf lesbar bleiben — ersetzt die reine Text-Kopfzeile durch ein echtes visuelles Signal, wie im Pflichtenheft für "Bannerplätze" gefordert. */