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]
}