diff --git a/site/src/components/LangPicker.astro b/site/src/components/LangPicker.astro index 1c6ec6b..16f96ab 100644 --- a/site/src/components/LangPicker.astro +++ b/site/src/components/LangPicker.astro @@ -1,5 +1,5 @@ --- -import { locales, defaultLocale, type Locale } from "../i18n/ui"; +import { locales, localizePath, type Locale } from "../i18n/ui"; interface Props { locale: Locale; @@ -13,7 +13,7 @@ const labels: Record = { fr: "FR", es: "ES", }; -const href = (l: Locale) => (l === defaultLocale ? path : `/${l}${path}`); +const href = (l: Locale) => localizePath(l, path); ---
{locales.map((l) => ( diff --git a/site/src/components/Nav.astro b/site/src/components/Nav.astro index a39774d..6116eb1 100644 --- a/site/src/components/Nav.astro +++ b/site/src/components/Nav.astro @@ -1,5 +1,5 @@ --- -import { defaultLocale, useTranslations, type Locale } from "../i18n/ui"; +import { localizePath, useTranslations, type Locale } from "../i18n/ui"; import ThemeToggle from "./ThemeToggle.astro"; import LangPicker from "./LangPicker.astro"; @@ -9,7 +9,7 @@ interface Props { } const { locale, path } = Astro.props; const t = useTranslations(locale); -const p = (sub: string) => (locale === defaultLocale ? sub : `/${locale}${sub}`); +const p = (sub: string) => localizePath(locale, sub); ---
diff --git a/site/src/components/ThemeToggle.astro b/site/src/components/ThemeToggle.astro index a8a1c03..f0bf667 100644 --- a/site/src/components/ThemeToggle.astro +++ b/site/src/components/ThemeToggle.astro @@ -1,32 +1,31 @@ --- -// Tiny client island: flips data-theme + persists. Contract: writes "frappe"|"latte". +// Theme toggle. Contract: localStorage 'theme' = "frappe" | "latte". Safe to render multiple times. --- diff --git a/site/src/i18n/ui.ts b/site/src/i18n/ui.ts index 4f00424..a8084f8 100644 --- a/site/src/i18n/ui.ts +++ b/site/src/i18n/ui.ts @@ -25,6 +25,11 @@ export function isLocale(value: string): value is Locale { return (locales as readonly string[]).includes(value); } +/** Prefix a path with the locale, except for the default locale. */ +export function localizePath(locale: Locale, path: string): string { + return locale === defaultLocale ? path : `/${locale}${path}`; +} + /** Resolve a translator for `locale`, falling back to en, then to the key. */ export function useTranslations(locale: Locale) { const dict = dictionaries[locale] ?? dictionaries[defaultLocale]; diff --git a/site/src/styles/theme.css b/site/src/styles/theme.css index 89e6fdf..99bf32e 100644 --- a/site/src/styles/theme.css +++ b/site/src/styles/theme.css @@ -79,6 +79,11 @@ html { color: var(--color-text); } +/* Theme toggle icons: shown based on active theme, set before paint by the head bootstrap */ +[data-icon] { display: none; } +[data-theme="frappe"] [data-icon="frappe"] { display: inline; } +[data-theme="latte"] [data-icon="latte"] { display: inline; } + .blink { display: inline-block; width: 0.5rem;