import { createContext, useEffect, useState, useCallback, type ReactNode } from 'react'; import { themes, type Theme } from '~/styles/themes.css'; import { themeVars } from '~/styles/vars.css'; interface ThemeContextValue { theme: string; setTheme: (theme: string) => void; setCustomTheme: (theme: Theme) => void; } const ThemeContext = createContext(undefined); function toKebabCase(str: string) { return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase()); } function applyCustomThemeVars(theme: Theme) { const root = document.documentElement; for (const [key, value] of Object.entries(theme)) { if (key === 'name') continue; root.style.setProperty(`--color-${toKebabCase(key)}`, value); } } function clearCustomThemeVars() { for (const cssVar of Object.values(themeVars)) { document.documentElement.style.removeProperty(cssVar); } } export function ThemeProvider({ theme: initialTheme, children, }: { theme: string; children: ReactNode; }) { const [theme, setThemeName] = useState(initialTheme); const setTheme = (theme: string) => { setThemeName(theme) } const setCustomTheme = useCallback((customTheme: Theme) => { localStorage.setItem('custom-theme', JSON.stringify(customTheme)); applyCustomThemeVars(customTheme); setTheme('custom'); }, []); useEffect(() => { const root = document.documentElement; root.setAttribute('data-theme', theme); localStorage.setItem('theme', theme) console.log(theme) if (theme === 'custom') { const saved = localStorage.getItem('custom-theme'); if (saved) { try { const parsed = JSON.parse(saved) as Theme; applyCustomThemeVars(parsed); } catch (err) { console.error('Invalid custom theme in localStorage', err); } } } else { clearCustomThemeVars() } }, [theme]); return ( {children} ); } export { ThemeContext };