diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 0bfabd7..f01d13c 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { connect, ConnectedProps } from "react-redux"; import clsx from "clsx"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; -import { makeStyles } from "@material-ui/core/styles"; +import { makeStyles, ThemeProvider } from "@material-ui/core/styles"; import AppBar from "@material-ui/core/AppBar"; import Drawer from "@material-ui/core/Drawer"; import Toolbar from "@material-ui/core/Toolbar"; @@ -26,6 +26,7 @@ import DoubleArrowIcon from "@material-ui/icons/DoubleArrow"; import CloseIcon from "@material-ui/icons/Close"; import { AppState } from "./store"; import { paths } from "./paths"; +import { makeTheme } from "./theme"; import { closeSnackbar } from "./actions/snackbarActions"; import ListItemLink from "./components/ListItemLink"; import SchedulersView from "./views/SchedulersView"; @@ -125,7 +126,10 @@ const useStyles = makeStyles((theme) => ({ })); function mapStateToProps(state: AppState) { - return { snackbar: state.snackbar }; + return { + snackbar: state.snackbar, + isDarkTheme: state.settings.isDarkTheme, + }; } const mapDispatchToProps = { @@ -141,151 +145,152 @@ function SlideUpTransition(props: TransitionProps) { function App(props: ConnectedProps) { const classes = useStyles(); const [open, setOpen] = useState(true); - const toggleDrawer = () => { - setOpen(!open); - }; + const toggleDrawer = () => setOpen(!open); + const theme = makeTheme(props.isDarkTheme); return ( - -
- - - - - - - Asynq Monitoring - - - -
- + +
+ - + + + + + Asynq Monitoring + + + +
+ - - - - } - /> - -
-
- -
- } - /> - } - /> - } - /> - } - /> -
-
- - } + + + + + } /> - - - - - - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - -
-
+ +
+
+ +
+ } + /> + } + /> + } + /> + } + /> +
+
+ + } + /> + + + + + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
-
- + + ); } diff --git a/ui/src/actions/settingsActions.ts b/ui/src/actions/settingsActions.ts index a920afb..e5b06d0 100644 --- a/ui/src/actions/settingsActions.ts +++ b/ui/src/actions/settingsActions.ts @@ -1,13 +1,18 @@ // 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'; interface PollIntervalChangeAction { type: typeof POLL_INTERVAL_CHANGE; value: number; // new poll interval value in seconds } +interface ToggleDarkThemeAction { + type: typeof TOGGLE_DARK_THEME; +} + // Union of all settings related action types. -export type SettingsActionTypes = PollIntervalChangeAction; +export type SettingsActionTypes = PollIntervalChangeAction | ToggleDarkThemeAction; export function pollIntervalChange(value: number) { return { @@ -15,3 +20,10 @@ export function pollIntervalChange(value: number) { value, }; } + +export function toggleDarkTheme() { + return { + type: TOGGLE_DARK_THEME + } +} + diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 68a19ec..163bcea 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -2,19 +2,15 @@ import React from "react"; import ReactDOM from "react-dom"; import CssBaseline from "@material-ui/core/CssBaseline"; import { Provider } from "react-redux"; -import { ThemeProvider } from "@material-ui/core/styles"; import App from "./App"; import store from "./store"; -import theme from "./theme"; import * as serviceWorker from "./serviceWorker"; ReactDOM.render( - - - + , document.getElementById("root") diff --git a/ui/src/reducers/settingsReducer.ts b/ui/src/reducers/settingsReducer.ts index 6032bca..34edd7c 100644 --- a/ui/src/reducers/settingsReducer.ts +++ b/ui/src/reducers/settingsReducer.ts @@ -1,23 +1,24 @@ -import { - POLL_INTERVAL_CHANGE, - SettingsActionTypes, -} from "../actions/settingsActions"; +import {POLL_INTERVAL_CHANGE, SettingsActionTypes, TOGGLE_DARK_THEME,} from '../actions/settingsActions'; interface SettingsState { pollInterval: number; + isDarkTheme: boolean; } const initialState: SettingsState = { pollInterval: 8, + isDarkTheme: false, }; function settingsReducer( - state = initialState, - action: SettingsActionTypes -): SettingsState { + state = initialState, action: SettingsActionTypes): SettingsState { switch (action.type) { case POLL_INTERVAL_CHANGE: - return { ...state, pollInterval: action.value }; + return {...state, pollInterval: action.value}; + case TOGGLE_DARK_THEME: + return { + ...state, isDarkTheme: !state.isDarkTheme + } default: return state; } diff --git a/ui/src/theme.tsx b/ui/src/theme.tsx index ef6465e..36b028a 100644 --- a/ui/src/theme.tsx +++ b/ui/src/theme.tsx @@ -1,18 +1,19 @@ -import { createMuiTheme } from "@material-ui/core/styles"; +import { createMuiTheme, Theme } from "@material-ui/core/styles"; -// Got color palette from https://htmlcolors.com/palette/31/stripe -const theme = createMuiTheme({ - palette: { - primary: { - main: "#4379FF", +export function makeTheme(isDarkTheme: boolean): Theme { + return createMuiTheme({ + // Got color palette from https://htmlcolors.com/palette/31/stripe + palette: { + primary: { + main: "#4379FF", + }, + secondary: { + main: "#97FBD1", + }, + background: { + default: "#f5f7f9", + }, + type: isDarkTheme ? "dark" : "light", }, - secondary: { - main: "#97FBD1", - }, - background: { - default: "#f5f7f9", - }, - }, -}); - -export default theme; + }); +} diff --git a/ui/src/views/SettingsView.tsx b/ui/src/views/SettingsView.tsx index cafb8d6..861ca34 100644 --- a/ui/src/views/SettingsView.tsx +++ b/ui/src/views/SettingsView.tsx @@ -5,8 +5,14 @@ import { makeStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; -import Slider from "@material-ui/core/Slider/Slider"; -import { pollIntervalChange } from "../actions/settingsActions"; +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 { + pollIntervalChange, + toggleDarkTheme, +} from "../actions/settingsActions"; import { AppState } from "../store"; const useStyles = makeStyles((theme) => ({ @@ -25,10 +31,11 @@ const useStyles = makeStyles((theme) => ({ function mapStateToProps(state: AppState) { return { pollInterval: state.settings.pollInterval, + isDarkTheme: state.settings.isDarkTheme, }; } -const mapDispatchToProps = { pollIntervalChange }; +const mapDispatchToProps = { pollIntervalChange, toggleDarkTheme }; const connector = connect(mapStateToProps, mapDispatchToProps); @@ -46,6 +53,9 @@ function SettingsView(props: PropsFromRedux) { props.pollIntervalChange(val as number); }; + const handleThemeChange = (event: React.ChangeEvent) => { + props.toggleDarkTheme(); + }; return ( @@ -75,6 +85,23 @@ function SettingsView(props: PropsFromRedux) { /> + + + theme switch + + + } + label="🌛" + /> + + + );