[object Object]

← 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

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 →