v0.2.0: 全面代码质量优化
- ESLint flat config + Prettier + EditorConfig - Markdown处理器LRU缓存 - Zustand选择器优化减少重渲染 - CodeMirror Compartment主题热切换 - Preview防抖(150ms) + IndexedDB去抖(500ms) - 组件拆分: App.tsx 310→104行, Sidebar.tsx 244→90行 - 统一错误处理 errorHandler.ts - ConfirmDialog替代原生confirm - LoadingSpinner加载状态 - Toast多条堆叠+类型区分 - 可访问性增强(ARIA属性、键盘导航) - Vitest测试框架(78个测试用例) - Git hooks(husky + lint-staged) - 项目文档(README.md, CONTRIBUTING.md)
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useTabStore } from '../stores/tabStore'
|
||||
import { useEditorStore } from '../stores/editorStore'
|
||||
import { recentFilesRepository } from '../db/recentFilesRepository'
|
||||
import { logError } from '../lib/errorHandler'
|
||||
import type { ToastType } from '../components/Toast/Toast'
|
||||
|
||||
/**
|
||||
* AR-01: 从 App.tsx 提取的文件操作逻辑
|
||||
* UX-02: 添加 loading 状态指示
|
||||
*/
|
||||
export function useFileOperations(showToast: (msg: string, type?: ToastType) => void) {
|
||||
const createTab = useTabStore(s => s.createTab)
|
||||
const getActiveTab = useTabStore(s => s.getActiveTab)
|
||||
const setLoading = useEditorStore(s => s.setLoading)
|
||||
|
||||
const handleOpenFile = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
if (!window.electronAPI) return
|
||||
setLoading('file-open', true)
|
||||
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 (error) {
|
||||
logError('打开文件失败', error)
|
||||
showToast('打开文件失败', 'error')
|
||||
} finally {
|
||||
setLoading('file-open', false)
|
||||
}
|
||||
}, [createTab, showToast, setLoading])
|
||||
|
||||
const handleSave = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
const tab = getActiveTab()
|
||||
if (!tab || !window.electronAPI) return
|
||||
const result = await window.electronAPI.saveFile({
|
||||
filePath: tab.filePath,
|
||||
content: tab.content
|
||||
})
|
||||
if (result.success) {
|
||||
useTabStore.getState().setModified(tab.id, false)
|
||||
showToast('已保存', 'success')
|
||||
}
|
||||
} catch (error) {
|
||||
logError('保存文件失败', error)
|
||||
showToast('保存失败', 'error')
|
||||
}
|
||||
}, [getActiveTab, showToast])
|
||||
|
||||
const handleSaveAs = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
const tab = getActiveTab()
|
||||
if (!tab || !window.electronAPI) return
|
||||
const result = await window.electronAPI.saveFileAs({ content: tab.content })
|
||||
if (result.success) {
|
||||
useTabStore.getState().setModified(tab.id, false)
|
||||
showToast('已保存', 'success')
|
||||
}
|
||||
} catch (error) {
|
||||
logError('另存为失败', error)
|
||||
showToast('另存为失败', 'error')
|
||||
}
|
||||
}, [getActiveTab, showToast])
|
||||
|
||||
const handleOpenRecent = useCallback(async (filePath: string): Promise<void> => {
|
||||
if (!window.electronAPI) return
|
||||
setLoading('file-open', true)
|
||||
try {
|
||||
const result = await window.electronAPI.readFile(filePath)
|
||||
if (result.success && result.content) {
|
||||
createTab(filePath, result.content)
|
||||
recentFilesRepository.add(filePath)
|
||||
setTimeout(() => useTabStore.getState().saveToDB(), 100)
|
||||
}
|
||||
} finally {
|
||||
setLoading('file-open', false)
|
||||
}
|
||||
}, [createTab, setLoading])
|
||||
|
||||
return { handleOpenFile, handleSave, handleSaveAs, handleOpenRecent }
|
||||
}
|
||||
Reference in New Issue
Block a user