Browse Source

add theme mode toggle

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 10 months ago
parent
commit
d4b58274d5

+ 7 - 22
client/src/App.tsx

@@ -1,45 +1,30 @@
-import React from 'react';
-import { ThemeProvider, StyledEngineProvider } from '@mui/material';
-import useMediaQuery from '@mui/material/useMediaQuery';
+import { StyledEngineProvider } from '@mui/material';
 import Router from './router/Router';
 import {
   RootProvider,
   NavProvider,
   AuthProvider,
   DataProvider,
-  PrometheusProvider,
   SystemProvider,
+  ColorModeProvider,
 } from './context';
-import { createTheme } from '@mui/material/styles';
-import getCommonThemes from './styles/theme';
-
-const ColorModeContext = React.createContext({ toggleColorMode: () => {} });
 
 function App() {
-  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
-
-  const theme = React.useMemo(
-    () => createTheme(getCommonThemes(prefersDarkMode ? 'dark' : 'light')),
-    [true]
-  );
-
   return (
     <StyledEngineProvider injectFirst>
-      <ThemeProvider theme={theme}>
+      <ColorModeProvider>
         <AuthProvider>
           <DataProvider>
             <RootProvider>
               <SystemProvider>
-                <PrometheusProvider>
-                  <NavProvider>
-                    <Router></Router>
-                  </NavProvider>
-                </PrometheusProvider>
+                <NavProvider>
+                  <Router></Router>
+                </NavProvider>
               </SystemProvider>
             </RootProvider>
           </DataProvider>
         </AuthProvider>
-      </ThemeProvider>
+      </ColorModeProvider>
     </StyledEngineProvider>
   );
 }

File diff suppressed because it is too large
+ 38 - 10
client/src/components/icons/Icons.tsx


+ 3 - 1
client/src/components/icons/Types.ts

@@ -55,4 +55,6 @@ export type IconsType =
   | 'code'
   | 'reset'
   | 'link'
-  | 'cross';
+  | 'cross'
+  | 'day'
+  | 'night';

+ 18 - 0
client/src/components/layout/Header.tsx

@@ -8,6 +8,8 @@ import CustomSelector from '@/components/customSelector/CustomSelector';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import icons from '../icons/Icons';
 import { makeStyles } from '@mui/styles';
+import IconButton from '@mui/material/IconButton';
+import { ColorModeContext } from '@/context';
 
 const useStyles = makeStyles((theme: Theme) => ({
   header: {
@@ -65,11 +67,20 @@ const useStyles = makeStyles((theme: Theme) => ({
       top: '4px',
     },
   },
+  modeBtn: {
+    marginRight: theme.spacing(1),
+    '& svg': {
+      fontSize: 18,
+    },
+    color: theme.palette.text.primary,
+  },
 }));
 
 const Header: FC = () => {
   const classes = useStyles();
+  // use context
   const { navInfo } = useContext(navContext);
+  const { mode, toggleColorMode } = useContext(ColorModeContext);
   const { database, databases, setDatabase, loading } = useContext(dataContext);
   const { authReq, logout } = useContext(authContext);
   const { address, username } = authReq;
@@ -142,6 +153,13 @@ const Header: FC = () => {
         </div>
 
         <div className={classes.addressWrapper}>
+          <IconButton
+            className={classes.modeBtn}
+            onClick={toggleColorMode}
+            color="inherit"
+          >
+            {mode === 'dark' ? <icons.night /> : <icons.day />}
+          </IconButton>
           <div className="text">
             <Typography className="address">{address}</Typography>
             <Typography className="status">{statusTrans.running}</Typography>

+ 1 - 0
client/src/consts/Localstorage.ts

@@ -14,3 +14,4 @@ export const LAST_TIME_HEALTHY_THRESHOLD_MEMORY =
 // new local storage keys
 export const ATTU_UI_TREE_WIDTH = 'attu.ui.tree.with';
 export const ATTU_AUTH_HISTORY = 'attu.auth.history';
+export const ATTU_THEME_MODE = 'attu.theme.mode';

+ 42 - 0
client/src/context/ColorMode.tsx

@@ -0,0 +1,42 @@
+import React, { useState, useEffect } from 'react';
+import useMediaQuery from '@mui/material/useMediaQuery';
+import { createTheme } from '@mui/material/styles';
+import getCommonThemes from '../styles/theme';
+import { ThemeProvider } from '@mui/material';
+
+export const ColorModeContext = React.createContext({
+  toggleColorMode: () => {},
+  mode: 'light',
+});
+import { ATTU_THEME_MODE } from '@/consts';
+
+const { Provider } = ColorModeContext;
+
+type theme = 'light' | 'dark';
+
+export const ColorModeProvider = (props: { children: React.ReactNode }) => {
+  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
+
+  const systemTheme = prefersDarkMode ? 'dark' : 'light';
+  const userThemeMode = localStorage.getItem(ATTU_THEME_MODE) || systemTheme;
+
+  const [mode, setMode] = useState<theme>(userThemeMode as theme);
+
+  const theme = React.useMemo(() => createTheme(getCommonThemes(mode)), [mode]);
+
+  const toggleColorMode = () => {
+    setMode(prevMode => (prevMode === 'light' ? 'dark' : 'light'));
+  };
+
+  // store the current mode in localStorage
+  useEffect(() => {
+    localStorage.setItem(ATTU_THEME_MODE, mode);
+
+  }, [mode]);
+
+  return (
+    <Provider value={{ toggleColorMode, mode }}>
+      <ThemeProvider theme={theme}>{props.children}</ThemeProvider>
+    </Provider>
+  );
+};

+ 2 - 0
client/src/context/index.tsx

@@ -5,3 +5,5 @@ export * from './Prometheus';
 export * from './Root';
 export * from './Types';
 export * from './Data';
+export * from './ColorMode';
+

Some files were not shown because too many files changed in this diff