Files
PhoneViewer/src/core/theme.ts
T

57 lines
1.6 KiB
TypeScript
Raw Normal View History

2026-10-26 17:44:44 +08:00
export type Theme = 'dark' | 'light'
const STORAGE_KEY = 'viewer.theme'
const listeners = new Set<(theme: Theme) => void>()
export function initTheme(): Theme {
const isAndroidShell =
typeof (window as unknown as { AndroidViewer?: unknown }).AndroidViewer !== 'undefined'
let theme: Theme = 'dark'
try {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored === 'light' || stored === 'dark') {
theme = stored
} else if (!isAndroidShell && window.matchMedia?.('(prefers-color-scheme: light)').matches) {
theme = 'light'
}
} catch {
/* ignore */
}
applyTheme(theme, false)
return theme
}
export function getTheme(): Theme {
return document.documentElement.dataset.theme === 'light' ? 'light' : 'dark'
}
export function setTheme(theme: Theme): void {
applyTheme(theme, true)
}
export function toggleTheme(): Theme {
const next: Theme = getTheme() === 'dark' ? 'light' : 'dark'
setTheme(next)
return next
}
function applyTheme(theme: Theme, persist: boolean): void {
document.documentElement.dataset.theme = theme
document.documentElement.style.colorScheme = theme
const meta = document.querySelector('meta[name="theme-color"]')
if (meta) meta.setAttribute('content', theme === 'dark' ? '#0b0e14' : '#f2f5fa')
if (persist) {
try {
localStorage.setItem(STORAGE_KEY, theme)
} catch {
/* ignore */
}
}
for (const listener of listeners) listener(theme)
}
export function onThemeChange(listener: (theme: Theme) => void): () => void {
listeners.add(listener)
return () => listeners.delete(listener)
}