"use client"; import { createContext, useContext, useEffect, useState, type MouseEvent, type ReactNode } from "react"; type Theme = "light" | "dark"; interface ThemeContextType { theme: Theme; toggleTheme: (event?: MouseEvent) => void; } const ThemeContext = createContext(undefined); export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setTheme] = useState("light"); useEffect(() => { const savedTheme = localStorage.getItem("theme") as Theme | null; if (savedTheme) { // eslint-disable-next-line setTheme(savedTheme); document.documentElement.classList.toggle("dark", savedTheme === "dark"); } else { // Check system preference const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; const initialTheme = prefersDark ? "dark" : "light"; setTheme(initialTheme); document.documentElement.classList.toggle("dark", initialTheme === "dark"); } }, []); const toggleTheme = (event?: React.MouseEvent) => { const newTheme = theme === "light" ? "dark" : "light"; // Create circular animation if click event provided // eslint-disable-next-line @typescript-eslint/no-explicit-any if (event && (document as any).startViewTransition) { const x = event.clientX; const y = event.clientY; const endRadius = Math.hypot( Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y) ); // eslint-disable-next-line @typescript-eslint/no-explicit-any const transition = (document as any).startViewTransition(() => { setTheme(newTheme); localStorage.setItem("theme", newTheme); document.documentElement.classList.toggle("dark", newTheme === "dark"); }); transition.ready.then(() => { const clipPath = [ `circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)` ]; document.documentElement.animate( { clipPath }, { duration: 500, easing: "ease-in-out", pseudoElement: "::view-transition-new(root)" } ); }); } else { setTheme(newTheme); localStorage.setItem("theme", newTheme); document.documentElement.classList.toggle("dark", newTheme === "dark"); } }; return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (context === undefined) { throw new Error("useTheme must be used within a ThemeProvider"); } return context; }