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.
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:
- 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);
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": {
"type": "Text",
"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
},
"a-sidebar": {
"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]
},
"a-sidebar-lbl": {
"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
},
"a-center": {
"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]
},
"a-center-lbl": {
"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
},
"a-context": {
"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]
},
"a-context-lbl": {
"type": "Text", "parent": "a-context",
"left": 760, "top": 105, "text": "Context\npane",
"left": 760, "top": 100, "text": "Context\npane",
"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": {
"type": "Rectangle",
"left": 233, "top": 200, "width": 26, "height": 30,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 5, 5, 5]
"left": 238, "top": 294, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
},
"a-toggle-left-icon": {
"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": {
"type": "Rectangle",
"left": 721, "top": 200, "width": 26, "height": 30,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 5, 5, 5]
"left": 718, "top": 294, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
},
"a-toggle-right-icon": {
"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": {
"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
},
"a-note-right": {
"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
},
"titleB": {
"type": "Text",
"left": 40, "top": 410,
"text": "STATE B — both collapsed: same buttons stay anchored on center edge, chevrons flip to re-open",
"left": 40, "top": 388,
"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
},
"b-center": {
"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]
},
"b-center-lbl": {
"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
},
"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": {
"type": "Rectangle",
"left": 40, "top": 560, "width": 26, "height": 30,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [0, 5, 5, 0]
"left": 44, "top": 632, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
},
"b-toggle-left-icon": {
"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": {
"type": "Rectangle",
"left": 914, "top": 560, "width": 26, "height": 30,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [5, 0, 0, 5]
"left": 912, "top": 632, "width": 24, "height": 24,
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
},
"b-toggle-right-icon": {
"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": {
"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
},
"b-note-right": {
"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
},
"footer": {
"type": "Text",
"left": 40, "top": 720,
"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).",
"left": 40, "top": 700,
"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
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 98 KiB