Files
Momento/memento-note/lib/apply-document-theme.ts

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')
}
}
}