56 lines
1.5 KiB
TypeScript
56 lines
1.5 KiB
TypeScript
import { h } from 'preact';
|
|
import { useState, useEffect } from 'preact/hooks';
|
|
import { wsClient } from './lib/ws';
|
|
import ViewMode from './ViewMode';
|
|
import EditMode from './EditMode';
|
|
import FullscreenMode from './FullscreenMode';
|
|
import type { Interface } from './lib/types';
|
|
|
|
type AppMode = 'view' | 'edit';
|
|
|
|
// If URL has ?fs=<id>, render bare fullscreen canvas
|
|
const fsParam = new URLSearchParams(window.location.search).get('fs');
|
|
|
|
export default function App() {
|
|
const [mode, setMode] = useState<AppMode>('view');
|
|
const [wsStatus, setWsStatus] = useState('connecting');
|
|
const [editTarget, setEditTarget] = useState<Interface | null>(null);
|
|
|
|
useEffect(() => {
|
|
const unsub = wsClient.status.subscribe(setWsStatus);
|
|
return unsub;
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const dpr = window.devicePixelRatio ?? 1;
|
|
document.documentElement.style.setProperty('--dpr', String(dpr));
|
|
if (!fsParam) wsClient.connect('/ws');
|
|
}, []);
|
|
|
|
if (fsParam) {
|
|
return <FullscreenMode interfaceId={fsParam} />;
|
|
}
|
|
|
|
function enterEdit(iface?: Interface) {
|
|
setEditTarget(iface ?? null);
|
|
setMode('edit');
|
|
}
|
|
|
|
function exitEdit() {
|
|
setMode('view');
|
|
setEditTarget(null);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
{wsStatus === 'disconnected' && (
|
|
<div class="connection-banner">WebSocket disconnected — reconnecting…</div>
|
|
)}
|
|
{mode === 'view'
|
|
? <ViewMode onEdit={enterEdit} />
|
|
: <EditMode initial={editTarget} onDone={exitEdit} />
|
|
}
|
|
</div>
|
|
);
|
|
}
|