[object Object]

← back to Wallco Ai

me/saved: add sort dropdown (default Recently saved) + density slider per standing rule

d91974278b519bcbd167591f06106b6910227794 · 2026-06-01 17:17:50 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit d91974278b519bcbd167591f06106b6910227794
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 17:17:50 2026 -0700

    me/saved: add sort dropdown (default Recently saved) + density slider per standing rule
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 server.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 7f85409..51afac9 100644
--- a/server.js
+++ b/server.js
@@ -5475,7 +5475,12 @@ app.get('/me/saved', (req, res) => {
     console.error('[me/saved] query failed:', e.message);
   }
   const byId = new Map(DESIGNS.map(d => [d.id, d]));
-  const designs = savedIds.map(id => byId.get(id)).filter(Boolean);
+  let designs = savedIds.map(id => byId.get(id)).filter(Boolean);
+  // Sort — default keeps the saved_at DESC order ('saved'); any other key runs
+  // through the shared sortDesigns helper (Steve standing rule: every grid gets
+  // sort + density).
+  const sort = req.query.sort || 'saved';
+  if (sort !== 'saved') designs = sortDesigns(designs, sort);
   // Relative-time formatter (server-rendered so the badge ships in HTML — no JS
   // flash). Uses 'just now' under 60s, '12m', '4h', '3d', else date.
   const _meSavedRelTime = (iso) => {
@@ -5573,8 +5578,48 @@ ${htmlHeader('/me/saved')}
     })();
     </script>
   </div>
+  ${designs.length ? `<div class="catalog-toolbar" style="padding:0 0 14px">
+    <form method="get" action="/me/saved" class="filter-form">
+      <div class="toolbar-row" style="display:flex;gap:14px;flex-wrap:wrap;align-items:center">
+        <div style="display:flex;align-items:center;gap:6px">
+          <span style="font:11px var(--sans);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-faint)">Sort</span>
+          <select name="sort" aria-label="Sort saved designs" class="filter-select" onchange="this.form.submit()">
+            <option value="saved"       ${sort==='saved'?'selected':''}>Recently saved</option>
+            <option value="newest"      ${sort==='newest'?'selected':''}>Newest first</option>
+            <option value="oldest"      ${sort==='oldest'?'selected':''}>Oldest first</option>
+            <option value="title"       ${sort==='title'?'selected':''}>Title A → Z</option>
+            <option value="title-desc"  ${sort==='title-desc'?'selected':''}>Title Z → A</option>
+            <option value="color"       ${sort==='color'?'selected':''}>Color (group similar hues)</option>
+            <option value="light-dark"  ${sort==='light-dark'?'selected':''}>Light → Dark</option>
+            <option value="dark-light"  ${sort==='dark-light'?'selected':''}>Dark → Light</option>
+            <option value="color-wheel" ${sort==='color-wheel'?'selected':''}>Color Wheel (warm → cool)</option>
+            <option value="vivid"       ${sort==='vivid'?'selected':''}>Most Vivid</option>
+            <option value="muted"       ${sort==='muted'?'selected':''}>Most Muted</option>
+            <option value="style"       ${sort==='style'?'selected':''}>Style (grouped)</option>
+          </select>
+        </div>
+        <div class="density-wrap" style="display:flex;align-items:center;gap:7px">
+          <span style="font:11px var(--sans);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-faint)" title="Grid density">Density</span>
+          <input type="range" id="saved-density-slider" min="2" max="8" step="1" value="4"
+            aria-label="Grid density (columns)" aria-valuemin="2" aria-valuemax="8" aria-valuenow="4">
+          <span id="saved-density-value" style="font:11px var(--sans);color:var(--ink-faint);min-width:1ch">4</span>
+        </div>
+      </div>
+    </form>
+  </div>` : ''}
   ${designs.length
-    ? `<div class="design-grid catalog-grid" id="saved-grid">${cards}</div>`
+    ? `<div class="design-grid catalog-grid" id="saved-grid">${cards}</div>
+       <script>
+       (function(){
+         var slider=document.getElementById('saved-density-slider'),grid=document.getElementById('saved-grid'),label=document.getElementById('saved-density-value');
+         if(!slider||!grid)return;
+         var saved=localStorage.getItem('wallco-density'); if(saved)slider.value=saved;
+         function applyCols(v){var w=window.innerWidth,n=parseInt(v,10); if(w<=600)n=Math.min(n,2); else if(w<=900)n=Math.min(n,3); grid.style.setProperty('--cols',String(n)); if(label)label.textContent=String(n); slider.setAttribute('aria-valuenow',String(n));}
+         applyCols(slider.value);
+         slider.addEventListener('input',function(){applyCols(this.value);localStorage.setItem('wallco-density',this.value);});
+         window.addEventListener('resize',function(){applyCols(slider.value);});
+       })();
+       </script>`
     : `<div style="padding:56px 28px;text-align:center;color:var(--ink-soft,#555);font:14px/1.6 var(--sans);background:var(--card-bg,#faf8f3);border-radius:8px">
          <div style="font-size:42px;line-height:1;margin-bottom:14px;color:var(--gold,#c9a14b)">♡</div>
          <p style="margin:0 0 8px;font:300 22px/1.2 var(--serif,Georgia,serif);color:var(--ink,#111)">Nothing saved yet.</p>

← 031802d docs: convergence migration plan — make prod spoon_all_desig  ·  back to Wallco Ai  ·  designer-studio: add dead-thumbnail error-swap to its patter 8164572 →