fabrica

hanna/fabrica

fix(web): center empty-card notes and two-tone the label selector chips

1820303 · hanna committed on 2026-07-26

Zero a card's last child's bottom margin (mirroring the first-child rule) so a
card holding only an empty-state note ("No open issues.") sits centred instead
of bottom-heavy. In the label dropdown, render a checked scoped label's summary
chip two-tone (scope on a neutral background, value in colour) to match the
static label chips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
2 files changed · +18 −4UnifiedSplit
assets/base.css +6 −2
@@ -325,11 +325,15 @@ body.drawer-open .drawer-backdrop {
325 border-radius: var(--fb-radius);325 border-radius: var(--fb-radius);
326 padding: 1rem;326 padding: 1rem;
327}327}
328/* The first child sits against the card padding, so its own top margin would328/* The first/last child sits against the card padding, so its own top/bottom
329 double the gap (empty-state notes, first form labels, headings). */329 margin would double the gap — most visibly on a card holding only an
330 empty-state note ("No open issues."), which would otherwise sit off-centre. */
330.card > :first-child {331.card > :first-child {
331 margin-top: 0;332 margin-top: 0;
332}333}
334.card > :last-child {
335 margin-bottom: 0;
336}
333337
334.muted {338.muted {
335 color: var(--fb-fg-muted);339 color: var(--fb-fg-muted);
assets/fabrica.js +12 −2
@@ -77,10 +77,20 @@
77 return;77 return;
78 }78 }
79 checked.forEach(function (cb) {79 checked.forEach(function (cb) {
80 var name = cb.getAttribute("data-label-name") || cb.value;
80 var chip = document.createElement("span");81 var chip = document.createElement("span");
81 chip.className = "label-chip";
82 chip.style.setProperty("--label-color", cb.getAttribute("data-label-color") || "#888");82 chip.style.setProperty("--label-color", cb.getAttribute("data-label-color") || "#888");
83 chip.textContent = cb.getAttribute("data-label-name") || cb.value;83 var sep = name.indexOf(": ");
84 if (sep === -1) {
85 chip.className = "label-chip";
86 chip.textContent = name;
87 } else {
88 // Scoped label: static markup, text set via textContent (escaped).
89 chip.className = "label-chip label-chip-scoped";
90 chip.innerHTML = '<span class="label-scope"></span><span class="label-value"></span>';
91 chip.firstChild.textContent = name.slice(0, sep).trim();
92 chip.lastChild.textContent = name.slice(sep + 2).trim();
93 }
84 summaryLabel.appendChild(chip);94 summaryLabel.appendChild(chip);
85 });95 });
86 }96 }