Skip to content

fix(web): collapse the mobile "Live" badge into the action bar (IDEA-2297) - #1038

Merged
xarmian merged 3 commits into
mainfrom
fix/collection-toolbar-live-badge
Jul 27, 2026
Merged

fix(web): collapse the mobile "Live" badge into the action bar (IDEA-2297)#1038
xarmian merged 3 commits into
mainfrom
fix/collection-toolbar-live-badge

Conversation

@xarmian

@xarmian xarmian commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Closes IDEA-2297.

The wasted row

At ≤768px the collection page hides the <h1> (the collection name lives in MobileContextBar since IDEA-1835) but left SSEStatusIndicator in .title-group — so that row rendered a full line containing nothing but "● Live", stacked above the toolbar.

The badge now has a mobile mount at the trailing edge of .header-actions, collapsed to the coloured dot, pushed right by margin-left: auto (.header-actions is width: 100% under 768px, so no justify-content change is needed). .title-group drops out of layout entirely on mobile — with no rendered children it was still a 0-height flex item collecting .title-row's 12px column gap, which was the last of the wasted row.

Desktop is unchanged — the labelled badge stays beside the title.

Compact mode clips .sse-state-label rather than removing it: the span is a role="status" live region, and live regions announce on text-content change, so an aria-label-only element wouldn't reliably announce a drop to "Offline".

Uniform control height

IDEA-2297's second half. The row mixed four heights — quick-actions ⚡ trigger ~22px, New ~24px (no border), view dropdown ~26px, icon buttons 28px. All 28px now.

The ⚡ trigger is normalised in the page, not in QuickActionsMenu: ItemDetail's .meta-actions band sizes that same trigger to its own padding-based metrics, and a height baked into the shared component would fight it. This uses the same override shape and specificity reasoning that band already documents — the child's scoped .trigger-btn.svelte-<hash> is (0,2,0), so a bare :global(.trigger-btn) would tie and be settled by cross-file source order; the child combinator takes it to (0,3,0).

Mobile gaps 12px → 4px

The six controls total ~255px, so the dot's 12px inset didn't fit on one line at 360px (a common Android width) and wrapped — re-creating the row this PR removes. Only the gaps shrink; the controls stay 28px, so touch targets are untouched.

Verification

Playwright against the installed binary, /dave/docapp/bugs:

width .header-actions height dot inset from content edge
430 / 390 / 375 / 360 29.5px (single row) 12px
340 41.5px (wraps — also wrapped before) 12px

Desktop: badge still in .title-group, label visible, aria-label="Live updates: Live" intact on both breakpoints. All four controls measure 28px on both breakpoints. No horizontal overflow at any width tested.

npm run check clean (no new warnings), 490 web unit tests pass. No E2E selector depends on .sse-state or .title-group; the nine .trigger-btn locators in web/e2e/ are click/visibility assertions, and item-action-bar-band.spec.ts scopes to .meta-actions, which these rules don't reach.

https://claude.ai/code/session_01E2fRi12n8rARczvdEa2LYT

xarmian added 3 commits July 27, 2026 01:56
…2297)

At <=768px the collection page hid the h1 (the name lives in
MobileContextBar) but left the SSE status badge in .title-group, so that
row rendered a full line containing nothing but "* Live". The badge now
has a mobile mount at the trailing edge of .header-actions, collapsed to
the coloured dot alone, and .title-group drops out of layout entirely --
a 0-height flex item still collected .title-row's 12px column gap, which
was the last of the wasted row. Desktop is unchanged: the labelled badge
stays beside the title.

Compact mode CLIPS the label rather than removing it. The span is a
role="status" live region and live regions announce on text-content
change, so an aria-label-only element wouldn't reliably announce a drop
to "Offline".

Also gives the action bar one control height (IDEA-2297's second half).
The row mixed four: the quick-actions trigger ~22px, New ~24px (no
border), the view dropdown ~26px, icon buttons 28px. All are 28px now.
The trigger is normalised in the page rather than in QuickActionsMenu
because ItemDetail's .meta-actions band sizes the same trigger to its own
padding-based metrics; a height baked into the shared component would
fight it. Same override shape and specificity reasoning that band already
documents -- the child's scoped .trigger-btn.svelte-<hash> is (0,2,0), so
a bare :global(.trigger-btn) would tie and be settled by cross-file
source order.

Mobile gaps go 12px -> 4px. The six controls total ~255px, so the dot's
12px inset didn't fit on one line at 360px (a common Android width) and
wrapped, re-creating the row this change removes. Only the gaps shrink;
the controls stay 28px, so touch targets are untouched.

Verified in the browser against the installed binary: single row with a
12px inset at 430/390/375/360 (wraps at 340, as before); desktop badge
still in .title-group with its label visible and
aria-label="Live updates: Live" intact on both breakpoints; no
horizontal overflow. npm run check clean, 490 web unit tests pass.

Claude-Session: https://claude.ai/code/session_01E2fRi12n8rARczvdEa2LYT
Codex review of #1038: with the label clipped in compact mode, hue was
the only thing separating Live from Offline -- colour-alone conveyance
(WCAG 1.4.1), and red/green is the exact pair dichromatic vision
collapses.

Healthy is now a FILLED dot and every unhealthy state is a hollow ring,
so the distinction that matters ("is the stream up?") is carried by
shape. Reconnecting stays separated from Offline by its pulse, and by
hue for anyone running reduced-motion. Scoped to compact mode -- the
labelled desktop variant already names the state in words.

Verified by forcing each status class onto the live badge and reading
computed styles at 390px: connected is a filled green 8px dot
(border-width 0), reconnecting/disconnected/unauthorized are transparent
with a 2px currentColor ring in their own hue, all 8px.

Claude-Session: https://claude.ai/code/session_01E2fRi12n8rARczvdEa2LYT
Codex re-review of #1038: the hollow ring told Live apart from the
unhealthy states, but Reconnecting leaned on its pulse to separate itself
from Offline -- and the pulse is switched off under
prefers-reduced-motion, leaving amber-vs-red as the only difference for
those users.

Reconnecting now takes a dashed ring. Three states, three shapes --
filled, dashed ring, solid ring -- independent of both hue and motion.

Verified at 390px by forcing each status class and reading computed
styles under both prefers-reduced-motion settings: connected filled
(border-width 0), reconnecting transparent + 2px dashed, disconnected
transparent + 2px solid; the pulse animation resolves to none under
reduce while the dashed ring persists.

Claude-Session: https://claude.ai/code/session_01E2fRi12n8rARczvdEa2LYT
@xarmian
xarmian merged commit fd7c77c into main Jul 27, 2026
6 checks passed
@xarmian
xarmian deleted the fix/collection-toolbar-live-badge branch July 27, 2026 02:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant