feat(web/mazenet): fullscreen canvas mode (hides topbar + sidebar, Esc to exit)

This commit is contained in:
2026-04-22 18:11:37 -04:00
parent 31d02a9726
commit ef34df4a7d
2 changed files with 39 additions and 1 deletions

View File

@@ -1,5 +1,18 @@
/* ── MazeNET canvas ─────────────────────────── */ /* ── MazeNET canvas ─────────────────────────── */
body.maze-fullscreen .sidebar,
body.maze-fullscreen .topbar {
display: none !important;
}
body.maze-fullscreen .content-viewport {
padding: 16px 32px;
}
body.maze-fullscreen .maze-shell {
/* Full viewport minus content-viewport padding (16 top + 32 bottom) and header+gap. */
/* With flex:1 this stays correct because maze-page fills 100% of the new viewport. */
}
.maze-page { .maze-page {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useSearchParams, useNavigate } from 'react-router-dom'; import { useSearchParams, useNavigate } from 'react-router-dom';
import { import {
PanelRightOpen, PanelRightClose, PanelLeftOpen, PanelLeftClose, PanelRightOpen, PanelRightClose, PanelLeftOpen, PanelLeftClose,
RotateCcw, UploadCloud, ArrowLeft, Maximize2, Minimize2, RotateCcw, UploadCloud, ArrowLeft,
Plus, Trash2, Zap, Copy, Eye, ShieldAlert, GitMerge, Server, Plus, Trash2, Zap, Copy, Eye, ShieldAlert, GitMerge, Server,
} from 'lucide-react'; } from 'lucide-react';
import './MazeNET.css'; import './MazeNET.css';
@@ -48,6 +48,22 @@ const MazeNET: React.FC = () => {
const [selection, setSelection] = useState<Selection>(null); const [selection, setSelection] = useState<Selection>(null);
const [inspectorOpen, setInspectorOpen] = useState(true); const [inspectorOpen, setInspectorOpen] = useState(true);
const [paletteOpen, setPaletteOpen] = useState(true); const [paletteOpen, setPaletteOpen] = useState(true);
const [fullscreen, setFullscreen] = useState(false);
useEffect(() => {
const cls = 'maze-fullscreen';
if (fullscreen) document.body.classList.add(cls);
else document.body.classList.remove(cls);
return () => document.body.classList.remove(cls);
}, [fullscreen]);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape' && fullscreen) setFullscreen(false);
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [fullscreen]);
const [services, setServices] = useState<ServiceDef[]>(DEFAULT_SERVICES); const [services, setServices] = useState<ServiceDef[]>(DEFAULT_SERVICES);
const [archetypes, setArchetypes] = useState<Archetype[]>(DEFAULT_ARCHETYPES); const [archetypes, setArchetypes] = useState<Archetype[]>(DEFAULT_ARCHETYPES);
@@ -562,6 +578,15 @@ const MazeNET: React.FC = () => {
<button type="button" className="maze-btn ghost" onClick={() => setInspectorOpen((o) => !o)}> <button type="button" className="maze-btn ghost" onClick={() => setInspectorOpen((o) => !o)}>
{inspectorOpen ? <PanelRightClose size={12} /> : <PanelRightOpen size={12} />} INSPECTOR {inspectorOpen ? <PanelRightClose size={12} /> : <PanelRightOpen size={12} />} INSPECTOR
</button> </button>
<button
type="button"
className="maze-btn ghost"
onClick={() => setFullscreen((f) => !f)}
title={fullscreen ? 'Exit fullscreen (Esc)' : 'Fullscreen canvas'}
>
{fullscreen ? <Minimize2 size={12} /> : <Maximize2 size={12} />}
{fullscreen ? ' EXIT FULL' : ' FULLSCREEN'}
</button>
<button type="button" className="maze-btn ghost" onClick={refetch} title="Revert local state to server"> <button type="button" className="maze-btn ghost" onClick={refetch} title="Revert local state to server">
<RotateCcw size={12} /> REFRESH <RotateCcw size={12} /> REFRESH
</button> </button>