diff --git a/src/components/admin/KnowledgeGraph.jsx b/src/components/admin/KnowledgeGraph.jsx index a0c3e25..2e093ec 100644 --- a/src/components/admin/KnowledgeGraph.jsx +++ b/src/components/admin/KnowledgeGraph.jsx @@ -3,7 +3,7 @@ import * as d3 from 'd3'; import * as db from '../../lib/db'; import { callLLM } from '../../lib/llm'; import { EMIT_GRAPH_ACTIONS_TOOL } from '../../lib/llmTools'; -import { Network, Table2 } from 'lucide-react'; +import { Network, Table2, Maximize2, Minimize2 } from 'lucide-react'; import { useGraphData } from '../../hooks/useGraphData'; import { filterAiActions } from '../../lib/graphGuard'; import GraphControls from './graph/GraphControls'; @@ -87,6 +87,7 @@ const KnowledgeGraph = () => { const [analyzeNotice, setAnalyzeNotice] = useState(null); // info-level message from last analyze const [isRestoring, setIsRestoring] = useState(false); const [viewMode, setViewMode] = useState('graph'); // 'graph' | 'table' + const [isFullscreen, setIsFullscreen] = useState(false); const { topics, relations, snapshotMeta, @@ -96,15 +97,29 @@ const KnowledgeGraph = () => { // ── Canvas sizing ──────────────────────────────────────────────────────────── useEffect(() => { - if (!wrapperRef.current) return; const measure = () => { + if (!wrapperRef.current) return; const { width, height } = wrapperRef.current.getBoundingClientRect(); - setDimensions({ width, height }); + if (width > 0 && height > 0) setDimensions({ width, height }); }; - measure(); + // rAF: toggling view mode / fullscreen resizes the wrapper without firing a + // window resize event, so re-measure once the DOM has reflowed. + const raf = requestAnimationFrame(measure); window.addEventListener('resize', measure); - return () => window.removeEventListener('resize', measure); - }, []); + return () => { + cancelAnimationFrame(raf); + window.removeEventListener('resize', measure); + }; + }, [viewMode, isFullscreen]); + + // ── Esc exits fullscreen ───────────────────────────────────────────────────── + + useEffect(() => { + if (!isFullscreen) return; + const onKey = (e) => { if (e.key === 'Escape') setIsFullscreen(false); }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [isFullscreen]); // ── D3 force graph ─────────────────────────────────────────────────────────── @@ -433,7 +448,7 @@ const KnowledgeGraph = () => { // ── Render ─────────────────────────────────────────────────────────────────── return ( -