← 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 });
})();