refactor: 抽取 Modal 组件、支持 JSON/CSV 导出、清理冗余代码

- 新增 Modal 组件,消除 3 个 Dialog 中重复的遮罩层/Escape/stopPropagation 代码
- PathEditDialog/HelpDialog/ImportDialog 改用 Modal 包裹
- handleExport 支持 JSON/CSV 两种格式(CSV 导出代码之前存在但从未接线)
- App.tsx 移除冗余的 initDarkMode 后重复设 store 的逻辑
- ErrorBoundary 添加 componentDidCatch 日志和 console.error

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 00:51:32 +08:00
parent b159407773
commit d28861ff9c
7 changed files with 94 additions and 175 deletions
+9 -5
View File
@@ -2,7 +2,7 @@ import { useCallback, useEffect } from 'react';
import { useAppStore } from '@/store/app-store';
import { TargetType } from '@/core/undo-redo';
import { open } from '@tauri-apps/plugin-dialog';
import { importFromContent, exportToJson, flattenImportResult } from '@/core/import-export';
import { importFromContent, exportToJson, exportToCsv, flattenImportResult } from '@/core/import-export';
import { is_valid_path_format } from '@/core/validation';
import { useKeyboard } from './use-keyboard';
import i18n from '@/i18n';
@@ -101,14 +101,18 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
input.click();
}, [setImportDialog]);
const handleExport = useCallback(() => {
const handleExport = useCallback((format: 'json' | 'csv' = 'json') => {
const state = useAppStore.getState();
const content = exportToJson({ system: state.sysPaths, user: state.userPaths });
const blob = new Blob([content], { type: 'application/json' });
const data = { system: state.sysPaths, user: state.userPaths };
const isCsv = format === 'csv';
const content = isCsv ? exportToCsv(data) : exportToJson(data);
const mime = isCsv ? 'text/csv' : 'application/json';
const ext = isCsv ? '.csv' : '.json';
const blob = new Blob([isCsv ? '' : '', content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'patheditor_export.json';
a.download = `patheditor_export${ext}`;
a.click();
URL.revokeObjectURL(url);
}, []);