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;