84 lines
2.0 KiB
TypeScript
84 lines
2.0 KiB
TypeScript
/**
|
|
* Valeurs persistées pour User.theme / localStorage `theme-preference`.
|
|
* Une seule source de vérité pour le DOM : évite les écarts entre header, settings et hydratation.
|
|
*/
|
|
export const THEME_IDS = [
|
|
'light',
|
|
'dark',
|
|
'auto',
|
|
'sepia',
|
|
'midnight',
|
|
'rose',
|
|
'green',
|
|
'lavender',
|
|
'sand',
|
|
'ocean',
|
|
'sunset',
|
|
'blue',
|
|
] as const
|
|
|
|
export type ThemeId = (typeof THEME_IDS)[number]
|
|
|
|
const NAMED_PALETTE_IDS: ThemeId[] = [
|
|
'sepia',
|
|
'midnight',
|
|
'rose',
|
|
'green',
|
|
'lavender',
|
|
'sand',
|
|
'ocean',
|
|
'sunset',
|
|
'blue',
|
|
]
|
|
|
|
export function isThemeId(value: string | null | undefined): value is ThemeId {
|
|
return value !== undefined && value !== null && (THEME_IDS as readonly string[]).includes(value)
|
|
}
|
|
|
|
/** Corrige les anciennes valeurs (ex. formulaire « slate ») vers un thème supporté. */
|
|
export function normalizeThemeId(raw: string | null | undefined): ThemeId {
|
|
if (!raw) return 'light'
|
|
if (raw === 'slate') return 'light'
|
|
if (isThemeId(raw)) return raw
|
|
return 'light'
|
|
}
|
|
|
|
/**
|
|
* Applique le thème sur `<html>` : `class="dark"` et/ou `data-theme`.
|
|
* - `light` → papier par défaut (`:root`), pas de `data-theme`
|
|
* - `dark` → sombre global (`.dark`)
|
|
* - `auto` → `.dark` si prefers-color-scheme: dark
|
|
* - palettes nommées → `data-theme="<id>"` ; `midnight` force aussi `.dark` (variante sombre du thème)
|
|
*/
|
|
export function applyDocumentTheme(theme: string): void {
|
|
if (typeof document === 'undefined') return
|
|
|
|
const t = normalizeThemeId(theme)
|
|
const root = document.documentElement
|
|
root.classList.remove('dark')
|
|
root.removeAttribute('data-theme')
|
|
|
|
if (t === 'auto') {
|
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
root.classList.add('dark')
|
|
}
|
|
return
|
|
}
|
|
|
|
if (t === 'dark') {
|
|
root.classList.add('dark')
|
|
return
|
|
}
|
|
|
|
if (t === 'light') {
|
|
return
|
|
}
|
|
|
|
if ((NAMED_PALETTE_IDS as readonly string[]).includes(t)) {
|
|
root.setAttribute('data-theme', t)
|
|
if (t === 'midnight') {
|
|
root.classList.add('dark')
|
|
}
|
|
}
|
|
}
|