import { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { onDarkFontWeight, onLightFontWeight } from '../../config.css'; import { darkTheme, lightTheme } from '../../colors.css'; import { settingsAtom, ThemeId } from '../state/settings'; import { useSetting } from '../state/hooks/settings'; export enum ThemeKind { Light = 'light', Dark = 'dark', } export type Theme = { id: ThemeId; kind: ThemeKind; classNames: string[]; }; export const LightTheme: Theme = { id: 'light-theme', kind: ThemeKind.Light, classNames: ['light-theme', lightTheme, onLightFontWeight, 'prism-light'], }; export const DarkTheme: Theme = { id: 'dark-theme', kind: ThemeKind.Dark, classNames: ['dark-theme', darkTheme, onDarkFontWeight, 'prism-dark'], }; export const useSystemThemeKind = (): ThemeKind => { const darkModeQueryList = useMemo(() => window.matchMedia('(prefers-color-scheme: dark)'), []); const [themeKind, setThemeKind] = useState( darkModeQueryList.matches ? ThemeKind.Dark : ThemeKind.Light ); useEffect(() => { const handleMediaQueryChange = () => { setThemeKind(darkModeQueryList.matches ? ThemeKind.Dark : ThemeKind.Light); }; darkModeQueryList.addEventListener('change', handleMediaQueryChange); return () => { darkModeQueryList.removeEventListener('change', handleMediaQueryChange); }; }, [darkModeQueryList, setThemeKind]); return themeKind; }; export const useActiveTheme = (): Theme => { const systemThemeKind = useSystemThemeKind(); const [systemTheme] = useSetting(settingsAtom, 'useSystemTheme'); const [themeId] = useSetting(settingsAtom, 'themeId'); if (!systemTheme) { return themeId === DarkTheme.id ? DarkTheme : LightTheme; } return systemThemeKind === ThemeKind.Dark ? DarkTheme : LightTheme; }; const ThemeContext = createContext(null); export const ThemeContextProvider = ThemeContext.Provider; export const useTheme = (): Theme => { const theme = useContext(ThemeContext); if (!theme) { throw new Error('No theme provided!'); } return theme; };