Spaces:
Running
Running
import { createContext, useContext, useEffect, useState } from "react"; | |
type Theme = "dark" | "light" | "system"; | |
// Define the state type for the ThemeProvider | |
export type ThemeProviderState = { | |
theme: Theme; | |
setTheme: (theme: Theme) => void; | |
}; | |
// Define the initial state for the ThemeProvider | |
const initialState: ThemeProviderState = { | |
theme: "system", | |
setTheme: () => null, | |
}; | |
// Creates a 'bucket' that holds data that any componen can access without props if inside the provider | |
export const ThemeProviderContext = | |
createContext<ThemeProviderState>(initialState); | |
// Define the props type for the ThemeProvider | |
type ThemeProviderProps = { | |
children: React.ReactNode; | |
defaultTheme?: Theme; | |
}; | |
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ | |
children, | |
defaultTheme = "system", | |
}) => { | |
// Load theme from localStorage if available, otherwise use defaultTheme | |
const [theme, setTheme] = useState<Theme>(() => { | |
const storedTheme = localStorage.getItem("theme"); | |
if ( | |
storedTheme === "dark" || | |
storedTheme === "light" || | |
storedTheme === "system" | |
) { | |
return storedTheme; | |
} | |
return defaultTheme; | |
}); | |
// Effect to update the theme when it changes | |
useEffect(() => { | |
// Get the root element, which is the entire html document | |
const root = window.document.documentElement; | |
// Remove all existing theme classes on the root element | |
root.classList.remove("light", "dark"); | |
if (theme === "system") { | |
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") | |
.matches | |
? "dark" | |
: "light"; | |
root.classList.add(systemTheme); | |
return; | |
} | |
root.classList.add(theme); | |
}, [theme]); | |
const value = { | |
theme, | |
setTheme: (theme: Theme) => { | |
setTheme(theme); | |
localStorage.setItem("theme", theme); | |
}, | |
}; | |
return ( | |
<ThemeProviderContext.Provider value={value}> | |
{children} | |
</ThemeProviderContext.Provider> | |
); | |
}; | |