[object Object]

← back to Gated Queue Runner

queue viewer: day/night theme toggle (persisted, respects prefers-color-scheme) + ratings (val/urg/ease/safe) as sortable columns

e4dbef2ef9af7cc64e7d1505f39df08f9d39c7b6 · 2026-08-18 14:54:38 -0700 · Steve Abrams

Files touched

Diff

commit e4dbef2ef9af7cc64e7d1505f39df08f9d39c7b6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Aug 18 14:54:38 2026 -0700

    queue viewer: day/night theme toggle (persisted, respects prefers-color-scheme) + ratings (val/urg/ease/safe) as sortable columns
---
 index.html | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/index.html b/index.html
index 53e8ab4..27224ac 100644
--- a/index.html
+++ b/index.html
@@ -50,6 +50,32 @@
   dialog .dh { padding: 12px 16px; border-bottom: 1px solid #eee; font-weight: 700; display: flex; justify-content: space-between; }
   dialog pre { margin: 0; padding: 16px; white-space: pre-wrap; font-size: .82em; max-height: 70vh; overflow: auto; }
   dialog .x { cursor: pointer; border: none; background: #eee; border-radius: 8px; padding: 3px 10px; }
+  /* ---------- day / night ---------- */
+  .themebtn { border:1px solid #ccd3e0; background:#fff; border-radius:8px; padding:6px 10px; cursor:pointer; font-size:.85em; }
+  html.dark body { background:#0f1420; color:#e3e8f2; }
+  html.dark header { background:#161c2b; border-bottom-color:#263149; }
+  html.dark .sub { color:#8a93a8; }
+  html.dark .controls label { color:#9aa4bb; }
+  html.dark select, html.dark input[type=search], html.dark .themebtn,
+  html.dark #allshown, html.dark .card button { background:#1c2436; border-color:#2c3650; color:#e3e8f2; }
+  html.dark .chip { background:#1c2436; border-color:#2c3650; color:#cdd5e5; }
+  html.dark .chip.on { background:#2d5bff; color:#fff; border-color:#2d5bff; }
+  html.dark .card { background:#161c2b; border-color:#263149; box-shadow:none; }
+  html.dark .card .note { color:#e3e8f2; }
+  html.dark .card .when { color:#7c869c; }
+  html.dark .card .file { color:#66708a; }
+  html.dark table { background:#161c2b; }
+  html.dark thead th { background:#1c2436; color:#cdd5e5; border-bottom-color:#2c3650; }
+  html.dark thead th:hover { background:#232d44; }
+  html.dark tbody td { border-bottom-color:#232d44; }
+  html.dark tbody tr:hover { background:#1c2436; }
+  html.dark tbody tr.sel { background:#22305a; }
+  html.dark td.effect { color:#9aa4bb; }
+  html.dark td.file { color:#66708a; }
+  html.dark dialog { background:#161c2b; color:#e3e8f2; }
+  html.dark dialog .dh { border-bottom-color:#263149; }
+  html.dark dialog pre { color:#cdd5e5; }
+  html.dark dialog .x { background:#2c3650; color:#e3e8f2; }
 </style>
 </head>
 <body>
@@ -74,6 +100,7 @@
     </label>
     <label>Size <input type="range" id="dens" min="1" max="5" value="3"></label>
     <button id="allshown" style="border:1px solid #ccd3e0;background:#fff;border-radius:8px;padding:6px 10px;cursor:pointer;font-size:.85em">☑ select all shown</button>
+  <button id="theme" class="themebtn" title="day / night">🌙 Night</button>
   </div>
   <div class="chips" id="chips"></div>
 </header>
@@ -128,8 +155,15 @@ document.querySelectorAll('.act').forEach(btn=>btn.onclick=()=>{
 
 function fmtWhen(ms){ return new Date(ms).toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}); }
 
+// day / night
+function applyTheme(dark){ document.documentElement.classList.toggle('dark',dark); $('theme').textContent = dark?'☀️ Day':'🌙 Night'; localStorage.gqTheme = dark?'dark':'light'; }
+$('theme').onclick = ()=> applyTheme(!document.documentElement.classList.contains('dark'));
+applyTheme((localStorage.gqTheme||(matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'))==='dark');
+
 function load(){
   fetch('/api/gates').then(r=>r.json()).then(d=>{
+    // flatten ratings so every field is a sortable top-level column
+    (d.gates||[]).forEach(g=>{ const r=g.ratings||{}; g.rval=r.value; g.rurg=r.urgency; g.rease=r.ease; g.rsafe=r.safety; });
     DATA=d; $('sub').textContent = `${d.total} things need your OK. Check the boxes for the ones you want done, then Save.`;
     renderChips(); render(); bar();
   });
@@ -208,7 +242,7 @@ function renderCards(g){
   if(!g.length) grid.innerHTML='<p style="color:#889">Nothing matches.</p>';
 }
 // full column set for TABLE; compact subset for LIST — every column is click-to-sort
-const COLS_TABLE=[{f:'pick',l:'✔'},{f:'rank',l:'#'},{f:'pri',l:'Priority'},{f:'kind',l:'Kind'},{f:'title',l:'Title'},{f:'about',l:"What it's about"},{f:'effect',l:'If you say YES'},{f:'created',l:'When'},{f:'size',l:'Size'},{f:'file',l:'File'}];
+const COLS_TABLE=[{f:'pick',l:'✔'},{f:'rank',l:'#'},{f:'pri',l:'Priority'},{f:'rval',l:'💰Val'},{f:'rurg',l:'⏰Urg'},{f:'rease',l:'⚡Ease'},{f:'rsafe',l:'✅Safe'},{f:'kind',l:'Kind'},{f:'title',l:'Title'},{f:'about',l:"What it's about"},{f:'effect',l:'If you say YES'},{f:'created',l:'When'},{f:'size',l:'Size'},{f:'file',l:'File'}];
 const COLS_LIST =[{f:'pick',l:'✔'},{f:'rank',l:'#'},{f:'pri',l:'Priority'},{f:'kind',l:'Kind'},{f:'title',l:'Title'},{f:'created',l:'When'}];
 function cellFor(f,x){
   const t=(typeof TIER!=='undefined'&&TIER[x.tier])||{c:'#5a6a85',bg:'#eef2fb',l:'⚪ Low'};
@@ -216,6 +250,10 @@ function cellFor(f,x){
     case 'pick': return `<input type="checkbox" ${SEL.has(x.file)?'checked':''}>`;
     case 'rank': return `<span style="font-weight:800;color:#fff;background:${t.c};border-radius:6px;padding:1px 6px">#${x.rank}</span>`;
     case 'pri': return `<span style="white-space:nowrap;font-weight:700;color:${t.c}">${t.l}</span> <span style="color:#aab;font-size:.85em">${x.priority}</span>`;
+    case 'rval': return `<b>${x.rval??''}</b>`;
+    case 'rurg': return `<b>${x.rurg??''}</b>`;
+    case 'rease': return `<b>${x.rease??''}</b>`;
+    case 'rsafe': return `<b>${x.rsafe??''}</b>`;
     case 'kind': return `<span style="white-space:nowrap">${x.emoji} ${esc(x.catLabel)}</span>`;
     case 'title': return `<span class="ttl">${esc(x.title)}</span>`;
     case 'about': return esc(x.about);

← f843c57 queue viewer: add priority RANKING + per-item RATINGS (value  ·  back to Gated Queue Runner  ·  add creds-in-URL fetch guard to gated pages (TK-10984) ca7086b →