[object Object]

← back to Designer Wallcoverings

auto-save: 2026-06-22T14:06:44 (2 files) — shopify/collection-layout-override.json shopify/sections/

d61b657d06336e711de2d8f8bb3bb08a8d3ce8eb · 2026-06-22 14:06:49 -0700 · Steve Abrams

Files touched

Diff

commit d61b657d06336e711de2d8f8bb3bb08a8d3ce8eb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 22 14:06:49 2026 -0700

    auto-save: 2026-06-22T14:06:44 (2 files) — shopify/collection-layout-override.json shopify/sections/
---
 shopify/collection-layout-override.json            |  43 +++
 .../sections/collection-filters-horizontal.liquid  | 261 +++++++++++++++
 shopify/sections/collection-toolbar.liquid         | 357 +++++++++++++++++++++
 3 files changed, 661 insertions(+)

diff --git a/shopify/collection-layout-override.json b/shopify/collection-layout-override.json
new file mode 100644
index 00000000..3a9ae32c
--- /dev/null
+++ b/shopify/collection-layout-override.json
@@ -0,0 +1,43 @@
+{
+  "sections": {
+    "main": {
+      "type": "collection",
+      "settings": {
+        "show_collection_image": true,
+        "show_description": true,
+        "sorting": false,
+        "show_filters": false,
+        "layout": "default",
+        "products_per_row": 4,
+        "number_of_rows": 2
+      }
+    },
+    "collection-toolbar": {
+      "type": "collection-toolbar",
+      "settings": {
+        "show_sort": true,
+        "show_density": true,
+        "show_search": true,
+        "density_min": 3,
+        "density_max": 12,
+        "density_default": 4
+      }
+    },
+    "collection-filters": {
+      "type": "collection-filters-horizontal",
+      "settings": {
+        "show_color": true,
+        "show_style": true,
+        "show_brand": true,
+        "show_durability": true,
+        "show_price": true,
+        "layout": "horizontal"
+      }
+    }
+  },
+  "order": [
+    "collection-filters",
+    "collection-toolbar",
+    "main"
+  ]
+}
diff --git a/shopify/sections/collection-filters-horizontal.liquid b/shopify/sections/collection-filters-horizontal.liquid
new file mode 100644
index 00000000..c02a9516
--- /dev/null
+++ b/shopify/sections/collection-filters-horizontal.liquid
@@ -0,0 +1,261 @@
+{%- comment -%}
+  Horizontal Collection Filters — Replaces vertical sidebar filters
+
+  Features:
+  - Horizontal tab/chip layout for Color, Style, Brand, Durability, Price
+  - Wraps on mobile
+  - Active state persistence via URL params
+  - Accessible ARIA labels
+
+  Revision: 2026-06-22
+{%- endcomment -%}
+
+<div class="collection-filters" data-section-id="{{ section.id }}">
+  <style>
+    .collection-filters {
+      display: flex;
+      gap: 8px;
+      flex-wrap: wrap;
+      align-items: center;
+      padding: 16px 0;
+      border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.1));
+      margin-bottom: 20px;
+    }
+
+    .filter-group {
+      display: flex;
+      gap: 6px;
+      align-items: center;
+    }
+
+    .filter-label {
+      font-size: 10px;
+      letter-spacing: 0.32em;
+      text-transform: uppercase;
+      font-weight: 700;
+      color: var(--text-muted, rgba(0,0,0,0.6));
+      margin-right: 4px;
+    }
+
+    .filter-chip {
+      padding: 6px 12px;
+      font-size: 11px;
+      letter-spacing: 0.18em;
+      text-transform: uppercase;
+      font-weight: 600;
+      color: var(--text-color, inherit);
+      background: transparent;
+      border: 1px solid var(--border-color, rgba(0,0,0,0.12));
+      border-radius: 20px;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      text-decoration: none;
+      display: inline-flex;
+      align-items: center;
+      gap: 6px;
+    }
+
+    .filter-chip:hover {
+      border-color: var(--accent-color, rgba(0,0,0,0.3));
+      background: var(--bg-hover, rgba(0,0,0,0.02));
+    }
+
+    .filter-chip.active {
+      background: var(--accent-color, #000);
+      color: #fff;
+      border-color: var(--accent-color, #000);
+    }
+
+    .filter-chip .close {
+      font-size: 12px;
+      font-weight: 700;
+      opacity: 0.6;
+      transition: opacity 0.2s;
+    }
+
+    .filter-chip:hover .close {
+      opacity: 1;
+    }
+
+    .filter-divider {
+      width: 1px;
+      height: 20px;
+      background: var(--border-color, rgba(0,0,0,0.1));
+      margin: 0 4px;
+    }
+
+    .clear-filters {
+      font-size: 10px;
+      letter-spacing: 0.18em;
+      text-transform: uppercase;
+      font-weight: 600;
+      color: var(--accent-color, #000);
+      background: transparent;
+      border: 0;
+      cursor: pointer;
+      padding: 0;
+      margin-left: auto;
+      transition: opacity 0.2s;
+    }
+
+    .clear-filters:hover {
+      opacity: 0.7;
+    }
+
+    /* Mobile responsive */
+    @media (max-width: 720px) {
+      .collection-filters {
+        gap: 6px;
+        padding: 12px 0;
+      }
+
+      .filter-label {
+        display: none;
+      }
+
+      .filter-divider {
+        display: none;
+      }
+
+      .clear-filters {
+        margin-left: 0;
+        margin-top: 8px;
+        flex: 1 1 100%;
+      }
+    }
+  </style>
+
+  {%- assign active_filters = request.params -%}
+
+  <div class="filter-group">
+    <span class="filter-label">Filters</span>
+  </div>
+
+  {%- if section.settings.show_color -%}
+    <div class="filter-group">
+      <span class="filter-label">Color</span>
+      {%- for color in collection.metafields.custom.colors -%}
+        {%- assign color_url = request.path | append: '?color=' | append: color -%}
+        <a href="{{ color_url }}" class="filter-chip {% if request.params.color == color %}active{% endif %}">
+          {{ color }}
+        </a>
+      {%- endfor -%}
+    </div>
+  {%- endif -%}
+
+  {%- if section.settings.show_style -%}
+    <div class="filter-group">
+      <span class="filter-label">Style</span>
+      <button class="filter-chip" data-filter="style" aria-label="Filter by style">
+        Style
+      </button>
+    </div>
+  {%- endif -%}
+
+  {%- if section.settings.show_brand -%}
+    <div class="filter-group">
+      <span class="filter-label">Brand</span>
+      <button class="filter-chip" data-filter="brand" aria-label="Filter by brand">
+        Brand
+      </button>
+    </div>
+  {%- endif -%}
+
+  {%- if section.settings.show_durability -%}
+    <div class="filter-group">
+      <span class="filter-label">Durability</span>
+      <button class="filter-chip" data-filter="durability" aria-label="Filter by durability">
+        Durability
+      </button>
+    </div>
+  {%- endif -%}
+
+  {%- if section.settings.show_price -%}
+    <div class="filter-group">
+      <span class="filter-label">Price</span>
+      <button class="filter-chip" data-filter="price" aria-label="Filter by price">
+        Price
+      </button>
+    </div>
+  {%- endif -%}
+
+  {%- if active_filters -%}
+    <button class="clear-filters" aria-label="Clear all filters">
+      Clear Filters
+    </button>
+  {%- endif -%}
+</div>
+
+<script>
+(function() {
+  const clearBtn = document.querySelector('.clear-filters');
+  if (clearBtn) {
+    clearBtn.addEventListener('click', function() {
+      window.location.href = window.location.pathname;
+    });
+  }
+
+  // Future: Wire up filter dropdowns / modals for more complex filtering
+  // This is a simplified version that shows the chip layout
+})();
+</script>
+
+{% schema %}
+{
+  "name": "Collection Filters (Horizontal)",
+  "description": "Horizontal filter chips for collection pages",
+  "settings": [
+    {
+      "type": "checkbox",
+      "id": "show_color",
+      "label": "Show color filter",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_style",
+      "label": "Show style filter",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_brand",
+      "label": "Show brand filter",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_durability",
+      "label": "Show durability filter",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_price",
+      "label": "Show price filter",
+      "default": true
+    },
+    {
+      "type": "select",
+      "id": "layout",
+      "label": "Layout",
+      "options": [
+        {
+          "value": "horizontal",
+          "label": "Horizontal"
+        },
+        {
+          "value": "vertical",
+          "label": "Vertical"
+        }
+      ],
+      "default": "horizontal"
+    }
+  ],
+  "presets": [
+    {
+      "name": "Collection Filters (Horizontal)"
+    }
+  ]
+}
+{% endschema %}
diff --git a/shopify/sections/collection-toolbar.liquid b/shopify/sections/collection-toolbar.liquid
new file mode 100644
index 00000000..7cb2e83e
--- /dev/null
+++ b/shopify/sections/collection-toolbar.liquid
@@ -0,0 +1,357 @@
+{%- comment -%}
+  Collection Toolbar — Horizontal sort + grid density slider + search
+  Replaces Shopify's native sorting/filtering UI with a unified toolbar.
+
+  Features:
+  - Sort dropdown (Newest, Color, Style, SKU, Title, Price)
+  - Grid density slider (3–12 columns)
+  - localStorage persistence
+  - Responsive mobile stacking
+
+  Revision: 2026-06-22
+{%- endcomment -%}
+
+<div class="collection-toolbar" data-section-id="{{ section.id }}">
+  <style>
+    .collection-toolbar {
+      display: flex;
+      gap: 16px;
+      align-items: center;
+      justify-content: space-between;
+      flex-wrap: wrap;
+      padding: 20px 0;
+      border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.1));
+      margin-bottom: 24px;
+    }
+
+    .toolbar-left {
+      display: flex;
+      gap: 14px;
+      align-items: center;
+      flex-wrap: wrap;
+    }
+
+    .toolbar-label {
+      font-size: 11px;
+      letter-spacing: 0.22em;
+      text-transform: uppercase;
+      font-weight: 600;
+      color: var(--text-muted, rgba(0,0,0,0.6));
+    }
+
+    #collectionSort {
+      background: transparent;
+      border: 1px solid var(--border-color, rgba(0,0,0,0.12));
+      padding: 6px 10px;
+      font-family: inherit;
+      font-size: 12px;
+      letter-spacing: 0.08em;
+      text-transform: uppercase;
+      font-weight: 500;
+      color: var(--text-color, inherit);
+      cursor: pointer;
+      transition: all 0.2s ease;
+    }
+
+    #collectionSort:hover {
+      border-color: var(--accent-color, rgba(0,0,0,0.3));
+    }
+
+    #collectionSort:focus {
+      outline: 2px solid var(--accent-color, #000);
+      outline-offset: 2px;
+    }
+
+    .density-control {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      padding: 6px 0;
+    }
+
+    .density-control input[type="range"] {
+      flex: 0 0 120px;
+      -webkit-appearance: none;
+      appearance: none;
+      height: 1px;
+      background: var(--border-color, rgba(0,0,0,0.1));
+      outline: none;
+      cursor: pointer;
+    }
+
+    .density-control input[type="range"]::-webkit-slider-thumb {
+      -webkit-appearance: none;
+      appearance: none;
+      width: 13px;
+      height: 13px;
+      background: var(--accent-color, #000);
+      border-radius: 50%;
+      cursor: pointer;
+      transition: transform 0.2s ease;
+    }
+
+    .density-control input[type="range"]::-webkit-slider-thumb:hover {
+      transform: scale(1.2);
+    }
+
+    .density-control input[type="range"]::-moz-range-thumb {
+      width: 13px;
+      height: 13px;
+      background: var(--accent-color, #000);
+      border-radius: 50%;
+      border: 0;
+      cursor: pointer;
+      transition: transform 0.2s ease;
+    }
+
+    .density-control input[type="range"]::-moz-range-thumb:hover {
+      transform: scale(1.2);
+    }
+
+    .density-display {
+      font-size: 11px;
+      letter-spacing: 0.18em;
+      text-transform: uppercase;
+      font-weight: 600;
+      color: var(--text-muted, rgba(0,0,0,0.6));
+      min-width: 60px;
+      text-align: right;
+    }
+
+    .toolbar-search {
+      flex: 0 1 200px;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.1));
+      padding: 4px 0;
+    }
+
+    .toolbar-search input {
+      flex: 1;
+      background: transparent;
+      border: 0;
+      padding: 4px 0;
+      font-family: inherit;
+      font-size: 12px;
+      letter-spacing: 0.04em;
+      color: var(--text-color, inherit);
+      outline: none;
+    }
+
+    .toolbar-search input::placeholder {
+      color: var(--text-muted, rgba(0,0,0,0.4));
+    }
+
+    .toolbar-search svg {
+      width: 14px;
+      height: 14px;
+      stroke: var(--text-muted, rgba(0,0,0,0.4));
+      fill: none;
+      stroke-width: 1.5;
+      flex-shrink: 0;
+    }
+
+    /* Mobile responsive */
+    @media (max-width: 720px) {
+      .collection-toolbar {
+        gap: 12px;
+      }
+
+      .toolbar-left {
+        flex: 1 1 100%;
+        order: 1;
+      }
+
+      .toolbar-search {
+        flex: 1 1 100%;
+        order: 2;
+        margin-top: 8px;
+      }
+
+      .density-control {
+        display: none;
+      }
+    }
+  </style>
+
+  <div class="toolbar-left">
+    <label for="collectionSort" class="toolbar-label">Sort</label>
+    <select id="collectionSort" aria-label="Sort products">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+
+    <div class="density-control">
+      <span class="toolbar-label">Grid</span>
+      <input type="range" id="densitySlider" min="3" max="12" value="4" aria-label="Grid density">
+      <div class="density-display"><span id="densityLabel">4</span> col</div>
+    </div>
+  </div>
+
+  {% if section.settings.show_search %}
+    <div class="toolbar-search">
+      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
+        <circle cx="11" cy="11" r="8"></circle>
+        <path d="m21 21-4.35-4.35"></path>
+      </svg>
+      <input type="text" id="collectionSearch" placeholder="Search products…" aria-label="Search products">
+    </div>
+  {% endif %}
+</div>
+
+<script>
+(function() {
+  const sortSelect = document.getElementById('collectionSort');
+  const densitySlider = document.getElementById('densitySlider');
+  const densityLabel = document.getElementById('densityLabel');
+  const searchInput = document.getElementById('collectionSearch');
+  const STORAGE_KEY_SORT = 'dw_collection_sort';
+  const STORAGE_KEY_DENSITY = 'dw_collection_density';
+  const STORAGE_KEY_SEARCH = 'dw_collection_search';
+
+  // Load saved state
+  try {
+    const savedSort = localStorage.getItem(STORAGE_KEY_SORT);
+    if (savedSort) sortSelect.value = savedSort;
+
+    const savedDensity = localStorage.getItem(STORAGE_KEY_DENSITY);
+    if (savedDensity) {
+      densitySlider.value = savedDensity;
+      densityLabel.textContent = savedDensity;
+      updateGridDensity(parseInt(savedDensity));
+    }
+
+    const savedSearch = localStorage.getItem(STORAGE_KEY_SEARCH);
+    if (savedSearch) searchInput.value = savedSearch;
+  } catch (e) {}
+
+  // Sort change
+  sortSelect.addEventListener('change', function() {
+    try { localStorage.setItem(STORAGE_KEY_SORT, this.value); } catch (e) {}
+    applySort(this.value);
+  });
+
+  // Density slider
+  densitySlider.addEventListener('input', function() {
+    const cols = parseInt(this.value);
+    densityLabel.textContent = cols;
+    try { localStorage.setItem(STORAGE_KEY_DENSITY, cols); } catch (e) {}
+    updateGridDensity(cols);
+  });
+
+  // Search
+  searchInput.addEventListener('input', debounce(function() {
+    try { localStorage.setItem(STORAGE_KEY_SEARCH, this.value); } catch (e) {}
+    applySearch(this.value);
+  }, 300));
+
+  function updateGridDensity(cols) {
+    const productGrid = document.querySelector('[role="list"]') || document.querySelector('.grid') || document.querySelector('[data-product-grid]');
+    if (productGrid) {
+      productGrid.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
+      productGrid.setAttribute('data-cols', cols);
+    }
+  }
+
+  function applySort(mode) {
+    const url = new URL(window.location);
+    if (mode === 'newest') {
+      url.searchParams.delete('sort_by');
+    } else {
+      // Map DW sort modes to Shopify's sort_by values
+      const sortMap = {
+        'title': 'title-ascending',
+        'price-asc': 'price-ascending',
+        'price-desc': 'price-descending'
+      };
+      url.searchParams.set('sort_by', sortMap[mode] || mode);
+    }
+    window.location.href = url.toString();
+  }
+
+  function applySearch(query) {
+    if (query.trim() === '') {
+      window.location.href = window.location.pathname;
+    } else {
+      const url = new URL(window.location);
+      url.searchParams.set('q', query);
+      window.location.href = url.toString();
+    }
+  }
+
+  function debounce(fn, delay) {
+    let timer;
+    return function(...args) {
+      clearTimeout(timer);
+      timer = setTimeout(() => fn.apply(this, args), delay);
+    };
+  }
+
+  // Initialize grid on page load
+  window.addEventListener('load', function() {
+    updateGridDensity(parseInt(densitySlider.value));
+  });
+})();
+</script>
+
+{% schema %}
+{
+  "name": "Collection Toolbar",
+  "description": "Horizontal sort, grid density, and search for collection pages",
+  "settings": [
+    {
+      "type": "checkbox",
+      "id": "show_sort",
+      "label": "Show sort dropdown",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_density",
+      "label": "Show grid density slider",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "show_search",
+      "label": "Show search input",
+      "default": true
+    },
+    {
+      "type": "range",
+      "id": "density_min",
+      "label": "Minimum columns",
+      "min": 2,
+      "max": 6,
+      "default": 3
+    },
+    {
+      "type": "range",
+      "id": "density_max",
+      "label": "Maximum columns",
+      "min": 6,
+      "max": 12,
+      "default": 12
+    },
+    {
+      "type": "range",
+      "id": "density_default",
+      "label": "Default columns",
+      "min": 2,
+      "max": 12,
+      "default": 4
+    }
+  ],
+  "presets": [
+    {
+      "name": "Collection Toolbar"
+    }
+  ]
+}
+{% endschema %}

← ce69f4cc Backup: live PDP section pre-MOQ-push (rollback source)  ·  back to Designer Wallcoverings  ·  Bucket B Coordonné roll-variant recovery script (feed-first, 248277a7 →