Produktseiten: Zurück-Button oben, springt zur echten vorherigen Seite (alle 4 Sprachen)
Auf ausdrücklichen Wunsch: oben auf jeder Produktseite jetzt ein "← Zurück"-Button vor dem Breadcrumb. Nutzt den Browser-Verlauf (history.back()) statt fest zur Kategorieseite zu springen — landet man z.B. von der Startseite, einer Suche oder "Das könnte dir gefallen" auf einer Produktseite, kommt man genau dahin zurück. Fällt sauber auf einen normalen Link zur Kategorieseite zurück, wenn kein echter vorheriger Seitenaufruf im Verlauf existiert (Direkt- aufruf, neuer Tab, Suchmaschine). In allen 4 Sprachversionen (de/en/ch/fr) umgesetzt. Nebenbei behoben: t.common.skipToContent (Skip-Link aus der BFSG-Barrierefreiheits-Arbeit vom 04.08.) war nur für "de" gepflegt und dadurch auf den en/ch/fr-Seiten leer — jetzt für alle 4 Sprachen ergänzt (gleicher Commit, da hier ohnehin dieselbe common-Sektion bearbeitet wurde). Lokal mit wrangler pages dev end-to-end getestet (Login, echtes Produkt, Button + Skript im gerenderten HTML bestätigt). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e37d12b4c7
commit
90dfca2d4f
+4
-1
@@ -30,7 +30,7 @@ export const ui = {
|
|||||||
quantity: "Anzahl", photoSoon: "Produktfoto folgt", portraitSoon: "Porträtfoto von VanVan folgt",
|
quantity: "Anzahl", photoSoon: "Produktfoto folgt", portraitSoon: "Porträtfoto von VanVan folgt",
|
||||||
prevPhoto: "Vorheriges Foto", nextPhoto: "Nächstes Foto",
|
prevPhoto: "Vorheriges Foto", nextPhoto: "Nächstes Foto",
|
||||||
handmadeBadge: "🩵 Handgemacht",
|
handmadeBadge: "🩵 Handgemacht",
|
||||||
skipToContent: "Zum Inhalt springen",
|
skipToContent: "Zum Inhalt springen", back: "← Zurück",
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
articleNo: "Artikelnummer", material: "Material", size: "Größe", colors: "Farben",
|
articleNo: "Artikelnummer", material: "Material", size: "Größe", colors: "Farben",
|
||||||
@@ -348,6 +348,7 @@ export const ui = {
|
|||||||
quantity: "Quantity", photoSoon: "Product photo coming soon", portraitSoon: "VanVan's portrait photo coming soon",
|
quantity: "Quantity", photoSoon: "Product photo coming soon", portraitSoon: "VanVan's portrait photo coming soon",
|
||||||
prevPhoto: "Previous photo", nextPhoto: "Next photo",
|
prevPhoto: "Previous photo", nextPhoto: "Next photo",
|
||||||
handmadeBadge: "🩵 Handmade",
|
handmadeBadge: "🩵 Handmade",
|
||||||
|
skipToContent: "Skip to content", back: "← Back",
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
articleNo: "Item number", material: "Material", size: "Size", colors: "Colors",
|
articleNo: "Item number", material: "Material", size: "Size", colors: "Colors",
|
||||||
@@ -665,6 +666,7 @@ export const ui = {
|
|||||||
quantity: "Aazahl", photoSoon: "Produktfoto chunnt bald", portraitSoon: "Porträtfoto vo VanVan chunnt bald",
|
quantity: "Aazahl", photoSoon: "Produktfoto chunnt bald", portraitSoon: "Porträtfoto vo VanVan chunnt bald",
|
||||||
prevPhoto: "Vorherigs Foto", nextPhoto: "Nächschts Foto",
|
prevPhoto: "Vorherigs Foto", nextPhoto: "Nächschts Foto",
|
||||||
handmadeBadge: "🩵 Vo Hang gmacht",
|
handmadeBadge: "🩵 Vo Hang gmacht",
|
||||||
|
skipToContent: "Zum Inhalt springe", back: "← Zrugg",
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
articleNo: "Artikelnummer", material: "Material", size: "Grösse", colors: "Farbe",
|
articleNo: "Artikelnummer", material: "Material", size: "Grösse", colors: "Farbe",
|
||||||
@@ -982,6 +984,7 @@ export const ui = {
|
|||||||
quantity: "Quantité", photoSoon: "Photo du produit à venir", portraitSoon: "Photo de VanVan à venir",
|
quantity: "Quantité", photoSoon: "Photo du produit à venir", portraitSoon: "Photo de VanVan à venir",
|
||||||
prevPhoto: "Photo précédente", nextPhoto: "Photo suivante",
|
prevPhoto: "Photo précédente", nextPhoto: "Photo suivante",
|
||||||
handmadeBadge: "🩵 Fait main",
|
handmadeBadge: "🩵 Fait main",
|
||||||
|
skipToContent: "Aller au contenu", back: "← Retour",
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
articleNo: "Référence", material: "Matière", size: "Taille", colors: "Couleurs",
|
articleNo: "Référence", material: "Matière", size: "Taille", colors: "Couleurs",
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ const felder: [string, string | undefined][] = [
|
|||||||
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
||||||
<section class="section-tight">
|
<section class="section-tight">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="product-back-row">
|
||||||
|
<a href={`/ch/shop/${product.kategorie}/`} class="product-back-btn" id="product-back-btn">{t.common.back}</a>
|
||||||
|
</div>
|
||||||
<p class="small breadcrumb">
|
<p class="small breadcrumb">
|
||||||
<a href="/ch/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/ch/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
<a href="/ch/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/ch/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -194,6 +197,24 @@ const felder: [string, string | undefined][] = [
|
|||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Zrugg-Button obe uf de Produktsyte: springt zur würklich vorherige Syte im Browser-Verlauf
|
||||||
|
// (z.B. Shop-Grid mit vorheriger Scroll-Position, Suechergebnis, Startsyte …), statt immer fescht
|
||||||
|
// zur Kategorie z'gah. Nur wenn es en echte, gliich-originäre vorherige Syteufruef git
|
||||||
|
// (document.referrer) — susch bliibt de normal Link zur Kategoriesyte als sinnvolli Rückfallebeni.
|
||||||
|
const backBtn = document.getElementById("product-back-btn");
|
||||||
|
backBtn?.addEventListener("click", (e) => {
|
||||||
|
if (!document.referrer || window.history.length <= 1) return;
|
||||||
|
try {
|
||||||
|
if (new URL(document.referrer).origin === location.origin) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Kaputti/fremdi Referrer-URL — eifach bim normale Link zur Kategoriesyte blyybe.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
||||||
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ const felder: [string, string | undefined][] = [
|
|||||||
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
||||||
<section class="section-tight">
|
<section class="section-tight">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="product-back-row">
|
||||||
|
<a href={`/en/shop/${product.kategorie}/`} class="product-back-btn" id="product-back-btn">{t.common.back}</a>
|
||||||
|
</div>
|
||||||
<p class="small breadcrumb">
|
<p class="small breadcrumb">
|
||||||
<a href="/en/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/en/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
<a href="/en/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/en/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -194,6 +197,25 @@ const felder: [string, string | undefined][] = [
|
|||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Back button at the top of the product page: jumps to the actually previous page in the
|
||||||
|
// browser history (shop grid with its scroll position, search result, homepage, …) instead of
|
||||||
|
// always going to the category page. Only when a real same-origin previous page exists
|
||||||
|
// (document.referrer) — otherwise the normal link to the category page stays as a sensible
|
||||||
|
// fallback (e.g. direct visit, new tab, coming from a search engine).
|
||||||
|
const backBtn = document.getElementById("product-back-btn");
|
||||||
|
backBtn?.addEventListener("click", (e) => {
|
||||||
|
if (!document.referrer || window.history.length <= 1) return;
|
||||||
|
try {
|
||||||
|
if (new URL(document.referrer).origin === location.origin) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Broken/foreign referrer URL — just keep the normal link to the category page.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
||||||
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ const felder: [string, string | undefined][] = [
|
|||||||
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
||||||
<section class="section-tight">
|
<section class="section-tight">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="product-back-row">
|
||||||
|
<a href={`/fr/shop/${product.kategorie}/`} class="product-back-btn" id="product-back-btn">{t.common.back}</a>
|
||||||
|
</div>
|
||||||
<p class="small breadcrumb">
|
<p class="small breadcrumb">
|
||||||
<a href="/fr/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/fr/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
<a href="/fr/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/fr/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -194,6 +197,26 @@ const felder: [string, string | undefined][] = [
|
|||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Bouton retour en haut de la page produit : revient à la page VRAIMENT précédente dans
|
||||||
|
// l'historique du navigateur (grille boutique avec sa position de défilement, résultat de
|
||||||
|
// recherche, accueil…) plutôt que d'aller systématiquement à la page de catégorie. Uniquement
|
||||||
|
// si une page précédente de même origine existe réellement (document.referrer) — sinon le lien
|
||||||
|
// normal vers la page de catégorie reste un repli pertinent (visite directe, nouvel onglet,
|
||||||
|
// provenance d'un moteur de recherche).
|
||||||
|
const backBtn = document.getElementById("product-back-btn");
|
||||||
|
backBtn?.addEventListener("click", (e) => {
|
||||||
|
if (!document.referrer || window.history.length <= 1) return;
|
||||||
|
try {
|
||||||
|
if (new URL(document.referrer).origin === location.origin) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// URL de provenance cassée/étrangère — on garde simplement le lien normal vers la catégorie.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
||||||
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ const felder: [string, string | undefined][] = [
|
|||||||
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
<Layout title={name} description={desc} lang={lang} path={`/produkt/${product.slug}/`}>
|
||||||
<section class="section-tight">
|
<section class="section-tight">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{/* Auf ausdrücklichen Wunsch: oben auf jeder Produktseite ein Zurück-Button, der wirklich
|
||||||
|
zur vorherigen Seite zurückspringt (Browser-Verlauf), statt immer fest zur Kategorie zu
|
||||||
|
gehen — falls man z.B. von der Startseite, einer Suche oder "Das könnte dir gefallen"
|
||||||
|
kam. href bleibt als Rückfallebene gesetzt (kein JS / neuer Tab ohne Verlauf), das
|
||||||
|
Skript unten überschreibt den Klick nur, wenn ein echter vorheriger Seitenaufruf
|
||||||
|
derselben Seite im Verlauf existiert. */}
|
||||||
|
<div class="product-back-row">
|
||||||
|
<a href={`/shop/${product.kategorie}/`} class="product-back-btn" id="product-back-btn">{t.common.back}</a>
|
||||||
|
</div>
|
||||||
<p class="small breadcrumb">
|
<p class="small breadcrumb">
|
||||||
<a href="/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
<a href="/shop/">{t.shop.breadcrumbShop}</a> / <a href={`/shop/${product.kategorie}/`}>{category?.name[lang]}</a> / <strong>{name}</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -194,6 +203,25 @@ const felder: [string, string | undefined][] = [
|
|||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Zurück-Button oben auf der Produktseite: springt zur WIRKLICH vorherigen Seite im
|
||||||
|
// Browser-Verlauf (z.B. Shop-Grid mit vorheriger Scroll-Position, Suchergebnis, Startseite …),
|
||||||
|
// statt immer stur zur Kategorieseite zu gehen. Nur wenn ein echter, gleich-originärer voriger
|
||||||
|
// Seitenaufruf existiert (document.referrer) — sonst bleibt der normale Link zur Kategorieseite
|
||||||
|
// als sinnvoller Rückfall aktiv (z.B. Direktaufruf, neuer Tab, von einer Suchmaschine).
|
||||||
|
const backBtn = document.getElementById("product-back-btn");
|
||||||
|
backBtn?.addEventListener("click", (e) => {
|
||||||
|
if (!document.referrer || window.history.length <= 1) return;
|
||||||
|
try {
|
||||||
|
if (new URL(document.referrer).origin === location.origin) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Kaputte/fremde Referrer-URL — einfach beim normalen Link zur Kategorieseite bleiben.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
<script define:vars={{ onlyLeftTemplate: t.common.onlyXLeft("__N__"), maxInCartText: t.common.maxInCart, maxInCartShortText: t.common.maxInCartShort, soldOutText: t.common.soldOut, addToCartText: t.common.addToCart }}>
|
||||||
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
window.__productStockVars = { onlyLeftTemplate, maxInCartText, maxInCartShortText, soldOutText, addToCartText };
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1122,6 +1122,24 @@ a:focus-visible, button:focus-visible {
|
|||||||
/* Aktuelle Ebene (Haupt-/Unterkategorie, Produktname) hebt sich etwas vom "Shop"-Wurzel-Link ab. */
|
/* Aktuelle Ebene (Haupt-/Unterkategorie, Produktname) hebt sich etwas vom "Shop"-Wurzel-Link ab. */
|
||||||
.breadcrumb strong { color: var(--c-text); font-weight: 700; }
|
.breadcrumb strong { color: var(--c-text); font-weight: 700; }
|
||||||
|
|
||||||
|
/* Zurück-Button oben auf der Produktseite (siehe src/pages/produkt/[slug].astro) — springt per
|
||||||
|
Skript zur wirklich vorherigen Seite im Browser-Verlauf, der href hier ist die Rückfallebene. */
|
||||||
|
.product-back-row { margin-bottom: 0.9rem; }
|
||||||
|
.product-back-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4em;
|
||||||
|
padding: 0.4em 0.95em;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(244, 241, 247, 0.16);
|
||||||
|
background: rgba(244, 241, 247, 0.04);
|
||||||
|
color: var(--c-text-muted);
|
||||||
|
font-size: 0.86rem;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background 0.2s var(--ease), transform 0.2s var(--ease);
|
||||||
|
}
|
||||||
|
.product-back-btn:hover { border-color: var(--c-accent); color: var(--c-accent); transform: translateX(-2px); }
|
||||||
|
|
||||||
/* Überschrift über der "weitere Produkte"-Reihe auf Unterkategorie-Seiten — macht klar, dass da
|
/* Überschrift über der "weitere Produkte"-Reihe auf Unterkategorie-Seiten — macht klar, dass da
|
||||||
noch mehr Produkte derselben Reihe kommen (Charakter-Familie), egal wie viele es am Ende sind. */
|
noch mehr Produkte derselben Reihe kommen (Charakter-Familie), egal wie viele es am Ende sind. */
|
||||||
.more-variants-label { text-transform: uppercase; letter-spacing: 0.08em; color: var(--c-text-muted); margin-bottom: 0.8rem; }
|
.more-variants-label { text-transform: uppercase; letter-spacing: 0.08em; color: var(--c-text-muted); margin-bottom: 0.8rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user