[object Object]

← back to Corvette Dashboard Viewer

live new-arrivals viewer (new.html + /api/new-items): newest color-normalized SKUs, top 50, deep palette + fresh descriptors + image + href, auto-refresh

21a046bd657f44b5729928f7bb8e66e0df0e9679 · 2026-07-28 09:01:26 -0700 · Steve Abrams

Files touched

Diff

commit 21a046bd657f44b5729928f7bb8e66e0df0e9679
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 28 09:01:26 2026 -0700

    live new-arrivals viewer (new.html + /api/new-items): newest color-normalized SKUs, top 50, deep palette + fresh descriptors + image + href, auto-refresh
---
 public/new.html |  7 +++++--
 server.js       | 20 ++++++++++++++++----
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/public/new.html b/public/new.html
index b54420e..f93f2e2 100644
--- a/public/new.html
+++ b/public/new.html
@@ -26,9 +26,10 @@ header{display:flex;align-items:center;justify-content:space-between;gap:14px;
 .stats .lbl{font-size:9px;letter-spacing:3px;color:#8b8f98}
 .sub{text-align:center;font-size:10px;letter-spacing:4px;color:#7d818b;margin:12px 0 16px}
 .list{display:flex;flex-direction:column;gap:9px}
-.row{display:grid;grid-template-columns:38px 1fr 200px;gap:14px;align-items:center;
+.row{display:grid;grid-template-columns:30px 56px 1fr 200px;gap:13px;align-items:center;
   background:linear-gradient(180deg,#1a1a1c,#101011);border:1px solid #2c2c31;border-radius:12px;
   padding:11px 14px;box-shadow:0 5px 14px rgba(0,0,0,.45);transition:box-shadow .15s}
+.thumb{width:56px;height:56px;border-radius:8px;object-fit:cover;background:#222;border:1px solid #333;box-shadow:0 2px 6px rgba(0,0,0,.5)}
 .row:hover{box-shadow:0 8px 20px rgba(0,0,0,.7),0 0 0 1px rgba(255,179,0,.3)}
 .row.fresh{animation:land .8s ease}
 @keyframes land{0%{opacity:0;transform:translateY(-12px);box-shadow:0 0 0 2px var(--amber)}100%{opacity:1;transform:none}}
@@ -84,9 +85,11 @@ async function tick(){
       const chips=(p.tags||[]).map(t=>`<span class="chip">${esc(t)}</span>`).join('');
       const row=document.createElement('div');
       row.className='row'+(isNew?' fresh':'');
+      const thumb=p.image?`<img class="thumb" src="${p.image}&width=112" loading="lazy" alt="">`:`<div class="thumb"></div>`;
       row.innerHTML=`<div class="idx ${i<3?'top':''}">${i+1}</div>
+        ${p.href?`<a href="${p.href}" target="_blank">${thumb}</a>`:thumb}
         <div class="main"><div class="t">${title}</div>
-          <div class="meta">${esc(p.vendor)||'—'} · ${p.palette.length} colors</div>
+          <div class="meta">${esc(p.vendor)||'—'} · ${esc(p.sku)||'no sku'} · ${p.palette.length} colors</div>
           <div class="chips">${chips}</div></div>
         <div class="right"><div class="pal">${pal}</div>
           <div class="gidl">#${p.gid}</div>
diff --git a/server.js b/server.js
index a48a3f8..837aeaa 100644
--- a/server.js
+++ b/server.js
@@ -82,12 +82,20 @@ http.createServer((req, res) => {
       gids = lines.slice(-limit).reverse();
     } catch (e) {}
     if (!gids.length) { res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ records: [], processed: 0 })); }
-    // palette map (gid-number -> [{hex,pct}]), loaded once + cached
+    // palette map (gid-number -> [{hex,pct}]) + fresh descriptor maps my jobs applied
+    // (color/style/material), loaded once + cached. These are the values that ACTUALLY
+    // landed — truer than the stale mirror tags.
     if (!global.__pal) {
-      global.__pal = {};
+      global.__pal = {}; global.__desc = { color: {}, style: {}, material: {} };
       try { for (const l of fs.readFileSync(path.join(TK, 'palette-proposed.tsv'), 'utf8').split('\n')) {
         const f = l.split('\t'); if (f.length < 3 || f[2].startsWith('ERR')) continue;
-        try { global.__pal[f[0].replace(/.*\//, '')] = JSON.parse(f[2]); } catch (e) {} } } catch (e) {}
+        const k = f[0].replace(/.*\//, '');
+        try { global.__pal[k] = JSON.parse(f[2]); } catch (e) {}
+        global.__desc.color[k] = (f[1] || '').replace(/^color:/i, '').trim();
+      } } catch (e) {}
+      const load = (file, key) => { try { for (const l of fs.readFileSync(path.join(TK, file), 'utf8').split('\n')) {
+        const f = l.split('\t'); if (f[0] && f[1]) global.__desc[key][f[0].replace(/.*\//, '')] = f[1].trim(); } } catch (e) {} };
+      load('style-proposed.tsv', 'style'); load('material-primary-proposed.tsv', 'material');
     }
     const nums = gids.map(g => g.replace(/.*\//, ''));
     const inList = gids.map(g => `'${g.replace(/'/g, "''")}'`).join(',');
@@ -101,10 +109,14 @@ http.createServer((req, res) => {
     execFile('psql', ['-h', PGHOST, '-d', PGDB, '-tAc', sql], { maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {
       let byGid = {};
       if (!err && stdout.trim()) { try { JSON.parse(stdout.trim()).forEach(r => byGid[r.gid] = r); } catch (e) {} }
+      const D = global.__desc;
       const records = nums.map(n => {
         const d = byGid[n] || {};
+        // fresh descriptors first, then any surviving bare mirror tags
+        const fresh = [D.color[n], D.style[n], D.material[n]].filter(Boolean);
+        const tags = [...new Set([...fresh, ...(d.tags || [])])].slice(0, 8);
         return { gid: n, sku: d.sku || '', image: d.image_url || '', title: d.title || '(loading…)', vendor: d.vendor || '', handle: d.handle || '',
-          tags: d.tags || [], palette: global.__pal[n] || [],
+          color: D.color[n] || '', tags, palette: global.__pal[n] || [],
           href: d.handle ? `https://designer-laboratory-sandbox.myshopify.com/products/${d.handle}` : null };
       });
       res.writeHead(200, { 'Content-Type': 'application/json', 'X-Data-Source': 'live-progress' });

← c4c8d1a Live SKU ticker below engine (image+sku+palette, slide-in mo  ·  back to Corvette Dashboard Viewer  ·  pm2-manage the console (ecosystem.config.js, reboot-safe) 26818b3 →