Initial commit: Van's DIY & Bastelbedarf Astro shop
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
---
|
||||
import { locales, localeMeta, type Locale } from "../i18n/config";
|
||||
|
||||
interface Props {
|
||||
lang: Locale;
|
||||
/** Sprachneutraler Pfad der aktuellen Seite, z.B. "/shop/" oder "/produkt/foo/". */
|
||||
path: string;
|
||||
/** Seite existiert nur auf Deutsch (z.B. Rechtstexte) — alle Optionen führen zur DE-Version,
|
||||
* damit der Umschalter niemals auf eine 404-Seite verlinkt. */
|
||||
legalOnly?: boolean;
|
||||
}
|
||||
const { lang, path, legalOnly = false } = Astro.props;
|
||||
|
||||
function hrefFor(target: Locale) {
|
||||
if (legalOnly) return path; // immer die deutsche Original-URL
|
||||
const prefix = target === "de" ? "" : `/${target}`;
|
||||
return `${prefix}${path}` || "/";
|
||||
}
|
||||
|
||||
function globeStyle(l: Locale) {
|
||||
const m = localeMeta[l];
|
||||
return `--globe-color:${m.color}; --globe-glow:${m.glow}; --flag-1:${m.flag[0]}; --flag-2:${m.flag[1]}; --flag-3:${m.flag[2]}`;
|
||||
}
|
||||
---
|
||||
<div class="lang-switch" id="lang-switch">
|
||||
<button
|
||||
type="button"
|
||||
class="lang-switch-btn"
|
||||
id="lang-switch-btn"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
style={globeStyle(lang)}
|
||||
>
|
||||
<span class="lang-globe" aria-hidden="true">
|
||||
<span class="lang-globe-rotor">
|
||||
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round">
|
||||
<circle cx="12" cy="12" r="8.5" />
|
||||
<ellipse cx="12" cy="12" rx="3.6" ry="8.5" />
|
||||
<path d="M3.7 9.5h16.6M3.7 14.5h16.6" />
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span class="lang-label">{localeMeta[lang].label}</span>
|
||||
<span class="chevron">▼</span>
|
||||
</button>
|
||||
<div class="lang-switch-menu" role="menu">
|
||||
{locales.map((l) => (
|
||||
<a
|
||||
href={hrefFor(l)}
|
||||
role="menuitem"
|
||||
aria-current={l === lang ? "true" : "false"}
|
||||
title={legalOnly && l !== "de" ? "Nur auf Deutsch verfügbar / Only available in German" : undefined}
|
||||
style={globeStyle(l)}
|
||||
>
|
||||
<span class="lang-globe" aria-hidden="true">
|
||||
<span class="lang-globe-rotor">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round">
|
||||
<circle cx="12" cy="12" r="8.5" />
|
||||
<ellipse cx="12" cy="12" rx="3.6" ry="8.5" />
|
||||
<path d="M3.7 9.5h16.6M3.7 14.5h16.6" />
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span class="lang-label">{localeMeta[l].label}</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Jede Instanz für sich initialisieren (Desktop-Header + evtl. Mobile-Nav-Kopie).
|
||||
document.querySelectorAll(".lang-switch").forEach((el) => {
|
||||
const btn = el.querySelector(".lang-switch-btn");
|
||||
btn?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
document.querySelectorAll(".lang-switch.open").forEach((other) => {
|
||||
if (other !== el) other.classList.remove("open");
|
||||
});
|
||||
el.classList.toggle("open");
|
||||
btn.setAttribute("aria-expanded", el.classList.contains("open") ? "true" : "false");
|
||||
});
|
||||
});
|
||||
document.addEventListener("click", () => {
|
||||
document.querySelectorAll(".lang-switch.open").forEach((el) => el.classList.remove("open"));
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
document.querySelectorAll(".lang-switch.open").forEach((el) => el.classList.remove("open"));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user