From 3cecb0f9ebfd4871fc73fe1c1449669e9f44f442 Mon Sep 17 00:00:00 2001
From: thzxx
Date: Wed, 3 Jun 2026 21:02:56 +0800
Subject: [PATCH] =?UTF-8?q?v0.1.1:=20=E5=A4=9AAgent=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E8=B4=A8=E9=87=8F=E5=AE=A1=E6=9F=A5+=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- fix: useCodeMirror onChange闭包过期导致编辑器内容丢失同步(P0)
- feat: 全部组件添加displayName(React DevTools调试支持)
- feat: 全部组件添加ARIA属性(WCAG无障碍支持)
- fix: App异步操作添加try-catch错误边界
- fix: tabStore空catch块添加错误日志
- fix: sidebarStore Set→string[](Zustand可序列化)
- fix: useDragDrop readFile错误处理+空文件修复
- fix: useSettings/useTheme load()添加错误处理
- fix: useTheme toggleDarkMode引用优化
- chore: 版本号升级至0.1.1
---
DESIGN.md | 2 +-
README.md | 2 +-
package.json | 2 +-
src/renderer/App.tsx | 70 ++++++++++++-------
src/renderer/components/Editor/Editor.tsx | 4 +-
.../components/Editor/useCodeMirror.ts | 8 ++-
src/renderer/components/Preview/Preview.tsx | 5 ++
src/renderer/components/Sidebar/Sidebar.tsx | 13 ++--
.../components/StatusBar/StatusBar.tsx | 4 +-
src/renderer/components/TabBar/TabBar.tsx | 6 +-
src/renderer/components/Toolbar/Toolbar.tsx | 4 +-
src/renderer/hooks/useDragDrop.ts | 10 ++-
src/renderer/hooks/useSettings.ts | 2 +-
src/renderer/hooks/useTheme.ts | 6 +-
src/renderer/stores/sidebarStore.ts | 31 +++-----
src/renderer/stores/tabStore.ts | 3 +-
16 files changed, 106 insertions(+), 66 deletions(-)
diff --git a/DESIGN.md b/DESIGN.md
index 566cf1e..b4ce514 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,4 +1,4 @@
-# MarkLite v0.1.0 — 架构设计文档
+# MarkLite v0.1.1 — 架构设计文档
## 1. 项目概述
diff --git a/README.md b/README.md
index 1d0a458..500dd8d 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-
+
diff --git a/package.json b/package.json
index 44896ac..fd5c440 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "marklite",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "Lightweight Markdown Editor for Windows",
"main": "./dist/main/index.js",
"scripts": {
diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index f58e16f..1060834 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -21,9 +21,9 @@ import { ModifiedBanner } from './components/ModifiedBanner/ModifiedBanner'
import { DropOverlay } from './components/DropOverlay/DropOverlay'
import { AppIcon, Gitee } from './components/Icons'
-const APP_VERSION = 'v0.1.0'
+const APP_VERSION = 'v0.1.1'
-export default function App() {
+export function App() {
const tabs = useTabStore(s => s.tabs)
const activeTabId = useTabStore(s => s.activeTabId)
const getActiveTab = useTabStore(s => s.getActiveTab)
@@ -89,42 +89,54 @@ export default function App() {
// 打开文件
const handleOpenFile = useCallback(async () => {
- if (window.electronAPI) {
- const result = await window.electronAPI.openFile()
- if (result && 'filePath' in result) {
- createTab(result.filePath, result.content)
- if (result.filePath) recentFilesRepository.add(result.filePath)
- setTimeout(() => useTabStore.getState().saveToDB(), 100)
+ try {
+ if (window.electronAPI) {
+ const result = await window.electronAPI.openFile()
+ if (result && 'filePath' in result) {
+ createTab(result.filePath, result.content)
+ if (result.filePath) recentFilesRepository.add(result.filePath)
+ setTimeout(() => useTabStore.getState().saveToDB(), 100)
+ }
}
+ } catch {
+ showToast('操作失败')
}
- }, [createTab])
+ }, [createTab, showToast])
// 保存文件
const handleSave = useCallback(async () => {
- const tab = getActiveTab()
- if (!tab) return
- if (window.electronAPI) {
- const result = await window.electronAPI.saveFile({
- filePath: tab.filePath,
- content: tab.content
- })
- if (result.success) {
- useTabStore.getState().setModified(tab.id, false)
- showToast('已保存')
+ try {
+ const tab = getActiveTab()
+ if (!tab) return
+ if (window.electronAPI) {
+ const result = await window.electronAPI.saveFile({
+ filePath: tab.filePath,
+ content: tab.content
+ })
+ if (result.success) {
+ useTabStore.getState().setModified(tab.id, false)
+ showToast('已保存')
+ }
}
+ } catch {
+ showToast('操作失败')
}
}, [getActiveTab, showToast])
// 另存为
const handleSaveAs = useCallback(async () => {
- const tab = getActiveTab()
- if (!tab) return
- if (window.electronAPI) {
- const result = await window.electronAPI.saveFileAs({ content: tab.content })
- if (result.success) {
- useTabStore.getState().setModified(tab.id, false)
- showToast('已保存')
+ try {
+ const tab = getActiveTab()
+ if (!tab) return
+ if (window.electronAPI) {
+ const result = await window.electronAPI.saveFileAs({ content: tab.content })
+ if (result.success) {
+ useTabStore.getState().setModified(tab.id, false)
+ showToast('已保存')
+ }
}
+ } catch {
+ showToast('操作失败')
}
}, [getActiveTab, showToast])
@@ -247,7 +259,7 @@ export default function App() {
{/* 关于弹框 */}
{showAbout && (
-
setShowAbout(false)}>
+
setShowAbout(false)} role="dialog" aria-modal="true" aria-label="关于 MarkLite">
e.stopPropagation()}>
@@ -289,3 +301,7 @@ export default function App() {
)
}
+
+App.displayName = 'App'
+
+export default App
diff --git a/src/renderer/components/Editor/Editor.tsx b/src/renderer/components/Editor/Editor.tsx
index e4cf33f..4461fc3 100644
--- a/src/renderer/components/Editor/Editor.tsx
+++ b/src/renderer/components/Editor/Editor.tsx
@@ -87,9 +87,11 @@ export function Editor({ darkMode }: EditorProps) {
}, [viewRef])
return (
-
+
)
}
+
+Editor.displayName = 'Editor'
\ No newline at end of file
diff --git a/src/renderer/components/Editor/useCodeMirror.ts b/src/renderer/components/Editor/useCodeMirror.ts
index f2a4eb7..d247ab3 100644
--- a/src/renderer/components/Editor/useCodeMirror.ts
+++ b/src/renderer/components/Editor/useCodeMirror.ts
@@ -17,6 +17,12 @@ export function useCodeMirror({ content, onChange, darkMode }: UseCodeMirrorOpti
const containerRef = useRef
(null)
const viewRef = useRef(null)
const isExternalUpdate = useRef(false)
+ const onChangeRef = useRef(onChange)
+
+ // 始终保持 onChangeRef 为最新回调
+ useEffect(() => {
+ onChangeRef.current = onChange
+ }, [onChange])
// 初始化编辑器
useEffect(() => {
@@ -61,7 +67,7 @@ export function useCodeMirror({ content, onChange, darkMode }: UseCodeMirrorOpti
EditorView.lineWrapping,
EditorView.updateListener.of(update => {
if (update.docChanged && !isExternalUpdate.current) {
- onChange(update.state.doc.toString())
+ onChangeRef.current(update.state.doc.toString())
}
})
]
diff --git a/src/renderer/components/Preview/Preview.tsx b/src/renderer/components/Preview/Preview.tsx
index e7cf783..a5ba72b 100644
--- a/src/renderer/components/Preview/Preview.tsx
+++ b/src/renderer/components/Preview/Preview.tsx
@@ -56,8 +56,13 @@ export function Preview() {
ref={previewRef}
id="preview"
className="markdown-body"
+ role="region"
+ aria-label="Markdown预览"
+ aria-live="polite"
onClick={handleClick}
dangerouslySetInnerHTML={{ __html: html }}
/>
)
}
+
+Preview.displayName = 'Preview'
\ No newline at end of file
diff --git a/src/renderer/components/Sidebar/Sidebar.tsx b/src/renderer/components/Sidebar/Sidebar.tsx
index 57c6b80..73979d2 100644
--- a/src/renderer/components/Sidebar/Sidebar.tsx
+++ b/src/renderer/components/Sidebar/Sidebar.tsx
@@ -128,7 +128,7 @@ export function Sidebar() {
-