diff --git a/frontend/packages/swarm-ui/src/shell/LinksMenu.css b/frontend/packages/swarm-ui/src/shell/LinksMenu.css index 68dfc5fd..ddb2fd89 100644 --- a/frontend/packages/swarm-ui/src/shell/LinksMenu.css +++ b/frontend/packages/swarm-ui/src/shell/LinksMenu.css @@ -1,6 +1,10 @@ /* — a single header icon-button + popover. Kept visually quiet (no border/fill until interacted with) so it reads as chrome, - not another nav item. */ + not another nav item. Button is sized to the same touch-target floor + as the shared `ui/` kit (2.75em ≈ 44px, WCAG 2.5.5) even though it + isn't built from that kit — a bespoke icon trigger, not a form + control, but the floor applies regardless of which component drew + it. */ .links-menu { position: relative; margin-left: auto; @@ -9,8 +13,8 @@ display: flex; align-items: center; justify-content: center; - width: 2em; - height: 2em; + width: 2.75em; + height: 2.75em; padding: 0; border: 1px solid transparent; border-radius: 0.4em; @@ -43,6 +47,7 @@ display: flex; align-items: center; gap: 0.5em; + min-height: 2.75em; padding: 0.4em 0.6em; border-radius: 0.35em; color: var(--fg); diff --git a/frontend/packages/swarm-ui/src/shell/Shell.css b/frontend/packages/swarm-ui/src/shell/Shell.css index 4a6de52c..b3bfffc4 100644 --- a/frontend/packages/swarm-ui/src/shell/Shell.css +++ b/frontend/packages/swarm-ui/src/shell/Shell.css @@ -2,10 +2,17 @@ renders into. Colour vars come from ../theme.css (same base16 slots the per-hive dashboard uses, so this reads as recognizably hyperhive) — the layout itself is this package's own, not - @hive/shared's chrome.css. */ + @hive/shared's chrome.css. + + `flex-wrap` on the header and nav rather than a hamburger/collapse + menu: a narrow viewport (phone or a tiled desktop window) wraps onto + a second line instead of overflowing — "don't break, don't + over-invest" is the explicit scope here, not full mobile navigation + redesign. */ .shell-header { display: flex; align-items: center; + flex-wrap: wrap; gap: 1.5em; padding: 0.75em 1.25em; border-bottom: 1px solid var(--border); @@ -18,17 +25,35 @@ } .shell-nav { display: flex; + flex-wrap: wrap; gap: 1em; } +/* Touch target and active-state underline are deliberately on two + different elements. An earlier version put both `min-height: 2.75em` + and `border-bottom` on the same box: centering the text within a + 2.75em box pushes a bottom-edge border ~0.7em away from the text, + which argus caught by actually rendering it — a real visual + regression, not just a touch-target win. So: `.shell-nav-link` (the + ``) owns the full-height tappable box (same 2.75em / ~44px WCAG + 2.5.5 floor as the rest of the shared kit — this is the primary nav, + the single most-clicked/tapped element in the whole shell), and + `.shell-nav-link-text` (an inner span hugging just the text) owns + the underline, so the indicator stays directly under the label + regardless of how tall the tappable box around it is. */ .shell-nav-link { + display: flex; + align-items: center; + min-height: 2.75em; color: var(--muted); text-decoration: none; - padding: 0.25em 0; - border-bottom: 2px solid transparent; } .shell-nav-link:hover { color: var(--fg); } +.shell-nav-link-text { + padding-bottom: 0.25em; + border-bottom: 2px solid transparent; +} .shell-nav-link-active { color: var(--fg); border-bottom-color: var(--purple); diff --git a/frontend/packages/swarm-ui/src/shell/Shell.tsx b/frontend/packages/swarm-ui/src/shell/Shell.tsx index fe5fc69d..70538e0b 100644 --- a/frontend/packages/swarm-ui/src/shell/Shell.tsx +++ b/frontend/packages/swarm-ui/src/shell/Shell.tsx @@ -34,8 +34,12 @@ const DEFAULT_BRAND = 'hyperhive swarm'; function NavLink({ href, label }: { href: string; label: string }) { const [active] = useRoute(href); return ( - - {label} + + {/* Touch target (min-height) lives on the so the whole row is + tappable; the active-state underline lives on this inner span + so it hugs the text instead of sitting at the bottom of the + full-height box, ~0.7em away from it. */} + {label} ); } diff --git a/frontend/packages/swarm-ui/src/ui/table/Table.css b/frontend/packages/swarm-ui/src/ui/table/Table.css index f990dae6..68407656 100644 --- a/frontend/packages/swarm-ui/src/ui/table/Table.css +++ b/frontend/packages/swarm-ui/src/ui/table/Table.css @@ -1,3 +1,8 @@ +/* Scrolls horizontally within its own box on a narrow viewport instead + of forcing the whole page to overflow — see Table.tsx's comment. */ +.ui-table-scroll { + overflow-x: auto; +} .ui-table { width: 100%; border-collapse: collapse; diff --git a/frontend/packages/swarm-ui/src/ui/table/Table.tsx b/frontend/packages/swarm-ui/src/ui/table/Table.tsx index 3e852063..e8e82c44 100644 --- a/frontend/packages/swarm-ui/src/ui/table/Table.tsx +++ b/frontend/packages/swarm-ui/src/ui/table/Table.tsx @@ -3,6 +3,12 @@ // their own cell rendering rather than this component knowing about // any particular row shape, so it stays reusable for the swarm-wide // agent roster later without a rewrite. +// +// Wrapped in a scrollable container rather than letting a wide table +// force the whole page to overflow horizontally on a narrow viewport — +// a `` doesn't shrink below its content's natural width on its +// own, so without this the page itself would break, not just look +// cramped. import type { ComponentChildren } from 'preact'; import './Table.css'; @@ -22,23 +28,25 @@ export function Table({ rowKey: (row: T) => string; }) { return ( -
- - - {columns.map((c) => ( - - ))} - - - - {rows.map((row) => ( - +
+
{c.header}
+ + {columns.map((c) => ( - + ))} - ))} - -
{c.render(row)}{c.header}
+ + + {rows.map((row) => ( + + {columns.map((c) => ( + {c.render(row)} + ))} + + ))} + + + ); }