import { lightTheme } from 'folds'; import { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { onDarkFontWeight, onLightFontWeight } from '../../config.css'; import { bloodRedTheme, butterTheme, classicMatrixTheme, cyberpunkTheme, darkTheme, lotusTerminalLightTheme, lotusTerminalTheme, midnightTheme, oceanTheme, silverTheme, } from '../../colors.css'; import { settingsAtom } from '../state/settings'; import { useSetting } from '../state/hooks/settings'; export enum ThemeKind { Light = 'light', Dark = 'dark', } export type Theme = { id: string; kind: ThemeKind; classNames: string[]; }; export const LightTheme: Theme = { id: 'light-theme', kind: ThemeKind.Light, classNames: [lightTheme, onLightFontWeight, 'prism-light'], }; export const SilverTheme: Theme = { id: 'silver-theme', kind: ThemeKind.Light, classNames: ['silver-theme', silverTheme, onLightFontWeight, 'prism-light'], }; export const DarkTheme: Theme = { id: 'dark-theme', kind: ThemeKind.Dark, classNames: ['dark-theme', darkTheme, onDarkFontWeight, 'prism-dark'], }; export const ButterTheme: Theme = { id: 'butter-theme', kind: ThemeKind.Dark, classNames: ['butter-theme', butterTheme, onDarkFontWeight, 'prism-dark'], }; export const CyberpunkTheme: Theme = { id: 'cyberpunk-theme', kind: ThemeKind.Dark, classNames: ['cyberpunk-theme', cyberpunkTheme, onDarkFontWeight, 'prism-dark'], }; export const OceanTheme: Theme = { id: 'ocean-theme', kind: ThemeKind.Dark, classNames: ['ocean-theme', oceanTheme, onDarkFontWeight, 'prism-dark'], }; export const BloodRedTheme: Theme = { id: 'blood-red-theme', kind: ThemeKind.Dark, classNames: ['blood-red-theme', bloodRedTheme, onDarkFontWeight, 'prism-dark'], }; export const ClassicMatrixTheme: Theme = { id: 'classic-matrix-theme', kind: ThemeKind.Dark, classNames: ['classic-matrix-theme', classicMatrixTheme, onDarkFontWeight, 'prism-dark'], }; export const MidnightTheme: Theme = { id: 'midnight-theme', kind: ThemeKind.Dark, classNames: ['midnight-theme', midnightTheme, onDarkFontWeight, 'prism-dark'], }; export const LotusTerminalTheme: Theme = { id: 'lotus-terminal-theme', kind: ThemeKind.Dark, classNames: ['lotus-terminal-theme', lotusTerminalTheme, onDarkFontWeight, 'prism-tds-dark'], }; export const LotusTerminalLightTheme: Theme = { id: 'lotus-terminal-light-theme', kind: ThemeKind.Light, classNames: [ 'lotus-terminal-light-theme', lotusTerminalLightTheme, onLightFontWeight, 'prism-tds-light', ], }; export const useThemes = (): Theme[] => { const themes: Theme[] = useMemo( () => [ LightTheme, SilverTheme, DarkTheme, ButterTheme, CyberpunkTheme, OceanTheme, BloodRedTheme, ClassicMatrixTheme, MidnightTheme, ], [], ); return themes; }; export const useThemeNames = (): Record => useMemo( () => ({ [LightTheme.id]: 'Light', [SilverTheme.id]: 'Silver', [DarkTheme.id]: 'Dark', [ButterTheme.id]: 'Butter', [CyberpunkTheme.id]: 'Cyberpunk', [OceanTheme.id]: 'Ocean', [BloodRedTheme.id]: 'Blood Red', [ClassicMatrixTheme.id]: 'Classic Matrix', [MidnightTheme.id]: 'Midnight', }), [], ); 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 themes = useThemes(); const [systemTheme] = useSetting(settingsAtom, 'useSystemTheme'); const [themeId] = useSetting(settingsAtom, 'themeId'); const [lightThemeId] = useSetting(settingsAtom, 'lightThemeId'); const [darkThemeId] = useSetting(settingsAtom, 'darkThemeId'); if (!systemTheme) { const selectedTheme = themes.find((theme) => theme.id === themeId) ?? LightTheme; return selectedTheme; } const selectedTheme = systemThemeKind === ThemeKind.Dark ? (themes.find((theme) => theme.id === darkThemeId) ?? DarkTheme) : (themes.find((theme) => theme.id === lightThemeId) ?? LightTheme); return selectedTheme; }; 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; };