diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts index cba482a..b3f85dd 100644 --- a/src/i18n/ui.ts +++ b/src/i18n/ui.ts @@ -45,6 +45,7 @@ export const ui = { 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", mainCategoryLabel: "Hauptkategorie", subcategoryEmpty: "Für diesen Bereich stellt VanVan bald die ersten Produkte ein – schau bald wieder vorbei.", moreAbout: "Mehr über", moreVariants: "Weitere Modelle", + moreAboutCharacterLead: "Wenn du mehr über mich erfahren möchtest, dann klicke", }, sale: { eyebrow: "% Sale", title: "Aktuelle Angebote", lead: "Zeitlich begrenzte Rabatte auf ausgewählte handgemachte Stücke.", @@ -233,6 +234,7 @@ export const ui = { 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", mainCategoryLabel: "Main category", subcategoryEmpty: "VanVan will be adding the first products here soon – check back shortly.", moreAbout: "More about", moreVariants: "More designs", + moreAboutCharacterLead: "If you'd like to learn more about me, click", }, sale: { eyebrow: "% Sale", title: "Current offers", lead: "Time-limited discounts on selected handmade pieces.", @@ -421,6 +423,7 @@ export const ui = { 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", mainCategoryLabel: "Hauptkategorie", subcategoryEmpty: "Für das da stellt VanVan bald die erschte Produkt i – lueg bald wieder verbi.", moreAbout: "Meh über", moreVariants: "Witeri Modell", + moreAboutCharacterLead: "Wenn du meh über mich erfahre witsch, dänn klick", }, sale: { eyebrow: "% Aktion", title: "Aktuelli Aktion", lead: "Zytlich begrenzti Rabatt uf uswählti, vo Hang gmachti Sächeli.", @@ -609,6 +612,7 @@ export const ui = { 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", mainCategoryLabel: "Catégorie principale", subcategoryEmpty: "VanVan ajoutera bientôt les premiers produits ici – repassez bientôt.", moreAbout: "En savoir plus sur", moreVariants: "Autres modèles", + moreAboutCharacterLead: "Si tu veux en savoir plus sur moi, clique", }, 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/shop/[kategorie]/[unterkategorie].astro b/src/pages/ch/shop/[kategorie]/[unterkategorie].astro index a31c23e..df52d1f 100644 --- a/src/pages/ch/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/ch/shop/[kategorie]/[unterkategorie].astro @@ -21,19 +21,18 @@ const sub = getSubcategory(kategorie!, unterkategorie!)!; // Alle Produkte dieser Unterkategorie (unabhängig davon, welchem Charakter sie zugeordnet sind). const alleProdukte = productsByUnterkategorie(category.slug, sub.slug); -// Jeder Charakter dieser Tier-Familie bekommt seine eigene kompakte Karte (wie die Produktkarten -// im Shop-Grid), alle nebeneinander in einer Reihe. Sobald VanVan im Adminbereich neue -// Charaktere UND passende Produkte ergänzt, wächst diese Reihe automatisch mit. Fehlt einem -// Charakter noch ein echtes Produkt, zeigt seine Karte trotzdem schon den Charaktertext (nur ohne -// Foto) — die Seite muss nicht auf das erste Foto warten, um zu existieren. +// Ein Charakter (aus dem Kategorien-Bereich im Admin) ist erstmal nur eine VORBEREITETE +// Definition — er erscheint auf der Seite NUR, wenn ihm im Admin auch wirklich ein Produkt mit +// genau diesem Charakter-Code zugeordnet wurde (das Feld "Charakter" am Produkt = seine "Rolle"). +// Ohne zugeordnetes Produkt taucht er hier NICHT auf, auch nicht als Platzhalter — nur echte, +// im Admin angelegte Artikel dürfen auf der Seite erscheinen. const characters = sub.characters ?? []; -const characterEntries = characters.map((char) => ({ - char, - product: alleProdukte.find((p) => p.charakter === char.slug), -})); +const characterEntries = characters + .map((char) => ({ char, product: alleProdukte.find((p) => p.charakter === char.slug) })) + .filter((e) => e.product); // Produkte ohne (bekannte) Charakter-Zuordnung landen als "weitere Modelle" darunter. -const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product?.slug).filter(Boolean)); +const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product!.slug)); const weitere = alleProdukte.filter((p) => !zugeordneteSlugs.has(p.slug)); const hatCharaktere = characterEntries.length > 0; const hatWeitere = weitere.length > 0; @@ -55,34 +54,23 @@ const komplettLeer = !hatCharaktere && !hatWeitere; {hatCharaktere && (
- {characterEntries.some(({ product }) => product) && ( -
- {characterEntries.filter(({ product }) => product).map(({ char }) => ( -
- {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} -

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

- {char.mehrLink && ( +
+ {characterEntries.map(({ char }) => ( +
+ {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} +

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

+ {char.mehrLink && ( +

+ {t.shop.moreAboutCharacterLead}{" "} da → - )} -

- ))} -
- )} +

+ )} +
+ ))} +
- {characterEntries.map(({ char, product }) => - product ? ( - - ) : ( -
-
- -
-

{char.name[lang]}

-

{t.shop.subcategoryEmpty}

-
- ) - )} + {characterEntries.map(({ product }) => )}
diff --git a/src/pages/en/shop/[kategorie]/[unterkategorie].astro b/src/pages/en/shop/[kategorie]/[unterkategorie].astro index fe6efa0..8f0b31e 100644 --- a/src/pages/en/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/en/shop/[kategorie]/[unterkategorie].astro @@ -21,19 +21,18 @@ const sub = getSubcategory(kategorie!, unterkategorie!)!; // Alle Produkte dieser Unterkategorie (unabhängig davon, welchem Charakter sie zugeordnet sind). const alleProdukte = productsByUnterkategorie(category.slug, sub.slug); -// Jeder Charakter dieser Tier-Familie bekommt seine eigene kompakte Karte (wie die Produktkarten -// im Shop-Grid), alle nebeneinander in einer Reihe. Sobald VanVan im Adminbereich neue -// Charaktere UND passende Produkte ergänzt, wächst diese Reihe automatisch mit. Fehlt einem -// Charakter noch ein echtes Produkt, zeigt seine Karte trotzdem schon den Charaktertext (nur ohne -// Foto) — die Seite muss nicht auf das erste Foto warten, um zu existieren. +// Ein Charakter (aus dem Kategorien-Bereich im Admin) ist erstmal nur eine VORBEREITETE +// Definition — er erscheint auf der Seite NUR, wenn ihm im Admin auch wirklich ein Produkt mit +// genau diesem Charakter-Code zugeordnet wurde (das Feld "Charakter" am Produkt = seine "Rolle"). +// Ohne zugeordnetes Produkt taucht er hier NICHT auf, auch nicht als Platzhalter — nur echte, +// im Admin angelegte Artikel dürfen auf der Seite erscheinen. const characters = sub.characters ?? []; -const characterEntries = characters.map((char) => ({ - char, - product: alleProdukte.find((p) => p.charakter === char.slug), -})); +const characterEntries = characters + .map((char) => ({ char, product: alleProdukte.find((p) => p.charakter === char.slug) })) + .filter((e) => e.product); // Produkte ohne (bekannte) Charakter-Zuordnung landen als "weitere Modelle" darunter. -const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product?.slug).filter(Boolean)); +const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product!.slug)); const weitere = alleProdukte.filter((p) => !zugeordneteSlugs.has(p.slug)); const hatCharaktere = characterEntries.length > 0; const hatWeitere = weitere.length > 0; @@ -55,34 +54,23 @@ const komplettLeer = !hatCharaktere && !hatWeitere; {hatCharaktere && (
- {characterEntries.some(({ product }) => product) && ( -
- {characterEntries.filter(({ product }) => product).map(({ char }) => ( -
- {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} -

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

- {char.mehrLink && ( +
+ {characterEntries.map(({ char }) => ( +
+ {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} +

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

+ {char.mehrLink && ( +

+ {t.shop.moreAboutCharacterLead}{" "} here → - )} -

- ))} -
- )} +

+ )} +
+ ))} +
- {characterEntries.map(({ char, product }) => - product ? ( - - ) : ( -
-
- -
-

{char.name[lang]}

-

{t.shop.subcategoryEmpty}

-
- ) - )} + {characterEntries.map(({ product }) => )}
diff --git a/src/pages/fr/shop/[kategorie]/[unterkategorie].astro b/src/pages/fr/shop/[kategorie]/[unterkategorie].astro index 593b52e..0442a28 100644 --- a/src/pages/fr/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/fr/shop/[kategorie]/[unterkategorie].astro @@ -21,19 +21,18 @@ const sub = getSubcategory(kategorie!, unterkategorie!)!; // Alle Produkte dieser Unterkategorie (unabhängig davon, welchem Charakter sie zugeordnet sind). const alleProdukte = productsByUnterkategorie(category.slug, sub.slug); -// Jeder Charakter dieser Tier-Familie bekommt seine eigene kompakte Karte (wie die Produktkarten -// im Shop-Grid), alle nebeneinander in einer Reihe. Sobald VanVan im Adminbereich neue -// Charaktere UND passende Produkte ergänzt, wächst diese Reihe automatisch mit. Fehlt einem -// Charakter noch ein echtes Produkt, zeigt seine Karte trotzdem schon den Charaktertext (nur ohne -// Foto) — die Seite muss nicht auf das erste Foto warten, um zu existieren. +// Ein Charakter (aus dem Kategorien-Bereich im Admin) ist erstmal nur eine VORBEREITETE +// Definition — er erscheint auf der Seite NUR, wenn ihm im Admin auch wirklich ein Produkt mit +// genau diesem Charakter-Code zugeordnet wurde (das Feld "Charakter" am Produkt = seine "Rolle"). +// Ohne zugeordnetes Produkt taucht er hier NICHT auf, auch nicht als Platzhalter — nur echte, +// im Admin angelegte Artikel dürfen auf der Seite erscheinen. const characters = sub.characters ?? []; -const characterEntries = characters.map((char) => ({ - char, - product: alleProdukte.find((p) => p.charakter === char.slug), -})); +const characterEntries = characters + .map((char) => ({ char, product: alleProdukte.find((p) => p.charakter === char.slug) })) + .filter((e) => e.product); // Produkte ohne (bekannte) Charakter-Zuordnung landen als "weitere Modelle" darunter. -const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product?.slug).filter(Boolean)); +const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product!.slug)); const weitere = alleProdukte.filter((p) => !zugeordneteSlugs.has(p.slug)); const hatCharaktere = characterEntries.length > 0; const hatWeitere = weitere.length > 0; @@ -55,34 +54,23 @@ const komplettLeer = !hatCharaktere && !hatWeitere; {hatCharaktere && (
- {characterEntries.some(({ product }) => product) && ( -
- {characterEntries.filter(({ product }) => product).map(({ char }) => ( -
- {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} -

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

- {char.mehrLink && ( +
+ {characterEntries.map(({ char }) => ( +
+ {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} +

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

+ {char.mehrLink && ( +

+ {t.shop.moreAboutCharacterLead}{" "} ici → - )} -

- ))} -
- )} +

+ )} +
+ ))} +
- {characterEntries.map(({ char, product }) => - product ? ( - - ) : ( -
-
- -
-

{char.name[lang]}

-

{t.shop.subcategoryEmpty}

-
- ) - )} + {characterEntries.map(({ product }) => )}
diff --git a/src/pages/shop/[kategorie]/[unterkategorie].astro b/src/pages/shop/[kategorie]/[unterkategorie].astro index db582d2..460e0ee 100644 --- a/src/pages/shop/[kategorie]/[unterkategorie].astro +++ b/src/pages/shop/[kategorie]/[unterkategorie].astro @@ -21,19 +21,18 @@ const sub = getSubcategory(kategorie!, unterkategorie!)!; // Alle Produkte dieser Unterkategorie (unabhängig davon, welchem Charakter sie zugeordnet sind). const alleProdukte = productsByUnterkategorie(category.slug, sub.slug); -// Jeder Charakter dieser Tier-Familie bekommt seine eigene kompakte Karte (wie die Produktkarten -// im Shop-Grid), alle nebeneinander in einer Reihe. Sobald VanVan im Adminbereich neue -// Charaktere UND passende Produkte ergänzt, wächst diese Reihe automatisch mit. Fehlt einem -// Charakter noch ein echtes Produkt, zeigt seine Karte trotzdem schon den Charaktertext (nur ohne -// Foto) — die Seite muss nicht auf das erste Foto warten, um zu existieren. +// Ein Charakter (aus dem Kategorien-Bereich im Admin) ist erstmal nur eine VORBEREITETE +// Definition — er erscheint auf der Seite NUR, wenn ihm im Admin auch wirklich ein Produkt mit +// genau diesem Charakter-Code zugeordnet wurde (das Feld "Charakter" am Produkt = seine "Rolle"). +// Ohne zugeordnetes Produkt taucht er hier NICHT auf, auch nicht als Platzhalter — nur echte, +// im Admin angelegte Artikel dürfen auf der Seite erscheinen. const characters = sub.characters ?? []; -const characterEntries = characters.map((char) => ({ - char, - product: alleProdukte.find((p) => p.charakter === char.slug), -})); +const characterEntries = characters + .map((char) => ({ char, product: alleProdukte.find((p) => p.charakter === char.slug) })) + .filter((e) => e.product); // Produkte ohne (bekannte) Charakter-Zuordnung landen als "weitere Modelle" darunter. -const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product?.slug).filter(Boolean)); +const zugeordneteSlugs = new Set(characterEntries.map((e) => e.product!.slug)); const weitere = alleProdukte.filter((p) => !zugeordneteSlugs.has(p.slug)); const hatCharaktere = characterEntries.length > 0; const hatWeitere = weitere.length > 0; @@ -61,35 +60,24 @@ const komplettLeer = !hatCharaktere && !hatWeitere;
{/* Die persönlichen Charaktergeschichten stehen als eigene, volle Breite Boxen ÜBER der Kartenreihe — getrennt von den "Shop"-Karten darunter, die nur Foto/Preis/Infos zeigen. */} - {characterEntries.some(({ product }) => product) && ( -
- {characterEntries.filter(({ product }) => product).map(({ char }) => ( -
- {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} -

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

- {char.mehrLink && ( +
+ {characterEntries.map(({ char }) => ( +
+ {char.vorstellung && {char.vorstellung[lang].split("\n")[0]}} +

{char.vorstellung ? char.vorstellung[lang].split("\n")[1] : ""}

+ {char.mehrLink && ( +

+ {t.shop.moreAboutCharacterLead}{" "} hier → - )} -

- ))} -
- )} +

+ )} +
+ ))} +
{/* Kartenreihe wie im Shop-Grid — nur Foto, Preis und Kaufinfos, keine Geschichten. */}
- {characterEntries.map(({ char, product }) => - product ? ( - - ) : ( -
-
- -
-

{char.name[lang]}

-

{t.shop.subcategoryEmpty}

-
- ) - )} + {characterEntries.map(({ product }) => )}
diff --git a/src/styles/global.css b/src/styles/global.css index db3f0e4..23e4295 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -868,6 +868,13 @@ a:focus-visible, button:focus-visible { color: transparent; } .character-story p { margin: 0 0 1.1rem; max-width: 62ch; font-size: 1.02rem; color: var(--c-text-muted); } +.character-story .character-more-lead { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.55em; + margin-bottom: 0; +} .character-story .btn { background: linear-gradient(135deg, var(--c-accent), var(--c-purple-glow)); color: #08181c;