← back to Rentv 2026
auto-save: 2026-07-25T00:01:48 (4 files) — data/markets.json data/news.json data/ticker.json public/market-pulse.html
ce438f6416d510e90303da83fae62a9f1d08c1ca · 2026-07-25 00:01:54 -0700 · Steve Abrams
Files touched
M data/markets.jsonM data/news.jsonM data/ticker.jsonM public/market-pulse.html
Diff
commit ce438f6416d510e90303da83fae62a9f1d08c1ca
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 00:01:54 2026 -0700
auto-save: 2026-07-25T00:01:48 (4 files) — data/markets.json data/news.json data/ticker.json public/market-pulse.html
---
data/markets.json | 2 +-
data/news.json | 2 +-
data/ticker.json | 2 +-
public/market-pulse.html | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+), 3 deletions(-)
diff --git a/data/markets.json b/data/markets.json
index 1eccc30d..27426343 100644
--- a/data/markets.json
+++ b/data/markets.json
@@ -1,5 +1,5 @@
{
- "fetched_at": "2026-07-25T06:27:01.642Z",
+ "fetched_at": "2026-07-25T06:47:02.458Z",
"source": "Yahoo Finance — live (CBOE Treasury yields, Dow Jones/MSCI REIT indices)",
"curve": [
{
diff --git a/data/news.json b/data/news.json
index 3302c4e3..ed8f8be5 100644
--- a/data/news.json
+++ b/data/news.json
@@ -1,6 +1,6 @@
{
"source": "rentv.com — live",
- "fetched_at": "2026-07-25T06:27:01.447Z",
+ "fetched_at": "2026-07-25T06:47:02.252Z",
"count": 23,
"items": [
{
diff --git a/data/ticker.json b/data/ticker.json
index cccbbd02..2dc6a8fd 100644
--- a/data/ticker.json
+++ b/data/ticker.json
@@ -1,5 +1,5 @@
{
- "fetched_at": "2026-07-25T06:27:01.617Z",
+ "fetched_at": "2026-07-25T06:47:02.424Z",
"la_office_vac": {
"label": "LA OFFICE VAC",
"value": "23.1%",
diff --git a/public/market-pulse.html b/public/market-pulse.html
index 05ad55ba..380c31c1 100644
--- a/public/market-pulse.html
+++ b/public/market-pulse.html
@@ -196,6 +196,42 @@
.funds{grid-template-columns:1fr}
.wrap{padding:16px 14px 40px}
}
+
+ /* ---------- Persistent left rail (always populated, categories collapsed) ---------- */
+ .mp-layout{display:flex;align-items:flex-start;gap:0}
+ .mp-layout>.wrap{flex:1;min-width:0;max-width:1200px;margin:0}
+ .mp-rail{
+ position:sticky;top:54px;align-self:flex-start;flex:none;width:288px;
+ height:calc(100vh - 54px);overflow-y:auto;
+ background:linear-gradient(180deg,#0b0f16,#080b11);
+ border-right:1px solid var(--line);padding:16px 12px 30px;
+ }
+ .mp-rail .rail-h{display:flex;align-items:center;gap:8px;padding:4px 8px 12px;
+ font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--ink-dim)}
+ .mp-rail .rail-h::before{content:"";width:3px;height:13px;background:var(--accent);border-radius:2px}
+ .mp-cat{border:1px solid var(--line);border-radius:10px;margin-bottom:8px;background:var(--panel);overflow:hidden}
+ .mp-cat>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:8px;
+ padding:11px 12px;font-size:12px;font-weight:600;letter-spacing:.4px;color:var(--ink);user-select:none}
+ .mp-cat>summary::-webkit-details-marker{display:none}
+ .mp-cat>summary:hover{background:var(--panel-2)}
+ .mp-cat>summary .badge{font-family:var(--mono);font-size:10.5px;font-weight:700;color:#04120f;
+ background:#2dd4bf;border-radius:20px;padding:1px 7px;min-width:20px;text-align:center}
+ .mp-cat>summary .chev{margin-left:auto;color:var(--ink-faint);font-size:10px;transition:transform .2s}
+ .mp-cat[open]>summary .chev{transform:rotate(90deg)}
+ .mp-cat[open]>summary{border-bottom:1px solid var(--line-soft)}
+ .mp-rows{padding:2px 6px 8px}
+ .mp-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
+ padding:6px;border-top:1px solid var(--line-soft);font-size:12px}
+ .mp-row:first-child{border-top:0}
+ .mp-row .rl{color:var(--ink-dim)}
+ .mp-row .rv{font-family:var(--mono);font-weight:600;font-variant-numeric:tabular-nums}
+ .mp-row .rv.up{color:var(--up)}.mp-row .rv.down{color:var(--down)}.mp-row .rv.flat{color:var(--ink)}
+ .mp-rail .rail-foot{padding:12px 8px 0;font-size:10px;letter-spacing:.3px;color:var(--ink-faint)}
+ @media (max-width:900px){
+ .mp-layout{flex-direction:column}
+ .mp-rail{position:static;width:auto;height:auto;border-right:0;border-bottom:1px solid var(--line)}
+ .mp-layout>.wrap{max-width:none}
+ }
</style>
</head>
<body>
@@ -226,6 +262,8 @@
<div class="df">RENTV.com — Commercial real estate news, Western U.S.</div>
</aside>
+<div class="mp-layout">
+<aside class="mp-rail" id="mpRail"></aside>
<div class="wrap">
<div class="pulse-band">
@@ -282,6 +320,7 @@
</footer>
</div>
+</div>
<script>
/* ============================================================
@@ -510,8 +549,32 @@ function tick(){
' ' + (Intl.DateTimeFormat().resolvedOptions().timeZone || '');
}
+/* ---------- persistent left rail: ALWAYS lists every field, categories
+ collapsed by default. Rebuilt on each refresh but open state is preserved
+ so a live update never blanks the panel or re-collapses what you opened. ---------- */
+const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'}[c]));
+function renderRail(){
+ const rail = $('#mpRail');
+ if(!rail) return;
+ const openSet = new Set([...rail.querySelectorAll('.mp-cat[open]')].map(d => d.dataset.cat));
+ const cats = [
+ {key:'curve', name:'Yield Curve', rows: marketData.curve.map(c => ({l:c.label + ' UST', v:c.value, d:c.dir}))},
+ {key:'spreads', name:'Curve Spreads', rows: marketData.spreads.map(s => ({l:s.label, v:s.value, d:s.dir}))},
+ {key:'reits', name:'REIT Performance', rows: marketData.reits.map(r => ({l:r.label, v:r.value, d:r.dir}))},
+ {key:'funds', name:'Market Fundamentals', rows: marketData.fundamentals.map(f => ({l:f.label, v:f.value, d:'flat'}))}
+ ];
+ rail.innerHTML = '<div class="rail-h">Market Data</div>' + cats.map(c => `
+ <details class="mp-cat" data-cat="${c.key}"${openSet.has(c.key) ? ' open' : ''}>
+ <summary>${esc(c.name)}<span class="badge">${c.rows.length}</span><span class="chev">▶</span></summary>
+ <div class="mp-rows">${c.rows.map(r =>
+ `<div class="mp-row"><span class="rl">${esc(r.l)}</span><span class="rv ${r.d}">${esc(r.v)}</span></div>`
+ ).join('')}</div>
+ </details>`).join('') + '<div class="rail-foot">All fields shown · click a category to expand</div>';
+}
+
/* ---------- render everything from the current marketData ---------- */
function renderAll(){
+ renderRail();
renderKPIs();
renderSpreads();
renderReits();
← 78d7b01d Add CRE Market Pulse (rates terminal) page + front-page tick
·
back to Rentv 2026
·
market-pulse: pin full site nav into the persistent left rai 83c2c24c →