[object Object]

← back to Resume Queue Viewer

Add search box + live per-tab counts to the queue viewer

39b98486dc46d64c35977a11443017b306016f5c · 2026-05-18 17:29:48 -0700 · SteveStudio2

Files touched

Diff

commit 39b98486dc46d64c35977a11443017b306016f5c
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Mon May 18 17:29:48 2026 -0700

    Add search box + live per-tab counts to the queue viewer
---
 server.js | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/server.js b/server.js
index c3dd24a..cba312d 100644
--- a/server.js
+++ b/server.js
@@ -136,7 +136,11 @@ const PAGE = `<!doctype html>
   .bar .grow { flex:1; }
   .bar label { color:var(--dim); font-size:12px; }
   select, input[type=range] { vertical-align:middle; }
-  select { background:var(--card); color:var(--txt); border:1px solid var(--line); border-radius:7px; padding:5px 8px; font-size:13px; }
+  select, input[type=search] { background:var(--card); color:var(--txt); border:1px solid var(--line); border-radius:7px; padding:5px 8px; font-size:13px; }
+  input[type=search] { width:170px; }
+  input[type=search]:focus { outline:none; border-color:var(--accent); }
+  .bar button .ct { color:var(--dim); font-size:11px; margin-left:4px; }
+  .bar button.on .ct { color:#fff; opacity:.8; }
   main { padding:22px 32px 60px; }
   .grid { display:grid; grid-template-columns:repeat(var(--cols),1fr); gap:14px; }
   .card { background:var(--card); border:1px solid var(--line); border-radius:11px; padding:15px 16px;
@@ -177,10 +181,11 @@ const PAGE = `<!doctype html>
   <div class="sub" id="sub">loading…</div>
 </header>
 <div class="bar">
-  <button data-f="all" class="on">All</button>
-  <button data-f="parking">Parking Lot</button>
-  <button data-f="recap">Recaps</button>
-  <button data-f="win">Wins</button>
+  <button data-f="all" class="on">All<span class="ct" data-ct="all"></span></button>
+  <button data-f="parking">Parking Lot<span class="ct" data-ct="parking"></span></button>
+  <button data-f="recap">Recaps<span class="ct" data-ct="recap"></span></button>
+  <button data-f="win">Wins<span class="ct" data-ct="win"></span></button>
+  <input type="search" id="q" placeholder="search…" autocomplete="off">
   <span class="grow"></span>
   <label>Sort</label>
   <select id="sort">
@@ -198,20 +203,34 @@ let DATA = { parking:[], recaps:[], wins:[] };
 let filter = localStorage.getItem('rq.filter') || 'all';
 let sort = localStorage.getItem('rq.sort') || 'new';
 let dens = +(localStorage.getItem('rq.dens') || 3);
+let query = '';
 
 const TAGCLASS = { parking:'parking', recap:'recap', win:'win' };
 const esc = s => String(s||'').replace(/[&<>"]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
 
 function render() {
   document.documentElement.style.setProperty('--cols', dens);
-  let items = [...DATA.parking, ...DATA.recaps, ...DATA.wins];
-  if (filter !== 'all') items = items.filter(i => i.type === filter);
+  let all = [...DATA.parking, ...DATA.recaps, ...DATA.wins];
+  const q = query.trim().toLowerCase();
+  if (q) all = all.filter(i =>
+    ((i.title||'')+' '+(i.body||'')+' '+(i.project||'')).toLowerCase().includes(q));
+
+  const counts = { all: all.length, parking:0, recap:0, win:0 };
+  all.forEach(i => { counts[i.type] = (counts[i.type]||0) + 1; });
+  document.querySelectorAll('.ct').forEach(el => {
+    el.textContent = ' ' + (counts[el.dataset.ct] || 0); });
+
+  let items = filter === 'all' ? all : all.filter(i => i.type === filter);
   if (sort === 'new') items.sort((a,b)=>b.ts-a.ts);
   else if (sort === 'old') items.sort((a,b)=>a.ts-b.ts);
   else items.sort((a,b)=>a.type.localeCompare(b.type) || b.ts-a.ts);
 
   const g = document.getElementById('grid');
-  if (!items.length) { g.innerHTML = '<div class="empty">Nothing in the queue.</div>'; return; }
+  if (!items.length) {
+    g.innerHTML = '<div class="empty">' +
+      (q ? 'No matches for “' + esc(query.trim()) + '”.' : 'Nothing in the queue.') + '</div>';
+    return;
+  }
   window.LASTITEMS = items;
   g.innerHTML = items.map((i, idx) => {
     const stars = i.type==='win' ? '<span class="stars">'+'★'.repeat(i.rank||3)+'</span>' : '';
@@ -286,6 +305,7 @@ document.getElementById('grid').addEventListener('click', e => {
   const btn = e.target.closest('button.run');
   if (btn) runItem(+btn.dataset.idx, btn);
 });
+document.getElementById('q').addEventListener('input', e => { query = e.target.value; render(); });
 
 document.getElementById('sort').value = sort;
 document.getElementById('dens').value = dens;

← eaf6280 Add launchd plist reference copy for auto-start  ·  back to Resume Queue Viewer  ·  Add Done/Reopen toggle on parking items — writes discussed f 6f6a34a →