diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..1552e97 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git push:*)" + ] + } +} diff --git a/electron/main.mjs b/electron/main.mjs index a74943c..d6021a8 100644 --- a/electron/main.mjs +++ b/electron/main.mjs @@ -30,6 +30,9 @@ if (argsGlobal.headless) { } app.commandLine.appendSwitch('disable-gpu-shader-disk-cache'); +app.commandLine.appendSwitch('enable-webgl'); +app.commandLine.appendSwitch('ignore-gpu-blacklist'); +app.commandLine.appendSwitch('enable-accelerated-2d-canvas'); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/src/App.tsx b/src/App.tsx index 3b2a8e9..95b2546 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,21 @@ console.log = (...args) => { window.electronAPI?.log('log', ...args); _origLog.a console.error = (...args) => { window.electronAPI?.log('error', ...args); _origError.apply(console, args); }; console.warn = (...args) => { window.electronAPI?.log('warn', ...args); _origWarn.apply(console, args); }; +const STORAGE_KEY = 'xc-docs-config'; + +function loadStoredDocsPath(): string { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (stored) { + const config = JSON.parse(stored); + return config.docsPath || ''; + } + } catch { + // Ignore parse errors + } + return ''; +} + type Page = 'docs' | 'blueprint'; declare global { @@ -33,7 +48,7 @@ declare global { function App() { const [currentPage, setCurrentPage] = useState('docs'); - const [docsPath, setDocsPath] = useState(''); + const [docsPath, setDocsPath] = useState(loadStoredDocsPath()); const [showAddModal, setShowAddModal] = useState(false); // Docs state lifted from ApiDocViewer to persist across view changes @@ -89,7 +104,8 @@ function App() {
{currentPage === 'docs' ? ( setShowAddModal(false)} externalDocs={externalDocs} diff --git a/src/components/ApiDocViewer.tsx b/src/components/ApiDocViewer.tsx index 63ebc77..518907f 100644 --- a/src/components/ApiDocViewer.tsx +++ b/src/components/ApiDocViewer.tsx @@ -13,7 +13,8 @@ interface ExternalDoc { } interface ApiDocViewerProps { - onDocsPathChange?: (path: string) => void; + docsPath?: string; + setDocsPath?: (path: string) => void; showAddModal?: boolean; onCloseAddModal?: () => void; externalDocs: ExternalDoc[]; @@ -45,7 +46,8 @@ function saveStoredConfig(docsPath: string, externalDocs: ExternalDoc[], selecte } export const ApiDocViewer = ({ - onDocsPathChange, + docsPath: docsPathProp, + setDocsPath: setDocsPathProp, showAddModal, onCloseAddModal, externalDocs, @@ -59,10 +61,17 @@ export const ApiDocViewer = ({ }: ApiDocViewerProps) => { const stored = loadStoredConfig(); const [showModal, setShowModal] = useState(false) - const [docsPath, setDocsPath] = useState(stored.docsPath) + const [docsPath, setDocsPath] = useState(docsPathProp ?? stored.docsPath) const [isLoading, setIsLoading] = useState(false) const [errorMsg, setErrorMsg] = useState(null) + // Sync with prop when it changes (e.g., when switching views back to docs) + useEffect(() => { + if (docsPathProp !== undefined) { + setDocsPath(docsPathProp) + } + }, [docsPathProp]) + useEffect(() => { if (showAddModal) { setShowModal(true) @@ -94,8 +103,9 @@ export const ApiDocViewer = ({ } }, [externalDocs, fileTree, selectedPath, stored.selectedPath, setSelectedPath, setCurrentContent]) + // Save to localStorage when docsPath changes useEffect(() => { - if (docsPath && externalDocs.length > 0) { + if (docsPath) { saveStoredConfig(docsPath, externalDocs, selectedPath) } }, [docsPath, externalDocs, selectedPath]) @@ -212,7 +222,7 @@ export const ApiDocViewer = ({ if (success) { setShowModal(false) onCloseAddModal?.() - onDocsPathChange?.(docsPath.trim()) + setDocsPathProp?.(docsPath.trim()) } } diff --git a/src/components/blueprint/BlueprintPage.tsx b/src/components/blueprint/BlueprintPage.tsx index b65b3d9..c4495fb 100644 --- a/src/components/blueprint/BlueprintPage.tsx +++ b/src/components/blueprint/BlueprintPage.tsx @@ -1,8 +1,20 @@ import Scene3D from './Scene3D'; import DetailPanel from './DetailPanel'; import { useBlueprintStore } from '../../store/blueprintStore'; -import { useEffect, useCallback } from 'react'; -import { parseBlueprintFromMd } from '../../data/blueprintParser'; +import { useEffect, useCallback, Component, ReactNode } from 'react'; +import { parseBlueprintFromMd, blueprintData } from '../../data/blueprintParser'; + +class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> { + state = { hasError: false }; + static getDerivedStateFromError() { return { hasError: true }; } + componentDidCatch(e: Error, info: React.ErrorInfo) { + console.error('[BlueprintPage] Error:', e, info); + } + render() { + if (this.state.hasError) return
3D渲染出错
; + return this.props.children; + } +} interface BlueprintPageProps { docsPath: string; @@ -10,9 +22,13 @@ interface BlueprintPageProps { export default function BlueprintPage({ docsPath }: BlueprintPageProps) { const setBlueprintData = useBlueprintStore(state => state.setBlueprintData); - + const loadBlueprint = useCallback(async () => { - if (!docsPath) return; + // Use default blueprint data if no docsPath is set + if (!docsPath) { + setBlueprintData(blueprintData); + return; + } const blueprintPath = docsPath.replace(/\\/g, '/') + '/blueprint.md'; let content: string | null = null; @@ -31,6 +47,9 @@ export default function BlueprintPage({ docsPath }: BlueprintPageProps) { if (content) { const data = parseBlueprintFromMd(content); setBlueprintData(data); + } else { + // Fallback to default if file not found + setBlueprintData(blueprintData); } }, [docsPath, setBlueprintData]); @@ -41,7 +60,9 @@ export default function BlueprintPage({ docsPath }: BlueprintPageProps) { return (
- + + +
diff --git a/src/components/blueprint/Scene3D.tsx b/src/components/blueprint/Scene3D.tsx index f6b544f..e4517dc 100644 --- a/src/components/blueprint/Scene3D.tsx +++ b/src/components/blueprint/Scene3D.tsx @@ -6,14 +6,22 @@ import SystemStructure from './SystemStructure'; export default function Scene3D() { return (
- + - + - +