Skip to content

Instantly share code, notes, and snippets.

@GraysonRicketts
Created March 1, 2022 02:30
Show Gist options
  • Save GraysonRicketts/38a7fd27373a4429d4f6c321fff9761a to your computer and use it in GitHub Desktop.
Save GraysonRicketts/38a7fd27373a4429d4f6c321fff9761a to your computer and use it in GitHub Desktop.
ThemeContext
import React, {
useCallback,
useContext,
useState,
} from "react";
enum Theme {
LIGHT = 1,
DARK,
}
const THEME = "theme";
const DARK = "dark";
const LIGHT = "light";
type ThemeContextType = { theme: Theme; toggleTheme: () => void };
const ThemeContext = React.createContext<ThemeContextType | null>(null);
function getDefaultTheme(): Theme {
// First, check user default
const sysDefaultIsDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (sysDefaultIsDark) {
return Theme.DARK;
}
// Then, check the local storage
const savedTheme = localStorage.getItem(THEME);
if (savedTheme === DARK) {
return Theme.DARK;
} else if (savedTheme === LIGHT) {
return Theme.LIGHT;
}
return Theme.LIGHT;
}
const ThemeGuard: React.FC = ({ children }) => {
const [theme, setTheme] = useState<Theme>(getDefaultTheme());
const toggleTheme = useCallback(() => {
let newTheme = Theme.DARK;
if (theme === Theme.DARK) {
newTheme = Theme.LIGHT;
}
localStorage.setItem(THEME, newTheme === Theme.DARK ? DARK : LIGHT);
setTheme(newTheme);
}, [setTheme]);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeGuard");
}
return context;
}
export default ThemeGuard;
export { Theme, useTheme };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment