Add system default as dark theme preference option

This commit is contained in:
Peizhi Zheng 2021-01-13 13:58:10 -08:00 committed by GitHub
parent e7cfbc6bf7
commit b3beef97df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 55 deletions

View File

@ -131,7 +131,7 @@ const useStyles = (theme: Theme) =>
function mapStateToProps(state: AppState) { function mapStateToProps(state: AppState) {
return { return {
snackbar: state.snackbar, snackbar: state.snackbar,
isDarkTheme: state.settings.isDarkTheme, themePreference: state.settings.themePreference,
}; };
} }
@ -146,7 +146,7 @@ function SlideUpTransition(props: TransitionProps) {
} }
function App(props: ConnectedProps<typeof connector>) { function App(props: ConnectedProps<typeof connector>) {
const theme = makeTheme(props.isDarkTheme); const theme = makeTheme(props.themePreference);
const classes = useStyles(theme)(); const classes = useStyles(theme)();
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const toggleDrawer = () => setOpen(!open); const toggleDrawer = () => setOpen(!open);

View File

@ -1,6 +1,8 @@
import { ThemePreference } from "../reducers/settingsReducer";
// List of settings related action types. // List of settings related action types.
export const POLL_INTERVAL_CHANGE = 'POLL_INTERVAL_CHANGE'; export const POLL_INTERVAL_CHANGE = "POLL_INTERVAL_CHANGE";
export const TOGGLE_DARK_THEME = 'TOGGLE_DARK_THEME'; export const THEME_PREFERENCE_CHANGE = "THEME_PREFERENCE_CHANGE";
interface PollIntervalChangeAction { interface PollIntervalChangeAction {
type: typeof POLL_INTERVAL_CHANGE; type: typeof POLL_INTERVAL_CHANGE;
@ -8,11 +10,14 @@ interface PollIntervalChangeAction {
} }
interface ToggleDarkThemeAction { interface ToggleDarkThemeAction {
type: typeof TOGGLE_DARK_THEME; type: typeof THEME_PREFERENCE_CHANGE;
value: ThemePreference;
} }
// Union of all settings related action types. // Union of all settings related action types.
export type SettingsActionTypes = PollIntervalChangeAction | ToggleDarkThemeAction; export type SettingsActionTypes =
| PollIntervalChangeAction
| ToggleDarkThemeAction;
export function pollIntervalChange(value: number) { export function pollIntervalChange(value: number) {
return { return {
@ -21,9 +26,9 @@ export function pollIntervalChange(value: number) {
}; };
} }
export function toggleDarkTheme() { export function selectTheme(value: ThemePreference) {
return { return {
type: TOGGLE_DARK_THEME type: THEME_PREFERENCE_CHANGE,
} value,
};
} }

View File

@ -1,17 +1,22 @@
import { import {
POLL_INTERVAL_CHANGE, POLL_INTERVAL_CHANGE,
SettingsActionTypes, SettingsActionTypes,
TOGGLE_DARK_THEME, THEME_PREFERENCE_CHANGE,
} from "../actions/settingsActions"; } from "../actions/settingsActions";
export enum ThemePreference {
SystemDefault,
Always,
Never,
}
interface SettingsState { interface SettingsState {
pollInterval: number; pollInterval: number;
isDarkTheme: boolean; themePreference: ThemePreference;
} }
const initialState: SettingsState = { const initialState: SettingsState = {
pollInterval: 8, pollInterval: 8,
isDarkTheme: true, themePreference: ThemePreference.SystemDefault,
}; };
function settingsReducer( function settingsReducer(
@ -21,10 +26,10 @@ function settingsReducer(
switch (action.type) { switch (action.type) {
case POLL_INTERVAL_CHANGE: case POLL_INTERVAL_CHANGE:
return { ...state, pollInterval: action.value }; return { ...state, pollInterval: action.value };
case TOGGLE_DARK_THEME: case THEME_PREFERENCE_CHANGE:
return { return {
...state, ...state,
isDarkTheme: !state.isDarkTheme, themePreference: action.value,
}; };
default: default:
return state; return state;

View File

@ -1,6 +1,15 @@
import { createMuiTheme, Theme } from "@material-ui/core/styles"; import { createMuiTheme, Theme } from "@material-ui/core/styles";
import { ThemePreference } from "./reducers/settingsReducer";
import useMediaQuery from "@material-ui/core/useMediaQuery";
export function makeTheme(isDarkTheme: boolean): Theme { export function makeTheme(themePreference: ThemePreference): Theme {
// eslint-disable-next-line react-hooks/rules-of-hooks
let prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
if (themePreference === ThemePreference.Always) {
prefersDarkMode = true;
} else if (themePreference === ThemePreference.Never) {
prefersDarkMode = false;
}
return createMuiTheme({ return createMuiTheme({
// Got color palette from https://htmlcolors.com/palette/31/stripe // Got color palette from https://htmlcolors.com/palette/31/stripe
palette: { palette: {
@ -13,7 +22,7 @@ export function makeTheme(isDarkTheme: boolean): Theme {
background: { background: {
default: "#f5f7f9", default: "#f5f7f9",
}, },
type: isDarkTheme ? "dark" : "light", type: prefersDarkMode ? "dark" : "light",
}, },
}); });
} }

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { connect, ConnectedProps } from "react-redux"; import { connect, ConnectedProps } from "react-redux";
import Container from "@material-ui/core/Container"; import Container from "@material-ui/core/Container";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles, useTheme, Theme } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
@ -31,7 +31,7 @@ function mapStateToProps(state: AppState) {
redisAddress: state.redis.address, redisAddress: state.redis.address,
redisInfoRaw: state.redis.rawData, redisInfoRaw: state.redis.rawData,
pollInterval: state.settings.pollInterval, pollInterval: state.settings.pollInterval,
isDarkTheme: state.settings.isDarkTheme, themePreference: state.settings.themePreference,
}; };
} }
@ -40,14 +40,9 @@ type Props = ConnectedProps<typeof connector>;
function RedisInfoView(props: Props) { function RedisInfoView(props: Props) {
const classes = useStyles(); const classes = useStyles();
const { const { pollInterval, getRedisInfoAsync, redisInfo, redisInfoRaw } = props;
pollInterval, const theme = useTheme<Theme>();
getRedisInfoAsync, const isDarkTheme = theme.palette.type === "dark";
redisInfo,
redisInfoRaw,
isDarkTheme,
} = props;
usePolling(getRedisInfoAsync, pollInterval); usePolling(getRedisInfoAsync, pollInterval);
// Metrics to show // Metrics to show

View File

@ -5,15 +5,14 @@ import { makeStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import Switch from "@material-ui/core/Switch";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import FormGroup from "@material-ui/core/FormGroup";
import Slider from "@material-ui/core/Slider"; import Slider from "@material-ui/core/Slider";
import { import { pollIntervalChange, selectTheme } from "../actions/settingsActions";
pollIntervalChange,
toggleDarkTheme,
} from "../actions/settingsActions";
import { AppState } from "../store"; import { AppState } from "../store";
import FormControl from "@material-ui/core/FormControl/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import { ThemePreference } from "../reducers/settingsReducer";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
container: { container: {
@ -26,16 +25,23 @@ const useStyles = makeStyles((theme) => ({
overflow: "auto", overflow: "auto",
flexDirection: "column", flexDirection: "column",
}, },
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
})); }));
function mapStateToProps(state: AppState) { function mapStateToProps(state: AppState) {
return { return {
pollInterval: state.settings.pollInterval, pollInterval: state.settings.pollInterval,
isDarkTheme: state.settings.isDarkTheme, themePreference: state.settings.themePreference,
}; };
} }
const mapDispatchToProps = { pollIntervalChange, toggleDarkTheme }; const mapDispatchToProps = { pollIntervalChange, selectTheme };
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
@ -53,8 +59,8 @@ function SettingsView(props: PropsFromRedux) {
props.pollIntervalChange(val as number); props.pollIntervalChange(val as number);
}; };
const handleThemeChange = (event: React.ChangeEvent<HTMLElement>) => { const handleThemeChange = (event: React.ChangeEvent<{ value: unknown }>) => {
props.toggleDarkTheme(); props.selectTheme(event.target.value as ThemePreference);
}; };
return ( return (
<Container maxWidth="lg" className={classes.container}> <Container maxWidth="lg" className={classes.container}>
@ -87,23 +93,22 @@ function SettingsView(props: PropsFromRedux) {
/> />
</Paper> </Paper>
</Grid> </Grid>
<Grid item xs={5}> <FormControl variant="outlined" className={classes.formControl}>
<Paper> <InputLabel id="theme-label">Dark theme</InputLabel>
<Typography color="textPrimary">theme switch</Typography> <Select
<FormGroup row> labelId="theme-label"
<FormControlLabel id="theme-selected"
control={ value={props.themePreference}
<Switch onChange={handleThemeChange}
checked={props.isDarkTheme} label="theme preference"
onChange={handleThemeChange} >
name="DarkTheme" <MenuItem value={ThemePreference.SystemDefault}>
/> System Default
} </MenuItem>
label="🌛" <MenuItem value={ThemePreference.Always}>Always</MenuItem>
/> <MenuItem value={ThemePreference.Never}>Never</MenuItem>
</FormGroup> </Select>
</Paper> </FormControl>
</Grid>
</Grid> </Grid>
</Container> </Container>
); );