| import React, { createContext, useContext, useEffect, useState } from 'react'; | |
| type Theme = 'dark' | 'light' | 'system'; | |
| type ThemeProviderProps = { | |
| children: React.ReactNode; | |
| defaultTheme?: Theme; | |
| storageKey?: string; | |
| }; | |
| type ThemeProviderState = { | |
| theme: Theme; | |
| setTheme: (theme: Theme) => void; | |
| }; | |
| const initialState: ThemeProviderState = { | |
| theme: 'light', | |
| setTheme: () => null, | |
| }; | |
| const ThemeProviderContext = createContext<ThemeProviderState>(initialState); | |
| export function ThemeProvider({ | |
| children, | |
| defaultTheme = 'light', | |
| storageKey = 'vite-ui-theme', | |
| ...props | |
| }: ThemeProviderProps) { | |
| const [theme, setTheme] = useState<Theme>( | |
| () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, | |
| ); | |
| useEffect(() => { | |
| const root = window.document.documentElement; | |
| root.classList.remove('light', 'dark'); | |
| localStorage.setItem(storageKey, theme); | |
| root.classList.add(theme); | |
| }, [storageKey, theme]); | |
| return ( | |
| <ThemeProviderContext.Provider | |
| {...props} | |
| value={{ | |
| theme, | |
| setTheme, | |
| }} | |
| > | |
| {children} | |
| </ThemeProviderContext.Provider> | |
| ); | |
| } | |
| export const useTheme = () => { | |
| const context = useContext(ThemeProviderContext); | |
| if (context === undefined) | |
| throw new Error('useTheme must be used within a ThemeProvider'); | |
| return context; | |
| }; | |
| export const useIsDarkTheme = () => { | |
| const { theme } = useTheme(); | |
| return theme === 'dark'; | |
| }; | |