feat: lift docs state to App for persistence across view changes
Move externalDocs, fileTree, selectedPath, and currentContent state from ApiDocViewer to App component so that docs state persists when switching between docs and blueprint views. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
24
src/App.tsx
24
src/App.tsx
@@ -3,6 +3,14 @@ import { FileText, Box, Plus } from 'lucide-react';
|
|||||||
import { ApiDocViewer } from './components/ApiDocViewer';
|
import { ApiDocViewer } from './components/ApiDocViewer';
|
||||||
import BlueprintPage from './components/blueprint/BlueprintPage';
|
import BlueprintPage from './components/blueprint/BlueprintPage';
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
|
import type { DocFile } from '@/lib/types';
|
||||||
|
|
||||||
|
interface ExternalDoc {
|
||||||
|
name: string
|
||||||
|
path: string
|
||||||
|
relativePath: string
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
const _origLog = console.log;
|
const _origLog = console.log;
|
||||||
const _origError = console.error;
|
const _origError = console.error;
|
||||||
@@ -27,6 +35,12 @@ function App() {
|
|||||||
const [currentPage, setCurrentPage] = useState<Page>('docs');
|
const [currentPage, setCurrentPage] = useState<Page>('docs');
|
||||||
const [docsPath, setDocsPath] = useState<string>('');
|
const [docsPath, setDocsPath] = useState<string>('');
|
||||||
const [showAddModal, setShowAddModal] = useState(false);
|
const [showAddModal, setShowAddModal] = useState(false);
|
||||||
|
|
||||||
|
// Docs state lifted from ApiDocViewer to persist across view changes
|
||||||
|
const [externalDocs, setExternalDocs] = useState<ExternalDoc[]>([]);
|
||||||
|
const [fileTree, setFileTree] = useState<DocFile[]>([]);
|
||||||
|
const [selectedPath, setSelectedPath] = useState<string | undefined>(undefined);
|
||||||
|
const [currentContent, setCurrentContent] = useState<string>('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = config.projectName;
|
document.title = config.projectName;
|
||||||
@@ -74,10 +88,18 @@ function App() {
|
|||||||
</header>
|
</header>
|
||||||
<main className="flex-1 overflow-hidden">
|
<main className="flex-1 overflow-hidden">
|
||||||
{currentPage === 'docs' ? (
|
{currentPage === 'docs' ? (
|
||||||
<ApiDocViewer
|
<ApiDocViewer
|
||||||
onDocsPathChange={setDocsPath}
|
onDocsPathChange={setDocsPath}
|
||||||
showAddModal={showAddModal}
|
showAddModal={showAddModal}
|
||||||
onCloseAddModal={() => setShowAddModal(false)}
|
onCloseAddModal={() => setShowAddModal(false)}
|
||||||
|
externalDocs={externalDocs}
|
||||||
|
setExternalDocs={setExternalDocs}
|
||||||
|
fileTree={fileTree}
|
||||||
|
setFileTree={setFileTree}
|
||||||
|
selectedPath={selectedPath}
|
||||||
|
setSelectedPath={setSelectedPath}
|
||||||
|
currentContent={currentContent}
|
||||||
|
setCurrentContent={setCurrentContent}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<BlueprintPage docsPath={docsPath} />
|
<BlueprintPage docsPath={docsPath} />
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ interface ApiDocViewerProps {
|
|||||||
onDocsPathChange?: (path: string) => void;
|
onDocsPathChange?: (path: string) => void;
|
||||||
showAddModal?: boolean;
|
showAddModal?: boolean;
|
||||||
onCloseAddModal?: () => void;
|
onCloseAddModal?: () => void;
|
||||||
|
externalDocs: ExternalDoc[];
|
||||||
|
setExternalDocs: React.Dispatch<React.SetStateAction<ExternalDoc[]>>;
|
||||||
|
fileTree: DocFile[];
|
||||||
|
setFileTree: React.Dispatch<React.SetStateAction<DocFile[]>>;
|
||||||
|
selectedPath: string | undefined;
|
||||||
|
setSelectedPath: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||||
|
currentContent: string;
|
||||||
|
setCurrentContent: React.Dispatch<React.SetStateAction<string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STORAGE_KEY = 'xc-docs-config';
|
const STORAGE_KEY = 'xc-docs-config';
|
||||||
@@ -36,14 +44,22 @@ function saveStoredConfig(docsPath: string, externalDocs: ExternalDoc[], selecte
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ApiDocViewer = ({ onDocsPathChange, showAddModal, onCloseAddModal }: ApiDocViewerProps) => {
|
export const ApiDocViewer = ({
|
||||||
|
onDocsPathChange,
|
||||||
|
showAddModal,
|
||||||
|
onCloseAddModal,
|
||||||
|
externalDocs,
|
||||||
|
setExternalDocs,
|
||||||
|
fileTree,
|
||||||
|
setFileTree,
|
||||||
|
selectedPath,
|
||||||
|
setSelectedPath,
|
||||||
|
currentContent,
|
||||||
|
setCurrentContent
|
||||||
|
}: ApiDocViewerProps) => {
|
||||||
const stored = loadStoredConfig();
|
const stored = loadStoredConfig();
|
||||||
const [fileTree, setFileTree] = useState<DocFile[]>([])
|
|
||||||
const [selectedPath, setSelectedPath] = useState<string | undefined>(stored.selectedPath)
|
|
||||||
const [currentContent, setCurrentContent] = useState<string>('')
|
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const [docsPath, setDocsPath] = useState(stored.docsPath)
|
const [docsPath, setDocsPath] = useState(stored.docsPath)
|
||||||
const [externalDocs, setExternalDocs] = useState<ExternalDoc[]>(stored.externalDocs)
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [errorMsg, setErrorMsg] = useState<string | null>(null)
|
const [errorMsg, setErrorMsg] = useState<string | null>(null)
|
||||||
|
|
||||||
@@ -54,6 +70,7 @@ export const ApiDocViewer = ({ onDocsPathChange, showAddModal, onCloseAddModal }
|
|||||||
}
|
}
|
||||||
}, [showAddModal])
|
}, [showAddModal])
|
||||||
|
|
||||||
|
// Auto-select first document when externalDocs and fileTree are loaded
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (externalDocs.length > 0 && fileTree.length > 0 && !selectedPath) {
|
if (externalDocs.length > 0 && fileTree.length > 0 && !selectedPath) {
|
||||||
const fileList = externalDocs
|
const fileList = externalDocs
|
||||||
@@ -65,17 +82,17 @@ export const ApiDocViewer = ({ onDocsPathChange, showAddModal, onCloseAddModal }
|
|||||||
return filename !== parentFolder
|
return filename !== parentFolder
|
||||||
})
|
})
|
||||||
.map(d => d.relativePath)
|
.map(d => d.relativePath)
|
||||||
|
|
||||||
const targetPath = stored.selectedPath && externalDocs.find(d => d.relativePath === stored.selectedPath)
|
const targetPath = stored.selectedPath && externalDocs.find(d => d.relativePath === stored.selectedPath)
|
||||||
? stored.selectedPath
|
? stored.selectedPath
|
||||||
: fileList[0]
|
: fileList[0]
|
||||||
|
|
||||||
if (targetPath) {
|
if (targetPath) {
|
||||||
setSelectedPath(targetPath)
|
setSelectedPath(targetPath)
|
||||||
setCurrentContent(externalDocs.find(d => d.relativePath === targetPath)?.content || '')
|
setCurrentContent(externalDocs.find(d => d.relativePath === targetPath)?.content || '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [externalDocs, fileTree, selectedPath])
|
}, [externalDocs, fileTree, selectedPath, stored.selectedPath, setSelectedPath, setCurrentContent])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (docsPath && externalDocs.length > 0) {
|
if (docsPath && externalDocs.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user