← back to Wallco Ai
prompt-vs-image: add Sort (newest/oldest/category/id↑↓) client-side over loaded set + persist; density already present [yolo tick5, local-only]
8bed130269c828bfde622687a3a5071afa1f72e6 · 2026-06-02 13:03:34 -0700 · Steve Abrams
Files touched
M public/admin/prompt-vs-image.html
Diff
commit 8bed130269c828bfde622687a3a5071afa1f72e6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 2 13:03:34 2026 -0700
prompt-vs-image: add Sort (newest/oldest/category/id↑↓) client-side over loaded set + persist; density already present [yolo tick5, local-only]
---
public/admin/prompt-vs-image.html | 41 ++++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/public/admin/prompt-vs-image.html b/public/admin/prompt-vs-image.html
index 92a7fdf..5776e07 100644
--- a/public/admin/prompt-vs-image.html
+++ b/public/admin/prompt-vs-image.html
@@ -82,6 +82,15 @@
<option value="all">All</option>
</select>
</label>
+ <label class="ctl">Sort
+ <select id="sort">
+ <option value="newest">Newest</option>
+ <option value="oldest">Oldest</option>
+ <option value="category">Category A→Z</option>
+ <option value="id">ID ↑</option>
+ <option value="id_desc">ID ↓</option>
+ </select>
+ </label>
<label class="ctl">Density
<input type="range" id="density" min="1" max="4" step="1" value="2"
aria-label="Pairs per row"><span id="density-val" class="pill"><b>2</b></span>
@@ -102,17 +111,20 @@
var emptyEl = document.getElementById('empty');
var catSel = document.getElementById('cat');
var filterSel = document.getElementById('filter');
+ var sortSel = document.getElementById('sort');
var density = document.getElementById('density');
+ var ITEMS = [];
var densityVal = document.getElementById('density-val');
var ratedCountEl = document.getElementById('rated-count');
var showCountEl = document.getElementById('show-count');
// ── Density + filter persistence (Steve standing rule: every grid persists
// its controls to localStorage).
- var DKEY='wallco.pvi.density', FKEY='wallco.pvi.filter', CKEY='wallco.pvi.cat';
+ var DKEY='wallco.pvi.density', FKEY='wallco.pvi.filter', CKEY='wallco.pvi.cat', SKEY='wallco.pvi.sort';
try {
var sd = localStorage.getItem(DKEY); if(sd){ density.value = sd; }
var sf = localStorage.getItem(FKEY); if(sf){ filterSel.value = sf; }
+ var ss = localStorage.getItem(SKEY); if(ss){ sortSel.value = ss; }
} catch(e){}
function applyDensity(){
var n = parseInt(density.value,10) || 2;
@@ -124,6 +136,25 @@
applyDensity();
filterSel.addEventListener('change', function(){ try{localStorage.setItem(FKEY,this.value);}catch(e){} load(); });
catSel.addEventListener('change', function(){ try{localStorage.setItem(CKEY,this.value);}catch(e){} load(); });
+ // Sort is client-side over the already-loaded set — no refetch needed.
+ sortSel.addEventListener('change', function(){ try{localStorage.setItem(SKEY,this.value);}catch(e){} render(); });
+
+ function sortItems(rows){
+ var r = rows.slice(), m = sortSel.value;
+ if(m==='newest') r.sort(function(a,b){ return String(b.created_at||'').localeCompare(String(a.created_at||'')); });
+ else if(m==='oldest') r.sort(function(a,b){ return String(a.created_at||'').localeCompare(String(b.created_at||'')); });
+ else if(m==='category') r.sort(function(a,b){ return String(a.category||'').localeCompare(String(b.category||'')) || (b.id-a.id); });
+ else if(m==='id') r.sort(function(a,b){ return a.id-b.id; });
+ else if(m==='id_desc') r.sort(function(a,b){ return b.id-a.id; });
+ return r;
+ }
+ function render(){
+ if(!ITEMS.length){ grid.innerHTML=''; emptyEl.style.display='block'; ratedCountEl.textContent='0'; showCountEl.textContent='0'; return; }
+ emptyEl.style.display='none';
+ showCountEl.textContent = ITEMS.length;
+ grid.innerHTML = sortItems(ITEMS).map(card).join('');
+ markRated();
+ }
function fmtDate(iso){
if(!iso) return '';
@@ -249,12 +280,8 @@
try {
var r = await fetch(q('/api/admin/prompt-rate/list?'+params.toString()));
var j = await r.json();
- var items = j.items || [];
- showCountEl.textContent = items.length;
- if(!items.length){ grid.innerHTML=''; emptyEl.style.display='block'; ratedCountEl.textContent='0'; return; }
- emptyEl.style.display='none';
- grid.innerHTML = items.map(card).join('');
- markRated();
+ ITEMS = j.items || [];
+ render();
} catch(e){
grid.innerHTML = '<div class="empty">Error: '+esc(e.message)+'</div>';
}
← 9f25013 yolo loop tick 5: customizer smoke test 33/34 pass ($0)
·
back to Wallco Ai
·
yolo-backlog: T5 — N5 theme-gallery skipped (theme switcher) f4956d3 →