refactor(frontend): add createTabStrip + migrate logs sub-tabs (#1464 step 1)

Adds @hive/shared/tabs.js — createTabStrip(tabbar, {defaultId, onShow}):
a hash-routed tab strip that resolves controls by `[data-tab="<id>"]`
inside the passed container and panels by `[data-tab-pane="<id>"]`,
toggling `.hive-tab--active` + aria-selected + the panel's `hidden`, and
firing onShow(id) for per-tab side-effects. Always hash-routed (deep-
linkable + back/forward), no element-resolver callbacks (convention over
config), per the #1464 design review.

Wires it up: @hive/shared exports `./tabs.js` + `./tabs.css`, and
common.css @imports tabs.css (component structure, not a swap target, so
inlining is fine — unlike theme.css).

Migrates the logs sub-tabs as the first consumer: markup uses
`.hive-tab`/`data-tab`/`data-tab-pane`, logs.css drops the duplicated
base styles (keeps only its `flex:1` layout delta), and logs.js swaps its
activeTab/showTab/hashchange for createTabStrip (onShow lazy-loads the
SYSTEM tab). Behaviour-preserving. aria-selected is now standardised.
This commit is contained in:
iris 2026-06-08 22:03:39 +02:00
commit e1c276a06e
7 changed files with 103 additions and 60 deletions

View file

@ -17,17 +17,17 @@
points to the H0M3 hub (served at /), not the dashboard. -->
<header class="logs-header">
<a class="logs-back" href="/">← home</a>
<nav class="logs-tabbar" id="logs-tabbar" role="tablist">
<a class="logs-tab" id="logs-tab-build" href="#build" role="tab"
aria-controls="logs-pane-build" data-logs-tab="build">
<nav class="hive-tabbar logs-tabbar" id="logs-tabbar" role="tablist">
<a class="hive-tab" id="logs-tab-build" href="#build" role="tab"
aria-controls="logs-pane-build" data-tab="build">
<span class="logs-tab-label">BUILD</span>
</a>
<a class="logs-tab" id="logs-tab-agent" href="#agent" role="tab"
aria-controls="logs-pane-agent" data-logs-tab="agent">
<a class="hive-tab" id="logs-tab-agent" href="#agent" role="tab"
aria-controls="logs-pane-agent" data-tab="agent">
<span class="logs-tab-label">AGENT</span>
</a>
<a class="logs-tab" id="logs-tab-system" href="#system" role="tab"
aria-controls="logs-pane-system" data-logs-tab="system">
<a class="hive-tab" id="logs-tab-system" href="#system" role="tab"
aria-controls="logs-pane-system" data-tab="system">
<span class="logs-tab-label">SYSTEM</span>
</a>
</nav>
@ -39,7 +39,7 @@
nixos-container invocations across all agents, with
click-to-expand full stdout+stderr. Backed by
GET /api/build-logs?limit=30. -->
<section class="logs-pane" id="logs-pane-build"
<section class="logs-pane" id="logs-pane-build" data-tab-pane="build"
role="tabpanel" aria-labelledby="logs-tab-build">
<div class="logs-toolbar">
<button type="button" class="btn btn-restart" id="build-refresh">↻ refresh</button>
@ -50,7 +50,7 @@
<!-- AGENT: journald viewer for a specific agent container.
Agent selector + unit filter + line count. Backed by
GET /api/journal/{agent}?unit=<unit>&lines=N. -->
<section class="logs-pane" id="logs-pane-agent"
<section class="logs-pane" id="logs-pane-agent" data-tab-pane="agent"
role="tabpanel" aria-labelledby="logs-tab-agent">
<div class="logs-toolbar">
<select id="agent-select" class="journal-unit"></select>
@ -66,7 +66,7 @@
<!-- SYSTEM: host-side service logs. Shows the hive-c0re daemon
journal via GET /api/journal-host?unit=hive-c0re.service. -->
<section class="logs-pane" id="logs-pane-system"
<section class="logs-pane" id="logs-pane-system" data-tab-pane="system"
role="tabpanel" aria-labelledby="logs-tab-system">
<div class="logs-toolbar">
<select id="system-unit-select" class="journal-unit">