import { useEffect, useState } from 'react'; import { Cpu, Settings, Wifi, Network, HardDrive, Activity, Search, Wrench, User, LogOut, Bell, FileText, AppWindow, Folder, Edit, Eye, Database, Upload, Download, Code2, LayoutList, Image, ChevronLeft, Loader2, Check, AlertCircle, RefreshCw, Terminal, Link, Printer, Maximize2, Minimize2 } from 'lucide-react'; import { Toaster } from 'sonner'; import StatusPage from './components/StatusPage'; import DevicesPage from './components/DevicesPage'; import GeneralPage from './components/GeneralPage'; import NetworkPage from './components/NetworkPage'; import IECPage from './components/IECPage'; import ToolsPage from './components/ToolsPage'; import SearchOverlay from './components/SearchOverlay'; import MediaManager from './components/MediaManager'; import RealityOverridePage from './components/RealityOverridePage'; import RealityOverrideAdminPage from './components/RealityOverrideAdminPage'; import logoSvg from '../imports/logo.svg'; import { useSettings } from './settings'; import { WsProvider } from './ws'; type Page = 'status' | 'devices' | 'iec' | 'network' | 'general' | 'tools' | 'apps' | AppId; type AppId = | 'file-manager' | 'print-manager' | 'serial-console' | 'directory-editor' | 'sector-editor' | 'bam-editor' | 'disk-visualizer' | 'ramrom-explorer' | 'dump-disk-image' | 'write-disk-image' | 'prg-to-crt' | 'magic-desk-cart-builder' | 'easy-flash-cart-builder' | 'basic-editor' | 'assembler' | 'sprite-editor' | 'charset-editor' | 'petscii-editor' | 'idle-animation' | 'loading-animation' | 'reality-override' | 'reality-override-admin'; export default function App() { const [currentPage, setCurrentPage] = useState('status'); const { config, setConfig, saveStatus, pendingCount, flushNow, reload } = useSettings(); const [showSearch, setShowSearch] = useState(false); const [showProfileMenu, setShowProfileMenu] = useState(false); const [devicesOpenId, setDevicesOpenId] = useState(null); const [isFullscreen, setIsFullscreen] = useState(false); useEffect(() => { const onChange = () => setIsFullscreen(!!document.fullscreenElement); document.addEventListener('fullscreenchange', onChange); document.addEventListener('webkitfullscreenchange', onChange); return () => { document.removeEventListener('fullscreenchange', onChange); document.removeEventListener('webkitfullscreenchange', onChange); }; }, []); const toggleFullscreen = () => { if (!document.fullscreenElement) { (document.documentElement.requestFullscreen?.() ?? (document.documentElement as any).webkitRequestFullscreen?.()); } else { (document.exitFullscreen?.() ?? (document as any).webkitExitFullscreen?.()); } }; const pages = { status: , devices: setDevicesOpenId(null)} />, iec: , network: , general: , tools: , apps: (

Apps

{/* Manangement Group */}

Management

} label="Media Manager" onClick={() => setCurrentPage('file-manager')} /> } label="Print Manager" onClick={() => setCurrentPage('print-manager')} /> } label="Serial Console" onClick={() => setCurrentPage('serial-console')} /> } label="Short Codes" onClick={() => setCurrentPage('serial-console')} />
{/* Disk Group */}

Disk

} label="RAM/ROM Explorer" onClick={() => setCurrentPage('ramrom-explorer')} /> } label="BAM Editor" onClick={() => setCurrentPage('bam-editor')} /> } label="Directory Editor" onClick={() => setCurrentPage('directory-editor')} /> } label="Sector Editor" onClick={() => setCurrentPage('sector-editor')} /> } label="Disk Visualizer" onClick={() => setCurrentPage('disk-visualizer')} /> } label="Dump Disk Image" onClick={() => setCurrentPage('dump-disk-image')} /> } label="Write Disk Image" onClick={() => setCurrentPage('write-disk-image')} />
{/* Cartridge Group */}

Cartridge

} label="PRG to CRT" onClick={() => setCurrentPage('prg-to-crt')} /> } label="Magic Desk Cart Builder" onClick={() => setCurrentPage('magic-desk-cart-builder')} /> } label="Easy Flash Cart Builder" onClick={() => setCurrentPage('easy-flash-cart-builder')} />
{/* Development Group */}

Development

} label="Basic Editor" onClick={() => setCurrentPage('basic-editor')} /> } label="Assembler" onClick={() => setCurrentPage('assembler')} /> } label="Sprite Editor" onClick={() => setCurrentPage('sprite-editor')} /> } label="Character Set Editor" onClick={() => setCurrentPage('charset-editor')} /> } label="Petscii Editor" onClick={() => setCurrentPage('petscii-editor')} />
{/* Display Group */}

Display

} label="Idle Animation" onClick={() => setCurrentPage('idle-animation')} /> } label="Loading Animation" onClick={() => setCurrentPage('loading-animation')} /> } label="Reality Override" onClick={() => setCurrentPage('reality-override')} /> } label="Override Admin" onClick={() => setCurrentPage('reality-override-admin')} />
), // Individual app pages 'file-manager': setCurrentPage('apps')} config={config} setConfig={setConfig} onNavigateToDevice={(id) => { setCurrentPage('devices'); setDevicesOpenId(id); }} />, 'print-manager': setCurrentPage('apps')} config={config} setConfig={setConfig} />, 'serial-console': setCurrentPage('apps')} />, 'directory-editor': setCurrentPage('apps')} />, 'sector-editor': setCurrentPage('apps')} />, 'bam-editor': setCurrentPage('apps')} />, 'disk-visualizer': setCurrentPage('apps')} />, 'ramrom-explorer': setCurrentPage('apps')} />, 'dump-disk-image': setCurrentPage('apps')} />, 'write-disk-image': setCurrentPage('apps')} />, 'prg-to-crt': setCurrentPage('apps')} />, 'magic-desk-cart-builder': setCurrentPage('apps')} />, 'easy-flash-cart-builder': setCurrentPage('apps')} />, 'basic-editor': setCurrentPage('apps')} />, 'assembler': setCurrentPage('apps')} />, 'sprite-editor': setCurrentPage('apps')} />, 'charset-editor': setCurrentPage('apps')} />, 'petscii-editor': setCurrentPage('apps')} />, 'idle-animation': setCurrentPage('apps')} />, 'loading-animation': setCurrentPage('apps')} />, 'reality-override': setCurrentPage('apps')} />, 'reality-override-admin': setCurrentPage('apps')} /> }; // AppCard component for app grid function AppCard({ icon, label, onClick }: { icon: React.ReactNode; label: string; onClick: () => void }) { return ( ); } // AppPage component for individual app pages function AppPage({ title, onBack }: { title: string; onBack: () => void }) { return (

{title}

{title} coming soon...
); } return (
{showProfileMenu && (
)}
{pages[currentPage]}
{showSearch && ( setShowSearch(false)} /> )}
); } /** * Tiny indicator that reflects the current save status of the settings * file. Renders nothing when idle (so it doesn't clutter the header). */ function SaveStatusBadge({ status, pendingCount, onSave, onReload, }: { status: 'idle' | 'loading' | 'unsaved' | 'saving' | 'saved' | 'error'; pendingCount: number; onSave: () => void; onReload: () => void; }) { if (status === 'idle') return null; if (status === 'loading') { return ( Loading ); } if (status === 'unsaved') { return ( {pendingCount} unsaved ); } if (status === 'saving') { return ( Saving ); } if (status === 'saved') { return ( Saved ); } // error return ( ); }