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