added theme dark mode toggle in settings

master
Tudor Stanciu 2023-03-04 21:06:49 +02:00
parent dfcabbe0ce
commit 4e58eebd4e
9 changed files with 128 additions and 18 deletions

View File

@ -13,6 +13,7 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@flare/js-utils": "^1.0.3",
"@flare/tuitio-client-react": "^1.0.1", "@flare/tuitio-client-react": "^1.0.1",
"@material-ui/core": "^4.11.2", "@material-ui/core": "^4.11.2",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",

View File

@ -2,7 +2,7 @@ import React, { useContext, useEffect, useCallback } from "react";
import { import {
ApplicationStateContext, ApplicationStateContext,
ApplicationDispatchContext ApplicationDispatchContext
} from "../../../state/ApplicationContexts"; } from "../../../state/contexts";
import useApi from "../../../api"; import useApi from "../../../api";
import MachinesList from "./MachinesList"; import MachinesList from "./MachinesList";
import PageTitle from "../../../components/common/PageTitle"; import PageTitle from "../../../components/common/PageTitle";

View File

@ -1,8 +1,14 @@
import React from "react"; import React from "react";
import LanguageContainer from "./language/LanguageContainer"; import LanguageContainer from "./language/LanguageContainer";
import ThemeSettings from "./ThemeSettings";
const SettingsContainer = () => { const SettingsContainer = () => {
return <LanguageContainer />; return (
<>
<LanguageContainer />
<ThemeSettings />
</>
);
}; };
export default SettingsContainer; export default SettingsContainer;

View File

@ -0,0 +1,23 @@
import React from "react";
import { useApplicationTheme } from "../../../providers/ThemeProvider";
import { Switch } from "@material-ui/core";
const ThemeSettings = () => {
const { isDark, onDarkModeChanged } = useApplicationTheme();
const handleChange = event => {
const { checked } = event.target;
onDarkModeChanged(checked);
};
return (
<Switch
checked={isDark}
onChange={handleChange}
color="primary"
name="app-theme-switch"
/>
);
};
export default ThemeSettings;

View File

@ -1,7 +1,6 @@
import React, { Suspense } from "react"; import React, { Suspense } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { ThemeProvider } from "@material-ui/styles"; import ThemeProvider from "./providers/ThemeProvider";
import Themes from "./themes";
import CssBaseline from "@material-ui/core/CssBaseline"; import CssBaseline from "@material-ui/core/CssBaseline";
import App from "./components/App"; import App from "./components/App";
import { TuitioProvider } from "@flare/tuitio-client-react"; import { TuitioProvider } from "@flare/tuitio-client-react";
@ -12,7 +11,7 @@ import "./utils/i18n";
ReactDOM.render( ReactDOM.render(
<TuitioProvider tuitioUrl={process.env.REACT_APP_TUITIO_URL}> <TuitioProvider tuitioUrl={process.env.REACT_APP_TUITIO_URL}>
<ApplicationStateProvider> <ApplicationStateProvider>
<ThemeProvider theme={Themes.default}> <ThemeProvider>
<CssBaseline /> <CssBaseline />
<Suspense fallback={<div>Loading...</div>}> <Suspense fallback={<div>Loading...</div>}>
<ToastProvider> <ToastProvider>

View File

@ -3,7 +3,7 @@ import PropTypes from "prop-types";
import { import {
ApplicationStateContext, ApplicationStateContext,
ApplicationDispatchContext ApplicationDispatchContext
} from "../state/ApplicationContexts"; } from "../state/contexts";
import { import {
reducer, reducer,
dispatchActions as reducerDispatchActions dispatchActions as reducerDispatchActions

View File

@ -0,0 +1,82 @@
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;

View File

@ -1,12 +1,7 @@
import defaultTheme from "./default"; import defaultTheme from "./default";
import { createTheme } from "@material-ui/core/styles"; import { createTheme } from "@material-ui/core/styles";
const prefersDarkMode = false;
const overrides = { const overrides = {
palette: {
type: prefersDarkMode ? "dark" : "light"
},
typography: { typography: {
h1: { h1: {
fontSize: "3rem" fontSize: "3rem"
@ -29,12 +24,16 @@ const overrides = {
} }
}; };
const themes = { const getThemes = darkMode => {
default: createTheme({ const type = darkMode ? "dark" : "light";
...defaultTheme,
...overrides, return {
palette: { ...defaultTheme.palette, ...overrides.palette } default: createTheme({
}) ...defaultTheme,
...overrides,
palette: { ...defaultTheme.palette, type }
})
};
}; };
export default themes; export { getThemes };