import { useRef } from "react"; import { TerminalView } from "./TerminalView"; import type { LayoutNode } from "./layoutTypes"; import { setRatios, restartSurface } from "./socketBridge"; interface Props { workspaceId: string; layout: LayoutNode | null; /** surface_id -> running flag, from the latest status/events. */ running: Record; } export function LayoutEngine({ workspaceId, layout, running }: Props) { if (!layout) { return
Empty workspace — apply a preset to add panels.
; } return ; } function Node({ workspaceId, node, path, running }: { workspaceId: string; node: LayoutNode; path: number[]; running: Record }) { if ("leaf" in node) { const id = node.leaf.surface_id; if (running[id] === false) { return (
Process exited
); } return ; } const { orient, ratios, children } = node.split; const dir = orient === "h" ? "row" : "column"; return (
{children.map((child, i) => ( { const next = [...ratios]; next[i] = Math.max(0.05, next[i] + deltaFrac); next[i + 1] = Math.max(0.05, (next[i + 1] ?? 1) - deltaFrac); void setRatios(workspaceId, path, next); }}> ))}
); } function Pane({ grow, isLast, orient, onResize, children }: { grow: number; isLast: boolean; orient: "h" | "v"; onResize: (deltaFrac: number) => void; children: React.ReactNode }) { const ref = useRef(null); const startDrag = (e: React.MouseEvent) => { e.preventDefault(); const parent = ref.current?.parentElement; if (!parent) return; const total = orient === "h" ? parent.clientWidth : parent.clientHeight; const start = orient === "h" ? e.clientX : e.clientY; let last = start; const move = (ev: MouseEvent) => { const cur = orient === "h" ? ev.clientX : ev.clientY; const delta = (cur - last) / total; last = cur; onResize(delta); }; const up = () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); }; window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); }; return ( <>
{children}
{!isLast && (
)} ); }