[object Object]

← back to Commercialrealestate

feat(index): live facet counts (DTD verdict A, 2/3 Codex+Claude; Qwen dissent=saved-searches) — Asset-type/Firm/City chip counts update to reflect matches given the OTHER active filters (skip own dimension, Amazon-style narrowing); zero-match chips dimmed. Contrarian-gated, 0 errors.

b5a7c9fd46bb2332bcb54141055f9c17ad6537ed · 2026-07-02 11:52:16 -0700 · Steve Abrams

Officer: vp-engineering
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit b5a7c9fd46bb2332bcb54141055f9c17ad6537ed
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 2 11:52:16 2026 -0700

    feat(index): live facet counts (DTD verdict A, 2/3 Codex+Claude; Qwen dissent=saved-searches) — Asset-type/Firm/City chip counts update to reflect matches given the OTHER active filters (skip own dimension, Amazon-style narrowing); zero-match chips dimmed. Contrarian-gated, 0 errors.
    
    Officer: vp-engineering
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 public/index.html | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/public/index.html b/public/index.html
index 0ad8405..8afe5ef 100644
--- a/public/index.html
+++ b/public/index.html
@@ -38,6 +38,7 @@
   .chip:hover { color:var(--ink); }
   .chip.active { border-color:var(--blue); color:var(--blue); background:rgba(88,166,255,.08); }
   .chip .ct { color:var(--mut); font-size:10px; margin-left:4px; }
+  .chip.zero { opacity:.4; }
   .row2 { display:flex; gap:8px; }
   .fld { flex:1; }
   .fld label { display:block; font-size:10px; color:var(--mut); margin-bottom:3px; }
@@ -897,6 +898,33 @@ function applyFilters(list){
     return true;
   });
 }
+// Match everything EXCEPT one facet dimension — powers live facet counts (Amazon-style narrowing).
+function passExcept(p, skip){
+  if(skip!=='type' && F.types.size && !F.types.has(p.type)) return false;
+  if(skip!=='firm' && F.firms.size && !F.firms.has(firmLabel(p))) return false;
+  if(skip!=='city' && F.cityQuery){ const hay=((p.city||'')+' '+(p.address||'')).toLowerCase(); if(!hay.includes(F.cityQuery)) return false; }
+  if(F.priceMin!=null && p.price<F.priceMin) return false;
+  if(F.priceMax!=null && p.price>F.priceMax) return false;
+  if(F.capMin>0 && !(p.cap_rate!=null && p.cap_rate>=F.capMin)) return false;
+  if(F.unitsMin!=null && !(p.units>=F.unitsMin)) return false;
+  if(F.yearMin!=null && !(p.year_built && p.year_built>=F.yearMin)) return false;
+  if(F.status==='active' && /Under Contract|Pending|OUT OF BUDGET/i.test(p.status)) return false;
+  if(F.afford && !p.finance.affordable) return false;
+  if(F.unwarrantable && !(p.isCondo && p.warrantable_status && p.warrantable_status!=='fha_approved')) return false;
+  if(F.nonqm && !isNonQM(p)) return false;
+  if(F.shortlist && !SHORT.has(p.id)) return false;
+  return true;
+}
+function updateFacetCounts(){
+  const tc={}, fc={}, cc={};
+  DATA.ranked.forEach(p=>{
+    if(passExcept(p,'type')) tc[p.type]=(tc[p.type]||0)+1;
+    if(passExcept(p,'firm')){ const fl=firmLabel(p); fc[fl]=(fc[fl]||0)+1; }
+    if(p.city && passExcept(p,'city')) cc[p.city]=(cc[p.city]||0)+1;
+  });
+  const paint=(sel,attr,map)=>$$(sel).forEach(c=>{ const key=c.dataset[attr]; if(key==null) return; const ct=c.querySelector('.ct'); const n=map[key]||0; if(ct) ct.textContent=n; c.classList.toggle('zero', n===0 && !c.classList.contains('active')); });
+  paint('#fType .chip','t',tc); paint('#fFirm .chip','fm',fc); paint('#fCityChips .chip','cy',cc);
+}
 function activeFilterCount(){
   let n=0;
   if(F.types.size) n++; if(F.firms.size) n++; if(F.cityQuery) n++;
@@ -1056,7 +1084,7 @@ function render(){
   const g=$('#grid'); const fc=activeFilterCount();
   $('#fcount').textContent=fc; $('#fcount').classList.toggle('on',fc>0);
   { const sb=$('#shortbtn'); if(sb){ sb.textContent='⭐ Shortlist ('+SHORT.size+')'; sb.classList.toggle('shorton',F.shortlist); } }
-  renderActiveBar(); stateToURL();
+  renderActiveBar(); stateToURL(); updateFacetCounts();
   // Wait-for-selection: on a clean load (no filter chosen) don't dump 2,134 cards — prompt for a pick.
   if(fc===0 && !F.cityQuery){
     g.className='grid';

← 14963d5 feat(index): side-by-side Compare modal for shortlisted list  ·  back to Commercialrealestate  ·  feat(index): color-by-metric heat cues (DTD verdict D, 2/3 Q 681a9b8 →