72 lines
2.1 KiB
TypeScript
72 lines
2.1 KiB
TypeScript
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<ThemeKind>(
|
|
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<Theme | null>(null);
|
|
export const ThemeContextProvider = ThemeContext.Provider;
|
|
|
|
export const useTheme = (): Theme => {
|
|
const theme = useContext(ThemeContext);
|
|
if (!theme) {
|
|
throw new Error('No theme provided!');
|
|
}
|
|
|
|
return theme;
|
|
};
|