From 7c4ac182f6c5095241145372fb80f59d791023af Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Fri, 12 Jun 2026 13:25:04 +0200 Subject: [PATCH] file status-bar styling cohesion bug (T-417) Ticket-only commit so the pql changelog write-through persists. T-417 captures the font/size/token/vertical-alignment drift across the five bottom status bar items, filed under the UI tracker epic T-276. Co-Authored-By: Claude --- .pql/changelog/ticket_history/2026-06.sql | 20 ++++++++++++++ .pql/changelog/ticket_idmap/2026-06.sql | 1 + .pql/changelog/tickets/2026-06.sql | 32 +++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/.pql/changelog/ticket_history/2026-06.sql b/.pql/changelog/ticket_history/2026-06.sql index d6756a35..6a4f1085 100644 --- a/.pql/changelog/ticket_history/2026-06.sql +++ b/.pql/changelog/ticket_history/2026-06.sql @@ -4328,3 +4328,23 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3J7TXMG0F9E2WQDENPVJG', 'status', 'backlog', 'in_progress', NULL, '2026-06-12 10:25:53', '2026-06-12 10:25:53', '2026-06-12 10:25:53', NULL, 'dca846f23cb4353cc826ddd79a6c14f0', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3J7TXMG0F9E2WQDENPVJG', 'status', 'in_progress', 'done', NULL, '2026-06-12 10:56:52', '2026-06-12 10:56:52', '2026-06-12 10:56:52', NULL, 'fd7c4c5f0b0de9144c6220a4ce43476b', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3KRWM65MD3DS251NN9YX0', 'status', 'backlog', 'in_progress', NULL, '2026-06-12 10:56:52', '2026-06-12 10:56:52', '2026-06-12 10:56:52', NULL, 'd1eb3f87ceb5508e4dac1f191750f852', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3KRWM65MD3DS251NN9YX0', 'status', 'in_progress', 'done', NULL, '2026-06-12 11:06:36', '2026-06-12 11:06:36', '2026-06-12 11:06:36', NULL, 'b39b89981d73539635ddbff0d7ca137d', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P8YERJ5R7ENSD675BX00', 'status', 'backlog', 'in_progress', NULL, '2026-06-12 11:06:36', '2026-06-12 11:06:36', '2026-06-12 11:06:36', NULL, 'e90215a982fee656911727727259d318', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ4BYD4STCKCY8JNKF23Q4W', 'description', NULL, 'The bottom central status bar mixes fonts, sizes, color tokens, and vertical alignment across its items, so the bar reads as several unrelated strips instead of one cohesive surface (user screenshot, 2026-06-12). + +**Observed inconsistencies:** + +- **Claude pane context status** (`lib/builtin/claude/src/claude_pane.dart:131` `_statusWidget`, `_ModeBadge` at line 816): `clideFontSmall` (12) + `clideMonoFamily` — the only 12px mono run in the bar. +- **Git branch item** (`lib/builtin/git/src/git_status_item.dart:78`): `clideFontCaption` (14), default UI face (Josefin Sans w300) — sits directly next to the 12px mono Claude segment. +- **Output dock item** (`lib/builtin/output/src/dock_status_item.dart:77`): `clideFontCaption` + `tokens.globalForeground` instead of `tokens.statusBarForeground`; also embeds `▼`/`▲` glyphs as text rather than a `ClideIcon`. +- **IPC tool status** (`lib/builtin/ipc_status/src/status_item.dart:45`) and **theme switcher** (`lib/builtin/theme_picker/src/theme_status_item.dart:68`): `clideFontCaption` + `statusBarForeground` — these two agree with each other but not with the Claude segment. +- **Vertical alignment:** `PaneContextStatusItem` (`lib/builtin/claude/src/pane_context_status.dart:34`) clamps its content in a fixed 16px `SizedBox` inside `ClideMarquee`, while `StatusbarHost` (`lib/src/shell/layout.dart:251`) centers other items via `CrossAxisAlignment.center` on the full bar height — the differing font sizes/line metrics make the Claude run sit visibly off-center relative to its neighbours. + +**Direction (per /ui-design skill):** + +- Typography rule says status bar text is `clideFontCaption` (14); mono (`clideFontMono`/`clideMonoFamily`) is reserved for code/paths/IDs. Decide one type treatment for the bar — likely caption + UI face for labels, mono only for genuinely code-like fragments (e.g. `633k / 1.0M ctx`) if at all — and apply it to every item. +- All status bar items should use `tokens.statusBarForeground` (muted variant: `globalTextMuted`) — fix the `globalForeground` borrow in the output dock item. +- Ensure every item centers in the bar''s vertical space: same slot height strategy (or none) across items so baselines align; review the fixed `_slotHeight = 16` in `pane_context_status.dart` against the bar''s `statusHeight`. +- Separator `·` styling (claude_pane.dart:136) should be a shared affordance if other items adopt segmented content. + +Acceptance: one font family/size/token scheme across all five status items; all items visually centered in the bar''s vertical space; no `globalForeground` borrows; goldens updated.', NULL, '2026-06-12 11:23:21', '2026-06-12 11:23:21', '2026-06-12 11:23:21', NULL, 'dd7198e29cdc41d0837ce0ff068fa26f', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/ticket_idmap/2026-06.sql b/.pql/changelog/ticket_idmap/2026-06.sql index 7edbc3b4..67c5a4c0 100644 --- a/.pql/changelog/ticket_idmap/2026-06.sql +++ b/.pql/changelog/ticket_idmap/2026-06.sql @@ -241,3 +241,4 @@ INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_ INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P8YERJ5R7ENSD675BX00', 'T-414', '2026-06-12 08:59:28', '2026-06-12 08:59:28', NULL, '7d973f16c99441dbba0f8df89a665b32', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P91QQQDT5J50F52FPCKM', 'T-415', '2026-06-12 08:59:28', '2026-06-12 08:59:28', NULL, 'a2dea9268d44b9e8a1fd746bbb947c92', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ8QNGJFFK7G24CBWQAR2C', 'T-416', '2026-06-12 10:25:00', '2026-06-12 10:25:00', NULL, 'f8c2a125e661607d5dd0c73cd2c3f2ab', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); +INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ4BYD4STCKCY8JNKF23Q4W', 'T-417', '2026-06-12 11:22:15', '2026-06-12 11:22:15', NULL, '15aa9b25417162126cbcde174d3537da', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); diff --git a/.pql/changelog/tickets/2026-06.sql b/.pql/changelog/tickets/2026-06.sql index 092b1de8..b53bc78b 100644 --- a/.pql/changelog/tickets/2026-06.sql +++ b/.pql/changelog/tickets/2026-06.sql @@ -4717,3 +4717,35 @@ UX when supported: ''/effort '' sets directly (optimistic status merge, t INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3KRWM65MD3DS251NN9YX0', 'story', '06FBP3EZC7AJANXZVF3D91QYWM', 'Open-in-clide command family: /permissions /config /memory /mcp /agents /todos /status /help', 'The ''owned'' routes that map a TUI command to an existing clide surface — thin per-command glue, one story. /permissions → open the permission-mode picker (T-275 control). /config → focus the Claude sidebar Config tab (T-183). /memory → open CLAUDE.md (and memory files) in the editor. /mcp, /agents, /hooks → their Config-tab sections. /todos → focus the task dock (T-308). /status → focus the sidebar Activity tab. /help → a clide help card listing owned commands + advertised skills (NOT the CLI''s TUI help). Each lands in the routing table (T-411) as ''owned''; D-6 parity notes: these are also the navigation targets the catch-all hint card (T-411) points at. Keep each handler a few lines — navigation/publish on the existing MessageBus + panel APIs, no new surfaces. Tests: each command routes to its surface (message published / tab activated), none forwards to the session.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-12 08:59:08', '2026-06-12 10:56:52', NULL, '395cba57154e147b6a35212e23e2d17e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3KRWM65MD3DS251NN9YX0', 'story', '06FBP3EZC7AJANXZVF3D91QYWM', 'Open-in-clide command family: /permissions /config /memory /mcp /agents /todos /status /help', 'The ''owned'' routes that map a TUI command to an existing clide surface — thin per-command glue, one story. /permissions → open the permission-mode picker (T-275 control). /config → focus the Claude sidebar Config tab (T-183). /memory → open CLAUDE.md (and memory files) in the editor. /mcp, /agents, /hooks → their Config-tab sections. /todos → focus the task dock (T-308). /status → focus the sidebar Activity tab. /help → a clide help card listing owned commands + advertised skills (NOT the CLI''s TUI help). + +Each lands in the routing table (T-411) as ''owned''; D-6 parity notes: these are also the navigation targets the catch-all hint card (T-411) points at. Keep each handler a few lines — navigation/publish on the existing MessageBus + panel APIs, no new surfaces. Tests: each command routes to its surface (message published / tab activated), none forwards to the session.', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 08:59:08', '2026-06-12 11:06:36', NULL, 'be2c0f83cfd0045e2ed7f5f2fdd38298', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P8YERJ5R7ENSD675BX00', 'story', '06FBP3EZC7AJANXZVF3D91QYWM', 'Config tab → interactive controls (model / effort / permission inline)', 'Turn the Claude sidebar Config tab''s read-only rows (T-183, split in T-395) into live controls — the heart of the power-panel epic. Inline: model picker (reuse the T-408 picker, anchored popover per D-ui primitive), permission-mode control (reuse T-275''s permission_mode_control), effort selector (lands with T-412; row shows ''n/a'' with a hint until supported). Each control reads live SessionStatus and writes through the same session APIs the slash commands use — one implementation, two surfaces (D-6). + +Per-session scoping: controls target the active/primary session; the Team tab''s per-member badges (T-157) stay as-is. Keep read-only rows for facts (version, transcript path, skills count). A11y: every control keyboard-reachable, semantics labels per the a11y contract; run make test-a11y. Golden for the new rows if visual. + +STYLING PASS (user, 2026-06-12): the Claude sidepanel looks bland and the font is +small. While making the Config tab interactive, also do a visual polish pass over +the whole Claude sidebar (Activity/Team/Config): bump the row/label typography to +the panel scale used elsewhere, give sections clearer hierarchy (headers, spacing, +accent marks per ui-design tokens), and make the controls feel like controls. +Treat ui-design skill as the reference for token/type choices.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-12 08:59:28', '2026-06-12 11:06:36', NULL, 'ed8b6c209963a835c66bb5e28b06eda1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ4BYD4STCKCY8JNKF23Q4W', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Status bar: inconsistent fonts, sizes, tokens, and vertical alignment across items', NULL, 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 11:22:15', '2026-06-12 11:22:15', NULL, '5abf1d2c781c21eae8bc965cd1f3cbe2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ4BYD4STCKCY8JNKF23Q4W', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Status bar: inconsistent fonts, sizes, tokens, and vertical alignment across items', 'The bottom central status bar mixes fonts, sizes, color tokens, and vertical alignment across its items, so the bar reads as several unrelated strips instead of one cohesive surface (user screenshot, 2026-06-12). + +**Observed inconsistencies:** + +- **Claude pane context status** (`lib/builtin/claude/src/claude_pane.dart:131` `_statusWidget`, `_ModeBadge` at line 816): `clideFontSmall` (12) + `clideMonoFamily` — the only 12px mono run in the bar. +- **Git branch item** (`lib/builtin/git/src/git_status_item.dart:78`): `clideFontCaption` (14), default UI face (Josefin Sans w300) — sits directly next to the 12px mono Claude segment. +- **Output dock item** (`lib/builtin/output/src/dock_status_item.dart:77`): `clideFontCaption` + `tokens.globalForeground` instead of `tokens.statusBarForeground`; also embeds `▼`/`▲` glyphs as text rather than a `ClideIcon`. +- **IPC tool status** (`lib/builtin/ipc_status/src/status_item.dart:45`) and **theme switcher** (`lib/builtin/theme_picker/src/theme_status_item.dart:68`): `clideFontCaption` + `statusBarForeground` — these two agree with each other but not with the Claude segment. +- **Vertical alignment:** `PaneContextStatusItem` (`lib/builtin/claude/src/pane_context_status.dart:34`) clamps its content in a fixed 16px `SizedBox` inside `ClideMarquee`, while `StatusbarHost` (`lib/src/shell/layout.dart:251`) centers other items via `CrossAxisAlignment.center` on the full bar height — the differing font sizes/line metrics make the Claude run sit visibly off-center relative to its neighbours. + +**Direction (per /ui-design skill):** + +- Typography rule says status bar text is `clideFontCaption` (14); mono (`clideFontMono`/`clideMonoFamily`) is reserved for code/paths/IDs. Decide one type treatment for the bar — likely caption + UI face for labels, mono only for genuinely code-like fragments (e.g. `633k / 1.0M ctx`) if at all — and apply it to every item. +- All status bar items should use `tokens.statusBarForeground` (muted variant: `globalTextMuted`) — fix the `globalForeground` borrow in the output dock item. +- Ensure every item centers in the bar''s vertical space: same slot height strategy (or none) across items so baselines align; review the fixed `_slotHeight = 16` in `pane_context_status.dart` against the bar''s `statusHeight`. +- Separator `·` styling (claude_pane.dart:136) should be a shared affordance if other items adopt segmented content. + +Acceptance: one font family/size/token scheme across all five status items; all items visually centered in the bar''s vertical space; no `globalForeground` borrows; goldens updated.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 11:22:15', '2026-06-12 11:23:21', NULL, 'a558e4c5edebc1aa89665bc1c35a6b38', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);