import { createContext, useContext, useEffect, useState } from "react"; type Theme = "light" | "dark"; interface ThemeContextValue { theme: Theme; toggleTheme: () => void; } const ThemeContext = createContext({ theme: "light", toggleTheme: () => {}, }); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState(() => { const stored = localStorage.getItem("p2p_theme"); if (stored === "dark" || stored === "light") return stored; return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; }); useEffect(() => { const root = document.documentElement; root.classList.toggle("dark", theme === "dark"); localStorage.setItem("p2p_theme", theme); }, [theme]); // The colour-transition is opt-in per switch rather than a standing global // rule, so ordinary hovers and mounts don't animate. Skipped entirely when // the user prefers reduced motion. const toggleTheme = () => { const root = document.documentElement; const animate = !window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (animate) { root.classList.add("theming"); window.setTimeout(() => root.classList.remove("theming"), 220); } setTheme((t) => (t === "light" ? "dark" : "light")); }; return ( {children} ); } export const useTheme = () => useContext(ThemeContext);