[object Object]

← back to Rentv 2026

News map: collapse nav into a hamburger + log all articles in sitemap

5c689bb610221f5b283ac35d817122b542fb1fbb · 2026-08-06 09:51:25 -0700 · Steve Abrams

- Map chrome was eating 310px (393 on mobile) before the map. Hide the injected
  region/section tab strip and move ALL nav into a hamburger drawer (upper-right);
  collapse the filter controls to one compact scrollable row; hide util bar + legend
  on mobile. Map now starts at ~150px desktop / ~138px mobile.
- sitemap.xml: log EVERY RENTV article (full corpus, ~4,466) individually, not just
  the 30 recent — deduped corpus + live-feed.

TK-10284

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 5c689bb610221f5b283ac35d817122b542fb1fbb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 6 09:51:25 2026 -0700

    News map: collapse nav into a hamburger + log all articles in sitemap
    
    - Map chrome was eating 310px (393 on mobile) before the map. Hide the injected
      region/section tab strip and move ALL nav into a hamburger drawer (upper-right);
      collapse the filter controls to one compact scrollable row; hide util bar + legend
      on mobile. Map now starts at ~150px desktop / ~138px mobile.
    - sitemap.xml: log EVERY RENTV article (full corpus, ~4,466) individually, not just
      the 30 recent — deduped corpus + live-feed.
    
    TK-10284
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/map.html | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 server.js       |  8 ++++++--
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/public/map.html b/public/map.html
index 8f914e1b..b7761419 100644
--- a/public/map.html
+++ b/public/map.html
@@ -78,10 +78,52 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
 .cl.g{background:rgba(26,158,75,.9)}.cl.r{background:rgba(200,16,46,.88)}
 .me{background:#1467d6;border:3px solid #fff;border-radius:50%;width:18px;height:18px;box-shadow:0 0 0 4px rgba(20,103,214,.3)}
 @media(max-width:760px){aside{position:absolute;right:0;top:auto;bottom:0;height:44%;width:100%;flex-basis:auto;border-left:0;border-top:1px solid var(--line);z-index:1000}
-  .stage{position:relative}.bar h1{font-size:16px}}
+  .stage{position:relative}.bar h1{font-size:15px}}
+/* ── Hamburger + drawer: all the nav tabs collapse in here so the map gets the screen ── */
+.rentvtabs{display:none!important} /* injected region/section strip → moved into the drawer */
+.mast{position:relative;display:flex;align-items:center;justify-content:center;padding:10px 54px}
+.ham{position:absolute;right:14px;top:50%;transform:translateY(-50%);background:#fff;border:1.5px solid var(--line);border-radius:9px;font-size:17px;line-height:1;padding:8px 11px;cursor:pointer;color:var(--ink)}
+.ham:hover{border-color:var(--red);color:var(--red)}
+.drawer{position:fixed;inset:0;z-index:4000;display:none}
+.drawer.open{display:block}
+.drawer .bd{position:absolute;inset:0;background:rgba(0,0,0,.45)}
+.drawer .pl{position:absolute;top:0;right:0;width:min(88vw,320px);height:100%;background:#fff;overflow:auto;padding:18px 16px 44px;box-shadow:-10px 0 44px rgba(0,0,0,.32)}
+.drawer .pl h3{font-family:'Playfair Display',serif;font-size:19px;margin:0 0 2px}
+.drawer .x{position:absolute;top:12px;right:14px;font-size:24px;background:none;border:0;cursor:pointer;color:var(--sub);line-height:1}
+.drawer .gt{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--sub);margin:18px 0 5px}
+.drawer a{display:block;padding:9px 4px;border-bottom:1px solid var(--line);color:var(--ink);font-weight:600;font-size:14.5px;white-space:normal}
+.drawer a:hover{color:var(--red)}
+.drawer .clone{display:flex;flex-wrap:wrap;gap:2px 4px}
+.drawer .clone a{border:0;display:inline-block;padding:5px 8px;font-size:12.5px;background:var(--wash);border-radius:6px;font-weight:600}
+.drawer .clone .rt-k,.drawer .clone .rt-div{display:none}
+/* compact single-row filter bar (scrolls sideways instead of stacking) */
+.bar .wrap{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;gap:10px 14px}
+.bar .wrap::-webkit-scrollbar{display:none}
+.bar h1{flex:0 0 auto}
+@media(max-width:760px){.legend{display:none}.mast{padding:8px 50px}.mast .logo{font-size:24px}.util{display:none}}
 </style></head><body>
 <div class="util"><div class="wrap"><a href="/">RENTV.com · Commercial Real Estate News</a><a href="/">← Front page</a></div></div>
-<header class="mast"><a class="logo" href="/">REN<span>TV</span>.com<small>News Map</small></a></header>
+<header class="mast"><a class="logo" href="/">REN<span>TV</span>.com<small>News Map</small></a><button class="ham" id="ham" aria-label="Open menu" aria-expanded="false">☰</button></header>
+<div class="drawer" id="drawer" aria-hidden="true">
+  <div class="bd" id="drawerBd"></div>
+  <div class="pl">
+    <button class="x" id="drawerX" aria-label="Close menu">×</button>
+    <h3>REN<span style="color:var(--red)">TV</span>.com</h3>
+    <div class="gt">Explore</div>
+    <a href="/">Front page</a>
+    <a href="/map">🗺 News Map</a>
+    <a href="/markets">Markets</a>
+    <a href="/review">The REview</a>
+    <a href="/cre-talk">CRE Talk</a>
+    <a href="/conferences">Conferences</a>
+    <a href="/blog">Blog</a>
+    <a href="/about">About</a>
+    <a href="/advertise">Advertise</a>
+    <a href="/subscribe">Subscribe</a>
+    <div class="gt">Regions &amp; Sections</div>
+    <div id="drawerNav"></div>
+  </div>
+</div>
 <div class="bar"><div class="wrap">
   <h1>News Around You <span class="n" id="cnt"></span></h1>
   <span class="legend"><span><span class="dot g"></span>Last 3 months</span><span><span class="dot r"></span>Older</span></span>
@@ -118,6 +160,23 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
 var esc=function(s){return (s||'').replace(/[&<>"]/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];});};
 var $=function(id){return document.getElementById(id);};
 
+// Hamburger drawer — houses ALL nav tabs (the injected region/section strip is hidden and
+// cloned in here) so the map keeps the screen.
+function openDrawer(){
+  var host=$('drawerNav');
+  if(!host.getAttribute('data-filled')){
+    var t=document.querySelector('.rentvtabs');
+    host.innerHTML = t ? '<div class="clone">'+t.innerHTML+'</div>' : '<div style="color:var(--sub);font-size:13px">Loading…</div>';
+    if(t) host.setAttribute('data-filled','1'); // retry next open until the injected nav exists
+  }
+  var d=$('drawer'); d.classList.add('open'); d.setAttribute('aria-hidden','false'); $('ham').setAttribute('aria-expanded','true');
+}
+function closeDrawer(){ var d=$('drawer'); d.classList.remove('open'); d.setAttribute('aria-hidden','true'); $('ham').setAttribute('aria-expanded','false'); }
+$('ham').onclick=openDrawer; $('drawerX').onclick=closeDrawer; $('drawerBd').onclick=closeDrawer;
+document.addEventListener('keydown',function(e){if(e.key==='Escape')closeDrawer();});
+// close after tapping a link inside the drawer
+$('drawer').addEventListener('click',function(e){ if(e.target.closest('a')) closeDrawer(); });
+
 // "Last 3 months" is computed HERE, at load, so freshness is always relative to today.
 var CUTOFF=(function(){var d=new Date();d.setMonth(d.getMonth()-3);return d;})();
 function isFresh(a){ return a.date && new Date(a.date+'T00:00:00') >= CUTOFF; }
diff --git a/server.js b/server.js
index 5c9b49ca..dad4a748 100644
--- a/server.js
+++ b/server.js
@@ -1371,8 +1371,12 @@ app.get('/sitemap.xml', (req, r) => {
   const urls = ['/', '/map', '/markets', '/review', '/topics', '/blog'];
   (readHubs().hubs || []).forEach(h => { if (hubMatches(h, items).length > 0) urls.push('/topic/' + h.slug); });
   (readRegions().regions || []).forEach(reg => { if (regionMatches(reg, items).length > 0) urls.push('/region/' + reg.slug); });
-  // Article-level entries for the live news feed so stories are individually indexable.
-  (Array.isArray(items) ? items : []).forEach(it => { if (it && it.id) urls.push('/news/' + it.id); });
+  // Article-level entries for EVERY logged RENTV story — the full corpus plus any live-feed
+  // items not yet in it — so all articles by RENTV are individually indexable (deduped).
+  const seenIds = new Set();
+  const addArticle = (a) => { const id = a && a.id; if (id && !seenIds.has(id)) { seenIds.add(id); urls.push('/news/' + id); } };
+  try { corpus().forEach(addArticle); } catch {}
+  (Array.isArray(items) ? items : []).forEach(addArticle);
   const body = urls.map(u => `  <url><loc>${base}${u}</loc></url>`).join('\n');
   r.type('application/xml').send(`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${body}\n</urlset>\n`);
 });

← 89d927a8 chore: bump version to 0.21.1 (session close — cycles 16-40  ·  back to Rentv 2026  ·  auto-save: 2026-08-06T09:51:16 (8 files) — data/deals-regist cb99f313 →