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