From ce9f209653e643561189dd5d6e8ac15b39937850 Mon Sep 17 00:00:00 2001 From: michaelmkraus Date: Thu, 27 Nov 2025 13:03:13 +0100 Subject: [PATCH 1/3] feat(): add color mode switch for light and dark mode --- .../color-mode-switch/ColorModeSwitch.tsx | 24 ++++++ template/context/color-mode-context.tsx | 57 ++++++++++++++ template/layouts/default/shell/Shell.tsx | 74 +++++++++---------- .../shell/control-panel/primary-actions.tsx | 14 ++-- 4 files changed, 125 insertions(+), 44 deletions(-) create mode 100644 template/components/color-mode-switch/ColorModeSwitch.tsx create mode 100644 template/context/color-mode-context.tsx diff --git a/template/components/color-mode-switch/ColorModeSwitch.tsx b/template/components/color-mode-switch/ColorModeSwitch.tsx new file mode 100644 index 0000000..e80d10f --- /dev/null +++ b/template/components/color-mode-switch/ColorModeSwitch.tsx @@ -0,0 +1,24 @@ +import { DBSwitch, DBTooltip } from "@db-ux/react-core-components"; +import { useColorMode } from "@template/context/color-mode-context.tsx"; + +const ColorModeSwitch = () => { + const { colorMode, toggleColorMode } = useColorMode(); + const isDark = colorMode === "dark"; + + return ( + + + Switch color scheme (light/dark) + + Switch color scheme (light/dark) + + ); +}; + +export default ColorModeSwitch; \ No newline at end of file diff --git a/template/context/color-mode-context.tsx b/template/context/color-mode-context.tsx new file mode 100644 index 0000000..529fc46 --- /dev/null +++ b/template/context/color-mode-context.tsx @@ -0,0 +1,57 @@ +import { + createContext, + useContext, + useState, + useEffect, + type ReactNode, +} from "react"; + +type ColorMode = "light" | "dark"; + +interface ColorModeContextValue { + colorMode: ColorMode; + setColorMode: (colorMode: ColorMode) => void; + toggleColorMode: () => void; +} + +const ColorModeContext = createContext(undefined); + +export const ColorModeProvider = ({ children }: { children: ReactNode }) => { + const [colorMode, setColorMode] = useState("light"); + + useEffect(() => { + const stored = window.localStorage.getItem("db-ux-mode"); + if (stored === "light" || stored === "dark") { + setColorMode(stored); + } + }, []); + + useEffect(() => { + window.localStorage.setItem("db-ux-mode", colorMode); + + const shell = document.querySelector(".db-shell"); + if (shell instanceof HTMLElement) { + shell.setAttribute("data-mode", colorMode); + } + }, [colorMode]); + + const setMode = (next: ColorMode) => { + setColorMode(next); + }; + + const toggleColorMode = () => { + setColorMode((prev) => (prev === "light" ? "dark" : "light")); + }; + + const value: ColorModeContextValue = { colorMode, setColorMode: setMode, toggleColorMode }; + + return {children}; +}; + +export const useColorMode = (): ColorModeContextValue => { + const ctx = useContext(ColorModeContext); + if (!ctx) { + throw new Error("useColorMode must be used inside a ColorModeProvider"); + } + return ctx; +}; \ No newline at end of file diff --git a/template/layouts/default/shell/Shell.tsx b/template/layouts/default/shell/Shell.tsx index dd96c14..351cef3 100644 --- a/template/layouts/default/shell/Shell.tsx +++ b/template/layouts/default/shell/Shell.tsx @@ -1,10 +1,6 @@ import { type PropsWithChildren, type ReactElement } from "react"; - -import { - DBControlPanelDesktop, - DBControlPanelMobile, - DBShell, -} from "@db-ux/react-core-components"; +import { ColorModeProvider } from "@template/context/color-mode-context.tsx"; +import { DBControlPanelDesktop, DBControlPanelMobile, DBShell } from "@db-ux/react-core-components"; import PrimaryActions from "@template/layouts/default/shell/control-panel/primary-actions.tsx"; import MainNavigation from "@template/layouts/default/shell/control-panel/main-navigation.tsx"; import SubNavigation from "@template/layouts/default/shell/control-panel/sub-navigation.tsx"; @@ -12,38 +8,40 @@ import Brand from "@template/layouts/default/shell/control-panel/brand.tsx"; import { findSubNavigation } from "@template/utils/navigation.utils.ts"; export function Shell({ children }: PropsWithChildren): ReactElement { - const subNavigation = findSubNavigation(window.location.pathname); + const subNavigation = findSubNavigation(window.location.pathname); - /* - * TODO: We need to get the subNavigation if we are inside a subNavigation Item as well - * */ + /* + * TODO: We need to get the subNavigation if we are inside a subNavigation Item as well + * */ - return ( - : null - } - subNavigationMobilePosition="none" - controlPanelDesktop={ - } - primaryActions={} - > - - - } - controlPanelMobile={ - } - primaryActions={} - > - - - } - > - {children} - - ); + return ( + + : null + } + subNavigationMobilePosition="none" + controlPanelDesktop={ + } + primaryActions={} + > + + + } + controlPanelMobile={ + } + primaryActions={} + > + + + } + > + {children} + + + ); } diff --git a/template/layouts/default/shell/control-panel/primary-actions.tsx b/template/layouts/default/shell/control-panel/primary-actions.tsx index dfb5fd8..436c54c 100644 --- a/template/layouts/default/shell/control-panel/primary-actions.tsx +++ b/template/layouts/default/shell/control-panel/primary-actions.tsx @@ -1,14 +1,16 @@ import { DBControlPanelPrimaryActions } from "@db-ux/react-core-components"; import { appConfig } from "@root/app.config.ts"; import { Search } from "@template/layouts/default/shell/search"; +import ColorModeSwitch from "@template/components/color-mode-switch/ColorModeSwitch.tsx"; const PrimaryActions = () => ( - - { } - - Start now - - + + + { } + + Start now + + ); export default PrimaryActions; From 82c30fad76d8b095f43160063ce83d219ee0b896 Mon Sep 17 00:00:00 2001 From: michaelmkraus Date: Fri, 28 Nov 2025 08:35:11 +0100 Subject: [PATCH 2/3] feat(): place tooltip below icon --- template/layouts/default/shell/search/Search.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/layouts/default/shell/search/Search.tsx b/template/layouts/default/shell/search/Search.tsx index 2e4d385..feb95b2 100644 --- a/template/layouts/default/shell/search/Search.tsx +++ b/template/layouts/default/shell/search/Search.tsx @@ -73,7 +73,7 @@ export function Search(): ReactElement { onClick={() => setSearchOpen(true)} > Open Search - Open Search + Open Search setSearchOpen(false)}>
From abf5f14624da42bccc3148e6c8f854064e037f25 Mon Sep 17 00:00:00 2001 From: michaelmkraus Date: Fri, 28 Nov 2025 08:37:39 +0100 Subject: [PATCH 3/3] refactor(): introduce consts for static strings and replace useEffect --- template/context/color-mode-context.tsx | 27 ++++++++++++------- .../shell/control-panel/primary-actions.tsx | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/template/context/color-mode-context.tsx b/template/context/color-mode-context.tsx index 529fc46..1a7e929 100644 --- a/template/context/color-mode-context.tsx +++ b/template/context/color-mode-context.tsx @@ -14,22 +14,31 @@ interface ColorModeContextValue { toggleColorMode: () => void; } +const STORAGE_KEY = "db-ux-mode"; +const SHELL_SELECTOR = ".db-shell"; + const ColorModeContext = createContext(undefined); -export const ColorModeProvider = ({ children }: { children: ReactNode }) => { - const [colorMode, setColorMode] = useState("light"); +function getInitialColorMode(): ColorMode { + if (typeof window === "undefined") { + return "light"; + } - useEffect(() => { - const stored = window.localStorage.getItem("db-ux-mode"); - if (stored === "light" || stored === "dark") { - setColorMode(stored); - } - }, []); + const stored = window.localStorage.getItem(STORAGE_KEY); + if (stored === "light" || stored === "dark") { + return stored; + } + + return "light"; +} + +export const ColorModeProvider = ({ children }: { children: ReactNode }) => { + const [colorMode, setColorMode] = useState(getInitialColorMode); useEffect(() => { window.localStorage.setItem("db-ux-mode", colorMode); - const shell = document.querySelector(".db-shell"); + const shell = document.querySelector(SHELL_SELECTOR); if (shell instanceof HTMLElement) { shell.setAttribute("data-mode", colorMode); } diff --git a/template/layouts/default/shell/control-panel/primary-actions.tsx b/template/layouts/default/shell/control-panel/primary-actions.tsx index 436c54c..f915785 100644 --- a/template/layouts/default/shell/control-panel/primary-actions.tsx +++ b/template/layouts/default/shell/control-panel/primary-actions.tsx @@ -6,7 +6,7 @@ import ColorModeSwitch from "@template/components/color-mode-switch/ColorModeSwi const PrimaryActions = () => ( - { } + Start now