[object Object]

← back to Wallco Ai

wallco.ai · sortDesigns — boost has-room designs to top of every sort

47d55d2a7fcbcb3ba8ce8a31323fbeb2d8f3b6bf · 2026-05-12 01:51:46 -0700 · SteveStudio2

Designs with a pre-generated room preview are the "in-context" winners — they
self-advertise the catalog's deepest UX (hover-preview + 3-pill toggle on
/design/:id). With 228 designs across 4 pages, the 5 has-room cards used to
scatter (e.g. on sort=title #144 was on page 3). Now they always lead page 1
within whatever sort is active; the user's chosen sort still applies as the
tie-breaker for everything else.

Pattern: tie(cmp) higher-orders the existing comparator. has-room tested
across 5 sorts — all 5 has-room IDs (14, 24, 29, 72, 144) lead page 1.
Reversible: 1 helper fn + 1 line per case.

Files touched

Diff

commit 47d55d2a7fcbcb3ba8ce8a31323fbeb2d8f3b6bf
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Tue May 12 01:51:46 2026 -0700

    wallco.ai · sortDesigns — boost has-room designs to top of every sort
    
    Designs with a pre-generated room preview are the "in-context" winners — they
    self-advertise the catalog's deepest UX (hover-preview + 3-pill toggle on
    /design/:id). With 228 designs across 4 pages, the 5 has-room cards used to
    scatter (e.g. on sort=title #144 was on page 3). Now they always lead page 1
    within whatever sort is active; the user's chosen sort still applies as the
    tie-breaker for everything else.
    
    Pattern: tie(cmp) higher-orders the existing comparator. has-room tested
    across 5 sorts — all 5 has-room IDs (14, 24, 29, 72, 144) lead page 1.
    Reversible: 1 helper fn + 1 line per case.
---
 server.js | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/server.js b/server.js
index da8e615..13fa4cf 100644
--- a/server.js
+++ b/server.js
@@ -178,18 +178,26 @@ function titleFor(cat, hex, id) {
 
 function sortDesigns(designs, sort) {
   const d = [...designs];
+  // Designs with a pre-generated room preview surface first within any sort —
+  // they're the "in-context" winners visitors should encounter first. Tie-break
+  // falls through to whatever sort the user picked.
+  const hasRoom = x => ((x.room_mockups || []).length > 0) ? 0 : 1;
+  const tie = (cmp) => (a,b) => {
+    const r = hasRoom(a) - hasRoom(b);
+    return r !== 0 ? r : cmp(a,b);
+  };
   switch (sort) {
-    case 'title':       return d.sort((a,b) => a.title.localeCompare(b.title));
-    case 'category':    return d.sort((a,b) => a.category.localeCompare(b.category));
-    case 'light-dark':  return d.sort((a,b) => hexToHSL(b.dominant_hex)[2] - hexToHSL(a.dominant_hex)[2]);
-    case 'dark-light':  return d.sort((a,b) => hexToHSL(a.dominant_hex)[2] - hexToHSL(b.dominant_hex)[2]);
-    case 'color-wheel': return d.sort((a,b) => {
+    case 'title':       return d.sort(tie((a,b) => a.title.localeCompare(b.title)));
+    case 'category':    return d.sort(tie((a,b) => a.category.localeCompare(b.category)));
+    case 'light-dark':  return d.sort(tie((a,b) => hexToHSL(b.dominant_hex)[2] - hexToHSL(a.dominant_hex)[2]));
+    case 'dark-light':  return d.sort(tie((a,b) => hexToHSL(a.dominant_hex)[2] - hexToHSL(b.dominant_hex)[2]));
+    case 'color-wheel': return d.sort(tie((a,b) => {
       const [ha,,la] = hexToHSL(a.dominant_hex);
       const [hb,,lb] = hexToHSL(b.dominant_hex);
       const bA = Math.floor(ha/30), bB = Math.floor(hb/30);
       return bA !== bB ? bA-bB : la-lb;
-    });
-    default: return d; // newest (DB insertion order)
+    }));
+    default: return d.sort(tie(() => 0)); // newest = has-room first then DB order
   }
 }
 

← ece9e37 wallco.ai · POST /api/room — mirror admin-generated rooms in  ·  back to Wallco Ai  ·  wallco.ai · card-room-badge — dynamic room count ("4 rooms") 05812f4 →