From 36ada8352b34f473426c770bcb232142beba8786 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Wed, 28 May 2025 16:41:59 -0400 Subject: [PATCH 1/4] feat(new-webui): Add theme support with a toggle menu. --- .../log-viewer-webui/client/src/AntdApp.tsx | 16 ++++- .../components/Layout/MainLayout.module.css | 17 ++++- .../src/components/Layout/MainLayout.tsx | 44 ++++++++----- .../components/Layout/ThemeToggleMenuItem.tsx | 66 +++++++++++++++++++ .../log-viewer-webui/client/src/router.tsx | 11 +++- .../client/src/theme/index.tsx | 25 +++++++ .../client/src/theme/themeStore.ts | 56 ++++++++++++++++ .../client/src/theme/typings.ts | 8 +++ .../client/src/theme/utils.ts | 37 +++++++++++ 9 files changed, 260 insertions(+), 20 deletions(-) create mode 100644 components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx create mode 100644 components/log-viewer-webui/client/src/theme/index.tsx create mode 100644 components/log-viewer-webui/client/src/theme/themeStore.ts create mode 100644 components/log-viewer-webui/client/src/theme/typings.ts create mode 100644 components/log-viewer-webui/client/src/theme/utils.ts diff --git a/components/log-viewer-webui/client/src/AntdApp.tsx b/components/log-viewer-webui/client/src/AntdApp.tsx index 5435bae9d9..28de5c877f 100644 --- a/components/log-viewer-webui/client/src/AntdApp.tsx +++ b/components/log-viewer-webui/client/src/AntdApp.tsx @@ -1,6 +1,9 @@ import {RouterProvider} from "react-router"; +import {ConfigProvider} from "antd"; + import router from "./router"; +import THEME_CONFIG, {useThemeStore} from "./theme"; import "@ant-design/v5-patch-for-react-19"; @@ -11,7 +14,18 @@ import "@ant-design/v5-patch-for-react-19"; * @return */ const AntApp = () => { - return ; + const {algorithm} = useThemeStore(); + + return ( + + + + ); }; export default AntApp; diff --git a/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css b/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css index 784310750a..05a29739fa 100644 --- a/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css +++ b/components/log-viewer-webui/client/src/components/Layout/MainLayout.module.css @@ -1,5 +1,6 @@ .mainLayout { - min-height: 100vh; + height: 100vh; + overflow: hidden; } .siderLogoContainer { @@ -9,8 +10,20 @@ height: 64px; } +.siderContainer { + flex-direction: column; + display: flex; + justify-content: space-between; + height: 100%; +} + .siderLogo { max-width: 100%; max-height: 100%; - height: 32px; + padding-inline: 10%; + padding-block: 16px; +} + +.siderTopMenu { + flex-grow: 1; } diff --git a/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx b/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx index b3ef4f89c5..26778e0b5b 100644 --- a/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx +++ b/components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx @@ -1,7 +1,7 @@ -import {useState} from "react"; import { Link, Outlet, + useLocation, } from "react-router"; import { @@ -15,45 +15,57 @@ import { } from "antd"; import styles from "./MainLayout.module.css"; +import ThemeToggleMenuItem from "./ThemeToggleMenuItem"; const {Sider} = Layout; type MenuItem = Required["items"][number]; -const SIDEBAR_MENU_ITEMS: MenuItem[] = [ +const sidebarTopMenuItems: MenuItem[] = [ + {type: "divider"}, {label: Ingest, key: "/ingest", icon: }, {label: Search, key: "/search", icon: }, ]; +const sidebarBottomMenuItems = [ + , +]; + /** * The main layout of web ui. * * @return */ const MainLayout = () => { - const [collapsed, setCollapsed] = useState(false); + const {pathname} = useLocation(); return ( { - setCollapsed(value); - }} + width={"200"} > -
- {"CLP +
+
+ {"CLP +
+ + + {sidebarBottomMenuItems} +
- diff --git a/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx b/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx new file mode 100644 index 0000000000..07b64f7760 --- /dev/null +++ b/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx @@ -0,0 +1,66 @@ +import {useCallback} from "react"; + +import { + FormatPainterOutlined, + MoonOutlined, + SunOutlined, +} from "@ant-design/icons"; +import {Menu} from "antd"; + +import { + THEME_MODE, + useThemeStore, +} from "../../theme"; + + +/** + * Maps theme mode to icon. + */ +const THEME_MODE_TO_ICON: Record = Object.freeze({ + [THEME_MODE.SYSTEM]: , + [THEME_MODE.DARK]: , + [THEME_MODE.LIGHT]: , +}); + +/** + * Maps theme mode to label. + */ +const THEME_MODE_TO_LABEL: Record = Object.freeze({ + [THEME_MODE.SYSTEM]: "System", + [THEME_MODE.DARK]: "Dark", + [THEME_MODE.LIGHT]: "Light", +}); + +const {Item} = Menu; + +/** + * Displays a theme toggle menu item. + * + * @return + */ +const ThemeToggleMenuItem = () => { + const mode = useThemeStore((state) => state.mode); + + const handleClick = useCallback(() => { + const {setMode} = useThemeStore.getState(); + if (mode === THEME_MODE.SYSTEM) { + setMode(THEME_MODE.DARK); + } else if (mode === THEME_MODE.DARK) { + setMode(THEME_MODE.LIGHT); + } else { + setMode(THEME_MODE.SYSTEM); + } + }, [mode]); + + return ( + + {THEME_MODE_TO_LABEL[mode]} + + ); +}; + + +export default ThemeToggleMenuItem; diff --git a/components/log-viewer-webui/client/src/router.tsx b/components/log-viewer-webui/client/src/router.tsx index 45e498bbd1..3243f1a110 100644 --- a/components/log-viewer-webui/client/src/router.tsx +++ b/components/log-viewer-webui/client/src/router.tsx @@ -1,4 +1,7 @@ -import {createBrowserRouter} from "react-router"; +import { + createBrowserRouter, + Navigate, +} from "react-router"; import MainLayout from "./components/Layout/MainLayout"; import IngestPage from "./pages/IngestPage"; @@ -10,6 +13,12 @@ const router = createBrowserRouter([ path: "/", Component: MainLayout, children: [ + { + path: "/", + element: , + }, {path: "ingest", Component: IngestPage}, {path: "search", Component: SearchPage}, ], diff --git a/components/log-viewer-webui/client/src/theme/index.tsx b/components/log-viewer-webui/client/src/theme/index.tsx new file mode 100644 index 0000000000..18fa69f625 --- /dev/null +++ b/components/log-viewer-webui/client/src/theme/index.tsx @@ -0,0 +1,25 @@ +import type {ThemeConfig} from "antd/es/config-provider/context"; + +import useThemeStore from "./themeStore"; +import {THEME_MODE} from "./typings"; + + +/** + * Ant Design theme configuration. + */ +const THEME_CONFIG: ThemeConfig = Object.freeze({ + token: { + fontFamily: "'Inter', sans-serif", + colorPrimary: "#2a8efa", + borderRadius: 3, + }, + cssVar: true, + hashed: false, +}); + + +export { + THEME_MODE, + useThemeStore, +}; +export default THEME_CONFIG; diff --git a/components/log-viewer-webui/client/src/theme/themeStore.ts b/components/log-viewer-webui/client/src/theme/themeStore.ts new file mode 100644 index 0000000000..ad28f82b05 --- /dev/null +++ b/components/log-viewer-webui/client/src/theme/themeStore.ts @@ -0,0 +1,56 @@ +import type {MappingAlgorithm} from "antd/es/theme/interface"; +import {create} from "zustand"; +import {persist} from "zustand/middleware"; + +import {THEME_MODE} from "./typings"; +import { + getAlgorithm, + getSystemAlgorithm, +} from "./utils"; + + +interface ThemeValues { + algorithm: MappingAlgorithm; + mode: THEME_MODE; +} + +interface ThemeActions { + setMode: (mode: THEME_MODE) => void; +} + +type ThemeState = ThemeValues & ThemeActions; + +const THEME_DEFAULT: ThemeValues = { + algorithm: getSystemAlgorithm(), + mode: THEME_MODE.SYSTEM, +}; + +const useThemeStore = create( + persist( + (set) => ({ + ...THEME_DEFAULT, + setMode: (newMode: THEME_MODE) => { + set({mode: newMode}); + set({algorithm: getAlgorithm(newMode)}); + }, + }), + { + name: "theme-storage", + merge: (persistedState, currentState) => { + const safePersistedState = persistedState as Partial; + + return { + ...currentState, + ...safePersistedState, + ...( + safePersistedState.mode && + {algorithm: getAlgorithm(safePersistedState.mode)} + ), + }; + }, + } + ) +); + + +export default useThemeStore; diff --git a/components/log-viewer-webui/client/src/theme/typings.ts b/components/log-viewer-webui/client/src/theme/typings.ts new file mode 100644 index 0000000000..548dc6e959 --- /dev/null +++ b/components/log-viewer-webui/client/src/theme/typings.ts @@ -0,0 +1,8 @@ +enum THEME_MODE { + SYSTEM = "system", + DARK = "dark", + LIGHT = "light", +} + + +export {THEME_MODE}; diff --git a/components/log-viewer-webui/client/src/theme/utils.ts b/components/log-viewer-webui/client/src/theme/utils.ts new file mode 100644 index 0000000000..0f6215b6ed --- /dev/null +++ b/components/log-viewer-webui/client/src/theme/utils.ts @@ -0,0 +1,37 @@ +import {theme} from "antd"; + +import {THEME_MODE} from "./typings"; + + +/** + * Detects Antd theme algorithm from system theme. + * + * @return The system theme algorithm. + */ +const getSystemAlgorithm = () => { + return window.matchMedia("(prefers-color-scheme: dark)").matches ? + theme.darkAlgorithm : + theme.defaultAlgorithm; +}; + +/** + * Detects Antd theme algorithm for the given theme mode. + * + * @param mode + * @return The theme algorithm. + */ +const getAlgorithm = (mode: THEME_MODE) => { + if (mode === THEME_MODE.SYSTEM) { + return getSystemAlgorithm(); + } else if (mode === THEME_MODE.DARK) { + return theme.darkAlgorithm; + } + + return theme.defaultAlgorithm; +}; + + +export { + getAlgorithm, + getSystemAlgorithm, +}; From ff6bcb3d78224d4cfcdd35e653af947a4b5aaa8e Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Wed, 28 May 2025 16:46:15 -0400 Subject: [PATCH 2/4] revert route changes --- components/log-viewer-webui/client/src/router.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/components/log-viewer-webui/client/src/router.tsx b/components/log-viewer-webui/client/src/router.tsx index 3243f1a110..45e498bbd1 100644 --- a/components/log-viewer-webui/client/src/router.tsx +++ b/components/log-viewer-webui/client/src/router.tsx @@ -1,7 +1,4 @@ -import { - createBrowserRouter, - Navigate, -} from "react-router"; +import {createBrowserRouter} from "react-router"; import MainLayout from "./components/Layout/MainLayout"; import IngestPage from "./pages/IngestPage"; @@ -13,12 +10,6 @@ const router = createBrowserRouter([ path: "/", Component: MainLayout, children: [ - { - path: "/", - element: , - }, {path: "ingest", Component: IngestPage}, {path: "search", Component: SearchPage}, ], From 285d845ce8e8c243e2622755454cca1ccafc8004 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 31 May 2025 11:25:45 +0800 Subject: [PATCH 3/4] fix import --- .../log-viewer-webui/client/src/theme.tsx | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 components/log-viewer-webui/client/src/theme.tsx diff --git a/components/log-viewer-webui/client/src/theme.tsx b/components/log-viewer-webui/client/src/theme.tsx deleted file mode 100644 index a06f77a6b2..0000000000 --- a/components/log-viewer-webui/client/src/theme.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import type {ThemeConfig} from "antd"; - - -/** - * Ant Design theme configuration. - */ -const THEME_CONFIG: ThemeConfig = Object.freeze({ - token: { - fontFamily: "'Inter', sans-serif", - colorPrimary: "#2a8efa", - borderRadius: 3, - }, - cssVar: true, - hashed: false, -}); - - -export default THEME_CONFIG; From dd8f898e8ebc773d00c42ed8f2ce1aca0d11fc30 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 31 May 2025 12:08:03 +0800 Subject: [PATCH 4/4] Add Material UI icons for theme toggle options --- .../log-viewer-webui/client/package-lock.json | 292 ++++++++++++++++-- .../log-viewer-webui/client/package.json | 1 + .../components/Layout/ThemeToggleMenuItem.tsx | 21 +- 3 files changed, 284 insertions(+), 30 deletions(-) diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index f585c02ff2..5f407e7e25 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -12,6 +12,7 @@ "@ant-design/v5-patch-for-react-19": "^1.0.3", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^7.1.0", "@mui/joy": "^5.0.0-beta.51", "@sinclair/typebox": "^0.34.25", "antd": "^5.24.5", @@ -428,13 +429,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz", - "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz", + "integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } @@ -1503,6 +1501,32 @@ "url": "https://opencollective.com/mui-org" } }, + "node_modules/@mui/icons-material": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.1.0.tgz", + "integrity": "sha512-1mUPMAZ+Qk3jfgL5ftRR06ATH/Esi0izHl1z56H+df6cwIlCWG66RXciUqeJCttbOXOQ5y2DCjLZI/4t3Yg3LA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.1.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/joy": { "version": "5.0.0-beta.51", "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.51.tgz", @@ -1544,6 +1568,202 @@ } } }, + "node_modules/@mui/material": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.1.0.tgz", + "integrity": "sha512-ahUJdrhEv+mCp4XHW+tHIEYzZMSRLg8z4AjUOsj44QpD1ZaMxQoVOG2xiHvLFdcsIPbgSRx1bg1eQSheHBgvtg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/core-downloads-tracker": "^7.1.0", + "@mui/system": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.1.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.1.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/core-downloads-tracker": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.0.tgz", + "integrity": "sha512-E0OqhZv548Qdc0PwWhLVA2zmjJZSTvaL4ZhoswmI8NJEC1tpW2js6LLP827jrW9MEiXYdz3QS6+hask83w74yQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material/node_modules/@mui/private-theming": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.1.0.tgz", + "integrity": "sha512-4Kck4jxhqF6YxNwJdSae1WgDfXVg0lIH6JVJ7gtuFfuKcQCgomJxPvUEOySTFRPz1IZzwz5OAcToskRdffElDA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/utils": "^7.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/styled-engine": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.1.0.tgz", + "integrity": "sha512-m0mJ0c6iRC+f9hMeRe0W7zZX1wme3oUX0+XTVHjPG7DJz6OdQ6K/ggEOq7ZdwilcpdsDUwwMfOmvO71qDkYd2w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.27.1", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/system": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.1.0.tgz", + "integrity": "sha512-iedAWgRJMCxeMHvkEhsDlbvkK+qKf9me6ofsf7twk/jfT4P1ImVf7Rwb5VubEA0sikrVL+1SkoZM41M4+LNAVA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/private-theming": "^7.1.0", + "@mui/styled-engine": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/types": "^7.4.2", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/private-theming": { "version": "5.16.14", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.14.tgz", @@ -1644,10 +1864,13 @@ } }, "node_modules/@mui/types": { - "version": "7.2.21", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", - "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz", + "integrity": "sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1" + }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2336,7 +2559,6 @@ "version": "19.0.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", - "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -2362,6 +2584,16 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@types/unist": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", @@ -3817,6 +4049,17 @@ "node": ">=0.10.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -7314,9 +7557,9 @@ } }, "node_modules/react-is": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", - "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "license": "MIT" }, "node_modules/react-refresh": { @@ -7379,6 +7622,23 @@ "node": "*" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -7427,12 +7687,6 @@ "node": ">=6" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 9f3d6f23e5..e0ae26db5a 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -17,6 +17,7 @@ "@ant-design/v5-patch-for-react-19": "^1.0.3", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^7.1.0", "@mui/joy": "^5.0.0-beta.51", "@sinclair/typebox": "^0.34.25", "antd": "^5.24.5", diff --git a/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx b/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx index 07b64f7760..54a60d5947 100644 --- a/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx +++ b/components/log-viewer-webui/client/src/components/Layout/ThemeToggleMenuItem.tsx @@ -1,25 +1,26 @@ -import {useCallback} from "react"; +import React, {useCallback} from "react"; -import { - FormatPainterOutlined, - MoonOutlined, - SunOutlined, -} from "@ant-design/icons"; import {Menu} from "antd"; +import DarkModeOutlinedIcon from "@mui/icons-material/DarkModeOutlined"; +import LightModeOutlinedIcon from "@mui/icons-material/LightModeOutlined"; +import SettingsBrightnessOutlinedIcon from "@mui/icons-material/SettingsBrightnessOutlined"; + import { THEME_MODE, useThemeStore, } from "../../theme"; +const {Item} = Menu; + /** * Maps theme mode to icon. */ const THEME_MODE_TO_ICON: Record = Object.freeze({ - [THEME_MODE.SYSTEM]: , - [THEME_MODE.DARK]: , - [THEME_MODE.LIGHT]: , + [THEME_MODE.SYSTEM]: , + [THEME_MODE.DARK]: , + [THEME_MODE.LIGHT]: , }); /** @@ -31,8 +32,6 @@ const THEME_MODE_TO_LABEL: Record = Object.freeze({ [THEME_MODE.LIGHT]: "Light", }); -const {Item} = Menu; - /** * Displays a theme toggle menu item. *