nabrok

Untitled

Sep 10th, 2025
368
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { createContext, useContext, useEffect, useState } from 'react';
  2.  
  3. /** Local storage key for preferred theme */
  4. const key = 'theme_v4';
  5.  
  6. const themes = [ 'auto', 'light', 'dark' ] as const;
  7. type ValidTheme = typeof themes[number];
  8.  
  9. type ThemeContext = {
  10.     setTheme: (theme: ValidTheme) => void
  11.     themes: typeof themes,
  12.     theme: ValidTheme,
  13.     resolved_theme: Exclude<ValidTheme, 'auto'>
  14. };
  15.  
  16. const Context = createContext<ThemeContext>(null);
  17.  
  18. function getPreferredTheme(): 'dark' | 'light' {
  19.     if (typeof window === 'undefined') return 'light';
  20.     if (window.matchMedia('(prefers-color-scheme: dark)').matches) return 'dark';
  21.     return 'light';
  22. }
  23.  
  24. function getStoredTheme(key: string): 'dark' | 'light' | undefined {
  25.     if (typeof localStorage === 'undefined') return;
  26.     const stored = localStorage.getItem(key);
  27.     if (stored === 'dark' || stored === 'light') return stored;
  28. }
  29.  
  30. /**
  31.  * Set CSS theme
  32.  */
  33. export function useTheme() {
  34.     const ctx = useContext(Context);
  35.     if (! ctx) throw new Error("ThemeProvider not loaded!");
  36.     return ctx;
  37. }
  38.  
  39. interface ThemeProviderProps {
  40.     children: React.ReactNode;
  41.     theme?: ValidTheme
  42. }
  43.  
  44. function ThemeProvider(props: ThemeProviderProps) {
  45.     const { children } = props;
  46.     const [ theme, setTheme ] = useState<ValidTheme>(
  47.         props.theme ||
  48.         getStoredTheme(key) ||
  49.         'auto'
  50.     );
  51.  
  52.     useEffect(() => {
  53.         if (theme === 'auto') {
  54.             document.documentElement.setAttribute('data-bs-theme', getPreferredTheme());
  55.             localStorage.removeItem(key);
  56.         } else {
  57.             document.documentElement.setAttribute('data-bs-theme', theme);
  58.             localStorage.setItem(key, theme);
  59.         }
  60.     }, [theme]);
  61.  
  62.     return <Context.Provider value={{
  63.         setTheme,
  64.         themes,
  65.         theme,
  66.         resolved_theme: theme === 'auto' ? getPreferredTheme() : theme
  67.     }}>
  68.         { children }
  69.     </Context.Provider>;
  70. }
  71.  
  72. export default ThemeProvider;
  73.  
Advertisement
Add Comment
Please, Sign In to add comment