Files
TeleWave/frontend/src/theme/ThemeProvider.tsx
T

40 lines
1.4 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState, type ReactNode } from 'react'
import { THEME_STORAGE_KEY, ThemeContext, type Theme } from './theme-context'
function resolve(theme: Theme): 'light' | 'dark' {
if (theme === 'system') {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
return theme
}
function applyTheme(theme: Theme) {
const root = document.documentElement
root.classList.toggle('dark', resolve(theme) === 'dark')
}
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setThemeState] = useState<Theme>(
() => (localStorage.getItem(THEME_STORAGE_KEY) as Theme | null) ?? 'dark',
)
useEffect(() => {
applyTheme(theme)
if (theme !== 'system') return
const media = window.matchMedia('(prefers-color-scheme: dark)')
const onChange = () => applyTheme('system')
media.addEventListener('change', onChange)
return () => media.removeEventListener('change', onChange)
}, [theme])
const setTheme = useCallback((next: Theme) => {
localStorage.setItem(THEME_STORAGE_KEY, next)
setThemeState(next)
}, [])
// Литерал в value пересоздавался бы на каждый рендер и перерисовывал всех потребителей темы.
const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme])
return <ThemeContext value={value}>{children}</ThemeContext>
}