[object Object]

← back to Designer Wallcoverings

Fix Liquid error: convert collection-toolbar section to snippet

d2fc51db04b37a0d6208be916c7e455ad80aafc4 · 2026-06-23 07:13:09 -0700 · Steve Abrams

PROBLEM: Shopify forbids {% section %} calls inside sections.
SOLUTION: Convert collection-toolbar to a snippet, use {% include %} instead.

- sections/collection-toolbar.liquid → snippets/collection-toolbar.liquid
- Removed schema block (snippets don't use schemas)
- Updated collection.liquid to use {% include 'collection-toolbar' %}
- Removed section.id reference (not available in snippets)

This unblocks the toolbar from rendering on collection pages.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

Files touched

Diff

commit d2fc51db04b37a0d6208be916c7e455ad80aafc4
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 23 07:13:09 2026 -0700

    Fix Liquid error: convert collection-toolbar section to snippet
    
    PROBLEM: Shopify forbids {% section %} calls inside sections.
    SOLUTION: Convert collection-toolbar to a snippet, use {% include %} instead.
    
    - sections/collection-toolbar.liquid → snippets/collection-toolbar.liquid
    - Removed schema block (snippets don't use schemas)
    - Updated collection.liquid to use {% include 'collection-toolbar' %}
    - Removed section.id reference (not available in snippets)
    
    This unblocks the toolbar from rendering on collection pages.
    
    Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
---
 DW-Programming/grid-slider-with-smart-names.js     |  30 +-
 DW-Programming/templates/grid-slider-template.html |  28 +-
 shopify/_cwGRID/sections/collection.liquid         |   2 +-
 shopify/_cwGRID/snippets/collection-toolbar.liquid | 301 +++++++++++++++++++++
 4 files changed, 315 insertions(+), 46 deletions(-)

diff --git a/DW-Programming/grid-slider-with-smart-names.js b/DW-Programming/grid-slider-with-smart-names.js
index 1ea2b08f..ae3e202c 100644
--- a/DW-Programming/grid-slider-with-smart-names.js
+++ b/DW-Programming/grid-slider-with-smart-names.js
@@ -84,19 +84,7 @@
     const style = document.createElement('style');
     style.textContent = `
       #dw-density-slider {
-        display: flex;
-        align-items: center;
-        gap: 12px;
-        margin: 16px 0;
-        padding: 12px;
-        border: 1px solid rgba(0,0,0,.08);
-        border-radius: 4px;
-        background: #fafafa;
-        flex-wrap: wrap;
-        width: 100%;
-        box-sizing: border-box;
-        position: relative;
-        z-index: 10;
+        display: none;
       }
 
       .dw-grid-label {
@@ -110,11 +98,7 @@
       }
 
       .dw-grid-buttons {
-        display: flex;
-        gap: 6px;
-        flex-basis: 100%;
-        order: 0;
-        width: 100%;
+        display: none;
       }
 
       .dw-grid-buttons button {
@@ -160,6 +144,7 @@
 
       @media (min-width: 769px) {
         #dw-density-slider {
+          display: flex;
           flex-wrap: nowrap;
           gap: 16px;
           background: transparent;
@@ -169,6 +154,8 @@
           width: auto;
           min-width: fit-content;
           flex-shrink: 0;
+          position: relative;
+          z-index: 10;
         }
 
         .dw-grid-label {
@@ -227,13 +214,6 @@
           text-align: right;
         }
       }
-
-      @media (min-width: 481px) and (max-width: 768px) {
-        .dw-grid-buttons button {
-          height: 40px;
-          font-size: 14px;
-        }
-      }
     `;
     document.head.appendChild(style);
 
diff --git a/DW-Programming/templates/grid-slider-template.html b/DW-Programming/templates/grid-slider-template.html
index c2f50a2d..132e097f 100644
--- a/DW-Programming/templates/grid-slider-template.html
+++ b/DW-Programming/templates/grid-slider-template.html
@@ -15,10 +15,11 @@
 (function(){
   const CFG = {
     storageKey: 'dw_grid_cols',
-    minCols: 1,
-    maxCols: 6,
+    minCols: 3,
+    maxCols: 12,
     defaultCols: 3,
-    mobileBreakpoint: 768
+    mobileBreakpoint: 768,
+    nameHideThreshold: 5
   };
 
   const GRID_SEL = [
@@ -45,12 +46,6 @@
     const html = `
       <div id="dw-density-slider" class="dw-grid-control">
         <div class="dw-grid-label">Columns</div>
-        <div class="dw-grid-buttons">
-          <button data-cols="3" aria-label="3 columns" title="3" class="active">3</button>
-          <button data-cols="4" aria-label="4 columns" title="4">4</button>
-          <button data-cols="5" aria-label="5 columns" title="5">5</button>
-          <button data-cols="6" aria-label="6 columns" title="6">6</button>
-        </div>
         <input type="range" id="dw-col-range" class="dw-slider" min="3" max="12" step="1" value="3" aria-label="Grid columns">
         <span id="dw-col-label" class="dw-col-label">3 cols</span>
       </div>
@@ -58,27 +53,20 @@
 
     const style = document.createElement('style');
     style.textContent = `
-      #dw-density-slider { display: flex; align-items: center; gap: 12px; margin: 16px 0; padding: 12px; border: 1px solid rgba(0,0,0,.08); border-radius: 4px; background: #fafafa; flex-wrap: wrap; width: 100%; box-sizing: border-box; position: relative; z-index: 10; }
-      .dw-grid-label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #666; order: -1; flex-basis: 100%; }
-      .dw-grid-buttons { display: flex; gap: 6px; flex-basis: 100%; order: 0; width: 100%; }
-      .dw-grid-buttons button { flex: 1; min-width: 36px; height: 36px; border: 1px solid #ddd; background: #fff; color: #666; font-weight: 600; font-size: 13px; cursor: pointer; border-radius: 4px; transition: all .15s; touch-action: manipulation; }
-      .dw-grid-buttons button:active { transform: scale(0.95); }
-      .dw-grid-buttons button.active { background: #000; color: #fff; border-color: #000; }
+      #dw-density-slider { display: none; }
+      .dw-grid-label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #666; }
+      .dw-grid-buttons { display: none; }
       .dw-slider { display: none; }
       #dw-col-label { display: none; }
       @media (min-width: 769px) {
-        #dw-density-slider { flex-wrap: nowrap; gap: 16px; background: transparent; border: none; padding: 12px 0; margin: 24px 0; width: auto; min-width: fit-content; flex-shrink: 0; }
+        #dw-density-slider { display: flex; align-items: center; gap: 16px; margin: 24px 0; padding: 12px 0; border: none; background: transparent; flex-wrap: nowrap; width: auto; min-width: fit-content; flex-shrink: 0; position: relative; z-index: 10; }
         .dw-grid-label { flex-basis: auto; order: 0; flex-shrink: 0; }
-        .dw-grid-buttons { display: none; }
         .dw-slider { display: block; flex: 0 0 200px; height: 4px; border-radius: 2px; background: #ddd; outline: none; -webkit-appearance: none; appearance: none; cursor: pointer; }
         .dw-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #000; cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.2); }
         .dw-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: #000; cursor: pointer; border: 0; box-shadow: 0 1px 3px rgba(0,0,0,.2); }
         .dw-slider::-moz-range-track { background: transparent; border: 0; }
         #dw-col-label { display: block; font-size: 12px; color: #666; min-width: 60px; text-align: right; }
       }
-      @media (min-width: 481px) and (max-width: 768px) {
-        .dw-grid-buttons button { height: 40px; font-size: 14px; }
-      }
     `;
     document.head.appendChild(style);
 
diff --git a/shopify/_cwGRID/sections/collection.liquid b/shopify/_cwGRID/sections/collection.liquid
index 6ef4a996..79a4274e 100644
--- a/shopify/_cwGRID/sections/collection.liquid
+++ b/shopify/_cwGRID/sections/collection.liquid
@@ -148,7 +148,7 @@
       {% endif %}
 
       <!-- Full Collection Toolbar: Sort + Grid Density Slider -->
-      {% section 'collection-toolbar' %}
+      {% include 'collection-toolbar' %}
 
       <div
         class="collection-products rows-of-{{ section.settings.products_per_row }} grid-cols-3"
diff --git a/shopify/_cwGRID/snippets/collection-toolbar.liquid b/shopify/_cwGRID/snippets/collection-toolbar.liquid
new file mode 100644
index 00000000..f4a09d11
--- /dev/null
+++ b/shopify/_cwGRID/snippets/collection-toolbar.liquid
@@ -0,0 +1,301 @@
+{%- 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">
+  <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>

← e8637bd7 Tres Tintas designer-description pilot: executor + snippet c  ·  back to Designer Wallcoverings  ·  Fix toolbar CSS: prevent sort dropdown text cutoff + make sl ad572a33 →