mirror of https://github.com/usememos/memos.git
refactor(web): use MobX observer for Mermaid theme detection
Replace MutationObserver with MobX observer pattern for cleaner, more reactive theme detection in MermaidBlock component. Changes: - Use observer() wrapper from mobx-react-lite - Watch instanceStore.state.theme and userStore.state.userGeneralSetting.theme - Use resolveTheme() utility to handle "system" theme resolution - Remove MutationObserver boilerplate code - Use useMemo for computed theme value Benefits: - Consistent with app's state management architecture (same as App.tsx) - Automatic re-renders via MobX reactivity - Cleaner code with less boilerplate - Better performance - MobX handles optimization - More reliable - reacts to source of truth instead of DOM changes
This commit is contained in:
parent
6fb7520518
commit
1bcc8dfb6f
|
|
@ -1,6 +1,9 @@
|
||||||
import mermaid from "mermaid";
|
import mermaid from "mermaid";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { instanceStore, userStore } from "@/store";
|
||||||
|
import { resolveTheme } from "@/utils/theme";
|
||||||
|
|
||||||
interface MermaidBlockProps {
|
interface MermaidBlockProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
|
@ -9,10 +12,10 @@ interface MermaidBlockProps {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps app theme to Mermaid theme
|
* Maps app theme to Mermaid theme
|
||||||
* @param appTheme - The app's theme value from data-theme attribute
|
* @param appTheme - The resolved app theme
|
||||||
* @returns Mermaid theme name
|
* @returns Mermaid theme name
|
||||||
*/
|
*/
|
||||||
const getMermaidTheme = (appTheme: string | null): "default" | "dark" => {
|
const getMermaidTheme = (appTheme: string): "default" | "dark" => {
|
||||||
switch (appTheme) {
|
switch (appTheme) {
|
||||||
case "default-dark":
|
case "default-dark":
|
||||||
return "dark";
|
return "dark";
|
||||||
|
|
@ -24,41 +27,23 @@ const getMermaidTheme = (appTheme: string | null): "default" | "dark" => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
export const MermaidBlock = observer(({ children, className }: MermaidBlockProps) => {
|
||||||
* Gets the current theme from the document
|
|
||||||
*/
|
|
||||||
const getCurrentTheme = (): string => {
|
|
||||||
return document.documentElement.getAttribute("data-theme") || "default";
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MermaidBlock = ({ children, className }: MermaidBlockProps) => {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [svg, setSvg] = useState<string>("");
|
const [svg, setSvg] = useState<string>("");
|
||||||
const [error, setError] = useState<string>("");
|
const [error, setError] = useState<string>("");
|
||||||
const [currentTheme, setCurrentTheme] = useState<string>(getCurrentTheme());
|
|
||||||
|
|
||||||
// Extract the code element and its content
|
// Extract the code element and its content
|
||||||
const codeElement = children as React.ReactElement;
|
const codeElement = children as React.ReactElement;
|
||||||
const codeContent = String(codeElement?.props?.children || "").replace(/\n$/, "");
|
const codeContent = String(codeElement?.props?.children || "").replace(/\n$/, "");
|
||||||
|
|
||||||
// Watch for theme changes
|
// Get current theme from store (reactive via MobX observer)
|
||||||
useEffect(() => {
|
// This will automatically trigger re-render when theme changes
|
||||||
const observer = new MutationObserver((mutations) => {
|
const currentTheme = useMemo(() => {
|
||||||
mutations.forEach((mutation) => {
|
const userTheme = userStore.state.userGeneralSetting?.theme;
|
||||||
if (mutation.type === "attributes" && mutation.attributeName === "data-theme") {
|
const instanceTheme = instanceStore.state.theme;
|
||||||
const newTheme = getCurrentTheme();
|
const theme = userTheme || instanceTheme;
|
||||||
setCurrentTheme(newTheme);
|
return resolveTheme(theme);
|
||||||
}
|
}, [userStore.state.userGeneralSetting?.theme, instanceStore.state.theme]);
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
observer.observe(document.documentElement, {
|
|
||||||
attributes: true,
|
|
||||||
attributeFilter: ["data-theme"],
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Render diagram when content or theme changes
|
// Render diagram when content or theme changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -114,4 +99,4 @@ export const MermaidBlock = ({ children, className }: MermaidBlockProps) => {
|
||||||
dangerouslySetInnerHTML={{ __html: svg }}
|
dangerouslySetInnerHTML={{ __html: svg }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue