← 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 →