mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
84 lines
2.9 KiB
Plaintext
84 lines
2.9 KiB
Plaintext
---
|
|
// biome-ignore-all lint/correctness/noUnusedImports: Astro template consumes component imports.
|
|
// biome-ignore-all lint/correctness/noUnusedVariables: Astro template consumes frontmatter values.
|
|
// apps/landing/src/components/LanguageSwitcher.astro
|
|
import { LANDING_LOCALES, nativeName, t } from "@/i18n";
|
|
import { localizeHref } from "@/lib/i18n-page";
|
|
|
|
interface Props {
|
|
locale: string;
|
|
path: string; // the un-prefixed page path, e.g. "/faq"
|
|
}
|
|
|
|
const { locale, path } = Astro.props;
|
|
const options = LANDING_LOCALES.map((code) => ({
|
|
code,
|
|
label: nativeName(code),
|
|
href: localizeHref(code, path),
|
|
}));
|
|
---
|
|
|
|
<div class="relative" data-language-switcher>
|
|
<button
|
|
type="button"
|
|
class="flex items-center gap-1.5 rounded-lg border border-border px-2.5 py-1.5 text-sm font-medium transition-colors hover:bg-background-alt"
|
|
aria-haspopup="listbox"
|
|
aria-expanded="false"
|
|
aria-label={t(locale, "switcher.label")}
|
|
data-switcher-button
|
|
>
|
|
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<circle cx="12" cy="12" r="10" />
|
|
<path d="M2 12h20" />
|
|
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
|
</svg>
|
|
<span>{nativeName(locale)}</span>
|
|
</button>
|
|
<ul
|
|
class="absolute end-0 bottom-full z-50 mb-2 hidden max-h-80 w-44 overflow-y-auto rounded-xl border border-border bg-surface py-1.5 text-sm shadow-xl"
|
|
role="listbox"
|
|
data-switcher-menu
|
|
>
|
|
{options.map((o) => (
|
|
<li>
|
|
<a
|
|
href={o.href}
|
|
class="block px-4 py-2 text-foreground no-underline transition-colors hover:bg-primary-subtle"
|
|
data-locale={o.code}
|
|
aria-current={o.code === locale ? "true" : undefined}
|
|
>
|
|
{o.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<script is:inline>
|
|
(function () {
|
|
document.querySelectorAll("[data-language-switcher]").forEach(function (root) {
|
|
var btn = root.querySelector("[data-switcher-button]");
|
|
var menu = root.querySelector("[data-switcher-menu]");
|
|
if (!btn || !menu) return;
|
|
btn.addEventListener("click", function () {
|
|
var open = !menu.classList.contains("hidden");
|
|
menu.classList.toggle("hidden");
|
|
btn.setAttribute("aria-expanded", String(!open));
|
|
});
|
|
menu.querySelectorAll("a[data-locale]").forEach(function (a) {
|
|
a.addEventListener("click", function () {
|
|
try {
|
|
localStorage.setItem("snapotter:locale", a.getAttribute("data-locale") || "en");
|
|
} catch (e) {}
|
|
});
|
|
});
|
|
document.addEventListener("click", function (e) {
|
|
if (!root.contains(e.target)) {
|
|
menu.classList.add("hidden");
|
|
btn.setAttribute("aria-expanded", "false");
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
</script>
|