[object Object]

← back to Desktop Dotbar

dotbar: ticket states as vertical chips with right-edge labels

26f22db2b8cc5825fdd168af4b85b31f93234c81 · 2026-09-23 11:36:21 -0700 · Steve Abrams

Render blocked/open/idle/doing/parked as individual vertical .chip elements
(colour dot + count left, state word pushed to the right edge via margin-left:
auto) matching the colour-dot chips above, replacing the cramped horizontal
🔴/⚪/⚫ segment footer. Only non-zero states show; each still opens the Fleet
board filtered to its section. Moved into the top cluster (before the spacers)
so they read as a continuation of the list, not a bottom footer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019excZ7L7VE14hbPqKQqH3i

Files touched

Diff

commit 26f22db2b8cc5825fdd168af4b85b31f93234c81
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 23 11:36:21 2026 -0700

    dotbar: ticket states as vertical chips with right-edge labels
    
    Render blocked/open/idle/doing/parked as individual vertical .chip elements
    (colour dot + count left, state word pushed to the right edge via margin-left:
    auto) matching the colour-dot chips above, replacing the cramped horizontal
    🔴/⚪/⚫ segment footer. Only non-zero states show; each still opens the Fleet
    board filtered to its section. Moved into the top cluster (before the spacers)
    so they read as a continuation of the list, not a bottom footer.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019excZ7L7VE14hbPqKQqH3i
---
 public/index.html | 51 +++++++++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/public/index.html b/public/index.html
index c15e3ed..6ff543c 100644
--- a/public/index.html
+++ b/public/index.html
@@ -66,6 +66,10 @@
   @media (prefers-reduced-motion: reduce){ .dot.pulse, .rdot.pulse { animation:none; opacity:1; } }
   .cnt { font-variant-numeric:tabular-nums; font-weight:700; font-size:14px; }
   .nm { color:var(--dim); font-size:11px; }
+  /* Ticket-state chips (Steve 2026-09-23): colour dot + count stay left, the state WORD
+     (blocked/open/idle/…) is pushed to the chip's right edge. margin-left:auto eats the free
+     space between count and label on the full-width side-dock chip. */
+  .tkchip .nm { margin-left:auto; padding-left:8px; }
   /* the flexible gap that pushes #meta to the far end (right on top; bottom on side) */
   #spacer, #spacer2 { flex:1; -webkit-app-region:drag; }
   /* Individually-clickable ticket-state segments (Steve 2026-09-23): hover highlights the one under the cursor. */
@@ -186,30 +190,33 @@ function renderBar(){
   snbtn.textContent = ram.on ? '🔫 ON' : '🔫 OFF';
   snbtn.onclick = toggleSniper;
   bar.appendChild(snbtn);
-  // Left spacer, then the ticket-board summary CENTERED in the middle band (Steve 2026-09-23),
-  // then a right spacer — the two-spacer flexbox trick centers tickets between the sniper button
-  // and #meta. Five live states: blocked / open / idle(stopped) / doing / parked. Click → fleet board.
-  const sp1 = document.createElement('div'); sp1.id='spacer'; bar.appendChild(sp1);
+  // Ticket-board states as INDIVIDUAL vertical chips (Steve 2026-09-23) — same dot+count+label
+  // style as the colour chips above, instead of one cramped horizontal 🔴/⚪/⚫ segment row. Each
+  // chip opens the Fleet board filtered to its section (idle maps to the board's `stopped`). Only
+  // non-zero states show (mirrors the empty-group filter on the colour chips). Placed in the top
+  // cluster BEFORE the spacers so they read as a continuation of the list, not a bottom footer.
   if (tickets.updated) {
-    const tchip = document.createElement('div');
-    tchip.className = 'chip tickets';
-    tchip.title = `Board — ${tickets.blocked} blocked · ${tickets.open} open · ${tickets.idle} idle · ${tickets.doing} doing · ${tickets.parked} parked${tickets.latest ? '\n↳ latest: ' + tickets.latest : ''}`;
-    // Each state is INDIVIDUALLY clickable (Steve 2026-09-23): a segment loads the Fleet board
-    // filtered to that section. idle maps to the board's `stopped` section. stopPropagation keeps
-    // a segment click from also firing the whole-chip (all-tickets) fallback.
-    const seg = (emoji, n, section, label, color) =>
-      `<span class="tkseg" title="load ${label} tickets (${n})" onclick="event.stopPropagation();openBoard('${section}')" `
-      + `style="color:${color};font-weight:700;cursor:pointer;padding:2px 4px;border-radius:5px">${emoji}${n}</span>`;
-    tchip.innerHTML = `<span class="cnt" style="font-size:12px;display:flex;gap:6px;align-items:center">`
-      + seg('🔴', tickets.blocked, 'blocked', 'blocked', '#f87171')
-      + seg('⚪', tickets.open, 'open', 'open', '#e5e7eb')
-      + seg('⚫', tickets.idle, 'stopped', 'idle', '#9ca3af')
-      + seg('🔵', tickets.doing, 'doing', 'doing', '#60a5fa')
-      + seg('🩷', tickets.parked, 'parked', 'parked', '#f9a8d4')
-      + `</span>`;
-    tchip.onclick = () => openBoard('all');   // clicking the gaps opens the whole board
-    bar.appendChild(tchip);
+    const showName = cfg.orientation !== 'top';   // a side dock has vertical room for the label
+    const TSTATES = [
+      { n: tickets.blocked, section:'blocked', label:'blocked', css:'#f87171' },
+      { n: tickets.open,    section:'open',    label:'open',    css:'#e5e7eb' },
+      { n: tickets.idle,    section:'stopped', label:'idle',    css:'#9ca3af' },
+      { n: tickets.doing,   section:'doing',   label:'doing',   css:'#60a5fa' },
+      { n: tickets.parked,  section:'parked',  label:'parked',  css:'#f9a8d4' },
+    ];
+    for (const t of TSTATES) {
+      if (!t.n) continue;                          // hide zero-count states, like the colour groups
+      const tc = document.createElement('div');
+      tc.className = 'chip tkchip';
+      tc.title = `${t.n} ${t.label} — open the Fleet board`;
+      tc.innerHTML = `<span class="dot" style="background:${t.css}"></span>`
+        + `<span class="cnt">${t.n}</span>`
+        + (showName ? `<span class="nm">${t.label}</span>` : '');
+      tc.onclick = () => openBoard(t.section);
+      bar.appendChild(tc);
+    }
   }
+  const sp1 = document.createElement('div'); sp1.id='spacer'; bar.appendChild(sp1);
   const sp2 = document.createElement('div'); sp2.id='spacer2'; sp2.className='spacer-grow'; bar.appendChild(sp2);
   const meta = document.createElement('div'); meta.id='meta';
   const nextO = cfg.orientation==='top'?'left':cfg.orientation==='left'?'right':'top';

← 385c3af dotbar: free-position persistence — bar stays where dragged,  ·  back to Desktop Dotbar  ·  Jev classifies dotbar dot colors ($0 builtin default; paid T cf77e2f →