release: v0.4.1 — MetonaEditor 0.1.10 升级与三主题系统

- chore: 升级 @metona-team/metona-editor 0.1.3 → 0.1.10
- feat: 三主题系统(亮色/暗色/暖色),循环切换
- feat: 应用颜色自动同步编辑器主题(MeEditor.themes.exportCSSVars)
- feat: 启用编辑器新功能(lineNumbers/autoBrackets/readOnly/autofocus/exportTool)
- refactor: 主题从 boolean darkMode 重构为 ThemeMode 枚举
- refactor: 插件注册改用字符串数组(与 demo 一致)
- refactor: 主题同步从手动 CSS 覆写改为 editor.setTheme() 实例 API
- refactor: Ctrl+S 双通道(编辑器 onSave + 全局兜底)+ 防重入锁
- style: 移除 variables.css 中硬编码 .dark 色值,改为 JS 动态驱动
- test: 更新 editorStore 测试覆盖新的 themeMode/cycleTheme
This commit is contained in:
2026-07-24 13:58:37 +08:00
parent 10cfe0066b
commit 7bd625b9ce
20 changed files with 712 additions and 504 deletions
+11 -1
View File
@@ -1,4 +1,4 @@
import { useCallback } from 'react'
import { useCallback, useRef } from 'react'
import { useTabStore } from '../stores/tabStore'
import { useEditorStore } from '../stores/editorStore'
import { recentFilesRepository } from '../db/recentFilesRepository'
@@ -8,12 +8,16 @@ import { showToast } from '../lib/toast'
/**
* AR-01: 从 App.tsx 提取的文件操作逻辑
* UX-02: 添加 loading 状态指示
* v0.1.9: handleSave 添加防重入锁,避免编辑器 onSave + 全局 Ctrl+S 双重触发
*/
export function useFileOperations() {
const createTab = useTabStore(s => s.createTab)
const getActiveTab = useTabStore(s => s.getActiveTab)
const setLoading = useEditorStore(s => s.setLoading)
// 防重入:onSave 回调 + 全局 Ctrl+S handler 可能在 300ms 内双重触发
const savingGate = useRef(false)
const handleOpenFile = useCallback(async (): Promise<void> => {
try {
if (!window.electronAPI) return
@@ -33,6 +37,9 @@ export function useFileOperations() {
}, [createTab, setLoading])
const handleSave = useCallback(async (): Promise<void> => {
// 防重入:300ms 内忽略重复调用(编辑器 onSave + 全局 Ctrl+S 双重触发)
if (savingGate.current) return
savingGate.current = true
try {
const tab = getActiveTab()
if (!tab || !window.electronAPI) return
@@ -47,6 +54,9 @@ export function useFileOperations() {
} catch (error) {
logError('保存文件失败', error)
showToast('保存失败', 'error')
} finally {
// 300ms 后释放锁,允许下次保存
setTimeout(() => { savingGate.current = false }, 300)
}
}, [getActiveTab])