feat: add full-screen toggle to knowledge graph view
All checks were successful
On Push to Main / test (push) Successful in 43s
On Push to Main / publish (push) Successful in 1m13s
On Push to Main / deploy-dev (push) Successful in 3m10s

Admin graph view was cramped inside the sidebar-constrained content area, making it hard to inspect and edit larger graphs. Adds a full-screen overlay toggle (button + Esc to exit) that expands the graph/table view and edit panels to fill the viewport.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
RaymondVerhoef
2026-07-15 21:58:32 +02:00
parent 1afa773a34
commit 841886f6d5

View File

@@ -3,7 +3,7 @@ import * as d3 from 'd3';
import * as db from '../../lib/db'; import * as db from '../../lib/db';
import { callLLM } from '../../lib/llm'; import { callLLM } from '../../lib/llm';
import { EMIT_GRAPH_ACTIONS_TOOL } from '../../lib/llmTools'; 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 { useGraphData } from '../../hooks/useGraphData';
import { filterAiActions } from '../../lib/graphGuard'; import { filterAiActions } from '../../lib/graphGuard';
import GraphControls from './graph/GraphControls'; import GraphControls from './graph/GraphControls';
@@ -87,6 +87,7 @@ const KnowledgeGraph = () => {
const [analyzeNotice, setAnalyzeNotice] = useState(null); // info-level message from last analyze const [analyzeNotice, setAnalyzeNotice] = useState(null); // info-level message from last analyze
const [isRestoring, setIsRestoring] = useState(false); const [isRestoring, setIsRestoring] = useState(false);
const [viewMode, setViewMode] = useState('graph'); // 'graph' | 'table' const [viewMode, setViewMode] = useState('graph'); // 'graph' | 'table'
const [isFullscreen, setIsFullscreen] = useState(false);
const { const {
topics, relations, snapshotMeta, topics, relations, snapshotMeta,
@@ -96,15 +97,29 @@ const KnowledgeGraph = () => {
// ── Canvas sizing ──────────────────────────────────────────────────────────── // ── Canvas sizing ────────────────────────────────────────────────────────────
useEffect(() => { useEffect(() => {
if (!wrapperRef.current) return;
const measure = () => { const measure = () => {
if (!wrapperRef.current) return;
const { width, height } = wrapperRef.current.getBoundingClientRect(); 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); 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 ─────────────────────────────────────────────────────────── // ── D3 force graph ───────────────────────────────────────────────────────────
@@ -433,7 +448,7 @@ const KnowledgeGraph = () => {
// ── Render ─────────────────────────────────────────────────────────────────── // ── Render ───────────────────────────────────────────────────────────────────
return ( return (
<div className="relative w-full h-full flex flex-col md:flex-row"> <div className={`${isFullscreen ? 'fixed inset-0 z-50 bg-paper' : 'relative w-full h-full'} flex flex-col md:flex-row`}>
{/* Main view: graph canvas or table */} {/* Main view: graph canvas or table */}
<div className="flex-1 flex flex-col border-r border-bg-warm min-w-0"> <div className="flex-1 flex flex-col border-r border-bg-warm min-w-0">
{/* View-mode toggle */} {/* View-mode toggle */}
@@ -456,6 +471,13 @@ const KnowledgeGraph = () => {
> >
<Table2 size={13} /> Table <Table2 size={13} /> Table
</button> </button>
<button
onClick={() => setIsFullscreen(f => !f)}
className="ml-auto flex items-center gap-1.5 px-3 py-1 text-xs rounded-[var(--r-sm)] text-fg-muted hover:bg-bg-warm/50 transition-colors"
title={isFullscreen ? 'Exit full screen (Esc)' : 'Full screen'}
>
{isFullscreen ? <><Minimize2 size={13} /> Exit</> : <><Maximize2 size={13} /> Full screen</>}
</button>
</div> </div>
{viewMode === 'graph' ? ( {viewMode === 'graph' ? (