[object Object]

← back to Ventura Corridor

feat(news): vertical filter dropdown on /news.html

8172d9365b6263f73b5aac5527992b9ffa337d87 · 2026-05-07 22:39:06 -0700 · SteveStudio2

Adds an "All categories" select next to the search and sort controls
on /news.html. Categories are populated from the rendered data so the
dropdown stays in sync with whatever the API returned (uses prefix
match so picking "amenity: restaurant" matches that exact subcategory,
"shop" matches every shop:* subcategory).

Pure client-side filter, no server change — /api/news/recent already
returns category per row.

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

Files touched

Diff

commit 8172d9365b6263f73b5aac5527992b9ffa337d87
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Thu May 7 22:39:06 2026 -0700

    feat(news): vertical filter dropdown on /news.html
    
    Adds an "All categories" select next to the search and sort controls
    on /news.html. Categories are populated from the rendered data so the
    dropdown stays in sync with whatever the API returned (uses prefix
    match so picking "amenity: restaurant" matches that exact subcategory,
    "shop" matches every shop:* subcategory).
    
    Pure client-side filter, no server change — /api/news/recent already
    returns category per row.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 public/news.html | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/public/news.html b/public/news.html
index e078bd6..4e07741 100644
--- a/public/news.html
+++ b/public/news.html
@@ -76,6 +76,9 @@ select{background:var(--noir-rise);color:var(--ink);border:1px solid var(--rule)
   <div class="controls">
     <div class="left">
       <input type="search" id="q" placeholder="Filter by business, title, or text…" autocomplete="off">
+      <select id="vertical">
+        <option value="">All categories</option>
+      </select>
       <select id="sort">
         <option value="recent">Most recent</option>
         <option value="biz">By business A→Z</option>
@@ -105,6 +108,7 @@ const truncate = (s, n) => {
 function render() {
   const q = (document.getElementById('q').value || '').toLowerCase().trim();
   const sort = document.getElementById('sort').value;
+  const vertical = document.getElementById('vertical').value || '';
   let rows = ROWS;
   if (q) {
     rows = rows.filter(r =>
@@ -113,6 +117,9 @@ function render() {
       (r.summary||r.excerpt||'').toLowerCase().includes(q)
     );
   }
+  if (vertical) {
+    rows = rows.filter(r => (r.category || '').toLowerCase().startsWith(vertical.toLowerCase()));
+  }
   rows = rows.slice();
   if (sort === 'biz') {
     rows.sort((a, b) => (a.business_name||'').localeCompare(b.business_name||''));
@@ -161,6 +168,16 @@ async function load() {
     const fresh = ROWS.filter(r => new Date(r.fetched_at).getTime() > week).length;
     document.getElementById('s-fresh').textContent = fresh;
     document.getElementById('status').textContent = ROWS.length + ' total';
+
+    // Populate vertical dropdown from data
+    const cats = [...new Set(ROWS.map(r => r.category).filter(Boolean))].sort();
+    const sel = document.getElementById('vertical');
+    cats.forEach(c => {
+      const opt = document.createElement('option');
+      opt.value = c; opt.textContent = c;
+      sel.appendChild(opt);
+    });
+
     render();
   } catch (e) {
     document.getElementById('status').textContent = 'load error';
@@ -170,6 +187,7 @@ async function load() {
 
 document.getElementById('q').addEventListener('input', () => render());
 document.getElementById('sort').addEventListener('change', () => render());
+document.getElementById('vertical').addEventListener('change', () => render());
 load();
 </script>
 </body>

← b8a21eb feat(news): news counts in homepage build-status strip  ·  back to Ventura Corridor  ·  feat(coverage): ideas_accepted count in homepage build-statu c9a00d6 →