[object Object]

← back to Trending Dw

UX: tiered default sort — real product images lead, our-lane designs next, pending last

45d6a46767095e7f900f7b8aa4e559ffeeb59363 · 2026-07-15 11:46:47 -0700 · Steve

Files touched

Diff

commit 45d6a46767095e7f900f7b8aa4e559ffeeb59363
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 15 11:46:47 2026 -0700

    UX: tiered default sort — real product images lead, our-lane designs next, pending last
---
 data/bestsellers.json | 2 +-
 public/index.html     | 7 +++++--
 server.js             | 2 +-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/data/bestsellers.json b/data/bestsellers.json
index 17576ac..c2f46be 100644
--- a/data/bestsellers.json
+++ b/data/bestsellers.json
@@ -4497,5 +4497,5 @@
   ],
   "imagesAttachedAt": "2026-07-07",
   "imagesLocalizedAt": "2026-07-07",
-  "realImagesAttachedAt": "2026-07-15T18:38:52.951Z"
+  "realImagesAttachedAt": "2026-07-15T18:45:54.933Z"
 }
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index d45d3ec..e58b42b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -127,8 +127,8 @@
       <button class="queuebtn" id="queueBtn" onclick="openQueue()">🛍 Shopify queue <b id="qn">0</b></button>
       <div><label>Sort</label>
         <select id="sort">
+          <option value="have">Real images first</option>
           <option value="signal">Bestseller signal</option>
-          <option value="have">Imaged first</option>
           <option value="gap">Gaps first</option>
           <option value="newest">Newest</option>
           <option value="titleAZ">Title A–Z</option>
@@ -152,7 +152,10 @@ const store = k => { try{ return JSON.parse(localStorage.getItem(k)); }catch(e){
 // existed; now nearly everything is imaged, so 'signal' is the meaningful default.
 const savedSort = (()=>{ let s=localStorage.getItem('tdw_sort');
   if(s==='have'&&!localStorage.getItem('tdw_sort_mig')){ s='signal'; localStorage.setItem('tdw_sort','signal'); localStorage.setItem('tdw_sort_mig','1'); }
-  return s||'signal'; })();
+  // migration 2: real product images exist now — 'have' is tiered (real > our-lane > pending)
+  // and beats 'signal' as the default (signal interleaves placeholder tiles into the top fold).
+  if(s==='signal'&&!localStorage.getItem('tdw_sort_mig2')){ s='have'; localStorage.setItem('tdw_sort','have'); localStorage.setItem('tdw_sort_mig2','1'); }
+  return s||'have'; })();
 const state = {
   filters: store('tdw_filters2') || {},          // {dim: [values]}
   q:'', sort: savedSort, view: localStorage.getItem('tdw_view')||'grid',
diff --git a/server.js b/server.js
index e328fbb..0b84794 100644
--- a/server.js
+++ b/server.js
@@ -187,7 +187,7 @@ const server = http.createServer((req,res)=>{
     let items = applyFilters(loadItems(), u.searchParams);
     const sort = u.searchParams.get('sort') || 'signal';
     const cmp = {
-      have: (a,b)=> (((b.realImage||b.image)?1:0)-((a.realImage||a.image)?1:0)) || (b.signalRank||0)-(a.signalRank||0),
+      have: (a,b)=> ((b.realImage?2:(b.image?1:0))-(a.realImage?2:(a.image?1:0))) || (b.signalRank||0)-(a.signalRank||0),
       signal: (a,b)=> (b.signalRank||0)-(a.signalRank||0),
       gap: (a,b)=> (a.ourCoverage===b.ourCoverage?0:(a.ourCoverage==='gap'?-1:1)) || (b.signalRank||0)-(a.signalRank||0),
       titleAZ: (a,b)=> (a.title||'').localeCompare(b.title||''),

← 2374e12 UX: dedupe our-lane fallback heroes (full-bleed once per des  ·  back to Trending Dw  ·  chore: v0.3.0 (session close) — lint+refactor review clean, ae386f4 →