T-294: move collapse toggles into the status bar

Revise the mock — toggles no longer float on the pane edges; they live in
the bottom status bar, pinned to the center pane's left/right edge so each
slides to the far end when its pane collapses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 17:28:24 +02:00
co-authored by Claude Opus 4.8
parent 0c44bd25f3
commit da3043308a
4 changed files with 153 additions and 29 deletions
+61
View File
@@ -1190,3 +1190,64 @@ So this ticket is scoped to the VISUAL AFFORDANCE only:
- D-6 CLI/keyboard parity is already satisfied by the existing commands; this adds the mouse affordance. - D-6 CLI/keyboard parity is already satisfied by the existing commands; this adds the mouse affordance.
Mock: docs/design/wireframes/hud/pane-collapse-toggles.{json,png} — State A (open) + State B (collapsed).', NULL, '2026-06-09 15:24:00', '2026-06-09 15:24:00', '2026-06-09 15:24:00', NULL, '216c6fef2135525d9a901d01975f9f74', 1) ON CONFLICT(hash) DO NOTHING; Mock: docs/design/wireframes/hud/pane-collapse-toggles.{json,png} — State A (open) + State B (collapsed).', NULL, '2026-06-09 15:24:00', '2026-06-09 15:24:00', '2026-06-09 15:24:00', NULL, '216c6fef2135525d9a901d01975f9f74', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-294', 'description', 'Design and add collapse/expand controls for the left sidebar and the right context pane, along the lines of the reference screenshot (green arrows mark the two intended affordance locations — bottom-left of the sidebar and bottom-right of the context pane).
Scope of this ticket: set up a Frame0 mock to talk through the design before implementing.
Open questions to resolve in the mock:
- Affordance placement: footer/status-bar anchored (as the screenshot arrows suggest) vs. pane-edge chevron.
- Collapsed state: fully hidden vs. thin rail with a re-expand handle.
- Iconography (chevron direction) and hover/active states.
- Whether sidebar and context pane share one control pattern (parity) or differ.
- Keyboard/CLI parity (D-6): each collapse action needs a clide verb.
Deliverable: Frame0 wireframe(s) of collapsed + expanded states for both panes, reviewed before any code.
DESIGN DIRECTION (settled): anchor both toggles on the OUTER EDGES of the center (Claude conversation) pane — one on the left edge controlling the sidebar, one on the right edge controlling the context pane. The control stays fixed on the center-pane edge whether the adjacent pane is open or collapsed, so a single button both collapses an open pane and re-opens a collapsed one (chevron flips direction). This avoids needing a separate "re-expand" handle on the collapsed pane.
Implications for the mock:
- Collapsed pane can be fully hidden (no thin rail needed) since the re-open control lives on the center edge.
- Sidebar and context pane share one mirrored control pattern (parity).
- Chevron direction reflects state: points outward to expand, inward to collapse.
IMPLEMENTATION NOTE: the collapse logic already exists — no new toggle behaviour needed. Commands `sidebar.collapse` (ctrl+shift+1) and `context.collapse` (ctrl+shift+3) are registered in lib/builtin/default_layout/src/extension.dart, exposed in the command palette + menubar, and call arrangement.toggleCollapsed(Slots.sidebar|contextPanel), returning isCollapsed (D-051, D-054).
So this ticket is scoped to the VISUAL AFFORDANCE only:
- Add the two edge-anchored toggle buttons on the center (Claude) pane''s outer edges.
- On click, invoke the existing `sidebar.collapse` / `context.collapse` commands (do NOT reimplement collapse).
- Read arrangement.isCollapsed(...) to flip the chevron direction per state.
- D-6 CLI/keyboard parity is already satisfied by the existing commands; this adds the mouse affordance.
Mock: docs/design/wireframes/hud/pane-collapse-toggles.{json,png} — State A (open) + State B (collapsed).', 'Design and add collapse/expand controls for the left sidebar and the right context pane, along the lines of the reference screenshot (green arrows mark the two intended affordance locations — bottom-left of the sidebar and bottom-right of the context pane).
Scope of this ticket: set up a Frame0 mock to talk through the design before implementing.
Open questions to resolve in the mock:
- Affordance placement: footer/status-bar anchored (as the screenshot arrows suggest) vs. pane-edge chevron.
- Collapsed state: fully hidden vs. thin rail with a re-expand handle.
- Iconography (chevron direction) and hover/active states.
- Whether sidebar and context pane share one control pattern (parity) or differ.
- Keyboard/CLI parity (D-6): each collapse action needs a clide verb.
Deliverable: Frame0 wireframe(s) of collapsed + expanded states for both panes, reviewed before any code.
DESIGN DIRECTION (settled): anchor both toggles on the OUTER EDGES of the center (Claude conversation) pane — one on the left edge controlling the sidebar, one on the right edge controlling the context pane. The control stays fixed on the center-pane edge whether the adjacent pane is open or collapsed, so a single button both collapses an open pane and re-opens a collapsed one (chevron flips direction). This avoids needing a separate "re-expand" handle on the collapsed pane.
Implications for the mock:
- Collapsed pane can be fully hidden (no thin rail needed) since the re-open control lives on the center edge.
- Sidebar and context pane share one mirrored control pattern (parity).
- Chevron direction reflects state: points outward to expand, inward to collapse.
IMPLEMENTATION NOTE: the collapse logic already exists — no new toggle behaviour needed. Commands `sidebar.collapse` (ctrl+shift+1) and `context.collapse` (ctrl+shift+3) are registered in lib/builtin/default_layout/src/extension.dart, exposed in the command palette + menubar, and call arrangement.toggleCollapsed(Slots.sidebar|contextPanel), returning isCollapsed (D-051, D-054).
So this ticket is scoped to the VISUAL AFFORDANCE only:
- Add the two edge-anchored toggle buttons on the center (Claude) pane''s outer edges.
- On click, invoke the existing `sidebar.collapse` / `context.collapse` commands (do NOT reimplement collapse).
- Read arrangement.isCollapsed(...) to flip the chevron direction per state.
- D-6 CLI/keyboard parity is already satisfied by the existing commands; this adds the mouse affordance.
Mock: docs/design/wireframes/hud/pane-collapse-toggles.{json,png} — State A (open) + State B (collapsed).
PLACEMENT REVISED: toggles do NOT float vertically-centered on the pane edges. They live in the BOTTOM STATUS BAR. Each toggle is horizontally pinned to the center pane''s left/right edge, so when a pane collapses the toggle slides along the status bar to that end (open: at the inner pane boundary; collapsed: at the far status-bar end — matching where the reference-screenshot arrows pointed). Still mirrored left/right for parity; chevron flips per isCollapsed. Buttons invoke the existing sidebar.collapse / context.collapse commands.
Mock updated: docs/design/wireframes/hud/pane-collapse-toggles.{json,png}.', NULL, '2026-06-09 15:28:16', '2026-06-09 15:28:16', '2026-06-09 15:28:16', NULL, 'a41172c3ac1fa78bbfdbf3773467d681', 1) ON CONFLICT(hash) DO NOTHING;
+33
View File
@@ -2685,3 +2685,36 @@ Repro:
Notes: Notes:
- Surfaced while showing a Frame0 wireframe export during T-294. - Surfaced while showing a Frame0 wireframe export during T-294.
- Likely the image-show dispatch resolves a fixed/primary slot instead of the active tab context. Audit the target-resolution path for the image-show command.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-09 15:26:00', '2026-06-09 15:26:00', NULL, 'aa861a651e4bcc707a70e74ff2844ca8', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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); - Likely the image-show dispatch resolves a fixed/primary slot instead of the active tab context. Audit the target-resolution path for the image-show command.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-09 15:26:00', '2026-06-09 15:26:00', NULL, 'aa861a651e4bcc707a70e74ff2844ca8', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-294', 'task', 'T-276', 'Collapse buttons for sidebar and context pane', 'Design and add collapse/expand controls for the left sidebar and the right context pane, along the lines of the reference screenshot (green arrows mark the two intended affordance locations — bottom-left of the sidebar and bottom-right of the context pane).
Scope of this ticket: set up a Frame0 mock to talk through the design before implementing.
Open questions to resolve in the mock:
- Affordance placement: footer/status-bar anchored (as the screenshot arrows suggest) vs. pane-edge chevron.
- Collapsed state: fully hidden vs. thin rail with a re-expand handle.
- Iconography (chevron direction) and hover/active states.
- Whether sidebar and context pane share one control pattern (parity) or differ.
- Keyboard/CLI parity (D-6): each collapse action needs a clide verb.
Deliverable: Frame0 wireframe(s) of collapsed + expanded states for both panes, reviewed before any code.
DESIGN DIRECTION (settled): anchor both toggles on the OUTER EDGES of the center (Claude conversation) pane — one on the left edge controlling the sidebar, one on the right edge controlling the context pane. The control stays fixed on the center-pane edge whether the adjacent pane is open or collapsed, so a single button both collapses an open pane and re-opens a collapsed one (chevron flips direction). This avoids needing a separate "re-expand" handle on the collapsed pane.
Implications for the mock:
- Collapsed pane can be fully hidden (no thin rail needed) since the re-open control lives on the center edge.
- Sidebar and context pane share one mirrored control pattern (parity).
- Chevron direction reflects state: points outward to expand, inward to collapse.
IMPLEMENTATION NOTE: the collapse logic already exists — no new toggle behaviour needed. Commands `sidebar.collapse` (ctrl+shift+1) and `context.collapse` (ctrl+shift+3) are registered in lib/builtin/default_layout/src/extension.dart, exposed in the command palette + menubar, and call arrangement.toggleCollapsed(Slots.sidebar|contextPanel), returning isCollapsed (D-051, D-054).
So this ticket is scoped to the VISUAL AFFORDANCE only:
- Add the two edge-anchored toggle buttons on the center (Claude) pane''s outer edges.
- On click, invoke the existing `sidebar.collapse` / `context.collapse` commands (do NOT reimplement collapse).
- Read arrangement.isCollapsed(...) to flip the chevron direction per state.
- D-6 CLI/keyboard parity is already satisfied by the existing commands; this adds the mouse affordance.
Mock: docs/design/wireframes/hud/pane-collapse-toggles.{json,png} — State A (open) + State B (collapsed).
PLACEMENT REVISED: toggles do NOT float vertically-centered on the pane edges. They live in the BOTTOM STATUS BAR. Each toggle is horizontally pinned to the center pane''s left/right edge, so when a pane collapses the toggle slides along the status bar to that end (open: at the inner pane boundary; collapsed: at the far status-bar end — matching where the reference-screenshot arrows pointed). Still mirrored left/right for parity; chevron flips per isCollapsed. Buttons invoke the existing sidebar.collapse / context.collapse commands.
Mock updated: docs/design/wireframes/hud/pane-collapse-toggles.{json,png}.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-09 15:18:22', '2026-06-09 15:28:16', NULL, '184b328df71f40525172c27f13f8779d', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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);
@@ -4,116 +4,146 @@
"titleA": { "titleA": {
"type": "Text", "type": "Text",
"left": 40, "top": 50, "left": 40, "top": 50,
"text": "STATE A — both side panes open (toggles sit on center-pane edges)", "text": "STATE A — both panes open: toggles live in the status bar, pinned to the center-pane edges",
"fontColor": "#c8d8f0", "fontSize": 15 "fontColor": "#c8d8f0", "fontSize": 15
}, },
"a-sidebar": { "a-sidebar": {
"type": "Rectangle", "type": "Rectangle",
"left": 40, "top": 90, "width": 200, "height": 250, "left": 40, "top": 86, "width": 200, "height": 200,
"fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [6, 6, 6, 6] "fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [6, 6, 6, 6]
}, },
"a-sidebar-lbl": { "a-sidebar-lbl": {
"type": "Text", "parent": "a-sidebar", "type": "Text", "parent": "a-sidebar",
"left": 60, "top": 105, "text": "Sidebar\n(ticket list)", "left": 60, "top": 100, "text": "Sidebar\n(ticket list)",
"fontColor": "#c8d0e0", "fontSize": 13 "fontColor": "#c8d0e0", "fontSize": 13
}, },
"a-center": { "a-center": {
"type": "Rectangle", "type": "Rectangle",
"left": 250, "top": 90, "width": 480, "height": 250, "left": 250, "top": 86, "width": 480, "height": 200,
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [6, 6, 6, 6] "fillColor": "#2a3040", "strokeColor": "#333340", "corners": [6, 6, 6, 6]
}, },
"a-center-lbl": { "a-center-lbl": {
"type": "Text", "parent": "a-center", "type": "Text", "parent": "a-center",
"left": 270, "top": 105, "text": "Claude conversation (center)", "left": 270, "top": 100, "text": "Claude conversation (center)",
"fontColor": "#c8d0e0", "fontSize": 13 "fontColor": "#c8d0e0", "fontSize": 13
}, },
"a-context": { "a-context": {
"type": "Rectangle", "type": "Rectangle",
"left": 740, "top": 90, "width": 200, "height": 250, "left": 740, "top": 86, "width": 200, "height": 200,
"fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [6, 6, 6, 6] "fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [6, 6, 6, 6]
}, },
"a-context-lbl": { "a-context-lbl": {
"type": "Text", "parent": "a-context", "type": "Text", "parent": "a-context",
"left": 760, "top": 105, "text": "Context\npane", "left": 760, "top": 100, "text": "Context\npane",
"fontColor": "#c8d0e0", "fontSize": 13 "fontColor": "#c8d0e0", "fontSize": 13
}, },
"a-statusbar": {
"type": "Rectangle",
"left": 40, "top": 292, "width": 900, "height": 28,
"fillColor": "#15181d", "strokeColor": "#333340", "corners": [0, 0, 0, 0]
},
"a-status-left": {
"type": "Text", "parent": "a-statusbar",
"left": 56, "top": 299, "text": "main 13 skills",
"fontColor": "#8a92a6", "fontSize": 11
},
"a-status-right": {
"type": "Text", "parent": "a-statusbar",
"left": 820, "top": 299, "text": "Output terminal",
"fontColor": "#8a92a6", "fontSize": 11
},
"a-toggle-left": { "a-toggle-left": {
"type": "Rectangle", "type": "Rectangle",
"left": 233, "top": 200, "width": 26, "height": 30, "left": 238, "top": 294, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 5, 5, 5] "fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
}, },
"a-toggle-left-icon": { "a-toggle-left-icon": {
"type": "Text", "parent": "a-toggle-left", "type": "Text", "parent": "a-toggle-left",
"left": 240, "top": 205, "text": "<", "fontColor": "#c8d8f0", "fontSize": 16 "left": 246, "top": 299, "text": "<", "fontColor": "#c8d8f0", "fontSize": 14
}, },
"a-toggle-right": { "a-toggle-right": {
"type": "Rectangle", "type": "Rectangle",
"left": 721, "top": 200, "width": 26, "height": 30, "left": 718, "top": 294, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 5, 5, 5] "fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
}, },
"a-toggle-right-icon": { "a-toggle-right-icon": {
"type": "Text", "parent": "a-toggle-right", "type": "Text", "parent": "a-toggle-right",
"left": 729, "top": 205, "text": ">", "fontColor": "#c8d8f0", "fontSize": 16 "left": 726, "top": 299, "text": ">", "fontColor": "#c8d8f0", "fontSize": 14
}, },
"a-note-left": { "a-note-left": {
"type": "Text", "type": "Text",
"left": 150, "top": 348, "text": "click -> collapse sidebar (edge slides left)", "left": 150, "top": 328, "text": "sits under center's left edge -> collapse sidebar",
"fontColor": "#8a92a6", "fontSize": 11 "fontColor": "#8a92a6", "fontSize": 11
}, },
"a-note-right": { "a-note-right": {
"type": "Text", "type": "Text",
"left": 600, "top": 348, "text": "click -> collapse context (edge slides right)", "left": 600, "top": 328, "text": "sits under center's right edge -> collapse context",
"fontColor": "#8a92a6", "fontSize": 11 "fontColor": "#8a92a6", "fontSize": 11
}, },
"titleB": { "titleB": {
"type": "Text", "type": "Text",
"left": 40, "top": 410, "left": 40, "top": 388,
"text": "STATE B — both collapsed: same buttons stay anchored on center edge, chevrons flip to re-open", "text": "STATE B — both collapsed: each toggle slides along the status bar to the far end as its edge moves out",
"fontColor": "#c8d8f0", "fontSize": 15 "fontColor": "#c8d8f0", "fontSize": 15
}, },
"b-center": { "b-center": {
"type": "Rectangle", "type": "Rectangle",
"left": 40, "top": 450, "width": 900, "height": 250, "left": 40, "top": 424, "width": 900, "height": 200,
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [6, 6, 6, 6] "fillColor": "#2a3040", "strokeColor": "#333340", "corners": [6, 6, 6, 6]
}, },
"b-center-lbl": { "b-center-lbl": {
"type": "Text", "parent": "b-center", "type": "Text", "parent": "b-center",
"left": 380, "top": 465, "text": "Claude conversation — full width", "left": 380, "top": 438, "text": "Claude conversation — full width",
"fontColor": "#c8d0e0", "fontSize": 13 "fontColor": "#c8d0e0", "fontSize": 13
}, },
"b-statusbar": {
"type": "Rectangle",
"left": 40, "top": 630, "width": 900, "height": 28,
"fillColor": "#15181d", "strokeColor": "#333340", "corners": [0, 0, 0, 0]
},
"b-status-left": {
"type": "Text", "parent": "b-statusbar",
"left": 84, "top": 637, "text": "main 13 skills",
"fontColor": "#8a92a6", "fontSize": 11
},
"b-status-right": {
"type": "Text", "parent": "b-statusbar",
"left": 780, "top": 637, "text": "Output terminal",
"fontColor": "#8a92a6", "fontSize": 11
},
"b-toggle-left": { "b-toggle-left": {
"type": "Rectangle", "type": "Rectangle",
"left": 40, "top": 560, "width": 26, "height": 30, "left": 44, "top": 632, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [0, 5, 5, 0] "fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
}, },
"b-toggle-left-icon": { "b-toggle-left-icon": {
"type": "Text", "parent": "b-toggle-left", "type": "Text", "parent": "b-toggle-left",
"left": 48, "top": 565, "text": ">", "fontColor": "#c8d8f0", "fontSize": 16 "left": 52, "top": 637, "text": ">", "fontColor": "#c8d8f0", "fontSize": 14
}, },
"b-toggle-right": { "b-toggle-right": {
"type": "Rectangle", "type": "Rectangle",
"left": 914, "top": 560, "width": 26, "height": 30, "left": 912, "top": 632, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 0, 0, 5] "fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
}, },
"b-toggle-right-icon": { "b-toggle-right-icon": {
"type": "Text", "parent": "b-toggle-right", "type": "Text", "parent": "b-toggle-right",
"left": 921, "top": 565, "text": "<", "fontColor": "#c8d8f0", "fontSize": 16 "left": 920, "top": 637, "text": "<", "fontColor": "#c8d8f0", "fontSize": 14
}, },
"b-note-left": { "b-note-left": {
"type": "Text", "type": "Text",
"left": 80, "top": 595, "text": "click -> re-open sidebar", "left": 80, "top": 666, "text": "now at far-left -> re-open sidebar",
"fontColor": "#8a92a6", "fontSize": 11 "fontColor": "#8a92a6", "fontSize": 11
}, },
"b-note-right": { "b-note-right": {
"type": "Text", "type": "Text",
"left": 760, "top": 595, "text": "click -> re-open context pane", "left": 700, "top": 666, "text": "now at far-right -> re-open context pane",
"fontColor": "#8a92a6", "fontSize": 11 "fontColor": "#8a92a6", "fontSize": 11
}, },
"footer": { "footer": {
"type": "Text", "type": "Text",
"left": 40, "top": 720, "left": 40, "top": 700,
"text": "One control per edge, fixed to the center pane. Collapsed panes hide fully (no rail). Chevron points the way the edge travels. Mirrored left/right for parity. Each toggle = a clide verb (D-6).", "text": "Toggles live in the bottom status bar (not floating on the pane). Each is pinned to the center pane's left/right edge, so it slides to the status-bar end when its pane collapses. Mirrored for parity. Buttons call the existing sidebar.collapse / context.collapse commands; chevron reads isCollapsed.",
"fontColor": "#8a92a6", "fontSize": 11 "fontColor": "#8a92a6", "fontSize": 11
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 98 KiB