← back to Stars of Design
public/js/grid-controls.js
64 lines
// Density slider + sort select. Sort hits the server via querystring (matches lib/sort.js).
// Density adjusts CSS var --cols-min on the grid; both values persist in localStorage.
//
// Hydration order matters — per the standing rule, the saved sort MUST apply
// BEFORE the first grid render. Server-side sort happens via the `?sort=` URL
// param, so on page load we check: if URL has no sort param but a saved value
// exists in localStorage, redirect once with the saved value as `?sort=`.
// This makes the saved sort effective on the very first paint of a fresh visit.
(function () {
var KEY_SORT = 'sod-sort';
var KEY_DENS = 'sod-density';
var grid = document.querySelector('[data-designer-grid]');
var sortEl = document.querySelector('[data-sort]');
var densEl = document.querySelector('[data-density]');
// --- Sort: hydrate saved value BEFORE first render via one-time redirect ---
if (sortEl) {
try {
var savedSort = localStorage.getItem(KEY_SORT);
var url = new URL(window.location.href);
var urlSort = url.searchParams.get('sort');
// Only redirect if (a) we have a saved sort, (b) URL has no sort yet,
// (c) saved sort is actually one of the options on this page (don't
// cross-contaminate between /designers, /clients, /firms which each
// have different sort vocabularies). Also gate against loops with a
// sessionStorage flag.
if (savedSort && !urlSort && sortEl.querySelector('option[value="' + savedSort.replace(/"/g, '') + '"]')) {
var hydratedFlag = 'sod-sort-hydrated';
if (!sessionStorage.getItem(hydratedFlag)) {
sessionStorage.setItem(hydratedFlag, '1');
url.searchParams.set('sort', savedSort);
window.location.replace(url.toString());
return; // stop further setup; page will reload with the saved sort
}
}
} catch (e) {}
sortEl.addEventListener('change', function () {
try { localStorage.setItem(KEY_SORT, sortEl.value); } catch (e) {}
// sort selects inside a <form> already submit themselves (see clients.ejs
// / firms.ejs onchange="this.form.submit()"); for the standalone partial
// (home, /designers) we drive navigation here.
if (sortEl.form) return; // form submit handles it
var u = new URL(window.location.href);
u.searchParams.set('sort', sortEl.value);
window.location.href = u.toString();
});
}
// --- Density: pure client-side, persist + apply CSS var ---
if (densEl && grid) {
try {
var savedDens = localStorage.getItem(KEY_DENS);
if (savedDens) { densEl.value = savedDens; }
} catch (e) {}
grid.style.setProperty('--cols-min', densEl.value + 'px');
densEl.addEventListener('input', function () {
grid.style.setProperty('--cols-min', densEl.value + 'px');
try { localStorage.setItem(KEY_DENS, densEl.value); } catch (e) {}
});
}
})();