diff --git a/frontend/packages/agent/src/agent.css b/frontend/packages/agent/src/agent.css index 6776fce5..c3377703 100644 --- a/frontend/packages/agent/src/agent.css +++ b/frontend/packages/agent/src/agent.css @@ -128,6 +128,19 @@ body.agent-shell { margin: 0; gap: 0.5em; } +/* New Preact page only: `Header.tsx` nests `.agent-header-pills` + INSIDE `.agent-state-row` (badges + pills sharing one row — mara, + live: "can we put the badges on the same row as the links button + etc? then the header would be more compact"), unlike the old + app.js markup where `.agent-header-pills` is a separate header- + level column (index.html line ~54). Scoped as a descendant + selector so it only fires for that nesting — app.js's own + still-live 3-column layout below is untouched. Pushes the pills + cluster to the row's right edge; badges (`children`, rendered + first) fill the space to its left. */ +.agent-state-row .agent-header-pills { + margin-left: auto; +} /* Right cluster — flyout pills stacked / inline with the overflow trigger. Vertically centred against the full-height icon, no @@ -357,10 +370,16 @@ h2, h3 { /* Login flow overlay: only rendered when status != online. Sits centred over the (likely-empty) terminal area; doesn't take chrome - space in the normal online flow. */ + space in the normal online flow. `--agent-header-real-h` (set by + the new Preact page's `Header.tsx` via ResizeObserver, falling back + to the static `--agent-header-h` guess before the first + measurement / on the old app.js page, which never sets it) is the + header's ACTUAL rendered height, not an assumed one — see + Header.tsx's file comment for why this matters (a static guess is + wrong the moment the header wraps an extra line on some viewport). */ .agent-status-overlay { position: absolute; - top: calc(var(--agent-header-h) + 1.5em); + top: calc(var(--agent-header-real-h, var(--agent-header-h)) + 1.5em); left: 50%; transform: translateX(-50%); max-width: 44em; @@ -716,9 +735,9 @@ pre.diff { and last rows reachable with extra padding inside the scroll area. scroll-padding-* keeps anchor-jumps (the `↓ N new` pill, focus restore) clear of the floats too. */ - padding-top: calc(var(--agent-header-h) + 0.8em); + padding-top: calc(var(--agent-header-real-h, var(--agent-header-h)) + 0.8em); padding-bottom: calc(var(--agent-composer-h) + 0.8em); - scroll-padding-top: calc(var(--agent-header-h) + 0.8em); + scroll-padding-top: calc(var(--agent-header-real-h, var(--agent-header-h)) + 0.8em); scroll-padding-bottom: calc(var(--agent-composer-h) + 0.8em); overflow: auto; } @@ -739,7 +758,21 @@ pre.diff { rules below stay scoped to whichever ancestor owns it. */ .term-input .sendform-term { display: flex; - align-items: flex-start; + /* mara, live: "bottom input row text not aligned / inconsistent + sizes." Real cause: `.prompt` (1em, no line-height override) and + `.submit-hint` (0.8em, no line-height override) each get a + browser-default line-box at a different em-relative size, so + `align-items: flex-start` (their old value) pinned each one's + line-box top edge to the row's top — same nominal `padding-top` + but a DIFFERENT absolute offset per element, since 0.25em means + something different at 1em vs 0.8em font-size. `center` sidesteps + the whole "line-box for text this size" mismatch by aligning each + item's own box middle instead of a top edge that was never + actually equal. Still correct once the textarea grows multi-line + (a common composer-bar convention — Slack/Discord centre their + send affordance against a grown box too, not pin it to the first + line). */ + align-items: center; gap: 0.5em; /* The dashed in-frame separator is dropped — see the .agent-composer .term-input override above for the floating-bar @@ -747,9 +780,6 @@ pre.diff { border-top: 1px dashed var(--purple-dim); padding-top: 0.5em; } -.term-input .prompt, .term-input .submit-hint { - padding-top: 0.25em; -} .term-input .prompt { color: var(--green); text-shadow: 0 0 6px color-mix(in srgb, var(--green) 60%, transparent); diff --git a/frontend/packages/agent/src/components/Header.tsx b/frontend/packages/agent/src/components/Header.tsx index 974a0765..f4685227 100644 --- a/frontend/packages/agent/src/components/Header.tsx +++ b/frontend/packages/agent/src/components/Header.tsx @@ -1,13 +1,28 @@ //
— the agent page's identity strip: icon, glyphic title, the // "swarm / hive" label row, and a slot for the status row // (`` — ../status-chips/, kept separate so this component -// has no opinion on what badges exist). Structurally the same -// three-row shape as the old `#agent-header` markup in index.html -// (icon · main · pills) — see `docs/web-ui.md::Per-agent page` — this -// is a like-for-like layout port, the redesign work is in the children. -// Reuses `agent.css`'s existing `.agent-header*`/`.agent-icon` rules -// (loaded globally by index.html) rather than a component-scoped -// stylesheet — no new visual language needed for the chrome itself. +// has no opinion on what badges exist). Two columns (icon · main), +// NOT the old `#agent-header` markup's three (icon · main · pills) — +// see the `pills` prop doc below for why. Reuses `agent.css`'s +// existing `.agent-header*`/`.agent-icon` rules (loaded globally by +// index.html) rather than a component-scoped stylesheet — no new +// visual language needed for the chrome itself. + +// Measures its own rendered height via ResizeObserver, writes it to +// `--agent-header-real-h` (agent.css's downstream consumers — +// `.agent-status-overlay`, `.agent-main`'s scroll padding — prefer +// this over the static `--agent-header-h` guess). A static guess was +// the root cause of two "login card behind the header" reports on +// this PR (mara, live): any header content that can wrap an extra +// line breaks the guess at whatever width triggers it, and no width +// can be promised safe. Deliberately a SEPARATE var, not an overwrite +// of `--agent-header-h` in place: `.agent-header`'s own `min-height` +// also reads that var — overwriting it in place would make the +// header's own size react to its own just-measured height every +// tick, a real ResizeObserver feedback loop (confirmed live on the +// first pass of this fix). `--agent-header-h` stays the static floor; +// `--agent-header-real-h` is output-only. +import { useEffect, useRef } from 'preact/hooks'; import type { ComponentChildren } from 'preact'; // Icon 404s when the agent has no `hyperhive.icon` override (no @@ -26,35 +41,58 @@ function handleIconError(e: Event) { export interface HeaderProps { label: string; hiveLabel?: string | null; + /** The status/badge row (``) — shares its row with + * `pills` now (see below), not stacked in a row of its own. */ children?: ComponentChildren; - /** Right-cluster flyout triggers (inbox/todos/links pills, the - * overflow menu button) — mirrors the old markup's - * `.agent-header-pills` third column. Meta-nav (``) lives - * here too, as a fixed-size trigger — NOT in the title row the old - * markup put it in (`