Initial commit: Van's DIY & Bastelbedarf Astro shop

This commit is contained in:
qcigano
2026-08-02 13:22:55 +02:00
commit 2e340f7a8a
92 changed files with 11022 additions and 0 deletions
+91
View File
@@ -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>