// app.jsx — main shell wiring all screens together + tweaks const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#5B7CFA", "density": "comfortable", "gridSize": "md", "showSearch": true, "sidebarMode": "expanded" }/*EDITMODE-END*/; function App() { const [route, setRoute] = React.useState("home"); const [openAsset, setOpenAsset] = React.useState(null); const [openProject, setOpenProject] = React.useState(null); const [showNewRecorder, setShowNewRecorder] = React.useState(false); const [t, setTweak] = (window.useTweaks ? window.useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}]); React.useEffect(() => { document.documentElement.style.setProperty("--accent", t.accent); document.documentElement.style.setProperty("--accent-soft", hexToRgba(t.accent, 0.14)); document.documentElement.style.setProperty("--accent-soft-2", hexToRgba(t.accent, 0.22)); document.documentElement.style.setProperty("--accent-text", lighten(t.accent, 0.25)); document.documentElement.style.setProperty("--accent-hover", lighten(t.accent, 0.08)); }, [t.accent]); const navigate = (id) => { setOpenAsset(null); setRoute(id); }; const crumbs = React.useMemo(() => { if (openAsset) return [ { label: "Library", to: "library" }, { label: openAsset.project, to: "library" }, { label: openAsset.name }, ]; if (openProject) return [ { label: "Projects", to: "projects" }, { label: openProject.name }, ]; const labels = { home: ["Home"], library: ["Library", "Protour 2026"], projects: ["Projects"], upload: ["Ingest", "Upload"], recorders: ["Ingest", "Recorders"], capture: ["Ingest", "Capture"], monitors: ["Ingest", "Monitors"], jobs: ["Jobs"], editor: ["Editor"], users: ["Admin", "Users & Groups"], tokens: ["Admin", "Tokens"], containers: ["Admin", "Containers"], cluster: ["Admin", "Cluster"], settings: ["Admin", "Settings"], }; return (labels[route] || ["Home"]).map((label, i, arr) => i < arr.length - 1 ? { label } : { label }); }, [route, openAsset, openProject]); let content; if (openAsset) { content = setOpenAsset(null)} />; } else { switch (route) { case "home": content = ; break; case "library": content = ; break; case "projects": content = { setOpenProject(p); setRoute("library"); }} />; break; case "upload": content = ; break; case "recorders": content = setShowNewRecorder(true)} />; break; case "capture": content = ; break; case "monitors": content = ; break; case "jobs": content = ; break; case "editor": content = ; break; case "users": content = ; break; case "tokens": content = ; break; case "containers": content = ; break; case "cluster": content = ; break; case "settings": content = ; break; default: content = ; } } return (
{!openAsset && } {content}
{showNewRecorder && setShowNewRecorder(false)} />} {window.TweaksPanel && ( setTweak("accent", v)} options={["#5B7CFA", "#7C5CFF", "#2DD4A8", "#FF5B5B", "#F5A623", "#E8E8E8"]} /> setTweak("density", v)} options={[{ value: "comfortable", label: "Comfy" }, { value: "compact", label: "Compact" }]} /> setTweak("gridSize", v)} options={[{ value: "sm", label: "S" }, { value: "md", label: "M" }, { value: "lg", label: "L" }]} /> setTweak("sidebarMode", v)} options={[{ value: "expanded", label: "Expanded" }, { value: "collapsed", label: "Icons" }]} />
{[ ["home", "Home"], ["library", "Library"], ["recorders", "Recorders"], ["capture", "Capture"], ["monitors", "Monitors"], ["jobs", "Jobs"], ["editor", "Editor"], ["cluster", "Cluster"], ].map(([k, l]) => ( ))}
)}
); } function hexToRgba(hex, a) { const h = hex.replace("#", ""); const r = parseInt(h.slice(0, 2), 16); const g = parseInt(h.slice(2, 4), 16); const b = parseInt(h.slice(4, 6), 16); return `rgba(${r}, ${g}, ${b}, ${a})`; } function lighten(hex, amt) { const h = hex.replace("#", ""); const r = Math.min(255, parseInt(h.slice(0, 2), 16) + Math.round(amt * 255)); const g = Math.min(255, parseInt(h.slice(2, 4), 16) + Math.round(amt * 255)); const b = Math.min(255, parseInt(h.slice(4, 6), 16) + Math.round(amt * 255)); return `rgb(${r}, ${g}, ${b})`; } const root = ReactDOM.createRoot(document.getElementById("root")); root.render();