import React, { createContext, useContext, useState, useEffect, type ReactNode } from 'react'; type Theme = 'dark' | 'light'; interface ThemeContextType { theme: Theme; toggleTheme: (event?: React.MouseEvent | MouseEvent) => void; } const ThemeContext = createContext({ theme: 'dark', toggleTheme: () => {}, }); export const useTheme = () => useContext(ThemeContext); export const ThemeProvider = ({ children }: { children: ReactNode }) => { const [theme, setTheme] = useState(() => { const saved = localStorage.getItem('fakeshield-theme'); return (saved === 'light' || saved === 'dark') ? saved : 'dark'; }); useEffect(() => { localStorage.setItem('fakeshield-theme', theme); document.documentElement.setAttribute('data-theme', theme); }, [theme]); const toggleTheme = (event?: React.MouseEvent | MouseEvent) => { const isAppearanceTransition = (document as any).startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (!isAppearanceTransition) { setTheme(prev => (prev === 'dark' ? 'light' : 'dark')); return; } const x = event ? (event instanceof MouseEvent ? event.clientX : (event as React.MouseEvent).nativeEvent.clientX) : window.innerWidth / 2; const y = event ? (event instanceof MouseEvent ? event.clientY : (event as React.MouseEvent).nativeEvent.clientY) : window.innerHeight / 2; const endRadius = Math.hypot( Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y) ); document.documentElement.setAttribute('data-theme-transition', 'true'); document.documentElement.style.setProperty('--x', x + 'px'); document.documentElement.style.setProperty('--y', y + 'px'); document.documentElement.style.setProperty('--r', endRadius + 'px'); const transition = (document as any).startViewTransition(async () => { setTheme(prev => (prev === 'dark' ? 'light' : 'dark')); }); transition.finished.finally(() => { document.documentElement.removeAttribute('data-theme-transition'); }); }; return ( {children} ); };