hyperhive/frontend/packages/agent/src/Root.tsx
iris 93b34ebb9b agent: scaffold Preact rewrite, Header + StatusChips first slice
Adds a new Preact/TSX build alongside the existing app.js (esbuild
entry `main.tsx` → dist/static/main.{js,css}, same jsx/tsconfig shape
swarm-ui already uses) and the first real page slice: Header +
StatusChips, composing the Badge/Dropdown components from the prior
commit's PR. Not wired into index.html yet — app.js keeps rendering
the live page untouched while this fills in component by component
(state polling, the live SSE stream, login flow, inbox/todos, term
input) in follow-up commits on this branch.

StatusChips folds the model/effort pickers and pause into the badge
row itself (each badge IS its own control), replacing the old
overflow-menu-only pickers — the concrete fix the design guide already
names this page as needing. Presentational only for now (props, not
live data) so it's reviewable against sample data before being wired
to /api/state.

Screenshot-verified against the real agent.css/theme.css/colors.css
(headless chromium, sample data) — renders correctly.

Builds + tsc --noEmit clean.
2026-08-28 22:05:13 +02:00

37 lines
1.3 KiB
TypeScript

// <Root> — root of the Preact rewrite. Currently just `Header` +
// `StatusChips` wired to local component state as a first slice (real
// `/api/state` polling + the live SSE stream land in follow-up commits
// on this same PR, per mara's "one pr != one commit" note on the
// issue). Sample values below match the shapes in `types.ts`.
import { useState } from 'preact/hooks';
import { Header } from './components/Header.js';
import { StatusChips } from './components/StatusChips.js';
export function Root() {
const [model, setModel] = useState('sonnet');
const [effort, setEffort] = useState('high');
const [paused, setPaused] = useState(false);
return (
<Header label="IRIS" hiveLabel="constellation / pr1ma">
<StatusChips
aliveLabel="alive"
aliveTone="positive"
stateLabel="idle · 6m 1s"
stateTone="neutral"
stateTooltip="turn loop running, no claude invocation in flight"
model={model}
availableModels={['haiku', 'sonnet', 'opus']}
onSelectModel={setModel}
effort={effort}
availableEfforts={['low', 'medium', 'high', 'xhigh', 'max']}
onSelectEffort={setEffort}
ctxLabel="534k"
costLabel="$1.6M"
paused={paused}
onTogglePause={() => setPaused((p) => !p)}
lastTurnLabel="last turn 8.4s"
/>
</Header>
);
}