[object Object]

← back to Commercialrealestate

Polish corner nav: type-to-filter search, focus-on-open, current-link scroll, focus restore

bd5c023660a7cc01976ab8860754c6d5e2461220 · 2026-08-06 16:09:44 -0700 · Steve

- LEFT drawer gets a live filter box: type to match across all 26 links; matching
  sections auto-expand, empty ones hide, 'no pages match' on a miss, re-collapse on clear
- focus the search on open (left) / first link (right); scroll the current page into view
- restore focus to the opening hamburger on close (a11y)
Verified in real Chrome: filter isolates FHA pages, no-result + clear behave.

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

Files touched

Diff

commit bd5c023660a7cc01976ab8860754c6d5e2461220
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Aug 6 16:09:44 2026 -0700

    Polish corner nav: type-to-filter search, focus-on-open, current-link scroll, focus restore
    
    - LEFT drawer gets a live filter box: type to match across all 26 links; matching
      sections auto-expand, empty ones hide, 'no pages match' on a miss, re-collapse on clear
    - focus the search on open (left) / first link (right); scroll the current page into view
    - restore focus to the opening hamburger on close (a11y)
    Verified in real Chrome: filter isolates FHA pages, no-result + clear behave.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/corner-nav.js | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/public/corner-nav.js b/public/corner-nav.js
index 1fb26e6..28d9e01 100644
--- a/public/corner-nav.js
+++ b/public/corner-nav.js
@@ -71,17 +71,27 @@
     '.cnav-list a{display:block;padding:8px 16px 8px 22px;color:#c7cdd6;text-decoration:none;font-size:13.5px;border-left:2px solid transparent;}' +
     '.cnav-list a:hover{background:rgba(200,162,75,.08);color:#fff;}' +
     '.cnav-list a.cur{color:#C8A24B;border-left-color:#C8A24B;background:rgba(200,162,75,.10);font-weight:600;}' +
-    '.cnav-empty{padding:14px 16px;color:#8A93A2;font-size:13px;}';
+    '.cnav-empty{padding:14px 16px;color:#8A93A2;font-size:13px;}' +
+    '.cnav-search{position:relative;margin:10px 14px 6px;}' +
+    '.cnav-search input{width:100%;box-sizing:border-box;background:#0c1017;border:1px solid #232a38;border-radius:8px;padding:8px 10px 8px 30px;color:#e6e8ec;font-size:13px;}' +
+    '.cnav-search input:focus{outline:0;border-color:#C8A24B;}' +
+    '.cnav-search .ic{position:absolute;left:10px;top:8px;color:#8A93A2;font-size:12px;pointer-events:none;}' +
+    '.cnav-sec.hide{display:none;} .cnav-list a.hide{display:none;}' +
+    '.cnav-noresult{padding:12px 16px;color:#8A93A2;font-size:13px;display:none;}';
   var st = document.createElement('style'); st.textContent = css; document.head.appendChild(st);
 
   function el(tag, cls, html) { var e = document.createElement(tag); if (cls) e.className = cls; if (html != null) e.innerHTML = html; return e; }
 
   // ── overlay ───────────────────────────────────────────────────────────────────────
   var ov = el('div', 'cnav-ov'); document.body.appendChild(ov);
+  var lastOpener = null;
   function closeAll() {
+    var wasOpen = !!document.querySelector('.cnav-drawer.on');
     document.querySelectorAll('.cnav-drawer.on').forEach(function (d) { d.classList.remove('on'); });
     ov.classList.remove('on');
     document.querySelectorAll('.cnav-burger').forEach(function (b) { b.setAttribute('aria-expanded', 'false'); });
+    if (wasOpen && lastOpener) { try { lastOpener.focus(); } catch (e) {} }
+    lastOpener = null;
   }
   ov.addEventListener('click', closeAll);
   document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeAll(); });
@@ -132,6 +142,27 @@
     });
     left._body.appendChild(sec);
   });
+  // type-to-filter across all site links
+  var searchWrap = el('div', 'cnav-search', '<span class="ic">🔎</span>');
+  var searchIn = document.createElement('input');
+  searchIn.type = 'text'; searchIn.placeholder = 'Filter pages…'; searchIn.setAttribute('aria-label', 'Filter pages');
+  searchWrap.appendChild(searchIn);
+  left._body.insertBefore(searchWrap, left._body.firstChild);
+  var noRes = el('div', 'cnav-noresult', 'No pages match.'); left._body.appendChild(noRes);
+  function filterLeft(q) {
+    q = (q || '').trim().toLowerCase(); var anyVisible = false;
+    left._body.querySelectorAll('.cnav-sec').forEach(function (sec) {
+      var shown = 0;
+      sec.querySelectorAll('.cnav-list a').forEach(function (a) {
+        var m = !q || a.textContent.toLowerCase().indexOf(q) >= 0; a.classList.toggle('hide', !m); if (m) shown++;
+      });
+      sec.classList.toggle('hide', !!q && shown === 0);
+      sec.classList.toggle('collapsed', !q);            // expand matches while filtering, re-collapse when cleared
+      if (shown > 0) anyVisible = true;
+    });
+    noRes.style.display = (q && !anyVisible) ? 'block' : 'none';
+  }
+  searchIn.addEventListener('input', function () { filterLeft(searchIn.value); });
 
   // RIGHT — "On this page" jump links + the full site menu (all collapsed)
   var right = drawer('right', 'On this page', 'jump to a section');
@@ -165,7 +196,14 @@
     b.addEventListener('click', function (e) {
       e.stopPropagation();
       var open = target.classList.contains('on'); closeAll();
-      if (!open) { if (onOpen) onOpen(); target.classList.add('on'); ov.classList.add('on'); b.setAttribute('aria-expanded', 'true'); }
+      if (!open) {
+        if (onOpen) onOpen();
+        target.classList.add('on'); ov.classList.add('on'); b.setAttribute('aria-expanded', 'true'); lastOpener = b;
+        setTimeout(function () {
+          if (side === 'left') { if (searchIn) searchIn.focus(); var cur = target.querySelector('a.cur'); if (cur) cur.scrollIntoView({ block: 'nearest' }); }
+          else { var f = target.querySelector('.cnav-list a'); if (f) f.focus(); }
+        }, 60);
+      }
     });
     document.body.appendChild(b); return b;
   }

← 3814ddc Refine corner nav: thoughtful 6-group IA, all sections colla  ·  back to Commercialrealestate  ·  CRCP: soften dev-facing load errors + one-shot auto-retry on 00b8192 →