[object Object]

← back to Commercialrealestate

nav-agent: v1.1 merge-mode asset refresh

242d569cf41bcd71aad0d864944203f969dd20b4 · 2026-08-13 08:18:48 -0700 · Steve Abrams

Files touched

Diff

commit 242d569cf41bcd71aad0d864944203f969dd20b4
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 13 08:18:48 2026 -0700

    nav-agent: v1.1 merge-mode asset refresh
---
 public/fha-loans.html | 50 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 10 deletions(-)

diff --git a/public/fha-loans.html b/public/fha-loans.html
index 024e114..834505d 100644
--- a/public/fha-loans.html
+++ b/public/fha-loans.html
@@ -7,6 +7,7 @@
 <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='3' fill='%230a0d13'/%3E%3Ctext x='8' y='12' font-size='11' text-anchor='middle' fill='%23c8a24b'%3E%24%3C/text%3E%3C/svg%3E">
 <title>FHA / Low-Rate Loans — LA County CRE</title>
 <link rel="stylesheet" href="/crcp-grid.css">
+<link rel="stylesheet" href="/three-view.css">
 <script src="/crcp-grid.js"></script>
 <style>
   :root{
@@ -186,6 +187,8 @@
 
   <div class="glass controls" style="animation-delay:.08s">
     <input type="text" id="q" placeholder="search all fields — property, city, lender, rate, ZIP… (space = AND)">
+    <span class="tv-seg" id="fviewseg"></span>
+    <select id="fsort" title="Sort loans"></select>
     <label>density <input type="range" id="density" min="4" max="24" step="1"></label>
     <span class="count" id="count">…</span>
   </div>
@@ -194,9 +197,11 @@
     <div class="fha-shell">
       <aside class="fha-rail" id="fRail"></aside>
       <div class="fha-main">
-        <div class="tablewrap">
+        <div class="tablewrap" id="ftableView">
           <table id="ftable" data-no-sort><thead id="fthead"></thead><tbody id="ftbody"></tbody></table>
         </div>
+        <div id="fgridView" class="hide" style="padding:16px;display:grid;gap:16px;grid-template-columns:repeat(var(--fcols,3),minmax(0,1fr))"></div>
+        <div id="flistView" class="hide"></div>
         <div class="empty" id="femptymsg" style="display:none">loading real HUD data…</div>
       </div>
     </div>
@@ -302,6 +307,8 @@ function reinitResize(){
 
 // ── search + sort state ───────────────────────────────────────────────────────
 let q='', sortKey='rate', sortDir=1;
+// 3-view state (grid cards / compact list / dense table). Persisted. TK-10526.
+let VIEW=(function(){ let v=null; try{v=localStorage.getItem('fhaView');}catch(e){} return ['grid','list','table'].includes(v)?v:'table'; })();
 const FF={ chips:{}, ranges:{} };
 const gv=(r,fc)=>fc.calc?fc.calc(r):r[fc.k];
 FACETS.forEach(fc=>{ if(fc.type==='chip') FF.chips[fc.k]=new Set(); else FF.ranges[fc.k]={min:null,max:null}; });
@@ -334,20 +341,43 @@ function filtered(){
   return rows;
 }
 
-// ── render table ──────────────────────────────────────────────────────────────
+// ── render: grid (cards) / list (compact) / table (dense) ─────────────────────
 function render(){
   const rows=filtered(), cols=visCols();
   $('#count').innerHTML=`<b>${rows.length.toLocaleString()}</b> of ${ROWS.length.toLocaleString()} loans`;
-  $('#fthead').innerHTML='<tr>'+cols.map(c=>`<th data-k="${c.k}" draggable="true" title="Drag to reorder · click to sort" class="dragcol${sortKey===c.k?(sortDir>0?' asc sorted':' desc sorted'):''}">${esc(c.l)}<span class="ar"></span></th>`).join('')+'</tr>';
-  $('#ftbody').innerHTML=rows.map(r=>`<tr class="frow${r.red?' red':''}" data-id="${esc(r.__i)}">`
-    +cols.map(c=>{const numT=(c.t==='pct'||c.t==='money'||c.t==='num');return `<td class="${c.k==='property'?'prop':''}${numT?' num':''}">`
-      +(c.k==='property'?(esc(r.property||'(name n/a)')+(r.city||r.state?`<span class="loc">${esc([r.city,r.state].filter(Boolean).join(', ')+' '+(r.zip||''))}${r.holder?' · '+esc(r.holder):''}</span>`:'')):cell(r,c))
-      +'</td>';}).join('')+'</tr>').join('');
+  const show=id=>['#ftableView','#fgridView','#flistView'].forEach(s=>$(s).classList.toggle('hide',s!==id));
   if(!rows.length){ $('#femptymsg').style.display='block'; $('#femptymsg').textContent='no matches for these filters.'; }
   else $('#femptymsg').style.display='none';
-  const csig=cols.map(c=>c.k).join(',');
-  if(csig!==lastColSig){ lastColSig=csig; reinitResize(); }
-  else if(window.ColResize && window.ColResize.reattach){ window.ColResize.reattach(document.querySelector('#ftable')); } // resize handles survive sort/search re-render (TK-10089)
+  const propCell=r=>esc(r.property||'(name n/a)')+(r.city||r.state?`<span class="loc">${esc([r.city,r.state].filter(Boolean).join(', ')+' '+(r.zip||''))}${r.holder?' · '+esc(r.holder):''}</span>`:'');
+  if(VIEW==='table'){
+    show('#ftableView');
+    $('#fthead').innerHTML='<tr>'+cols.map(c=>`<th data-k="${c.k}" draggable="true" title="Drag to reorder · click to sort" class="dragcol${sortKey===c.k?(sortDir>0?' asc sorted':' desc sorted'):''}">${esc(c.l)}<span class="ar"></span></th>`).join('')+'</tr>';
+    $('#ftbody').innerHTML=rows.map(r=>`<tr class="frow${r.red?' red':''}" data-id="${esc(r.__i)}">`
+      +cols.map(c=>{const numT=(c.t==='pct'||c.t==='money'||c.t==='num');return `<td class="${c.k==='property'?'prop':''}${numT?' num':''}">`
+        +(c.k==='property'?propCell(r):cell(r,c))
+        +'</td>';}).join('')+'</tr>').join('');
+    const csig=cols.map(c=>c.k).join(',');
+    if(csig!==lastColSig){ lastColSig=csig; reinitResize(); }
+    else if(window.ColResize && window.ColResize.reattach){ window.ColResize.reattach(document.querySelector('#ftable')); } // resize handles survive sort/search re-render (TK-10089)
+  } else if(VIEW==='list'){
+    // COMPACT LIST — one scannable row per loan; every visible non-property column
+    // as inline key/value pairs (reuses cell() so red-flag badges etc. match).
+    show('#flistView');
+    const metaCols=cols.filter(c=>c.k!=='property');
+    $('#flistView').innerHTML='<div class="tv-rows">'+rows.map(r=>`<div class="tv-lrow frow${r.red?' red':''}" data-id="${esc(r.__i)}">`
+      +`<div class="tv-lmain"><span class="tv-la">${esc(r.property||'(name n/a)')}</span><span class="tv-lsub">${esc([r.city,r.state].filter(Boolean).join(', ')+' '+(r.zip||''))}${r.holder?' · '+esc(r.holder):''}</span>${r.red?badge(r):''}</div>`
+      +`<div class="tv-lmeta">`+metaCols.map(c=>`<span class="tv-lm"><span class="tv-lmk">${esc(c.l)}</span>${cell(r,c)}</span>`).join('')+`</div></div>`).join('')+'</div>';
+  } else {
+    // GRID — data cards, property title + visible fields as rows.
+    show('#fgridView');
+    const bodyCols=cols.filter(c=>c.k!=='property');
+    $('#fgridView').innerHTML=rows.map(r=>`<div class="glass tile frow${r.red?' red':''}" data-id="${esc(r.__i)}" style="padding:16px 18px;cursor:pointer;border:1px solid var(--glassb)">`
+      +`<div style="font-weight:700;color:#fff;margin-bottom:2px">${esc(r.property||'(name n/a)')}</div>`
+      +`<div style="font-size:11.5px;color:var(--muted);margin-bottom:8px">${esc([r.city,r.state].filter(Boolean).join(', ')+' '+(r.zip||''))}${r.holder?' · '+esc(r.holder):''}</div>`
+      +(r.red?`<div style="margin-bottom:8px">${badge(r)}</div>`:'')
+      +bodyCols.map(c=>`<div style="display:flex;justify-content:space-between;gap:10px;font-size:12.5px;padding:2px 0"><span style="color:var(--muted)">${esc(c.l)}</span><span>${cell(r,c)}</span></div>`).join('')
+      +`</div>`).join('');
+  }
 }
 
 // ── expandable row → detail modal (all fields) ───────────────────────────────

← b36efec mls.html: add compact-list view (3rd mode) — grid/list/table  ·  back to Commercialrealestate  ·  fha-loans.html: add grid(cards)+compact-list views + view to ff880e5 →