//
— 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). Same three-column shape as the // old `#agent-header` markup (icon · main · pills) — see the `pills` // prop doc below for what moved into that third column and 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 // bundled server-side default any more — see // `hive_agent::web_ui::screen::serve_icon`). Ports app.js's // `bindHeaderIconFallback` exactly: fire-and-forget load, swap to // `/favicon.svg` on failure, `dataset.fallback` guards against a // 404-on-the-fallback-itself loop. function handleIconError(e: Event) { const img = e.currentTarget as HTMLImageElement; if (img.dataset.fallback) return; img.dataset.fallback = '1'; img.src = '/favicon.svg'; } export interface HeaderProps { label: string; hiveLabel?: string | null; /** The status/badge row (``) — lives in the * `.agent-header-pills` cluster now, alongside `pills` (see below), * not stacked as its own row under the title. */ children?: ComponentChildren; /** Flyout triggers (inbox/todos/links pills, the overflow menu * button) — and, since this round, `children` (the status badges) * too, both in `.agent-header-pills`, the SAME header-level column * the old markup used for pills alone. First pass of this ask * nested pills into a row inside `.agent-header-main` instead — * backwards, mara corrected live: "i meant move badges to where the * dropdowns are, not the other way around. this way the height does * not change even on widescreen" — `.agent-header-main` now only * ever holds the title + hive-label rows, which don't wrap in * practice, so it stays a stable height; only this pills-cluster * column (already used to absorbing a variable pill count) grows to * fit badges+pills together. Meta-nav (``) lives in here * too, as a fixed-size trigger — not the old markup's inline list in * the title row (`