From fa3e0fc7f93a434d7f7b72a59b4e4d87a03a1b5e Mon Sep 17 00:00:00 2001 From: Johnny Date: Sun, 9 Nov 2025 14:19:11 +0800 Subject: [PATCH] fix(web): make MermaidBlock reactive to system theme changes and improve code quality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add system theme listener to detect OS theme changes in real-time - Refactor to eliminate duplicate theme preference extraction - Simplify getMermaidTheme function from switch statement to ternary - Move render guard outside async function for better readability - Update comments to be more concise and focused The component now properly re-renders Mermaid diagrams when the OS theme changes while using "system" theme preference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/MemoContent/MermaidBlock.tsx | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/web/src/components/MemoContent/MermaidBlock.tsx b/web/src/components/MemoContent/MermaidBlock.tsx index 3b09fb986..97516e4e4 100644 --- a/web/src/components/MemoContent/MermaidBlock.tsx +++ b/web/src/components/MemoContent/MermaidBlock.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react-lite"; import { useEffect, useMemo, useRef, useState } from "react"; import { cn } from "@/lib/utils"; import { instanceStore, userStore } from "@/store"; -import { resolveTheme } from "@/utils/theme"; +import { resolveTheme, setupSystemThemeListener } from "@/utils/theme"; interface MermaidBlockProps { children?: React.ReactNode; @@ -12,54 +12,49 @@ interface MermaidBlockProps { /** * Maps app theme to Mermaid theme - * @param appTheme - The resolved app theme - * @returns Mermaid theme name */ const getMermaidTheme = (appTheme: string): "default" | "dark" => { - switch (appTheme) { - case "default-dark": - return "dark"; - case "default": - case "paper": - case "whitewall": - default: - return "default"; - } + return appTheme === "default-dark" ? "dark" : "default"; }; export const MermaidBlock = observer(({ children, className }: MermaidBlockProps) => { const containerRef = useRef(null); const [svg, setSvg] = useState(""); const [error, setError] = useState(""); + const [systemThemeChange, setSystemThemeChange] = useState(0); - // Extract the code element and its content + // Extract Mermaid code content from children const codeElement = children as React.ReactElement; const codeContent = String(codeElement?.props?.children || "").replace(/\n$/, ""); - // Get current theme from store (reactive via MobX observer) - // This will automatically trigger re-render when theme changes - const currentTheme = useMemo(() => { - const userTheme = userStore.state.userGeneralSetting?.theme; - const instanceTheme = instanceStore.state.theme; - const theme = userTheme || instanceTheme; - return resolveTheme(theme); - }, [userStore.state.userGeneralSetting?.theme, instanceStore.state.theme]); + // Get theme preference (reactive via MobX observer) + const themePreference = userStore.state.userGeneralSetting?.theme || instanceStore.state.theme; + + // Resolve theme to actual value (handles "system" theme + system theme changes) + const currentTheme = useMemo(() => resolveTheme(themePreference), [themePreference, systemThemeChange]); - // Render diagram when content or theme changes + // Listen for OS theme changes when using "system" theme preference useEffect(() => { - const renderDiagram = async () => { - if (!codeContent || !containerRef.current) { - return; - } + if (themePreference !== "system") { + return; + } + + return setupSystemThemeListener(() => { + setSystemThemeChange((prev) => prev + 1); + }); + }, [themePreference]); + // Render Mermaid diagram when content or theme changes + useEffect(() => { + if (!codeContent || !containerRef.current) { + return; + } + + const renderDiagram = async () => { try { - // Generate a unique ID for this diagram const id = `mermaid-${Math.random().toString(36).substring(7)}`; - - // Get the appropriate Mermaid theme for current app theme const mermaidTheme = getMermaidTheme(currentTheme); - // Initialize mermaid with current theme mermaid.initialize({ startOnLoad: false, theme: mermaidTheme, @@ -67,7 +62,6 @@ export const MermaidBlock = observer(({ children, className }: MermaidBlockProps fontFamily: "inherit", }); - // Render the mermaid diagram const { svg: renderedSvg } = await mermaid.render(id, codeContent); setSvg(renderedSvg); setError("");