[object Object]

โ† back to Ventura Corridor

iter 76: category filter chips on /magazine.html โ€” /api/magazine accepts cat= query param to filter by category_tag; viewer adds 11-chip vertical-filter rail under the status chips (All / ๐Ÿด Restaurants / โš–๏ธ Professional / โœจ Beauty / ๐Ÿ’‡ Salon / ๐Ÿฉบ Medical / ๐Ÿ’ช Fitness / ๐Ÿ› Shops / ๐Ÿ  Real estate / ๐Ÿจ Hospitality / ๐Ÿš— Automotive); current 37 features distribute as 17 professional / 4 medical / 4 real-estate / 4 restaurant / 3 salon / 3 shop / 1 fitness / 1 beauty; click any chip filters the issue instantly

c229baf2c6c633b8d125cc8b7f4a68fdf9550c2b ยท 2026-05-06 16:25:17 -0700 ยท SteveStudio2

Files touched

Diff

commit c229baf2c6c633b8d125cc8b7f4a68fdf9550c2b
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Wed May 6 16:25:17 2026 -0700

    iter 76: category filter chips on /magazine.html โ€” /api/magazine accepts cat= query param to filter by category_tag; viewer adds 11-chip vertical-filter rail under the status chips (All / ๐Ÿด Restaurants / โš–๏ธ Professional / โœจ Beauty / ๐Ÿ’‡ Salon / ๐Ÿฉบ Medical / ๐Ÿ’ช Fitness / ๐Ÿ› Shops / ๐Ÿ  Real estate / ๐Ÿจ Hospitality / ๐Ÿš— Automotive); current 37 features distribute as 17 professional / 4 medical / 4 real-estate / 4 restaurant / 3 salon / 3 shop / 1 fitness / 1 beauty; click any chip filters the issue instantly
---
 public/magazine.html | 39 ++++++++++++++++++++++++++++++++++++---
 src/server/index.ts  |  2 ++
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/public/magazine.html b/public/magazine.html
index 8a8aa03..de28927 100644
--- a/public/magazine.html
+++ b/public/magazine.html
@@ -211,10 +211,13 @@
 
 <div class="chips">
   <button data-status="all" class="active">All features</button>
-  <button data-status="draft">โš™ Drafts (need review)</button>
+  <button data-status="draft">โš™ Drafts</button>
   <button data-status="reviewed">โœ“ Reviewed</button>
   <button data-status="published">โ˜… Published</button>
-  <button onclick="generateMore()">+ Generate 5 more (Mac1 Ollama)</button>
+</div>
+<div class="chips" id="cat-chips" style="border-bottom:1px solid var(--rule);padding-top:0">
+  <span style="color:var(--ink-mute);font-size:9px;letter-spacing:.22em;text-transform:uppercase;align-self:center;margin-right:8px">vertical โ†’</span>
+  <!-- chips injected by JS -->
 </div>
 
 <main class="spread" id="spread">
@@ -224,10 +227,40 @@
 <script>
 function escHtml(s) { return String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])); }
 let currentStatus = 'all';
+let currentCat    = 'all';
+
+const CATS = [
+  { id: 'all',          label: 'All' },
+  { id: 'restaurant',   label: '๐Ÿด Restaurants' },
+  { id: 'professional', label: 'โš–๏ธ Professional' },
+  { id: 'beauty',       label: 'โœจ Beauty' },
+  { id: 'salon',        label: '๐Ÿ’‡ Salon' },
+  { id: 'medical',      label: '๐Ÿฉบ Medical' },
+  { id: 'fitness',      label: '๐Ÿ’ช Fitness' },
+  { id: 'shop',         label: '๐Ÿ› Shops' },
+  { id: 'real-estate',  label: '๐Ÿ  Real estate' },
+  { id: 'hospitality',  label: '๐Ÿจ Hospitality' },
+  { id: 'automotive',   label: '๐Ÿš— Automotive' },
+];
+function renderCatChips() {
+  const root = document.getElementById('cat-chips');
+  // keep the leading label span if it's already there
+  const lead = root.querySelector('span') ? root.querySelector('span').outerHTML : '';
+  root.innerHTML = lead + CATS.map(c =>
+    `<button data-cat="${c.id}" class="${currentCat === c.id ? 'active' : ''}">${c.label}</button>`
+  ).join('');
+  root.querySelectorAll('button').forEach(b => {
+    b.addEventListener('click', () => { currentCat = b.dataset.cat; renderCatChips(); load(); });
+  });
+}
+renderCatChips();
 
 async function load() {
   try {
-    const url = currentStatus === 'all' ? '/api/magazine' : '/api/magazine?status=' + currentStatus;
+    const params = new URLSearchParams();
+    if (currentStatus !== 'all') params.set('status', currentStatus);
+    if (currentCat !== 'all')    params.set('cat',    currentCat);
+    const url = params.toString() ? '/api/magazine?' + params : '/api/magazine';
     const data = await fetch(url).then(r => r.json());
     const rows = data.rows || [];
     const counts = data.by_status || [];
diff --git a/src/server/index.ts b/src/server/index.ts
index df110f8..6cae9bc 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1766,9 +1766,11 @@ app.get('/api/magazine/stats', async (_req, res) => {
 app.get('/api/magazine', async (req, res) => {
   try {
     const status = String(req.query.status || 'all'); // all | draft | reviewed | published
+    const cat    = String(req.query.cat || 'all');
     const where: string[] = [];
     const params: any[] = [];
     if (status !== 'all') { params.push(status); where.push(`mf.status = $${params.length}`); }
+    if (cat !== 'all')    { params.push(cat);    where.push(`mf.category_tag = $${params.length}`); }
     const limit = Math.min(parseInt(String(req.query.limit ?? '50'), 10) || 50, 200);
     params.push(limit);
     const r = await query(

โ† e31d8bb iter 75: feature regen-via-API endpoint โ€” POST /api/magazine  ยท  back to Ventura Corridor  ยท  iter 77+78: dual-model alternating generation + /magazine/:i 34f78f5 โ†’