file T-305: unify collapser cards + wireframe
Two collapser-card families (ClideHolderCard group container, T-266; the
ConversationCard merged tool card, T-262) attach collapse differently and
render inconsistent header chrome — status mark placement, no fixed
counter slot, color knob on one but not the other. File T-305 (under the
T-276 UI tracker) to extract one ClideCollapserCard primitive both grab:
a `color` for border/text fidelity, a fixed-width counter slot, and the
status icon hard against the card edge.
Adds the Frame0 wireframe (collapsed color variants + expanded nested
cards) at docs/design/wireframes/cards/collapser-card.{json,png}.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2289,3 +2289,62 @@ 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 ('06FB0TNQM5YNEQM1WY25BV7TD8', 'status', 'backlog', 'ready', NULL, '2026-06-09 21:32:29', '2026-06-09 21:32:29', '2026-06-09 21:32:29', NULL, 'b6690849ecbdddf638c67dfa82192a3f', 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 ('06FB0TNQM50S6WRD81V3Z0NH1M', 'status', 'in_progress', 'done', NULL, '2026-06-09 21:36:05', '2026-06-09 21:36:05', '2026-06-09 21:36:05', NULL, 'c494cd6008aa55db47c5f372ab52c5b2', 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 ('06FB0TNQM5YNEQM1WY25BV7TD8', 'status', 'ready', 'done', NULL, '2026-06-09 21:42:59', '2026-06-09 21:42:59', '2026-06-09 21:42:59', NULL, '73d904ce53c8f0d5adbb6e724d47f885', 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 ('06FB16FJ7KXGFHQXEG88MYRFTG', 'description', 'Group/tool collapser cards (ClideHolderCard vs ConversationCard) handle collapse + visuals inconsistently; extract one shared collapser primitive with a color property, fixed-width counter slot, and the status icon hard against the card edge.', 'Group/tool collapser cards (ClideHolderCard vs ConversationCard) handle collapse + visuals inconsistently; extract one shared collapser primitive with a color property, fixed-width counter slot, and the status icon hard against the card edge.
|
||||
|
||||
## Bug / discrepancy
|
||||
|
||||
There are two collapser-card families with inconsistent collapse handling and
|
||||
"card within card" chrome:
|
||||
|
||||
- **`ClideHolderCard`** (lib/builtin/claude/src/holder_card.dart, T-266) — the
|
||||
group container for Activity (`_ActivityCard`) and Edits (`_EditRunCard`).
|
||||
Collapse = ticker row + frame background + a header caret. Header order:
|
||||
`[chevron] summary … [status] [count]`. Status indicator sits INBOARD, left
|
||||
of the count label. Border/text hardcoded to `panelBorder` / `globalTextMuted`
|
||||
(no color knob).
|
||||
- **`ConversationCard`** (lib/builtin/claude/src/conversation_card.dart, T-262)
|
||||
— the per-tool merged card. Collapse = a single leading caret only (no
|
||||
background/ticker). Header order: `[caret] label summary/spacer [status]
|
||||
[actions]`. Has `borderColor` + `accent`.
|
||||
|
||||
So the toggle is attached differently, the status mark sits in a different
|
||||
place, the counter has no fixed slot, and color customization exists on one but
|
||||
not the other. They should grab the SAME widget (each its own instance — NOT
|
||||
collapsing across types).
|
||||
|
||||
## Proposal — one `ClideCollapserCard` primitive
|
||||
|
||||
Both families render through a single collapser primitive. Requirements:
|
||||
|
||||
1. **`color` property** drives the border AND the label/text color, so each
|
||||
instance keeps its visual identity (activity = muted, edits = accent,
|
||||
error = red, sub-agent, …) through one widget. Default = panelBorder/muted.
|
||||
2. **Fixed-width counter slot** — the `N steps` / `N edits` count lives in a
|
||||
right-aligned fixed-width slot so it (and the trailing status icon) never
|
||||
shift as the number grows or the status appears/changes.
|
||||
3. **Status icon hard against the card edge** — flip the current
|
||||
`[count][status]` to `[status]` against the right edge with the counter
|
||||
inboard of it. The chevron already hugs the LEFT edge. Rule: both icons hug
|
||||
the card edges; text sits inboard.
|
||||
4. **Consistent collapse/expand attachment** across both uses (keep the
|
||||
group-container background-tap-to-collapse for the tail-follow case, D-78,
|
||||
but the visible control + header layout are identical).
|
||||
5. Status glyphs: `ClideRunStatus` running (logo-mark spinner ◐) / success ✓ /
|
||||
error ✕, reusing ClideStatusIndicator.
|
||||
|
||||
Nested sub-cards render the SAME primitive (card-within-card consistency).
|
||||
|
||||
## Scope
|
||||
|
||||
- New `ClideCollapserCard` in lib/widgets/src/ (exported from widgets.dart).
|
||||
- Migrate `ClideHolderCard` (Activity/Edits) and `ConversationCard` (merged
|
||||
tool card) onto it; keep per-type content/labels.
|
||||
- Hold visual fidelity via goldens (conversation_card_goldens_test,
|
||||
ClideHolderCard golden) + a11y (expanded/collapsed semantics, focusable
|
||||
toggle).
|
||||
|
||||
## Wireframe
|
||||
|
||||
docs/design/wireframes/cards/collapser-card.json (+ .png) — collapsed (3 color
|
||||
variants), expanded with nested sub-cards, annotated for the counter slot +
|
||||
edge-anchored icons.', NULL, '2026-06-10 08:16:05', '2026-06-10 08:16:05', '2026-06-10 08:16:05', NULL, 'fe6c300aa083f7faa80d3d78bd1ba0bf', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -129,3 +129,5 @@ 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 ('06FB0TNQM4KS233FGZE9H7ABWR', 'T-304', '2026-06-09 21:22:28', '2026-06-09 21:22:44', NULL, '252c572a5954883d0e5e71406b092a7f', 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 ('06FB0TNQM50S6WRD81V3Z0NH1M', 'T-298', '2026-06-09 16:06:41', '2026-06-09 21:36:05', NULL, 'f8666523eaf2642b918f6846e2801539', 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 ('06FB0TNQM5YNEQM1WY25BV7TD8', 'T-280', '2026-06-08 11:29:22', '2026-06-09 21:42:59', NULL, 'e9859dd425e0ac667ddbce721415572e', 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 ('06FB16FJ7KXGFHQXEG88MYRFTG', 'T-305', '2026-06-10 08:15:39', '2026-06-10 08:15:39', NULL, '288b0c9d74e98c2ac42ee25d3369f689', 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 ('06FB16YM1Y910T07Y1Y22MGTEM', 'T-306', '2026-06-10 08:17:42', '2026-06-10 08:17:42', NULL, 'af36af77224b697a61cb5447955605e5', 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);
|
||||
|
||||
@@ -1067,3 +1067,70 @@ Bisected (each a 45s-timeout repro, all on this box):
|
||||
- The full openFolder tap flow hangs even when project validation is stubbed to a synchronous, pure-Dart `.git` walk (no subprocess) AND `runAsync` is removed — so the wedge is not solely the git subprocess; something in the booted-app + extensions + open-folder command path holds a native port that teardown waits on forever.
|
||||
|
||||
Quarantined with `skip:` so the suite/gate stays green. Real fix: find the leaked native async resource (likely a Process/Isolate/FakeDaemonClient port reachable from the open-folder command or app boot under the test harness) and ensure it''s drained/cancelled before teardown — or drive the "no git repo" assertion without booting the resource. Then remove the skip.', 'done', 'high', NULL, NULL, NULL, '2026-06-08 11:29:22', '2026-06-09 21:42:59', NULL, 'c49e75c2d73ddec10469bf2405dde626', 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 ('06FB16FJ7KXGFHQXEG88MYRFTG', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'Unify collapser cards onto one ClideCollapserCard primitive', 'Group/tool collapser cards (ClideHolderCard vs ConversationCard) handle collapse + visuals inconsistently; extract one shared collapser primitive with a color property, fixed-width counter slot, and the status icon hard against the card edge.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-10 08:15:39', '2026-06-10 08:15:39', NULL, '0c5af482db33b4ea4dd241bd3491a51f', 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 ('06FB16FJ7KXGFHQXEG88MYRFTG', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'Unify collapser cards onto one ClideCollapserCard primitive', 'Group/tool collapser cards (ClideHolderCard vs ConversationCard) handle collapse + visuals inconsistently; extract one shared collapser primitive with a color property, fixed-width counter slot, and the status icon hard against the card edge.
|
||||
|
||||
## Bug / discrepancy
|
||||
|
||||
There are two collapser-card families with inconsistent collapse handling and
|
||||
"card within card" chrome:
|
||||
|
||||
- **`ClideHolderCard`** (lib/builtin/claude/src/holder_card.dart, T-266) — the
|
||||
group container for Activity (`_ActivityCard`) and Edits (`_EditRunCard`).
|
||||
Collapse = ticker row + frame background + a header caret. Header order:
|
||||
`[chevron] summary … [status] [count]`. Status indicator sits INBOARD, left
|
||||
of the count label. Border/text hardcoded to `panelBorder` / `globalTextMuted`
|
||||
(no color knob).
|
||||
- **`ConversationCard`** (lib/builtin/claude/src/conversation_card.dart, T-262)
|
||||
— the per-tool merged card. Collapse = a single leading caret only (no
|
||||
background/ticker). Header order: `[caret] label summary/spacer [status]
|
||||
[actions]`. Has `borderColor` + `accent`.
|
||||
|
||||
So the toggle is attached differently, the status mark sits in a different
|
||||
place, the counter has no fixed slot, and color customization exists on one but
|
||||
not the other. They should grab the SAME widget (each its own instance — NOT
|
||||
collapsing across types).
|
||||
|
||||
## Proposal — one `ClideCollapserCard` primitive
|
||||
|
||||
Both families render through a single collapser primitive. Requirements:
|
||||
|
||||
1. **`color` property** drives the border AND the label/text color, so each
|
||||
instance keeps its visual identity (activity = muted, edits = accent,
|
||||
error = red, sub-agent, …) through one widget. Default = panelBorder/muted.
|
||||
2. **Fixed-width counter slot** — the `N steps` / `N edits` count lives in a
|
||||
right-aligned fixed-width slot so it (and the trailing status icon) never
|
||||
shift as the number grows or the status appears/changes.
|
||||
3. **Status icon hard against the card edge** — flip the current
|
||||
`[count][status]` to `[status]` against the right edge with the counter
|
||||
inboard of it. The chevron already hugs the LEFT edge. Rule: both icons hug
|
||||
the card edges; text sits inboard.
|
||||
4. **Consistent collapse/expand attachment** across both uses (keep the
|
||||
group-container background-tap-to-collapse for the tail-follow case, D-78,
|
||||
but the visible control + header layout are identical).
|
||||
5. Status glyphs: `ClideRunStatus` running (logo-mark spinner ◐) / success ✓ /
|
||||
error ✕, reusing ClideStatusIndicator.
|
||||
|
||||
Nested sub-cards render the SAME primitive (card-within-card consistency).
|
||||
|
||||
## Scope
|
||||
|
||||
- New `ClideCollapserCard` in lib/widgets/src/ (exported from widgets.dart).
|
||||
- Migrate `ClideHolderCard` (Activity/Edits) and `ConversationCard` (merged
|
||||
tool card) onto it; keep per-type content/labels.
|
||||
- Hold visual fidelity via goldens (conversation_card_goldens_test,
|
||||
ClideHolderCard golden) + a11y (expanded/collapsed semantics, focusable
|
||||
toggle).
|
||||
|
||||
## Wireframe
|
||||
|
||||
docs/design/wireframes/cards/collapser-card.json (+ .png) — collapsed (3 color
|
||||
variants), expanded with nested sub-cards, annotated for the counter slot +
|
||||
edge-anchored icons.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-10 08:15:39', '2026-06-10 08:16:05', NULL, '384d36f5718f573bdaba210b0b8a147f', 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 ('06FB16YM1Y910T07Y1Y22MGTEM', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Card the ''context'' conversation block like the rest of the cards', 'The injected "context" block (skill-load / command-expansion / system-reminder messages) renders as a frameless `ConversationCardVariant.bare` card in `lib/builtin/claude/src/conversation_view.dart:410-419`, so it reads as a bare `> context …` row wedged between the fully-framed Skill and Bash tool cards (see pasted screenshot). It looks unfinished next to the carded tool calls.
|
||||
|
||||
Make the context block follow the standard collapser-card pattern established for all group/tool cards in the `collapser-card` wireframe (docs/design/wireframes/cards/): a proper card frame with the chevron toggle hard against the left edge, label, and the fixed-width right-aligned counter/status slot — so it is visually consistent with the Skill/Bash/Activity cards around it.
|
||||
|
||||
Keep the de-emphasis that D-78 calls for (muted accent, collapsed-by-default, first-line summary) — this is about giving it the same *frame* as the other cards, not the blue "you" accent. The same treatment likely applies to the sibling bare cards that share this branch (agent prompt, thinking) for consistency; scope to context first and note whether thinking/agent-prompt should follow.
|
||||
|
||||
Acceptance: the context row sits in a framed card matching the collapser-card wireframe geometry, still muted and collapsed by default, with the toggle and counter/status slot aligned to the other cards. Update/extend the relevant golden(s).', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-10 08:17:42', '2026-06-10 08:17:42', NULL, 'b7f1ad221558368a6c547e00043087b7', 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);
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"name": "ClideCollapserCard",
|
||||
"shapes": {
|
||||
"title": {
|
||||
"type": "Text",
|
||||
"left": 40, "top": 28,
|
||||
"text": "ClideCollapserCard — one collapser primitive for all group / tool cards",
|
||||
"fontColor": "#E2E8F5", "fontSize": 18
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "Text",
|
||||
"left": 40, "top": 56,
|
||||
"text": "Each card type grabs the same widget (no cross-type collapsing) · color property drives border + label/text · fixed-width counter slot · status icon hard against the card edge",
|
||||
"fontColor": "#6A7280", "fontSize": 12
|
||||
},
|
||||
|
||||
"lbl-collapsed": {
|
||||
"type": "Text",
|
||||
"left": 40, "top": 100,
|
||||
"text": "COLLAPSED (ticker row = toggle, focusable)",
|
||||
"fontColor": "#6A7280", "fontSize": 11
|
||||
},
|
||||
|
||||
"a1": {
|
||||
"type": "Rectangle",
|
||||
"left": 40, "top": 124, "width": 660, "height": 46,
|
||||
"fillColor": "#21262F", "strokeColor": "#393E48", "corners": [4, 4, 4, 4]
|
||||
},
|
||||
"a1-chev": { "type": "Text", "parent": "a1", "left": 52, "top": 138, "text": "›", "fontColor": "#6A7280", "fontSize": 16 },
|
||||
"a1-label": { "type": "Text", "parent": "a1", "left": 74, "top": 140, "text": "Activity", "fontColor": "#6A7280", "fontSize": 12 },
|
||||
"a1-summary": { "type": "Text", "parent": "a1", "left": 150, "top": 140, "text": "Read conversation_view.dart", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a1-count": { "type": "Text", "parent": "a1", "left": 560, "top": 140, "text": "3 steps", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a1-status": { "type": "Text", "parent": "a1", "left": 676, "top": 139, "text": "✓", "fontColor": "#00AB9A", "fontSize": 14 },
|
||||
|
||||
"a2": {
|
||||
"type": "Rectangle",
|
||||
"left": 40, "top": 178, "width": 660, "height": 46,
|
||||
"fillColor": "#21262F", "strokeColor": "#00AB9A", "corners": [4, 4, 4, 4]
|
||||
},
|
||||
"a2-chev": { "type": "Text", "parent": "a2", "left": 52, "top": 192, "text": "›", "fontColor": "#00AB9A", "fontSize": 16 },
|
||||
"a2-label": { "type": "Text", "parent": "a2", "left": 74, "top": 194, "text": "Edits", "fontColor": "#00AB9A", "fontSize": 12 },
|
||||
"a2-summary": { "type": "Text", "parent": "a2", "left": 150, "top": 194, "text": "clide_markdown.dart", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a2-count": { "type": "Text", "parent": "a2", "left": 560, "top": 194, "text": "7 edits", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a2-status": { "type": "Text", "parent": "a2", "left": 674, "top": 193, "text": "◐", "fontColor": "#00A3D2", "fontSize": 14 },
|
||||
|
||||
"a3": {
|
||||
"type": "Rectangle",
|
||||
"left": 40, "top": 232, "width": 660, "height": 46,
|
||||
"fillColor": "#21262F", "strokeColor": "#F06C6F", "corners": [4, 4, 4, 4]
|
||||
},
|
||||
"a3-chev": { "type": "Text", "parent": "a3", "left": 52, "top": 246, "text": "›", "fontColor": "#F06C6F", "fontSize": 16 },
|
||||
"a3-label": { "type": "Text", "parent": "a3", "left": 74, "top": 248, "text": "Bash", "fontColor": "#F06C6F", "fontSize": 12 },
|
||||
"a3-summary": { "type": "Text", "parent": "a3", "left": 150, "top": 248, "text": "npm test", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a3-count": { "type": "Text", "parent": "a3", "left": 560, "top": 248, "text": "1 step", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"a3-status": { "type": "Text", "parent": "a3", "left": 676, "top": 247, "text": "✕", "fontColor": "#F06C6F", "fontSize": 14 },
|
||||
|
||||
"counter-note": { "type": "Text", "left": 470, "top": 96, "text": "counters share a fixed-width right-aligned slot ▾ so the status icon never shifts", "fontColor": "#D08447", "fontSize": 10 },
|
||||
|
||||
"edge-note": { "type": "Text", "left": 470, "top": 286, "text": "status icon hard against the card edge ▲ (was inboard, left of the counter)", "fontColor": "#D08447", "fontSize": 10 },
|
||||
"left-note": { "type": "Text", "left": 40, "top": 286, "text": "chevron hard against the left edge — the toggle (keyboard / AT focusable)", "fontColor": "#D08447", "fontSize": 10 },
|
||||
|
||||
"lbl-expanded": {
|
||||
"type": "Text",
|
||||
"left": 40, "top": 332,
|
||||
"text": "EXPANDED (same header; framed body wraps the nested cards — which are the SAME primitive)",
|
||||
"fontColor": "#6A7280", "fontSize": 11
|
||||
},
|
||||
|
||||
"b": {
|
||||
"type": "Rectangle",
|
||||
"left": 40, "top": 356, "width": 660, "height": 196,
|
||||
"fillColor": "#21262F", "strokeColor": "#00AB9A", "corners": [4, 4, 4, 4]
|
||||
},
|
||||
"b-header": {
|
||||
"type": "Rectangle", "parent": "b",
|
||||
"left": 40, "top": 356, "width": 660, "height": 40,
|
||||
"fillColor": "#292E38", "strokeColor": "#393E48", "corners": [4, 4, 0, 0]
|
||||
},
|
||||
"b-chev": { "type": "Text", "parent": "b-header", "left": 52, "top": 368, "text": "⌄", "fontColor": "#00AB9A", "fontSize": 16 },
|
||||
"b-label": { "type": "Text", "parent": "b-header", "left": 74, "top": 369, "text": "Edits", "fontColor": "#00AB9A", "fontSize": 12 },
|
||||
"b-count": { "type": "Text", "parent": "b-header", "left": 560, "top": 369, "text": "7 edits", "fontColor": "#6A7280", "fontSize": 11 },
|
||||
"b-status": { "type": "Text", "parent": "b-header", "left": 676, "top": 368, "text": "✓", "fontColor": "#00AB9A", "fontSize": 14 },
|
||||
|
||||
"sub1": {
|
||||
"type": "Rectangle", "parent": "b",
|
||||
"left": 56, "top": 408, "width": 628, "height": 40,
|
||||
"fillColor": "#1A1E24", "strokeColor": "#393E48", "corners": [3, 3, 3, 3]
|
||||
},
|
||||
"sub1-chev": { "type": "Text", "parent": "sub1", "left": 66, "top": 420, "text": "›", "fontColor": "#6A7280", "fontSize": 14 },
|
||||
"sub1-label": { "type": "Text", "parent": "sub1", "left": 86, "top": 421, "text": "Edit", "fontColor": "#FA5F8B", "fontSize": 11 },
|
||||
"sub1-sum": { "type": "Text", "parent": "sub1", "left": 150, "top": 421, "text": "clide_markdown.dart · _urlLinkSpan", "fontColor": "#6A7280", "fontSize": 10 },
|
||||
"sub1-status": { "type": "Text", "parent": "sub1", "left": 660, "top": 420, "text": "✓", "fontColor": "#00AB9A", "fontSize": 13 },
|
||||
|
||||
"sub2": {
|
||||
"type": "Rectangle", "parent": "b",
|
||||
"left": 56, "top": 454, "width": 628, "height": 40,
|
||||
"fillColor": "#1A1E24", "strokeColor": "#393E48", "corners": [3, 3, 3, 3]
|
||||
},
|
||||
"sub2-chev": { "type": "Text", "parent": "sub2", "left": 66, "top": 466, "text": "›", "fontColor": "#6A7280", "fontSize": 14 },
|
||||
"sub2-label": { "type": "Text", "parent": "sub2", "left": 86, "top": 467, "text": "Edit", "fontColor": "#FA5F8B", "fontSize": 11 },
|
||||
"sub2-sum": { "type": "Text", "parent": "sub2", "left": 150, "top": 467, "text": "clide_markdown.dart · _isHttpUrl", "fontColor": "#6A7280", "fontSize": 10 },
|
||||
"sub2-status": { "type": "Text", "parent": "sub2", "left": 660, "top": 466, "text": "✓", "fontColor": "#00AB9A", "fontSize": 13 },
|
||||
|
||||
"sub3": {
|
||||
"type": "Rectangle", "parent": "b",
|
||||
"left": 56, "top": 500, "width": 628, "height": 40,
|
||||
"fillColor": "#1A1E24", "strokeColor": "#393E48", "corners": [3, 3, 3, 3]
|
||||
},
|
||||
"sub3-chev": { "type": "Text", "parent": "sub3", "left": 66, "top": 512, "text": "›", "fontColor": "#6A7280", "fontSize": 14 },
|
||||
"sub3-label": { "type": "Text", "parent": "sub3", "left": 86, "top": 513, "text": "Edit", "fontColor": "#FA5F8B", "fontSize": 11 },
|
||||
"sub3-sum": { "type": "Text", "parent": "sub3", "left": 150, "top": 513, "text": "clide_markdown.dart · build()", "fontColor": "#6A7280", "fontSize": 10 },
|
||||
"sub3-status": { "type": "Text", "parent": "sub3", "left": 660, "top": 512, "text": "◐", "fontColor": "#00A3D2", "fontSize": 13 },
|
||||
|
||||
"legend": {
|
||||
"type": "Text",
|
||||
"left": 40, "top": 572,
|
||||
"text": "Status glyph (right edge): ◐ running (logo-mark spinner) · ✓ success · ✕ error — set per-instance by a single `color` (border + label/text) + a `ClideRunStatus`.",
|
||||
"fontColor": "#6A7280", "fontSize": 11
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
Reference in New Issue
Block a user