diff --git a/website/src/App.tsx b/website/src/App.tsx
index d3f98fa4..f59434f0 100644
--- a/website/src/App.tsx
+++ b/website/src/App.tsx
@@ -8,6 +8,7 @@ import { grpc } from './Api';
import { AppState } from './AppState';
import { YourDevices } from './pages/YourDevices';
import { AllDevices } from './pages/admin/AllDevices';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
export const App = observer(class App extends React.Component {
async componentDidMount() {
@@ -18,20 +19,29 @@ export const App = observer(class App extends React.Component {
if (!AppState.info) {
return
loading...
;
}
+
+ const darkLightTheme = createTheme({
+ palette: {
+ mode: AppState.darkMode ? 'dark' : 'light',
+ },
+ });
+
return (
-
-
-
-
- } />
- {AppState.info.isAdmin && (
- <>
- } />
- >
- )}
-
-
+
+
+
+
+
+ } />
+ {AppState.info.isAdmin && (
+ <>
+ } />
+ >
+ )}
+
+
+
);
}
diff --git a/website/src/AppState.ts b/website/src/AppState.ts
index c7ef1f73..fb4d7220 100644
--- a/website/src/AppState.ts
+++ b/website/src/AppState.ts
@@ -1,13 +1,24 @@
-import { observable, makeObservable } from 'mobx';
+import {observable, makeObservable, runInAction} from 'mobx';
import { InfoRes } from './sdk/server_pb';
class GlobalAppState {
info?: InfoRes.AsObject;
+ darkMode: boolean;
constructor() {
makeObservable(this, {
- info: observable
+ info: observable,
+ darkMode: observable
});
+
+ this.darkMode = false;
+ }
+
+ setDarkMode(darkMode: boolean) {
+ runInAction(() => {
+ this.darkMode = darkMode;
+ })
+
}
}
diff --git a/website/src/components/Navigation.tsx b/website/src/components/Navigation.tsx
index 900e4bfb..6256f4c9 100644
--- a/website/src/components/Navigation.tsx
+++ b/website/src/components/Navigation.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useEffect} from 'react';
import makeStyles from '@mui/styles/makeStyles';
import { getCookie } from '../Cookies';
import { AppState } from '../AppState';
@@ -10,6 +10,10 @@ import Link from '@mui/material/Link';
import Button from '@mui/material/Button';
import Chip from '@mui/material/Chip';
import VpnKey from '@mui/icons-material/VpnKey';
+import IconButton from "@mui/material/IconButton";
+import Brightness4Icon from '@mui/icons-material/Brightness4';
+import Brightness7Icon from '@mui/icons-material/Brightness7';
+import {useMediaQuery} from "@mui/material";
const useStyles = makeStyles((theme) => ({
title: {
@@ -38,6 +42,8 @@ export default function Navigation() {
)}
+
+
{AppState.info?.isAdmin && (
@@ -53,3 +59,39 @@ export default function Navigation() {
);
}
+
+function DarkModeToggle() {
+
+ const CUSTOM_DARK_MODE_KEY = "customDarkMode";
+ const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
+
+ useEffect(()=>{
+ let customDarkMode = localStorage.getItem(CUSTOM_DARK_MODE_KEY);
+ if (customDarkMode) {
+ AppState.setDarkMode(JSON.parse(customDarkMode));
+ }
+ else {
+ AppState.setDarkMode(prefersDarkMode);
+ }
+
+ },[prefersDarkMode]);
+
+ function toggleDarkMode() {
+ AppState.setDarkMode(!AppState.darkMode);
+
+ // We only persist the preference in the local storage if it is different to the OS setting.
+ if (prefersDarkMode !== AppState.darkMode) {
+ localStorage.setItem(CUSTOM_DARK_MODE_KEY, JSON.stringify(AppState.darkMode));
+ }
+ else {
+ localStorage.removeItem(CUSTOM_DARK_MODE_KEY);
+ }
+ }
+
+ return (
+
+ {AppState.darkMode ? : }
+
+ );
+
+}
diff --git a/website/src/components/Present.tsx b/website/src/components/Present.tsx
index 5795b38e..14683593 100644
--- a/website/src/components/Present.tsx
+++ b/website/src/components/Present.tsx
@@ -4,6 +4,8 @@ import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
+import { AppState } from '../AppState';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
@@ -20,7 +22,14 @@ export function present(content: (close: (result: T) => void) => React.ReactN
}
export function confirm(msg: string): Promise {
+ const darkLightTheme = createTheme({
+ palette: {
+ mode: AppState.darkMode ? 'dark' : 'light',
+ },
+ });
+
return present((close) => (
+
+
));
}