feat(kanban-dashboard): native <details> collapse + skip empty metadata

Two follow-up improvements to Tranquil-Flow's metadata-panel restyle.
Both stay within the parent PR's "tone down the panel" scope.

1. Native <details>/<summary> collapse for verbose metadata.

   The parent PR consciously deferred this ("adding native expand/collapse
   would be the next step but requires UX agreement"). The default they
   asked for is straightforward: collapsed when the rendered JSON exceeds
   300 chars (the threshold where the max-height: 8.5rem cap actually
   starts mattering), expanded otherwise. <details>/<summary> is the right
   primitive — zero JS, browser-handled state, accessible by default
   (keyboard-navigable, screen-reader announces the disclosure state),
   and survives any react-state churn for free.

   The OS-default disclosure marker is suppressed (list-style: none +
   ::-webkit-details-marker hidden) and replaced with a CSS ::before
   chevron that rotates 90deg on the [open] attribute, so the look is
   consistent across Firefox/WebKit/Blink without the double-marker
   that would otherwise appear on the platforms that still render the
   default triangle.

2. Skip rendering when metadata is an empty object.

   `r.metadata && ...` truthy-checks, but `{}` is truthy in JS — so a
   completed task with no actual metadata would render a "Metadata"
   labeled disclosure block containing literal `{}`. Adds an
   Object.keys(r.metadata).length > 0 guard so empty payloads render
   nothing instead of an empty disclosure stub.

Tests: three new static-asset assertions covering the <details> shape,
the empty-object skip, and the suppress-default-marker + animated-chevron
CSS — all in `tests/plugins/test_kanban_dashboard_plugin.py`.
This commit is contained in:
Teknium 2026-05-10 08:30:02 -07:00
parent 0e0ddaac8f
commit a91e5a8759
3 changed files with 77 additions and 6 deletions

View file

@ -2397,12 +2397,18 @@
r.error
? h("div", { className: "hermes-kanban-run-error" }, r.error)
: null,
r.metadata
? h("div", { className: "hermes-kanban-run-meta-block" },
h("div", { className: "hermes-kanban-run-meta-label" }, "Metadata"),
h("code", { className: "hermes-kanban-run-meta" },
JSON.stringify(r.metadata, null, 2)),
)
(r.metadata && Object.keys(r.metadata).length > 0)
? (function () {
var json = JSON.stringify(r.metadata, null, 2);
var collapsed = json.length > 300;
return h("details", {
className: "hermes-kanban-run-meta-block",
open: !collapsed,
},
h("summary", { className: "hermes-kanban-run-meta-label" }, "Metadata"),
h("code", { className: "hermes-kanban-run-meta" }, json),
);
})()
: null,
);
}),

View file

@ -867,6 +867,8 @@
* sub-block with a thin left rule, capped height, and muted treatment so
* a verbose JSON blob (e.g. changed_files + URLs from a writer task) does
* not visually swamp the parent run row or get mistaken for a crash dump.
* Uses a native <details>/<summary> pair so collapse is browser-handled
* (zero JS); large blobs default collapsed via the open=false attribute.
* See issue #19548. */
.hermes-kanban-run-meta-block {
margin-top: 0.4rem;
@ -874,6 +876,23 @@
border-left: 2px solid var(--color-border);
background: transparent;
}
.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label {
cursor: pointer;
list-style: none;
}
.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label::-webkit-details-marker {
display: none;
}
.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label::before {
content: "▶ ";
display: inline-block;
font-size: 0.6rem;
margin-right: 0.25rem;
transition: transform 120ms ease;
}
.hermes-kanban-run-meta-block[open] > summary.hermes-kanban-run-meta-label::before {
transform: rotate(90deg);
}
.hermes-kanban-run-meta-label {
font-size: 0.65rem;
font-weight: 600;