[object Object]

← back to Silverleafwallpaper

fleet rebuild: dw-header (hamburgers UL + centered name) + unique high-res hero + accent — local pilot branch

8f1e381383346eaf399189897bf41addc415a98f · 2026-06-01 13:42:40 -0700 · Steve Abrams

Files touched

Diff

commit 8f1e381383346eaf399189897bf41addc415a98f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 13:42:40 2026 -0700

    fleet rebuild: dw-header (hamburgers UL + centered name) + unique high-res hero + accent — local pilot branch
---
 public/dw-header.js | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 public/hero-bg.jpg  | Bin 2348295 -> 5164204 bytes
 public/index.html   |   4 +-
 3 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/public/dw-header.js b/public/dw-header.js
new file mode 100644
index 0000000..0f10a0b
--- /dev/null
+++ b/public/dw-header.js
@@ -0,0 +1,129 @@
+/* dw-header.js — universal DW fleet header (drop-in).
+ *
+ * Spec (Steve 2026-06-01): BOTH hamburgers upper-LEFT, site name CENTERED.
+ *   - Public: ☰ (site nav) top-left · centered site name
+ *   - Admin (logged in): a SECOND ☰ beside it (accent-tinted) for admin tools
+ *
+ * Drop-in:  <script src="/dw-header.js" defer></script>
+ * Per-site override (set BEFORE the script loads):
+ *   window.DwHeaderConfig = {
+ *     siteName: 'Jute Wallpaper',           // default: derived from hostname
+ *     accent:   '#9B7B4F',                  // admin-burger tint (default: --accent var or #9B7B4F)
+ *     homeUrl:  '/',
+ *     navLinks:   [{name:'Home',url:'/'}, {name:'About',url:'/about'}, ...],
+ *     adminLinks: [{name:'Shopify admin', url:'https://admin.shopify.com', external:true}, ...],
+ *   };
+ * Admin reveal: ?admin=1 sets localStorage.dwAdmin=1 (stub until real auth wires in).
+ *
+ * Self-styled · idempotent · replaces inline ns-header + the upper-right corner-nav.
+ */
+(function () {
+  'use strict';
+  if (window.__dwHeaderLoaded) return;
+  window.__dwHeaderLoaded = true;
+
+  var CFG = window.DwHeaderConfig || {};
+  var DOMAIN = location.hostname.replace(/^www\./, '');
+  var STEM = DOMAIN.replace(/\..+$/, '');
+
+  function titleCase(s) {
+    return s.replace(/(wallcoverings?|wallpapers?|walls?|fabric|covering|paper|cover)/gi, ' $1')
+            .replace(/\s+/g, ' ').trim()
+            .replace(/\b\w/g, function (c) { return c.toUpperCase(); });
+  }
+  var SITE_NAME = CFG.siteName || titleCase(STEM);
+  var HOME = CFG.homeUrl || '/';
+  var ACCENT = CFG.accent || (getComputedStyle(document.documentElement).getPropertyValue('--accent').trim()) || '#9B7B4F';
+  var NAV = CFG.navLinks || [
+    { name: 'Home', url: '/' }, { name: 'About', url: '/about' },
+    { name: 'Care', url: '/care.html' }, { name: 'History', url: '/history.html' },
+  ];
+  var ADMIN = CFG.adminLinks || [
+    { name: 'Shopify admin', url: 'https://admin.shopify.com', external: true },
+    { name: 'Edit hero', url: '#' }, { name: 'Analytics', url: '#' },
+  ];
+
+  // admin reveal (stub auth)
+  var isAdmin = false;
+  try {
+    var p = new URLSearchParams(location.search);
+    if (p.get('admin') === '1') localStorage.setItem('dwAdmin', '1');
+    if (p.get('admin') === '0') localStorage.removeItem('dwAdmin');
+    isAdmin = localStorage.getItem('dwAdmin') === '1';
+  } catch (e) {}
+
+  function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;'); }
+  function linksHTML(arr) {
+    return arr.map(function (l) {
+      if (l.onclick) return '<button type="button" data-act="' + esc(l.onclick) + '">' + esc(l.name) + '</button>';
+      var ext = l.external ? ' target="_blank" rel="noopener noreferrer"' : '';
+      return '<a href="' + esc(l.url) + '"' + ext + '>' + esc(l.name) + '</a>';
+    }).join('');
+  }
+
+  // ---- styles ----
+  var css = document.createElement('style');
+  css.id = 'dw-header-styles';
+  css.textContent = [
+    '.dwh{position:sticky;top:0;z-index:200;display:flex;align-items:center;justify-content:space-between;padding:18px 28px;background:rgba(10,10,10,.92);backdrop-filter:blur(8px);border-bottom:1px solid rgba(245,241,232,.08)}',
+    '.dwh-burgers{display:flex;align-items:center;gap:10px;flex:1 1 0}',
+    '.dwh-spacer{flex:1 1 0}',
+    '.dwh-name{flex:0 0 auto;text-align:center;font-family:"Cormorant Garamond","Recoleta",Georgia,serif;font-style:italic;font-weight:500;font-size:22px;letter-spacing:.01em;color:#f5f1e8;text-decoration:none;white-space:nowrap}',
+    '.dwh-burger{display:flex;flex-direction:column;align-items:center;justify-content:center;width:34px;height:34px;gap:5px;background:transparent;border:0;cursor:pointer;padding:0}',
+    '.dwh-burger span{display:block;width:22px;height:1.5px;background:#f5f1e8;transition:transform .2s,opacity .2s}',
+    '.dwh-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}',
+    '.dwh-burger[aria-expanded="true"] span:nth-child(2){opacity:0}',
+    '.dwh-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}',
+    '.dwh-admin span{background:' + ACCENT + '}',
+    '.dwh-drawer{display:none;position:absolute;top:100%;left:18px;flex-direction:column;align-items:stretch;background:rgba(10,10,10,.97);backdrop-filter:blur(10px);border:1px solid rgba(245,241,232,.12);border-top:0;min-width:240px;padding:8px 0;margin:0;box-shadow:0 16px 40px rgba(0,0,0,.55);z-index:210}',
+    '.dwh-drawer.open{display:flex}',
+    '.dwh-drawer.dwh-admin-drawer{left:60px}',
+    '.dwh-drawer a,.dwh-drawer button{font-family:-apple-system,system-ui,sans-serif;font-size:14px;color:#f5f1e8;text-decoration:none;background:none;border:0;cursor:pointer;padding:12px 22px;text-align:left;width:100%;border-bottom:1px solid rgba(245,241,232,.08);display:block}',
+    '.dwh-drawer a:last-child,.dwh-drawer button:last-child{border-bottom:0}',
+    '.dwh-drawer a:hover,.dwh-drawer button:hover{background:rgba(245,241,232,.06)}',
+    '.dwh-head{padding:10px 22px 8px;font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:' + ACCENT + '}',
+  ].join('\n');
+  document.head.appendChild(css);
+
+  // ---- header markup ----
+  var header = document.createElement('header');
+  header.className = 'dwh';
+  header.innerHTML =
+    '<div class="dwh-burgers">' +
+      '<button type="button" class="dwh-burger" id="dwhNav" aria-label="Menu" aria-controls="dwhNavDrawer" aria-expanded="false"><span></span><span></span><span></span></button>' +
+      (isAdmin ? '<button type="button" class="dwh-burger dwh-admin" id="dwhAdmin" aria-label="Admin tools" aria-controls="dwhAdminDrawer" aria-expanded="false"><span></span><span></span><span></span></button>' : '') +
+    '</div>' +
+    '<a href="' + esc(HOME) + '" class="dwh-name">' + esc(SITE_NAME) + '</a>' +
+    '<div class="dwh-spacer"></div>' +
+    '<nav class="dwh-drawer" id="dwhNavDrawer" aria-label="Primary">' + linksHTML(NAV) + '</nav>' +
+    (isAdmin ? '<nav class="dwh-drawer dwh-admin-drawer" id="dwhAdminDrawer" aria-label="Admin tools"><div class="dwh-head">Admin tools</div>' + linksHTML(ADMIN) + '<button type="button" data-act="logout">Sign out admin</button></nav>' : '');
+
+  // remove any pre-existing inline header so we don't double up
+  var old = document.querySelector('header.ns-header, header.dwh:not(:first-of-type)');
+  if (old && old.className.indexOf('dwh') === -1) old.style.display = 'none';
+
+  document.body.insertBefore(header, document.body.firstChild);
+
+  // ---- behaviour ----
+  function drawer(id) { return document.getElementById(id); }
+  function close(navId, btnId) { var d = drawer(navId), b = document.getElementById(btnId); if (d) d.classList.remove('open'); if (b) b.setAttribute('aria-expanded', 'false'); }
+  function toggle(navId, btnId, otherNav, otherBtn) {
+    close(otherNav, otherBtn);
+    var d = drawer(navId), b = document.getElementById(btnId);
+    if (!d || !b) return;
+    var open = d.classList.toggle('open');
+    b.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  var navBtn = document.getElementById('dwhNav');
+  if (navBtn) navBtn.addEventListener('click', function () { toggle('dwhNavDrawer', 'dwhNav', 'dwhAdminDrawer', 'dwhAdmin'); });
+  var admBtn = document.getElementById('dwhAdmin');
+  if (admBtn) admBtn.addEventListener('click', function () { toggle('dwhAdminDrawer', 'dwhAdmin', 'dwhNavDrawer', 'dwhNav'); });
+
+  header.addEventListener('click', function (e) {
+    var act = e.target && e.target.getAttribute && e.target.getAttribute('data-act');
+    if (!act) return;
+    if (act === 'logout') { try { localStorage.removeItem('dwAdmin'); } catch (x) {} location.reload(); return; }
+    if (typeof window[act] === 'function') { e.preventDefault(); window[act](); }
+  });
+  document.addEventListener('keydown', function (e) { if (e.key === 'Escape') { close('dwhNavDrawer', 'dwhNav'); close('dwhAdminDrawer', 'dwhAdmin'); } });
+})();
diff --git a/public/hero-bg.jpg b/public/hero-bg.jpg
index bc081fc..6dc78bd 100644
Binary files a/public/hero-bg.jpg and b/public/hero-bg.jpg differ
diff --git a/public/index.html b/public/index.html
index df7213c..aef705a 100644
--- a/public/index.html
+++ b/public/index.html
@@ -925,6 +925,8 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
 <!-- ============================================================
      DW UNIVERSAL CONTACT MODULE — fashion-house UX
      Inject before   <script src="/hero-4grid.js" defer></script>
+<script>window.DwHeaderConfig={siteName:"Silverleaf Wallpaper",accent:"#D70000",navLinks:[{name:'Home',url:'/'},{name:'Collections',url:'#shop'},{name:'About',url:'/about'},{name:'Care',url:'/care.html'},{name:'History',url:'/history.html'}],adminLinks:[{name:'Shopify admin',url:'https://admin.shopify.com',external:true},{name:'Edit hero',url:'#'},{name:'Analytics',url:'#'}]};</script>
+<script src="/dw-header.js" defer></script>
 </body> in every DW-family sister site.
      Self-contained: CSS + 4 modals + JS submission handlers.
      Uses host site's CSS vars (--bg, --fg, --gold, --rule).
@@ -1270,7 +1272,7 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
 })();
 </script>
 
-<script src="/corner-nav.js" defer></script>
+<!-- corner-nav disabled (UL-hamburger rebuild) -->
 <script src="/sku-redact.js" defer></script>
 <!-- hero4-fix: activate 2x2 hero (self-contained; was commented placeholder) -->
 <script src="/hero-4grid.js" defer></script>

← e763b14 hero: activate self-contained 2x2 hero-4grid (fleet sweep, l  ·  back to Silverleafwallpaper  ·  Re-add Big Red embed (revert conflicted; re-injected) 80957b2 →