[object Object]

← back to Commercialrealestate

perf(index): paginated DOM rendering (DTD verdict D, UNANIMOUS 3/3 Codex+Qwen+Claude) — grid renders 60 cards / list 200 rows per page with a 'Show N more' button; count + stats strip + facet counts still computed over the FULL filtered set (only the DOM is windowed). Cuts a 1823-card Non-QM render to 60. Contrarian-gated, 0 errors.

793d08ba119b5a583b1be874c4d11ee8db6795c9 · 2026-07-02 13:21:08 -0700 · Steve Abrams

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

Files touched

Diff

commit 793d08ba119b5a583b1be874c4d11ee8db6795c9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 2 13:21:08 2026 -0700

    perf(index): paginated DOM rendering (DTD verdict D, UNANIMOUS 3/3 Codex+Qwen+Claude) — grid renders 60 cards / list 200 rows per page with a 'Show N more' button; count + stats strip + facet counts still computed over the FULL filtered set (only the DOM is windowed). Cuts a 1823-card Non-QM render to 60. Contrarian-gated, 0 errors.
    
    Officer: vp-engineering
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 public/index.html | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/public/index.html b/public/index.html
index 98bfb11..a0c3726 100644
--- a/public/index.html
+++ b/public/index.html
@@ -195,6 +195,9 @@
   .heatlegend { display:none; align-items:center; gap:5px; font-size:11px; color:var(--mut); }
   .heatlegend.on { display:inline-flex; }
   .heatlegend .bar { width:56px; height:8px; border-radius:4px; background:linear-gradient(90deg,hsl(0,70%,45%),hsl(60,70%,45%),hsl(120,70%,45%)); }
+  .showmore-wrap { grid-column:1/-1; text-align:center; padding:20px 0 6px; }
+  .showmore { background:var(--card); border:1px solid var(--line); color:var(--blue); border-radius:10px; padding:9px 20px; font-size:13px; cursor:pointer; }
+  .showmore:hover { border-color:var(--blue); }
   /* compare overlay */
   #cmpov { display:none; position:fixed; inset:0; background:rgba(0,0,0,.6); z-index:60; align-items:flex-start; justify-content:center; padding:40px 14px; overflow:auto; }
   #cmpov.on { display:flex; }
@@ -1085,6 +1088,17 @@ function openCompare(){
   body.innerHTML=`<table class="cmptbl"><thead>${head}</thead><tbody>${rows}</tbody></table>`;
   ov.classList.add('on');
 }
+// ---- paginated DOM (perf): render in pages, "Show more" appends ----
+let _rows=[], _shown=0;
+const PAGE=()=> view==='list'?200:60;
+function moreBtn(){ return _shown<_rows.length ? `<div class="showmore-wrap"><button class="showmore" id="showmore">Show ${Math.min(PAGE(),_rows.length-_shown)} more · showing ${_shown} of ${_rows.length}</button></div>` : ''; }
+function paintPage(){
+  const g=$('#grid'); const r=_rows; const slice=r.slice(0,_shown);
+  if(!r.length){ g.className='grid'; g.innerHTML=`<div class="empty">No properties match these filters.<br><span class="small">Loosen a filter or hit “Reset all”.</span></div>`; return; }
+  if(view==='list'){ g.className='listhost'; g.innerHTML=renderList(slice)+moreBtn(); }
+  else { g.className='grid'; g.innerHTML=slice.map(card).join('')+moreBtn(); enrichAssessor(); }
+  applyHeat(slice);
+}
 function median(a){ if(!a.length) return null; const s=a.slice().sort((x,y)=>x-y); const m=Math.floor(s.length/2); return s.length%2?s[m]:(s[m-1]+s[m])/2; }
 function renderStats(r){
   const sb=$('#statsbar'); if(!sb) return;
@@ -1120,10 +1134,8 @@ function render(){
   let r = applyFilters(DATA.ranked.slice());
   sortRows(r);
   renderStats(r);
-  if(!r.length){ g.className='grid'; g.innerHTML=`<div class="empty">No properties match these filters.<br><span class="small">Loosen a filter or hit “Reset all”.</span></div>`; }
-  else if(view==='list'){ g.className='listhost'; g.innerHTML=renderList(r); }
-  else { g.className='grid'; g.innerHTML=r.map(card).join(''); enrichAssessor(); }
-  if(r.length) applyHeat(r);
+  _rows=r; _shown=Math.min(PAGE(), r.length);   // paginate the DOM; stats/count/facets still use the full set
+  paintPage();
   $('#count').innerHTML = `<b>${r.length}</b> of ${DATA.ranked.length} properties${fc?` · ${fc} filter${fc>1?'s':''} active`:''}`;
   $('#foot').textContent = `${scenario==='cash'?'all-cash':SCEN[scenario].downPct+'% down @ '+SCEN[scenario].ratePct+'%'} · * →X% = projected cap after value-add (not in-place). Cap rates broker-stated — verify NOI in DD.`;
   saveState();
@@ -1369,7 +1381,7 @@ fetch('data/ranked.json').then(r=>r.json()).then(async d=>{
   $('#examples').innerHTML = EX.map(x=>`<button class="ex">${x}</button>`).join('');
   $('#examples').onclick=e=>{ if(e.target.classList.contains('ex')){ $('#q').value=e.target.textContent; $('#q').focus(); } };
   $('#chatform').onsubmit=e=>{ e.preventDefault(); const t=$('#q').value.trim(); if(!t) return; $('#q').value=''; ask(t); };
-  $('#grid').onclick=e=>{ const st=e.target.closest('[data-star]'); if(st){ toggleStar(st.dataset.star); st.classList.toggle('on',SHORT.has(st.dataset.star)); const sb=$('#shortbtn'); if(sb) sb.textContent='⭐ Shortlist ('+SHORT.size+')'; if(F.shortlist) render(); return; } const th=e.target.closest('.listtbl th[data-sortk]'); if(th){ const k=th.dataset.sortk; if(colSort&&colSort.key===k) colSort.dir*=-1; else colSort={key:k,dir:['type','firm','warr','broker','status','zip','addr','rec'].includes(k)?1:-1}; render(); return; } const b=e.target.closest('.lcbtn'); if(b){ fetchLiveComps(b.dataset.id); return; } const h=e.target.closest('.histbtn'); if(h) fetchHistory(h); };
+  $('#grid').onclick=e=>{ const more=e.target.closest('#showmore'); if(more){ _shown=Math.min(_shown+PAGE(), _rows.length); paintPage(); return; } const st=e.target.closest('[data-star]'); if(st){ toggleStar(st.dataset.star); st.classList.toggle('on',SHORT.has(st.dataset.star)); const sb=$('#shortbtn'); if(sb) sb.textContent='⭐ Shortlist ('+SHORT.size+')'; if(F.shortlist) render(); return; } const th=e.target.closest('.listtbl th[data-sortk]'); if(th){ const k=th.dataset.sortk; if(colSort&&colSort.key===k) colSort.dir*=-1; else colSort={key:k,dir:['type','firm','warr','broker','status','zip','addr','rec'].includes(k)?1:-1}; render(); return; } const b=e.target.closest('.lcbtn'); if(b){ fetchLiveComps(b.dataset.id); return; } const h=e.target.closest('.histbtn'); if(h) fetchHistory(h); };
   $('#shortbtn').onclick=()=>{ F.shortlist=!F.shortlist; render(); };
   $('#cmpbtn').onclick=openCompare;
   $('#heat').value=heat; $('#heat').onchange=()=>{ heat=$('#heat').value; localStorage.setItem('cre_heat',heat); render(); };

← bf0b600 afternoon CRE update 2026-07-02  ·  back to Commercialrealestate  ·  feat(index): empty-state quick-start chips (DTD verdict D, 2 ac724c3 →