feat: 标签页 IndexedDB 持久化 + 最近打开文件
1. 标签页持久化(关闭后恢复): - tabStore 新增 loadFromDB/saveToDB 方法 - 启动时从 IndexedDB 加载标签页快照 - 标签页增删改时异步保存到 IndexedDB - 关闭窗口后重新打开,所有标签页自动恢复 2. 最近打开文件: - 欢迎屏幕显示最近打开的 10 个文件 - 点击文件名直接打开 - 从侧边栏/对话框/主进程打开文件时自动记录 - 文件路径显示在文件名下方(灰色小字) - hover 高亮效果 REFACTOR-PLAN.md 实现进度更新: ✅ CodeMirror 6 编辑器 ✅ 格式化工具栏 ✅ 标签页 IndexedDB 持久化 ✅ 最近打开文件 UI ✅ Zustand stores ✅ TypeScript 全量类型 ✅ unified/rehype ✅ electron-vite ❌ CSS Modules(全局 CSS 已足够)
This commit is contained in:
@@ -7,6 +7,7 @@ import { useSettings } from './hooks/useSettings'
|
||||
import { useKeyboard } from './hooks/useKeyboard'
|
||||
import { useUnsavedWarning } from './hooks/useUnsavedWarning'
|
||||
import { useFileWatch } from './hooks/useFileWatch'
|
||||
import { recentFilesRepository } from './db/recentFilesRepository'
|
||||
import { Toolbar } from './components/Toolbar/Toolbar'
|
||||
import { TabBar } from './components/TabBar/TabBar'
|
||||
import { Editor } from './components/Editor/Editor'
|
||||
@@ -27,6 +28,8 @@ export default function App() {
|
||||
const createTab = useTabStore(s => s.createTab)
|
||||
const setModified = useTabStore(s => s.setModified)
|
||||
const updateTabContent = useTabStore(s => s.updateTabContent)
|
||||
const loadFromDB = useTabStore(s => s.loadFromDB)
|
||||
const saveToDB = useTabStore(s => s.saveToDB)
|
||||
|
||||
const viewMode = useEditorStore(s => s.viewMode)
|
||||
const splitRatio = useEditorStore(s => s.splitRatio)
|
||||
@@ -38,6 +41,11 @@ export default function App() {
|
||||
const [modifiedFilePath, setModifiedFilePath] = useState<string | null>(null)
|
||||
const [toastMessage, setToastMessage] = useState<string | null>(null)
|
||||
|
||||
// 启动时从 IndexedDB 加载标签页
|
||||
useEffect(() => {
|
||||
loadFromDB()
|
||||
}, [loadFromDB])
|
||||
|
||||
const showToast = useCallback((msg: string) => {
|
||||
setToastMessage(msg)
|
||||
setTimeout(() => setToastMessage(null), 3000)
|
||||
@@ -72,6 +80,10 @@ export default function App() {
|
||||
const result = await window.electronAPI.openFile()
|
||||
if (result && 'filePath' in result) {
|
||||
createTab(result.filePath, result.content)
|
||||
// 追踪最近打开文件
|
||||
if (result.filePath) recentFilesRepository.add(result.filePath)
|
||||
// 保存标签页到 DB
|
||||
setTimeout(() => useTabStore.getState().saveToDB(), 100)
|
||||
}
|
||||
}
|
||||
}, [createTab])
|
||||
@@ -108,6 +120,18 @@ export default function App() {
|
||||
// 快捷键
|
||||
useKeyboard(handleOpenFile, handleSave, handleSaveAs)
|
||||
|
||||
// 打开最近文件
|
||||
const handleOpenRecent = useCallback(async (filePath: string) => {
|
||||
if (window.electronAPI) {
|
||||
const result = await window.electronAPI.readFile(filePath)
|
||||
if (result.success && result.content) {
|
||||
createTab(filePath, result.content)
|
||||
recentFilesRepository.add(filePath)
|
||||
setTimeout(() => useTabStore.getState().saveToDB(), 100)
|
||||
}
|
||||
}
|
||||
}, [createTab])
|
||||
|
||||
// 视图模式切换
|
||||
const handleViewModeChange = useCallback((mode: 'split' | 'editor' | 'preview') => {
|
||||
saveViewMode(mode)
|
||||
@@ -125,6 +149,8 @@ export default function App() {
|
||||
|
||||
const onOpen = (data: { filePath: string; content: string }) => {
|
||||
createTab(data.filePath, data.content)
|
||||
recentFilesRepository.add(data.filePath)
|
||||
setTimeout(() => useTabStore.getState().saveToDB(), 100)
|
||||
}
|
||||
const onSave = () => handleSaveRef.current()
|
||||
const onSaveAs = () => handleSaveAsRef.current()
|
||||
@@ -207,6 +233,7 @@ export default function App() {
|
||||
<WelcomeScreen
|
||||
onOpen={handleOpenFile}
|
||||
onNew={() => createTab(null, '')}
|
||||
onOpenRecent={handleOpenRecent}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user