ThemeModeContext.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import React, { useMemo } from 'react';
  2. import type { FC, PropsWithChildren } from 'react';
  3. import type { ThemeDropDownValue } from 'components/NavBar/NavBar';
  4. interface ThemeModeContextProps {
  5. isDarkMode: boolean;
  6. themeMode: ThemeDropDownValue;
  7. setThemeMode: (value: string | number) => void;
  8. }
  9. export const ThemeModeContext = React.createContext<ThemeModeContextProps>({
  10. isDarkMode: false,
  11. themeMode: 'auto_theme',
  12. setThemeMode: () => {},
  13. });
  14. export const ThemeModeProvider: FC<PropsWithChildren<unknown>> = ({
  15. children,
  16. }) => {
  17. const matchDark = window.matchMedia('(prefers-color-scheme: dark)');
  18. const [themeMode, setThemeModeState] =
  19. React.useState<ThemeDropDownValue>('auto_theme');
  20. React.useLayoutEffect(() => {
  21. const mode = localStorage.getItem('mode');
  22. setThemeModeState((mode as ThemeDropDownValue) ?? 'auto_theme');
  23. }, [setThemeModeState]);
  24. const isDarkMode = React.useMemo(() => {
  25. if (themeMode === 'auto_theme') {
  26. return matchDark.matches;
  27. }
  28. return themeMode === 'dark_theme';
  29. }, [themeMode]);
  30. const setThemeMode = React.useCallback(
  31. (value: string | number) => {
  32. setThemeModeState(value as ThemeDropDownValue);
  33. localStorage.setItem('mode', value as string);
  34. },
  35. [setThemeModeState]
  36. );
  37. const contextValue = useMemo(
  38. () => ({
  39. isDarkMode,
  40. themeMode,
  41. setThemeMode,
  42. }),
  43. [isDarkMode, themeMode, setThemeMode]
  44. );
  45. return (
  46. <ThemeModeContext.Provider value={contextValue}>
  47. {children}
  48. </ThemeModeContext.Provider>
  49. );
  50. };