diff --git a/xinference/web/ui/src/App.js b/xinference/web/ui/src/App.js index 9ac335eb18..8e77d54f1e 100644 --- a/xinference/web/ui/src/App.js +++ b/xinference/web/ui/src/App.js @@ -1,4 +1,4 @@ -import { CssBaseline, ThemeProvider } from '@mui/material' +import { CssBaseline } from '@mui/material' import Snackbar from '@mui/material/Snackbar' import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' @@ -7,12 +7,11 @@ import { HashRouter } from 'react-router-dom' import { Alert } from './components/alertComponent' import { ApiContextProvider } from './components/apiContext' import AuthAlertDialog from './components/authAlertDialog' +import { ThemeProvider } from './components/themeContext' import { getEndpoint } from './components/utils' import WraperRoutes from './router/index' -import { useMode } from './theme' function App() { - const [theme] = useMode() const [cookie, setCookie, removeCookie] = useCookies(['token']) const [msg, setMsg] = useState('') @@ -61,25 +60,25 @@ function App() { return (
- - - {msg} - - - - + + + + {msg} + + + - - + +
) } diff --git a/xinference/web/ui/src/components/MenuSide.js b/xinference/web/ui/src/components/MenuSide.js index d8d763dfbe..9c8f10f601 100644 --- a/xinference/web/ui/src/components/MenuSide.js +++ b/xinference/web/ui/src/components/MenuSide.js @@ -21,6 +21,7 @@ import { useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import icon from '../media/icon.webp' +import ThemeButton from './themeButton' const navItems = [ { @@ -124,7 +125,7 @@ const MenuSide = () => { - + @@ -199,6 +200,7 @@ const MenuSide = () => { + ) } diff --git a/xinference/web/ui/src/components/Title.js b/xinference/web/ui/src/components/Title.js index 77820db4cb..fbec49add5 100644 --- a/xinference/web/ui/src/components/Title.js +++ b/xinference/web/ui/src/components/Title.js @@ -24,12 +24,7 @@ const Title = ({ title }) => { return ( - + {title} {(isValidBearerToken(cookie.token) || diff --git a/xinference/web/ui/src/components/themeButton.js b/xinference/web/ui/src/components/themeButton.js new file mode 100644 index 0000000000..f85f648f91 --- /dev/null +++ b/xinference/web/ui/src/components/themeButton.js @@ -0,0 +1,20 @@ +import DarkModeIcon from '@mui/icons-material/DarkMode' +import LightModeIcon from '@mui/icons-material/LightMode' +import { Box, IconButton } from '@mui/material' +import React from 'react' + +import { useThemeContext } from './themeContext' + +const ThemeButton = ({ sx }) => { + const { themeMode, toggleTheme } = useThemeContext() + + return ( + + + {themeMode === 'light' ? : } + + + ) +} + +export default ThemeButton diff --git a/xinference/web/ui/src/components/themeContext.js b/xinference/web/ui/src/components/themeContext.js new file mode 100644 index 0000000000..ebebf86924 --- /dev/null +++ b/xinference/web/ui/src/components/themeContext.js @@ -0,0 +1,36 @@ +import { ThemeProvider as MuiThemeProvider } from '@mui/material' +import { createContext, useContext, useState } from 'react' + +import { useMode } from '../theme' + +const ThemeContext = createContext() + +export function useThemeContext() { + return useContext(ThemeContext) +} + +export const ThemeProvider = ({ children }) => { + const themeKey = 'theme' + const systemPreference = window.matchMedia('(prefers-color-scheme: dark)') + .matches + ? 'dark' + : 'light' + const initialMode = localStorage.getItem(themeKey) || systemPreference + + const [themeMode, setThemeMode] = useState(initialMode) + const theme = useMode(themeMode)[0] + + const switchTheme = () => { + const nextTheme = themeMode === 'light' ? 'dark' : 'light' + setThemeMode(nextTheme) + localStorage.setItem(themeKey, nextTheme) + } + + return ( + + + {children} + + + ) +} diff --git a/xinference/web/ui/src/theme.js b/xinference/web/ui/src/theme.js index 4f4e175620..0a76e5bfa5 100644 --- a/xinference/web/ui/src/theme.js +++ b/xinference/web/ui/src/theme.js @@ -1,7 +1,7 @@ import { createTheme } from '@mui/material/styles' // mui theme settings -export const themeSettings = () => { +export const themeSettings = (mode) => { return { ERROR_COLOR: '#d8342c', typography: { @@ -32,10 +32,13 @@ export const themeSettings = () => { fontSize: 14, }, }, + palette: { + mode: mode, + }, } } -export const useMode = () => { - const theme = createTheme(themeSettings()) +export const useMode = (mode = 'light') => { + const theme = createTheme(themeSettings(mode)) return [theme] }