← back to Dw Material Reclassify

dw-material-nav.js

80 lines

/* ============================================================================
   DW Material filter  v1  (2026-07-22) — collection-page left-rail Material block.
   Injects a "Material" filter group into the Boost SD left filter tree that links
   to the material-* smart collections (tag=material-group-*). Server-side, robust,
   no Boost-index dependency (Shopify smart collections populate directly).
   Loaded by layout/theme.liquid after dw-card-hover.js.  Reversible: remove asset
   + the one <script> include.
   ========================================================================== */
(function () {
  if (window.__dwMaterialNav) return;
  window.__dwMaterialNav = true;

  var MATERIALS = [
    ['Grasscloth','material-grasscloth'], ['Natural Fiber','material-natural-fiber'],
    ['Paperweave','material-paperweave'], ['Cork','material-cork'],
    ['Silk','material-silk'], ['Linen','material-linen'],
    ['Non-Woven','material-non-woven'], ['Vinyl / Type II','material-vinyl-type-ii'],
    ['Metallic / Foil','material-metallic-foil'], ['Glass Bead','material-glass-bead'],
    ['Flock / Velvet','material-flock-velvet'], ['Leather','material-leather'],
    ['Wood Veneer','material-wood-veneer']
  ];
  // only on collection pages
  if (!/\/collections\//.test(location.pathname)) return;
  var here = (location.pathname.match(/\/collections\/([^/?#]+)/) || [])[1] || '';

  var STYLE_ID = 'dw-material-nav-style';
  if (!document.getElementById(STYLE_ID)) {
    var st = document.createElement('style'); st.id = STYLE_ID;
    st.textContent = [
      '.dw-material-filter{margin:0 0 18px;padding:0 0 14px;border-bottom:1px solid #e6e2da;',
        'font-family:-apple-system,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}',
      '.dw-material-filter h3{font-size:13px;font-weight:700;letter-spacing:.06em;',
        'text-transform:uppercase;color:#1a1a1a;margin:0 0 10px;}',
      '.dw-material-filter ul{list-style:none;margin:0;padding:0;}',
      '.dw-material-filter li{margin:0 0 6px;}',
      '.dw-material-filter a{display:block;font-size:13px;line-height:1.35;color:#4a4640;',
        'text-decoration:none;transition:color .15s;}',
      '.dw-material-filter a:hover{color:#8b7355;}',
      '.dw-material-filter a.dw-mat-active{color:#8b7355;font-weight:700;}'
    ].join('');
    document.head.appendChild(st);
  }

  function build() {
    var box = document.createElement('div');
    box.className = 'dw-material-filter';
    var html = '<h3>Material</h3><ul>';
    MATERIALS.forEach(function (m) {
      var active = (here === m[1]) ? ' class="dw-mat-active"' : '';
      html += '<li><a href="/collections/' + m[1] + '"' + active + '>' + m[0] + '</a></li>';
    });
    box.innerHTML = html + '</ul>';
    return box;
  }

  // Insert as the first child of the Boost left filter tree. Retry/observe because
  // Boost renders the tree client-side and re-renders on filter changes.
  function mount() {
    if (document.querySelector('.dw-material-filter')) return true;
    var tree = document.querySelector(
      '.boost-sd__filter-tree-vertical, .boost-sd__filter-tree-wrapper, .boost-sd__filter-tree, [class*="filter-tree"]'
    );
    if (!tree) return false;
    tree.insertBefore(build(), tree.firstChild);
    return true;
  }

  if (!mount()) {
    var tries = 0, t = setInterval(function () {
      if (mount() || ++tries > 40) clearInterval(t);   // up to ~10s
    }, 250);
  }
  // re-mount if Boost re-renders the tree (scoped to the filter column, not body)
  var host = document.querySelector('[class*="filter"]') || document.body;
  var obs = new MutationObserver(function () {
    if (!document.querySelector('.dw-material-filter')) mount();
  });
  obs.observe(host, { childList: true, subtree: true });
})();