From 4e82e2f6f79a26ad4bb7ad6d082681138098305e Mon Sep 17 00:00:00 2001 From: landaiqing Date: Fri, 21 Nov 2025 20:20:06 +0800 Subject: [PATCH] :recycle: Refactor the Markdown preview theme application logic --- .../src/components/loading/LoadingScreen.vue | 2 +- frontend/src/stores/editorStore.ts | 10 ++++- frontend/src/stores/themeStore.ts | 1 + frontend/src/views/editor/Editor.vue | 5 +-- .../extensions/markdownPreview/index.ts | 30 +++++++++++--- .../extensions/markdownPreview/panel.ts | 40 +++++++++++++++---- 6 files changed, 71 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/loading/LoadingScreen.vue b/frontend/src/components/loading/LoadingScreen.vue index fec414f..cb82dfc 100644 --- a/frontend/src/components/loading/LoadingScreen.vue +++ b/frontend/src/components/loading/LoadingScreen.vue @@ -142,7 +142,7 @@ onBeforeUnmount(() => { display: flex; align-items: center; justify-content: center; - font-family: var(--voidraft-font-mono, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace); + font-family: var(--voidraft-font-mono),serif; } .loading-word { diff --git a/frontend/src/stores/editorStore.ts b/frontend/src/stores/editorStore.ts index a7b8b93..b98fcb6 100644 --- a/frontend/src/stores/editorStore.ts +++ b/frontend/src/stores/editorStore.ts @@ -30,7 +30,7 @@ import {generateContentHash} from "@/common/utils/hashUtils"; import {createTimerManager, type TimerManager} from '@/common/utils/timerUtils'; import {EDITOR_CONFIG} from '@/common/constant/editor'; import {createHttpClientExtension} from "@/views/editor/extensions/httpclient"; -import {markdownPreviewExtension} from "@/views/editor/extensions/markdownPreview"; +import {markdownPreviewExtension, updateMarkdownPreviewTheme} from "@/views/editor/extensions/markdownPreview"; import {createDebounce} from '@/common/utils/debounce'; export interface DocumentStats { @@ -642,6 +642,13 @@ export const useEditorStore = defineStore('editor', () => { }); }; + // 应用 Markdown 预览主题 + const applyPreviewThemeSettings = () => { + editorCache.values().forEach(instance => { + updateMarkdownPreviewTheme(instance.view); + }); + }; + // 应用Tab设置 const applyTabSettings = () => { editorCache.values().forEach(instance => { @@ -783,6 +790,7 @@ export const useEditorStore = defineStore('editor', () => { // 配置更新方法 applyFontSettings, applyThemeSettings, + applyPreviewThemeSettings, applyTabSettings, applyKeymapSettings, diff --git a/frontend/src/stores/themeStore.ts b/frontend/src/stores/themeStore.ts index 55787ef..31e57da 100644 --- a/frontend/src/stores/themeStore.ts +++ b/frontend/src/stores/themeStore.ts @@ -141,6 +141,7 @@ export const useThemeStore = defineStore('theme', () => { const editorStore = useEditorStore(); editorStore?.applyThemeSettings(); + editorStore?.applyPreviewThemeSettings(); }; return { diff --git a/frontend/src/views/editor/Editor.vue b/frontend/src/views/editor/Editor.vue index 6213e06..8cc94e2 100644 --- a/frontend/src/views/editor/Editor.vue +++ b/frontend/src/views/editor/Editor.vue @@ -35,17 +35,16 @@ onMounted(async () => { // onBeforeUnmount(() => { // editorStore.clearAllEditors(); -// // }); diff --git a/frontend/src/views/editor/extensions/markdownPreview/index.ts b/frontend/src/views/editor/extensions/markdownPreview/index.ts index 1b51a50..a927001 100644 --- a/frontend/src/views/editor/extensions/markdownPreview/index.ts +++ b/frontend/src/views/editor/extensions/markdownPreview/index.ts @@ -2,6 +2,7 @@ * Markdown 预览扩展主入口 */ import { EditorView } from "@codemirror/view"; +import { Compartment } from "@codemirror/state"; import { useThemeStore } from "@/stores/themeStore"; import { usePanelStore } from "@/stores/panelStore"; import { useDocumentStore } from "@/stores/documentStore"; @@ -52,11 +53,30 @@ export function toggleMarkdownPreview(view: EditorView): boolean { /** * 导出 Markdown 预览扩展 */ -export function markdownPreviewExtension() { +const previewThemeCompartment = new Compartment(); + +const buildPreviewTheme = () => { const themeStore = useThemeStore(); const colors = themeStore.currentColors; - - const theme = colors ? createMarkdownPreviewTheme(colors) : EditorView.baseTheme({}); - - return [previewPanelState, previewPanelPlugin, theme]; + return colors ? createMarkdownPreviewTheme(colors) : EditorView.baseTheme({}); +}; + +export function markdownPreviewExtension() { + return [ + previewPanelState, + previewPanelPlugin, + previewThemeCompartment.of(buildPreviewTheme()) + ]; +} + +export function updateMarkdownPreviewTheme(view: EditorView): void { + if (!view?.dispatch) return; + + try { + view.dispatch({ + effects: previewThemeCompartment.reconfigure(buildPreviewTheme()) + }); + } catch (error) { + console.error("Failed to update markdown preview theme", error); + } } diff --git a/frontend/src/views/editor/extensions/markdownPreview/panel.ts b/frontend/src/views/editor/extensions/markdownPreview/panel.ts index 18844fe..eaa5c57 100644 --- a/frontend/src/views/editor/extensions/markdownPreview/panel.ts +++ b/frontend/src/views/editor/extensions/markdownPreview/panel.ts @@ -22,7 +22,7 @@ export class MarkdownPreviewPanel { private readonly resizeHandle: HTMLDivElement; private readonly content: HTMLDivElement; private view: EditorView; - private themeUnwatch?: () => void; + private themeUnwatchers: Array<() => void> = []; private lastRenderedContent: string = ""; private readonly debouncedUpdate: ReturnType; private isDestroyed: boolean = false; // 标记面板是否已销毁 @@ -38,11 +38,22 @@ export class MarkdownPreviewPanel { // 监听主题变化 const themeStore = useThemeStore(); - this.themeUnwatch = watch(() => themeStore.isDarkMode, (isDark) => { - const newTheme = isDark ? "dark" : "default"; - updateMermaidTheme(newTheme); - this.lastRenderedContent = ""; // 清空缓存,强制重新渲染 - }); + this.themeUnwatchers.push( + watch(() => themeStore.isDarkMode, (isDark) => { + const newTheme = isDark ? "dark" : "default"; + updateMermaidTheme(newTheme); + this.resetPreviewContent(); + }) + ); + this.themeUnwatchers.push( + watch( + () => themeStore.currentColors, + () => { + this.resetPreviewContent(); + }, + { deep: true } + ) + ); // 创建 DOM 结构 this.dom = document.createElement("div"); @@ -315,6 +326,16 @@ export class MarkdownPreviewPanel { }); } + private resetPreviewContent(): void { + if (this.isDestroyed) { + return; + } + + this.md = createMarkdownRenderer(); + this.lastRenderedContent = ""; + this.updateContentInternal(); + } + /** * 响应编辑器更新 */ @@ -339,9 +360,14 @@ export class MarkdownPreviewPanel { if (this.debouncedUpdate) { this.debouncedUpdate.cancel(); } - + // 清空缓存 this.lastRenderedContent = ""; + + if (this.themeUnwatchers.length) { + this.themeUnwatchers.forEach(unwatch => unwatch()); + this.themeUnwatchers = []; + } } /**