fix(workspaces): slim CLI pane header on mobile — icons + short labels, desktop unchanged#26
Merged
Merged
Conversation
…s, desktop unchanged
…status, 24px back-to-chat tap target Council review follow-ups: - LoopAutomationControl: the mobile bare-time span is now aria-hidden and an sr-only twin carries the full localized "Waking at … UTC"/"Retrying at …" string, so screen readers no longer hear an orphaned time; the kind ternaries are hoisted into wakeupTimeText/wakeupStatusText. - CliMainPane: back-to-chat button gets p-1.5 -m-1.5 (md:p-0 md:m-0) so the icon-only mobile target reaches ~24px without shifting layout; desktop rendering unchanged.
… breakpoint tie Simplify pass: - Merge the desktop status span and the mobile sr-only twin into one span via the sr-only md:not-sr-only idiom (same a11y tree at both widths, one less duplicated render of wakeupStatusText). - Hoist the triple-checked nextWakeup.kind comparison into isUsageLimitWake. - Comment the cross-file invariant: md: is the exact complement of useIsMobile's MOBILE_BREAKPOINT=767.
xhigh review follow-ups (comment accuracy only, no rendering change): - LoopAutomationControl: the sr-only note now names exactly what stays in the a11y tree (the Waking/Retrying string) and records that the attempts counter is intentionally hidden on mobile for AT and sighted users alike. - Both files: drop the 'exact complement' phrasing — fractional viewport widths between 767 and 768px match neither media query (pre-existing, app-wide trait of the 767/768 pairing).
…y reset not-sr-only resets white-space to normal at md:, silently undoing the parent span's whitespace-nowrap for the restored status text. Add md:whitespace-nowrap on the same span (whitespace utilities are emitted after the accessibility plugin, so it wins) — rendering-identical today, protects the h-8 row if the status area is ever width-constrained. Flagged independently by three review passes; final codex sweep marked it actionable.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The CLI pane header (
CliMainPane) packs "Claude CLI" + "persistent tmux session" + the fullLoopAutomationControlcluster ("Retrying at 14:32 · attempt 3/10" + cancel-X + ⟳ + "Keep going" + Switch + gear) + "Back to chat" into one non-wrappingh-8flex row with zero responsive handling. Every ancestor isoverflow-hidden, so on a 360–430px phone the right-hand controls (the switch, gear, back-to-chat) are clipped and unreachable.LoopAutomationControl(added in #23) is what pushed the row past viewport width.What changed
Pure Tailwind breakpoint gating at
md:(768px), which pairs withuseIsMobile's 767px boundary — no JS hook. Desktop ≥768px renders computed-style identical for typical content; under extreme width pressure (narrow split pane + loop ON + pending wakeup) the title now truncates gracefully with an ellipsis where it previously wrapped into the clippedh-8row.CliMainPane.tsx: header row getsgap-2 min-w-0; title span getsmin-w-0 truncate; mobile shows a new short titlecliMode.titleShort("CLI") while ≥768px keeps "Claude CLI"; the "persistent tmux session" hint ishidden md:inline; "Back to chat" text ishidden md:inline(icon-only on mobile) with an addedaria-label; right cluster getsgap-2 md:gap-3 shrink-0.LoopAutomationControl.tsx: rootgap-1.5 md:gap-2 min-w-0; wakeup status keeps the moon/clock icon + a bare time (14:32) on mobile vs the full "Retrying at …"/"Waking at … UTC" on desktop, withwhitespace-nowrap shrink-0; the "· attempt x/y" suffix and the standalone attempts span arehidden md:inline; "Keep going" label ishidden md:inline(icon + Switch remain, Switch already has an aria-label); toggle group and gear trigger getshrink-0.cliMode.titleShort: "CLI"to all 7 locales (en, es, fr, ja, ko, zh-Hans, zh-Hant).Review follow-ups (ship-it battery):
aria-hiddenand the full localized "Waking/Retrying at …" string stays in the accessibility tree (sr-only md:not-sr-only), so screen readers never hear an orphaned time; "Back to chat" gains a ~29.5px mobile tap target viap-1.5 -m-1.5(reset atmd:so the desktop box is unchanged).nextWakeup.kindcheck hoisted intoisUsageLimitWake; the 767/768 breakpoint tie documented in both files.Result on a 375px viewport (worst case, loop ON + pending wakeup):
CLI | [clock 14:32 ×] ⟳ [switch] ⚙ | [chat icon]— one row, nothing clipped.How verified
pnpm run web-core:check,pnpm run local-web:check(tsc) — pass.pnpm run local-web:lint(ESLint, max-warnings 0) — pass.node scripts/check-unused-i18n-keys.mjs— "No unused i18n keys found" (all hidden labels stay in JSX via CSS, andtitleShortis present in all 7 locales).pnpm run web-core:format/local-web:format(prettier) — clean.frontend-checksgreen on every push.Risks
shrink-0/whitespace-nowrapprotection; pre-PR behavior (text wrapping into the clippedh-8row) was also degraded.LoopAutomationControlis only mounted byCliMainPanetoday, so themd:classes are scoped correctly.ship-it battery
Full review battery run against this PR (head
18b4a360):9e6cfc14— sr-only wakeup status for mobile screen readers; ≥24px back-to-chat tap target. Deferred P3s: visible "UTC" marker on mobile (locked design: bare time + icon, sr-only carries the qualifier), "byte-identical" PR wording (fixed in this body).b6eb0492— merged the status spans viasr-only md:not-sr-only, hoistedisUsageLimitWake, documented the 767/768 tie. Rejected allmin-w-0/shrink-0/whitespace-nowrapremovals (brief-mandated defensive classes) and an IconButton swap (would change desktop markup).34fbc8b0(dropped the "exact complement" overclaim — fractional 767–768px widths match neither query; scoped the sr-only claim to the Waking/Retrying string). Rejected with reasons: mobile bare-UTC (locked), desktop narrow-pane rigidity (brief-mandated classes, documented above), attempts counter hidden from mobile AT (sighted/AT parity, popover addition explicitly out of scope), 44px tap-target convention (infeasible in anh-8header), 320px overflow claim (contradicted by arithmetic at the 8px/10px design-system font sizes).enabled=false(one string format per render, not worth the guard coupling).--api-keyrequired; same result as the feat(executors): Fable/Claude-5 model family, ultracode effort level, free-text model entry + effort for preset models #29 runner). Substituted a codex CodeRabbit-style final sweep on the head diff. Sweep 1 found 1 actionable (md:whitespace-nowrapmissing on thenot-sr-onlystatus span —not-sr-onlyresetswhite-spaceto normal, undoing the parent nowrap guard) → fixed in18b4a360. Sweep 2 on the new head: "ACTIONABLE FINDINGS: 0". The CodeRabbit GitHub App is not installed on this fork, so no app review will post.f001c9c8(original fix) →9e6cfc14(council r1 a11y) →b6eb0492(simplify) →34fbc8b0(comment accuracy) →18b4a360(nowrap hardening). CIfrontend-checksgreen on every push.