← 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
M public/new.htmlM server.js
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 →