← 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 →