network-resurrector-frontend/src/providers/ThemeProvider.js

83 lines
2.2 KiB
JavaScript

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 (
<ApplicationThemeContext.Provider
value={{
state,
actions
}}
>
<MuiThemeProvider theme={themes.default}>{children}</MuiThemeProvider>
</ApplicationThemeContext.Provider>
);
};
ThemeProvider.propTypes = {
children: PropTypes.node.isRequired
};
export { ThemeProvider, ApplicationThemeContext, useApplicationTheme };
export default ThemeProvider;