import React, { useReducer, useMemo, useContext } from "react"; import PropTypes from "prop-types"; import { ThemeProvider as MuiThemeProvider } from "@material-ui/styles"; import { localStorage } from "@flare/js-utils"; import { getThemes } from "../themes"; const ApplicationThemeContext = React.createContext(); const LOCAL_STORAGE_COLOR_SCHEME_KEY = "network-resurrector-color-scheme"; const COLOR_SCHEME = { LIGHT: "light", DARK: "dark" }; const colorScheme = localStorage.getItem(LOCAL_STORAGE_COLOR_SCHEME_KEY); const prefersDarkMode = window.matchMedia( "(prefers-color-scheme: dark)" ).matches; const initialState = { scheme: colorScheme ?? (prefersDarkMode ? COLOR_SCHEME.DARK : COLOR_SCHEME.LIGHT) }; const reducer = (state = initialState, action) => { switch (action.type) { case "onColorSchemeChanged": { return { ...state, scheme: action.scheme }; } default: { return state; } } }; const dispatchActions = dispatch => ({ onColorSchemeChanged: scheme => { dispatch({ type: "onColorSchemeChanged", scheme }); localStorage.setItem(LOCAL_STORAGE_COLOR_SCHEME_KEY, scheme); } }); const useApplicationTheme = () => { const { state, actions } = useContext(ApplicationThemeContext); const { onColorSchemeChanged } = actions; const { scheme } = state; const onDarkModeChanged = active => onColorSchemeChanged(active ? COLOR_SCHEME.DARK : COLOR_SCHEME.LIGHT); return { isDark: scheme === COLOR_SCHEME.DARK, onDarkModeChanged }; }; const ThemeProvider = ({ children }) => { const [state, dispatch] = useReducer(reducer, initialState); const actions = useMemo(() => dispatchActions(dispatch), [dispatch]); const themes = useMemo( () => getThemes(state.scheme === COLOR_SCHEME.DARK), [state.scheme] ); return ( {children} ); }; ThemeProvider.propTypes = { children: PropTypes.node.isRequired }; export { ThemeProvider, ApplicationThemeContext, useApplicationTheme }; export default ThemeProvider;