Mercurial
view hg-web/src/components/theme.tsx @ 278:8d560f50ed4c
Improve infinite canvas interactions and browser chrome
Render Lucide icons directly with Raylib, add searchable icon browsing, robust text editing, entity lifecycle animations, z-order-safe input, semantic themes, and animated editable browser controls. Document rendering, pinning, context, and component extension for future agents.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: f68442b1-fa8f-46a0-9689-81710613bbd4
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:16:14 -0700 |
| parents | 9f4429c49733 |
| children |
line wrap: on
line source
import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'; interface ThemeContextType { isDark: boolean; toggleTheme: () => void; } const ThemeContext = createContext<ThemeContextType | undefined>(undefined); // Apply theme class to document root function applyTheme(isDark: boolean) { const root = document.documentElement; if (isDark) { root.classList.add('dark'); root.classList.remove('light'); } else { root.classList.add('light'); root.classList.remove('dark'); } } interface ThemeProviderProps { children: ReactNode; } function ThemeProvider({ children }: ThemeProviderProps) { const [isDark, setIsDark] = useState(() => { const saved = localStorage.getItem('theme'); if (saved) return saved === 'dark'; return window.matchMedia('(prefers-color-scheme: dark)').matches; }); // Apply theme on mount and change useEffect(() => { applyTheme(isDark); localStorage.setItem('theme', isDark ? 'dark' : 'light'); }, [isDark]); // Listen for system theme changes useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = (e: MediaQueryListEvent) => { // Only apply if no explicit preference is saved if (!localStorage.getItem('theme')) { setIsDark(e.matches); } }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, []); const toggleTheme = useCallback(() => { setIsDark(prev => !prev); }, []); return ( <ThemeContext.Provider value={{ isDark, toggleTheme }}> {children} </ThemeContext.Provider> ); } function useTheme(): ThemeContextType { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } export { ThemeProvider, useTheme };