[object Object]

← back to Rentv 2026

Split nav into TWO hamburgers: upper-left (Explore+Regions) + upper-right (Sections+Tools)

2837beede329f6f37b2d5302f497c6336f3a8b97 · 2026-08-06 10:22:18 -0700 · Steve Abrams

Steve: 'Split hamburger between upper right and left.' Both the map's own build AND the
sitewide masthead build now render two hamburgers flanking a centered logo:
 • LEFT drawer (slides from left): Explore pages + Regions
 • RIGHT drawer (slides from right): Sections (+ the map's filters/legend/Near me/Reset on /map)
Region/Section links split from the hidden strip (.rt-geo → left, .rt-cat → right).
Verified markets/blog/map: 2 hamburgers, logo centered, correct split, 0 errors.

TK-10284

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

Files touched

Diff

commit 2837beede329f6f37b2d5302f497c6336f3a8b97
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 6 10:22:18 2026 -0700

    Split nav into TWO hamburgers: upper-left (Explore+Regions) + upper-right (Sections+Tools)
    
    Steve: 'Split hamburger between upper right and left.' Both the map's own build AND the
    sitewide masthead build now render two hamburgers flanking a centered logo:
     • LEFT drawer (slides from left): Explore pages + Regions
     • RIGHT drawer (slides from right): Sections (+ the map's filters/legend/Near me/Reset on /map)
    Region/Section links split from the hidden strip (.rt-geo → left, .rt-cat → right).
    Verified markets/blog/map: 2 hamburgers, logo centered, correct split, 0 errors.
    
    TK-10284
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/map.html     | 103 ++++++++++++++++++++++++++++++----------------------
 public/rentv-nav.js |  59 +++++++++++++++++++-----------
 2 files changed, 97 insertions(+), 65 deletions(-)

diff --git a/public/map.html b/public/map.html
index 061d81f1..8197a5c9 100644
--- a/public/map.html
+++ b/public/map.html
@@ -81,17 +81,20 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
   .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 */
-/* Minimal top bar: hamburger LEFT, wordmark, story count. Everything else lives in the drawer. */
-.mast{position:relative;display:flex;align-items:center;padding:12px 16px;min-height:52px}
+/* Minimal top bar: hamburger UPPER-LEFT + UPPER-RIGHT, wordmark centered. All nav/tools live
+   in the two drawers (left = Explore+Regions, right = Sections+Filters). */
+.mast{position:relative;display:flex;align-items:center;justify-content:center;padding:12px 56px;min-height:52px}
 .mast .logo{position:absolute;left:50%;transform:translateX(-50%);font-size:26px;white-space:nowrap}
-.cntpill{margin-left:auto;font-size:12px;font-weight:700;color:var(--sub);white-space:nowrap}
-@media(max-width:520px){.cntpill{display:none}}
-.ham{position:absolute;left: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);z-index:5}
+.cntpill{font-size:12px;font-weight:700;color:var(--sub);white-space:nowrap}
+.ham{position:absolute;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);z-index:5}
+.ham.hamL{left:14px}.ham.hamR{right:14px}
 .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;left:0;width:min(86vw,300px);height:100%;background:#fff;overflow:auto;padding:18px 16px 44px;box-shadow:10px 0 44px rgba(0,0,0,.32)}
+.drawer .pl{position:absolute;top:0;width:min(86vw,300px);height:100%;background:#fff;overflow:auto;padding:18px 16px 44px}
+.drawer.left .pl{left:0;box-shadow:10px 0 44px rgba(0,0,0,.32)}
+.drawer.right .pl{right:0;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:16px 0 6px}
@@ -110,17 +113,37 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
 @media(max-width:760px){.mast{padding:8px 12px 8px 54px}.mast .logo{font-size:22px}.util{display:none}}
 </style></head><body>
 <header class="mast">
-  <button class="ham" id="ham" aria-label="Open menu" aria-expanded="false">☰</button>
+  <button class="ham hamL" id="hamL" aria-label="Explore &amp; regions menu" aria-expanded="false">☰</button>
   <a class="logo" href="/">REN<span>TV</span>.com<small>News Map</small></a>
-  <span class="cntpill" id="cnt"></span>
+  <button class="ham hamR" id="hamR" aria-label="Sections &amp; filters menu" aria-expanded="false">☰</button>
 </header>
-<div class="drawer" id="drawer" data-own-nav aria-hidden="true">
-  <div class="bd" id="drawerBd"></div>
+<!-- LEFT drawer: Explore + Regions -->
+<div class="drawer left" id="drawerL" data-own-nav aria-hidden="true">
+  <div class="bd" data-close="L"></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>
+    <button class="x" data-close="L" aria-label="Close menu">×</button>
+    <h3>Explore</h3>
+    <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</div>
+    <div id="drawerRegions"></div>
+  </div>
+</div>
+<!-- RIGHT drawer: Sections + map tools/filters -->
+<div class="drawer right" id="drawerR" data-own-nav aria-hidden="true">
+  <div class="bd" data-close="R"></div>
+  <div class="pl">
+    <button class="x" data-close="R" aria-label="Close menu">×</button>
+    <h3>Filter the map <span class="cntpill" id="cnt"></span></h3>
     <span class="legend"><span><span class="dot g"></span>Last 3 months</span><span><span class="dot r"></span>Older</span></span>
-    <div class="gt">Map filters</div>
     <label class="fl">Show
       <select id="fresh">
         <option value="all">All stories</option>
@@ -135,19 +158,8 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
     <div class="yrs"><label class="fl" style="margin:0">From<select id="yfrom" title="From year"></select></label><label class="fl" style="margin:0">To<select id="yto" title="To year"></select></label></div>
     <button class="btn" id="near">📍 Near me</button>
     <button class="btn ghost" id="reset">Reset view</button>
-    <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 class="gt">Sections</div>
+    <div id="drawerSections"></div>
   </div>
 </div>
 <div class="stage">
@@ -164,22 +176,27 @@ 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');
+// Two drawers: LEFT (Explore + Regions), RIGHT (Sections + map filters). The region/section
+// links come from the hidden injected .rentvtabs strip — .rt-geo → Regions, .rt-cat → Sections.
+function cloneRows(hostId, rowSel){
+  var host=$(hostId); if(!host || host.getAttribute('data-filled')) return;
+  var row=document.querySelector('.rentvtabs '+rowSel);
+  if(row){ host.innerHTML='<div class="clone">'+row.innerHTML+'</div>'; host.setAttribute('data-filled','1'); }
+}
+function openL(){ cloneRows('drawerRegions','.rt-geo'); var d=$('drawerL'); d.classList.add('open'); d.setAttribute('aria-hidden','false'); $('hamL').setAttribute('aria-expanded','true'); }
+function openR(){ cloneRows('drawerSections','.rt-cat'); var d=$('drawerR'); d.classList.add('open'); d.setAttribute('aria-hidden','false'); $('hamR').setAttribute('aria-expanded','true'); }
+function closeDrawer(which){
+  var d=$('drawer'+which); if(!d) return; d.classList.remove('open'); d.setAttribute('aria-hidden','true');
+  $('ham'+which).setAttribute('aria-expanded','false');
 }
-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(); });
+function closeAll(){ closeDrawer('L'); closeDrawer('R'); }
+$('hamL').onclick=openL; $('hamR').onclick=openR;
+document.addEventListener('click',function(e){
+  var c=e.target.closest('[data-close]'); if(c){ closeDrawer(c.getAttribute('data-close')); return; }
+  // tap a link inside either drawer → close both
+  if(e.target.closest('.drawer a')) closeAll();
+});
+document.addEventListener('keydown',function(e){if(e.key==='Escape')closeAll();});
 
 // "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;})();
@@ -323,14 +340,14 @@ map.on('moveend',function(){ if(!meLatLng) refreshList(); });
 // controls
 $('fresh').onchange=function(e){fFresh=e.target.value;buildMarkers();};
 $('txn').onchange=function(e){fTxn=e.target.value;buildMarkers();};
-$('reset').onclick=function(){ closeDrawer(); meLatLng=null; if(meMarker){map.removeLayer(meMarker);meMarker=null;}
+$('reset').onclick=function(){ closeDrawer('R'); meLatLng=null; if(meMarker){map.removeLayer(meMarker);meMarker=null;}
   fFresh='all';$('fresh').value='all'; fTxn='';$('txn').value='';
   if($('yfrom').options.length){fYFrom=parseInt($('yfrom').options[$('yfrom').options.length-1].value,10);$('yfrom').value=fYFrom;
     fYTo=parseInt($('yto').options[0].value,10);$('yto').value=fYTo;}
   map.setView([37.5,-119],5); buildMarkers(); };
 $('near').onclick=function(){
   if(!navigator.geolocation){alert('Location isn’t available in this browser.');return;}
-  closeDrawer();
+  closeDrawer('R');
   $('near').textContent='📍 Locating…';
   navigator.geolocation.getCurrentPosition(function(pos){
     meLatLng=[pos.coords.latitude,pos.coords.longitude];
diff --git a/public/rentv-nav.js b/public/rentv-nav.js
index 76a85e06..db8a19e8 100644
--- a/public/rentv-nav.js
+++ b/public/rentv-nav.js
@@ -43,11 +43,14 @@
     // the data source cloned into the hamburger drawer on masthead pages.
     '.rentvtabs{display:none!important}',
     // Injected hamburger + left drawer for masthead-chrome pages (header.mast with no drawer).
-    '.rtnav-ham{position:absolute;left:14px;top:50%;transform:translateY(-50%);background:#fff;border:1.5px solid var(--line,#e4e7ea);border-radius:9px;font-size:17px;line-height:1;padding:7px 11px;cursor:pointer;color:#14171a;z-index:20}',
+    '.rtnav-ham{position:absolute;top:50%;transform:translateY(-50%);background:#fff;border:1.5px solid var(--line,#e4e7ea);border-radius:9px;font-size:17px;line-height:1;padding:7px 11px;cursor:pointer;color:#14171a;z-index:20}',
+    '.rtnav-ham.l{left:14px}.rtnav-ham.r{right:14px}',
     '.rtnav-ham:hover{border-color:var(--red,#c8102e);color:var(--red,#c8102e)}',
     '.rtnav-dr{position:fixed;inset:0;z-index:4000;display:none}.rtnav-dr.open{display:block}',
     '.rtnav-bd{position:absolute;inset:0;background:rgba(0,0,0,.45)}',
-    '.rtnav-pl{position:absolute;top:0;left:0;width:min(86vw,300px);height:100%;background:#fff;overflow:auto;padding:18px 16px 44px;box-shadow:10px 0 44px rgba(0,0,0,.32)}',
+    '.rtnav-pl{position:absolute;top:0;width:min(86vw,300px);height:100%;background:#fff;overflow:auto;padding:18px 16px 44px}',
+    '.rtnav-dr.left .rtnav-pl{left:0;box-shadow:10px 0 44px rgba(0,0,0,.32)}',
+    '.rtnav-dr.right .rtnav-pl{right:0;box-shadow:-10px 0 44px rgba(0,0,0,.32)}',
     '.rtnav-pl h3{font-family:"Playfair Display",serif;font-size:19px;margin:0 0 6px}.rtnav-pl h3 span{color:var(--red,#c8102e)}',
     '.rtnav-x{position:absolute;top:12px;right:14px;font-size:24px;background:none;border:0;cursor:pointer;color:#5b636b;line-height:1}',
     '.rtnav-gt{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:#9aa2ab;margin:16px 0 6px}',
@@ -150,33 +153,45 @@
     if (document.querySelector('.drawer')) return;      // has its own drawer (map / header.top) — skip
     if (document.querySelector('.rtnav-ham')) return;   // idempotent
     mast.classList.add('rtnav-has');
-    var ham = document.createElement('button');
-    ham.className = 'rtnav-ham'; ham.setAttribute('aria-label', 'Open menu'); ham.type = 'button'; ham.innerHTML = '☰';
-    mast.insertBefore(ham, mast.firstChild);
     var strip = document.querySelector('.rentvtabs');
-    var dr = document.createElement('div'); dr.className = 'rtnav-dr'; dr.setAttribute('aria-hidden', 'true');
-    dr.innerHTML = '<div class="rtnav-bd"></div><div class="rtnav-pl">' +
-      '<button class="rtnav-x" type="button" aria-label="Close">×</button>' +
-      '<h3>REN<span>TV</span>.com</h3>' +
-      '<div class="rtnav-gt">Explore</div>' +
+    var geo = strip ? (strip.querySelector('.rt-geo') || {}).innerHTML || '' : '';  // Regions row
+    var cat = strip ? (strip.querySelector('.rt-cat') || {}).innerHTML || '' : '';  // Sections row
+    function mkHam(side, label) {
+      var h = document.createElement('button'); h.type = 'button';
+      h.className = 'rtnav-ham ' + side; h.setAttribute('aria-label', label); h.innerHTML = '☰';
+      return h;
+    }
+    // LEFT hamburger + drawer → Explore + Regions
+    var hamL = mkHam('l', 'Explore & regions menu');
+    var drL = document.createElement('div'); drL.className = 'rtnav-dr left'; drL.setAttribute('aria-hidden', 'true');
+    drL.innerHTML = '<div class="rtnav-bd"></div><div class="rtnav-pl">' +
+      '<button class="rtnav-x" type="button" aria-label="Close">×</button><h3>Explore</h3>' +
       '<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="rtnav-gt">Regions &amp; Sections</div><div class="rtnav-clone">' + (strip ? strip.innerHTML : '') + '</div>' +
-      '</div>';
-    document.body.appendChild(dr);
-    // Hide the page's OWN horizontal nav bar (its links live in this drawer now). It's the first
-    // <nav> after the masthead; skip the injected (already-hidden) .rentvtabs strip.
+      '<div class="rtnav-gt">Regions</div><div class="rtnav-clone">' + geo + '</div></div>';
+    // RIGHT hamburger + drawer → Sections
+    var hamR = mkHam('r', 'Sections menu');
+    var drR = document.createElement('div'); drR.className = 'rtnav-dr right'; drR.setAttribute('aria-hidden', 'true');
+    drR.innerHTML = '<div class="rtnav-bd"></div><div class="rtnav-pl">' +
+      '<button class="rtnav-x" type="button" aria-label="Close">×</button><h3>Sections</h3>' +
+      '<div class="rtnav-clone">' + cat + '</div></div>';
+    mast.insertBefore(hamL, mast.firstChild);
+    mast.appendChild(hamR);
+    document.body.appendChild(drL); document.body.appendChild(drR);
+    // Hide the page's OWN horizontal nav bar — its links live in these drawers now.
     var sib = mast.nextElementSibling;
     while (sib && sib.tagName !== 'NAV') sib = sib.nextElementSibling;
     if (sib && !sib.classList.contains('rentvtabs')) sib.style.display = 'none';
-    var open = function () { dr.classList.add('open'); dr.setAttribute('aria-hidden', 'false'); };
-    var close = function () { dr.classList.remove('open'); dr.setAttribute('aria-hidden', 'true'); };
-    ham.onclick = open;
-    dr.querySelector('.rtnav-x').onclick = close;
-    dr.querySelector('.rtnav-bd').onclick = close;
-    dr.addEventListener('click', function (e) { if (e.target.closest('a')) close(); });
-    document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
+    function wire(ham, dr) {
+      ham.onclick = function () { dr.classList.add('open'); dr.setAttribute('aria-hidden', 'false'); };
+      var close = function () { dr.classList.remove('open'); dr.setAttribute('aria-hidden', 'true'); };
+      dr.querySelector('.rtnav-x').onclick = close;
+      dr.querySelector('.rtnav-bd').onclick = close;
+      dr.addEventListener('click', function (e) { if (e.target.closest('a')) close(); });
+      document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
+    }
+    wire(hamL, drL); wire(hamR, drR);
   }
 
   // ---- 3) Refresh the wordmark into the 2026 liquid-glass RENTV logo (faithful to rentv.com) ----

← ba9f632d logo: make it genuinely LIQUID — animated specular sweep + f  ·  back to Rentv 2026  ·  auto-data-snapshot: 2026-08-06T10:21:57 (6 data files) — dat f4d659e3 →