← 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 →