From 021a908c9cbc35751b0586f70dfd98220cbb64d3 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Tue, 24 Feb 2026 18:35:36 +0200 Subject: [PATCH] fix(canvas): not reacting to switch between light/dark mode --- apps/client/src/widgets/react/hooks.tsx | 25 +++++++++++++++++++ .../widgets/type_widgets/canvas/Canvas.tsx | 11 +++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 2dd5de4d5..8c0dc7808 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -1383,3 +1383,28 @@ export function useGetContextDataFrom( return data; } +export function useColorScheme() { + const themeStyle = getThemeStyle(); + const defaultValue = themeStyle === "auto" ? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) : themeStyle === "dark"; + const [ prefersDark, setPrefersDark ] = useState(defaultValue); + + useEffect(() => { + if (themeStyle !== "auto") return; + const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)"); + const listener = () => setPrefersDark((window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)); + + mediaQueryList.addEventListener("change", listener); + return () => mediaQueryList.removeEventListener("change", listener); + }, []); + + return prefersDark ? "dark" : "light"; +} + +function getThemeStyle() { + const style = window.getComputedStyle(document.body); + const themeStyle = style.getPropertyValue("--theme-style"); + if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) { + return themeStyle as "light" | "dark"; + } + return "auto"; +} diff --git a/apps/client/src/widgets/type_widgets/canvas/Canvas.tsx b/apps/client/src/widgets/type_widgets/canvas/Canvas.tsx index 6a5ea9377..3c22af9c7 100644 --- a/apps/client/src/widgets/type_widgets/canvas/Canvas.tsx +++ b/apps/client/src/widgets/type_widgets/canvas/Canvas.tsx @@ -1,7 +1,7 @@ import { Excalidraw } from "@excalidraw/excalidraw"; import { TypeWidgetProps } from "../type_widget"; import "@excalidraw/excalidraw/index.css"; -import { useNoteLabelBoolean, useTriliumOption } from "../../react/hooks"; +import { useColorScheme, useNoteLabelBoolean, useTriliumOption } from "../../react/hooks"; import { useCallback, useMemo, useRef } from "preact/hooks"; import { type ExcalidrawImperativeAPI, type AppState } from "@excalidraw/excalidraw/types"; import options from "../../../services/options"; @@ -19,12 +19,9 @@ window.EXCALIDRAW_ASSET_PATH = `${window.location.pathname}/node_modules/@excali export default function Canvas({ note, noteContext }: TypeWidgetProps) { const apiRef = useRef(null); const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly"); - const themeStyle = useMemo(() => { - const documentStyle = window.getComputedStyle(document.documentElement); - return documentStyle.getPropertyValue("--theme-style")?.trim() as AppState["theme"]; - }, []); + const colorScheme = useColorScheme(); const [ locale ] = useTriliumOption("locale"); - const persistence = useCanvasPersistence(note, noteContext, apiRef, themeStyle, isReadOnly); + const persistence = useCanvasPersistence(note, noteContext, apiRef, colorScheme, isReadOnly); /** Use excalidraw's native zoom instead of the global zoom. */ const onWheel = useCallback((e: MouseEvent) => { @@ -54,7 +51,7 @@ export default function Canvas({ note, noteContext }: TypeWidgetProps) {
apiRef.current = api} - theme={themeStyle} + theme={colorScheme} viewModeEnabled={isReadOnly || options.is("databaseReadonly")} zenModeEnabled={false} isCollaborating={false}