← back to Dw Theme Frontpage Cta
snapshot: live theme 144396058675 index+sections before front-page CTA edit
ef9a8fdb63b85262d66647a32e134f9606b67df5 · 2026-07-20 15:25:30 -0700 · Steve Abrams
Files touched
A sections/404.liquidA sections/age-gate.liquidA sections/appointment-booking.liquidA sections/apps.liquidA sections/article.liquidA sections/blog-masonry.liquidA sections/blog.liquidA sections/cart-ajax.liquidA sections/cart.liquidA sections/collection-list.liquidA sections/collection.liquidA sections/contact-for-price.liquidA sections/custom-liquid.liquidA sections/dw-all-collections.liquidA sections/dw-boost-filter-topbar.liquidA sections/dw-collection-hero.liquidA sections/footer-group.jsonA sections/footer.liquidA sections/header-group.jsonA sections/header.liquidA sections/home-blog.liquidA sections/home-collections.liquidA sections/home-masonry.liquidA sections/home-message.liquidA sections/home-product.liquidA sections/home-products.liquidA sections/home-promotion.liquidA sections/home-slideshow.liquidA sections/home-testimonials.liquidA sections/home-video.liquidA sections/main-product-high-variant.liquidA sections/mini-ajax.liquidA sections/natural-wallcoverings.liquidA sections/new-arrivals-banner.liquidA sections/page-contact.liquidA sections/page-inquiry.liquidA sections/page.liquidA sections/password.liquidA sections/predictive-search.liquidA sections/product-ajax.liquidA sections/product.liquidA sections/pxs-announcement-bar.liquidA sections/pxs-image-with-text-overlay.liquidA sections/pxs-map.liquidA sections/pxs-newsletter.liquidA sections/recently-viewed.liquidA sections/static-product-recommendations.liquidA sections/surface-pick-up.liquidA sections/template-search.liquidA templates/index.json
Diff
commit ef9a8fdb63b85262d66647a32e134f9606b67df5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jul 20 15:25:30 2026 -0700
snapshot: live theme 144396058675 index+sections before front-page CTA edit
---
sections/404.liquid | 15 +
sections/age-gate.liquid | 45 ++
sections/appointment-booking.liquid | 299 +++++++++++
sections/apps.liquid | 25 +
sections/article.liquid | 185 +++++++
sections/blog-masonry.liquid | 96 ++++
sections/blog.liquid | 111 ++++
sections/cart-ajax.liquid | 16 +
sections/cart.liquid | 145 +++++
sections/collection-list.liquid | 168 ++++++
sections/collection.liquid | 21 +
sections/contact-for-price.liquid | 184 +++++++
sections/custom-liquid.liquid | 34 ++
sections/dw-all-collections.liquid | 6 +
sections/dw-boost-filter-topbar.liquid | 514 ++++++++++++++++++
sections/dw-collection-hero.liquid | 90 ++++
sections/footer-group.json | 65 +++
sections/footer.liquid | 497 +++++++++++++++++
sections/header-group.json | 127 +++++
sections/header.liquid | 589 ++++++++++++++++++++
sections/home-blog.liquid | 92 ++++
sections/home-collections.liquid | 174 ++++++
sections/home-masonry.liquid | 235 ++++++++
sections/home-message.liquid | 94 ++++
sections/home-product.liquid | 298 +++++++++++
sections/home-products.liquid | 91 ++++
sections/home-promotion.liquid | 196 +++++++
sections/home-slideshow.liquid | 281 ++++++++++
sections/home-testimonials.liquid | 142 +++++
sections/home-video.liquid | 495 +++++++++++++++++
sections/main-product-high-variant.liquid | 50 ++
sections/mini-ajax.liquid | 12 +
sections/natural-wallcoverings.liquid | 77 +++
sections/new-arrivals-banner.liquid | 55 ++
sections/page-contact.liquid | 38 ++
sections/page-inquiry.liquid | 364 +++++++++++++
sections/page.liquid | 11 +
sections/password.liquid | 112 ++++
sections/predictive-search.liquid | 219 ++++++++
sections/product-ajax.liquid | 274 ++++++++++
sections/product.liquid | 712 +++++++++++++++++++++++++
sections/pxs-announcement-bar.liquid | 101 ++++
sections/pxs-image-with-text-overlay.liquid | 238 +++++++++
sections/pxs-map.liquid | 343 ++++++++++++
sections/pxs-newsletter.liquid | 144 +++++
sections/recently-viewed.liquid | 143 +++++
sections/static-product-recommendations.liquid | 99 ++++
sections/surface-pick-up.liquid | 141 +++++
sections/template-search.liquid | 7 +
templates/index.json | 382 +++++++++++++
50 files changed, 8852 insertions(+)
diff --git a/sections/404.liquid b/sections/404.liquid
new file mode 100644
index 0000000..a7004b5
--- /dev/null
+++ b/sections/404.liquid
@@ -0,0 +1,15 @@
+<h1 class="page-title">
+ {{ 'general.404.header' | t }}
+</h1>
+
+{% render 'breadcrumbs' %}
+
+<div class="four-oh-four rte">
+ {% capture searchLink %}
+ <a href="{{ routes.search_url }}">{{ 'general.404.search_link' | t }}</a>
+ {% endcapture %}
+ {% capture collectionLink %}
+ <a href="{{ routes.all_products_collection_url }}">{{ 'general.404.collection_link' | t }}</a>
+ {% endcapture %}
+ <p>{{ 'general.404.message_html' | t: search_link: searchLink, collection_link: collectionLink }}</p>
+</div>
diff --git a/sections/age-gate.liquid b/sections/age-gate.liquid
new file mode 100644
index 0000000..4444c8f
--- /dev/null
+++ b/sections/age-gate.liquid
@@ -0,0 +1,45 @@
+{% liquid
+ capture _
+ echo settings.show_age_gate_logo
+ endcapture
+%}
+
+<script
+ type="application/json"
+ data-section-type="age-gate"
+ data-section-id="{{ section.id }}"
+ data-section-data
+ data-required-age="||{{ section.settings.min_age }}||"
+>
+ {% assign age_gate_id = template.directory | append: template.name | append: template.suffix %}
+ {
+ "id": {{ age_gate_id | json }},
+ "required_age": {{ section.settings.min_age | json }}
+ }
+</script>
+
+{% schema %}
+ {
+ "name": "t:sections.age_gate.name",
+ "class": "shopify-section__age-gate",
+ "settings": [
+ {
+ "type": "number",
+ "id": "min_age",
+ "label": "t:sections.age_gate.minimum_age.label",
+ "default": 18
+ }
+ ],
+ "presets": [
+ {
+ "category": "t:sections.age_gate.presets.category",
+ "name": "t:sections.age_gate.presets.name"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+ }
+{% endschema %}
diff --git a/sections/appointment-booking.liquid b/sections/appointment-booking.liquid
new file mode 100644
index 0000000..cbf2c8c
--- /dev/null
+++ b/sections/appointment-booking.liquid
@@ -0,0 +1,299 @@
+{%- comment -%}
+ appointment-booking.liquid — Designer Wallcoverings appointment scheduler.
+
+ Self-contained OS-2.0 section. All CSS/JS scoped to #appt-{{ section.id }} so it
+ never collides with the theme. Talks to the DW appointments API (the mountable
+ router in shopify/quote-api/appointments) via fetch — availability + book.
+
+ Settings (Theme Editor):
+ api_base backend origin, e.g. https://www.designerwallcoverings.com
+ owner_email calendar owner (info@designerwallcoverings.com)
+ heading / intro page copy
+ in_person_note small print under the In-person option
+ days_ahead how many days forward to offer
+{%- endcomment -%}
+
+{%- assign api_base = section.settings.api_base | default: 'https://api.designerwallcoverings.com' | strip -%}
+{%- assign owner_email = section.settings.owner_email | default: 'info@designerwallcoverings.com' | strip -%}
+{%- assign days_ahead = section.settings.days_ahead | default: 21 -%}
+
+<section id="appt-{{ section.id }}" class="appt-root" data-api="{{ api_base }}" data-owner="{{ owner_email }}" data-days="{{ days_ahead }}">
+ <div class="appt-wrap">
+ <p class="appt-kicker">{{ section.settings.kicker | default: 'Designer Wallcoverings' }}</p>
+ <h2 class="appt-h">{{ section.settings.heading | default: 'Book an appointment' }}</h2>
+ {%- if section.settings.intro != blank -%}<p class="appt-intro">{{ section.settings.intro }}</p>{%- endif -%}
+
+ <div class="appt-card">
+ <!-- STEP 1 — type -->
+ <div class="appt-step">
+ <div class="appt-step-t"><span>1</span> How would you like to meet?</div>
+ <div class="appt-types" role="radiogroup" aria-label="Appointment type">
+ <button type="button" class="appt-type is-active" data-type="phone" role="radio" aria-checked="true">
+ <span class="appt-type-ic" aria-hidden="true">☎</span>
+ <span class="appt-type-l">Phone call</span>
+ <span class="appt-type-s">We call you · 1 hour</span>
+ </button>
+ <button type="button" class="appt-type" data-type="in_person" role="radio" aria-checked="false">
+ <span class="appt-type-ic" aria-hidden="true">⌖</span>
+ <span class="appt-type-l">In person at DW</span>
+ <span class="appt-type-s">{{ section.settings.in_person_note | default: 'At our Sherman Oaks showroom · 1 hour' }}</span>
+ </button>
+ </div>
+ </div>
+
+ <!-- STEP 2 — day -->
+ <div class="appt-step">
+ <div class="appt-step-t"><span>2</span> Choose a day</div>
+ <div class="appt-pager">
+ <button type="button" class="appt-pg" data-pg="prev" aria-label="Earlier days">‹</button>
+ <span class="appt-range" aria-live="polite"></span>
+ <button type="button" class="appt-pg" data-pg="next" aria-label="Later days">›</button>
+ </div>
+ <div class="appt-days" role="listbox" aria-label="Available days"></div>
+ </div>
+
+ <!-- STEP 3 — time -->
+ <div class="appt-step">
+ <div class="appt-step-t"><span>3</span> Choose a time <em>(Pacific)</em></div>
+ <div class="appt-slots" aria-live="polite"><p class="appt-hint">Pick a day above to see open times.</p></div>
+ </div>
+
+ <!-- STEP 4 — details -->
+ <form class="appt-form" novalidate>
+ <div class="appt-step-t"><span>4</span> Your details</div>
+ <div class="appt-grid">
+ <label class="appt-field"><span>Name</span><input name="name" required autocomplete="name"></label>
+ <label class="appt-field"><span>Email</span><input name="email" type="email" required autocomplete="email"></label>
+ <label class="appt-field" data-phone><span>Phone <em class="appt-req">(required)</em></span><input name="phone" type="tel" autocomplete="tel"></label>
+ <label class="appt-field appt-span"><span>What would you like to discuss? <em>(optional)</em></span><textarea name="notes" rows="3" placeholder="Rooms, patterns, square footage, timeline…"></textarea></label>
+ </div>
+ <div class="appt-foot">
+ <p class="appt-sel"><em>Select a type, day and time above.</em></p>
+ <button type="submit" class="appt-book" disabled>Confirm appointment</button>
+ </div>
+ <div class="appt-msg" role="status" aria-live="assertive"></div>
+ </form>
+ </div>
+
+ <!-- SUCCESS -->
+ <div class="appt-done" hidden>
+ <div class="appt-done-ic" aria-hidden="true">✓</div>
+ <h3>You're booked.</h3>
+ <p class="appt-done-when"></p>
+ <div class="appt-done-actions">
+ <a class="appt-book appt-ics" href="#">Add to calendar</a>
+ <a class="appt-ghost appt-conf" href="#" target="_blank" rel="noopener">View confirmation</a>
+ </div>
+ <button type="button" class="appt-again">Book another</button>
+ </div>
+ </div>
+</section>
+
+<style>
+ #appt-{{ section.id }}.appt-root{
+ --bg:#f7f4ef;--card:#fff;--ink:#2a2622;--soft:#6b6357;--rule:#e7e1d7;
+ --gold:#9c7a3c;--accent:#2a2622;--accent-ink:#fff;--active:#f3ece0;
+ background:var(--bg);color:var(--ink);padding:48px 18px;
+ font-family:{{ section.settings.body_font_stack | default: "-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif" }};
+ }
+ #appt-{{ section.id }} *{box-sizing:border-box}
+ #appt-{{ section.id }} .appt-wrap{max-width:760px;margin:0 auto}
+ #appt-{{ section.id }} .appt-kicker{font-size:11px;letter-spacing:.34em;text-transform:uppercase;color:var(--gold);font-weight:600;margin:0 0 8px}
+ #appt-{{ section.id }} .appt-h{font-family:'Cormorant Garamond',Georgia,serif;font-weight:600;font-size:40px;line-height:1.05;margin:0 0 10px}
+ #appt-{{ section.id }} .appt-intro{color:var(--soft);font-size:16px;margin:0 0 26px;max-width:54ch}
+ #appt-{{ section.id }} .appt-card{background:var(--card);border:1px solid var(--rule);border-radius:16px;padding:28px;box-shadow:0 30px 60px -42px rgba(42,38,34,.45)}
+ #appt-{{ section.id }} .appt-step{padding:6px 0 22px;border-bottom:1px solid var(--rule);margin-bottom:22px}
+ #appt-{{ section.id }} .appt-step-t{display:flex;align-items:center;gap:10px;font-size:13px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);font-weight:600;margin-bottom:14px}
+ #appt-{{ section.id }} .appt-step-t em{font-style:normal;color:var(--soft);text-transform:none;letter-spacing:0;font-weight:400}
+ #appt-{{ section.id }} .appt-step-t span{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background:var(--accent);color:var(--accent-ink);font-size:12px}
+ #appt-{{ section.id }} .appt-types{display:grid;grid-template-columns:1fr 1fr;gap:12px}
+ #appt-{{ section.id }} .appt-type{display:flex;flex-direction:column;align-items:flex-start;gap:3px;text-align:left;padding:16px;border:1px solid var(--rule);border-radius:12px;background:#fff;cursor:pointer;transition:.15s}
+ #appt-{{ section.id }} .appt-type:hover{border-color:var(--gold)}
+ #appt-{{ section.id }} .appt-type.is-active{border-color:var(--accent);background:var(--active);box-shadow:inset 0 0 0 1px var(--accent)}
+ #appt-{{ section.id }} .appt-type-ic{font-size:20px}
+ #appt-{{ section.id }} .appt-type-l{font-weight:600;font-size:15px}
+ #appt-{{ section.id }} .appt-type-s{font-size:12.5px;color:var(--soft)}
+ #appt-{{ section.id }} .appt-pager{display:flex;align-items:center;gap:14px;margin-bottom:12px}
+ #appt-{{ section.id }} .appt-pg{width:34px;height:34px;border:1px solid var(--rule);background:#fff;border-radius:8px;cursor:pointer;font-size:18px;line-height:1;color:var(--ink)}
+ #appt-{{ section.id }} .appt-pg:disabled{opacity:.32;cursor:not-allowed}
+ #appt-{{ section.id }} .appt-range{font-size:13px;color:var(--soft);letter-spacing:.04em}
+ #appt-{{ section.id }} .appt-days{display:grid;grid-template-columns:repeat(7,1fr);gap:7px}
+ #appt-{{ section.id }} .appt-day{padding:10px 2px;border:1px solid var(--rule);border-radius:9px;background:#fff;text-align:center;cursor:pointer;transition:.12s}
+ #appt-{{ section.id }} .appt-day:hover:not(.is-off){border-color:var(--gold)}
+ #appt-{{ section.id }} .appt-day.is-active{border-color:var(--accent);background:var(--active);box-shadow:inset 0 0 0 1px var(--accent)}
+ #appt-{{ section.id }} .appt-day.is-off{opacity:.34;cursor:not-allowed}
+ #appt-{{ section.id }} .appt-day .dow{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--soft)}
+ #appt-{{ section.id }} .appt-day .num{font-family:'Cormorant Garamond',Georgia,serif;font-size:22px;line-height:1;margin-top:3px}
+ #appt-{{ section.id }} .appt-slots{display:grid;grid-template-columns:repeat(auto-fill,minmax(108px,1fr));gap:8px;min-height:46px}
+ #appt-{{ section.id }} .appt-slot{padding:11px 6px;border:1px solid var(--rule);border-radius:8px;background:#fff;cursor:pointer;font-size:14px;text-align:center;transition:.12s}
+ #appt-{{ section.id }} .appt-slot:hover{border-color:var(--gold)}
+ #appt-{{ section.id }} .appt-slot.is-active{border-color:var(--accent);background:var(--accent);color:var(--accent-ink)}
+ #appt-{{ section.id }} .appt-hint,#appt-{{ section.id }} .appt-empty{grid-column:1/-1;color:var(--soft);font-style:italic;font-size:14px;padding:6px 0}
+ #appt-{{ section.id }} .appt-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
+ #appt-{{ section.id }} .appt-span{grid-column:1/-1}
+ #appt-{{ section.id }} .appt-field{display:block}
+ #appt-{{ section.id }} .appt-field>span{display:block;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--soft);margin-bottom:6px}
+ #appt-{{ section.id }} .appt-field em{text-transform:none;letter-spacing:0;color:var(--soft)}
+ #appt-{{ section.id }} .appt-field input,#appt-{{ section.id }} .appt-field textarea{width:100%;padding:12px;border:1px solid var(--rule);border-radius:9px;font:inherit;font-size:15px;color:var(--ink);background:#fff}
+ #appt-{{ section.id }} .appt-field input:focus,#appt-{{ section.id }} .appt-field textarea:focus{outline:none;border-color:var(--accent)}
+ #appt-{{ section.id }} .appt-foot{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:20px;flex-wrap:wrap}
+ #appt-{{ section.id }} .appt-sel{font-size:14px;color:var(--soft);margin:0}
+ #appt-{{ section.id }} .appt-sel strong{color:var(--ink)}
+ #appt-{{ section.id }} .appt-book{background:var(--accent);color:var(--accent-ink);border:none;border-radius:9px;padding:14px 26px;font-size:13px;letter-spacing:.06em;font-weight:600;cursor:pointer;text-decoration:none;display:inline-block}
+ #appt-{{ section.id }} .appt-book:disabled{opacity:.4;cursor:not-allowed}
+ #appt-{{ section.id }} .appt-ghost{border:1px solid var(--rule);border-radius:9px;padding:14px 26px;font-size:13px;color:var(--ink);text-decoration:none;display:inline-block}
+ #appt-{{ section.id }} .appt-msg{margin-top:14px;font-size:14px}
+ #appt-{{ section.id }} .appt-msg.is-err{color:#9a3b3b}
+ #appt-{{ section.id }} .appt-done{text-align:center;background:var(--card);border:1px solid var(--rule);border-radius:16px;padding:44px 28px}
+ #appt-{{ section.id }} .appt-done-ic{width:54px;height:54px;border-radius:50%;background:#eef7ee;color:#2f6b2f;font-size:26px;display:flex;align-items:center;justify-content:center;margin:0 auto 14px}
+ #appt-{{ section.id }} .appt-done h3{font-family:'Cormorant Garamond',Georgia,serif;font-size:30px;margin:0 0 6px}
+ #appt-{{ section.id }} .appt-done-when{color:var(--soft);margin:0 0 22px}
+ #appt-{{ section.id }} .appt-done-actions{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
+ #appt-{{ section.id }} .appt-again{margin-top:18px;background:none;border:none;color:var(--gold);cursor:pointer;font-size:13px;text-decoration:underline}
+ @media (max-width:560px){
+ #appt-{{ section.id }} .appt-h{font-size:30px}
+ #appt-{{ section.id }} .appt-types,#appt-{{ section.id }} .appt-grid{grid-template-columns:1fr}
+ #appt-{{ section.id }} .appt-days{grid-template-columns:repeat(4,1fr)}
+ }
+</style>
+
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600&display=swap" media="print" onload="this.media='all'">
+
+<script>
+(function(){
+ var root = document.getElementById('appt-{{ section.id }}');
+ if(!root || root.dataset.bound) return; root.dataset.bound='1';
+ var API = root.dataset.api.replace(/\/+$/,''), OWNER = root.dataset.owner, DAYS = parseInt(root.dataset.days,10)||21;
+ var $ = function(s){return root.querySelector(s)}, $$ = function(s){return [].slice.call(root.querySelectorAll(s))};
+ var state = {type:'phone', date:null, slot:null, pageStart:0};
+ var availCache = {}; // iso -> slots[]
+
+ function fmtTime(iso){return new Date(iso).toLocaleTimeString([], {hour:'numeric',minute:'2-digit',timeZone:'America/Los_Angeles'});}
+ function fmtLong(iso){return new Date(iso).toLocaleString([], {weekday:'long',month:'long',day:'numeric',hour:'numeric',minute:'2-digit',timeZone:'America/Los_Angeles'});}
+ function isoOf(d){return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');}
+
+ // ── type ──
+ $$('.appt-type').forEach(function(b){b.addEventListener('click',function(){
+ state.type=b.dataset.type;
+ $$('.appt-type').forEach(function(x){var on=x===b;x.classList.toggle('is-active',on);x.setAttribute('aria-checked',on);});
+ var pf=$('.appt-field[data-phone]'); var req=pf.querySelector('.appt-req');
+ if(state.type==='phone'){req.textContent='(required)';} else {req.textContent='(optional)';}
+ updateFoot();
+ });});
+
+ // ── days ──
+ function renderDays(){
+ var wrap=$('.appt-days'), now=new Date(), html='', first=null, last=null;
+ for(var i=0;i<7;i++){
+ var idx=state.pageStart+i; if(idx>=DAYS) break;
+ var d=new Date(now.getFullYear(),now.getMonth(),now.getDate()+idx);
+ var iso=isoOf(d), dow=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][d.getDay()];
+ var off=(d.getDay()===0||d.getDay()===6); // weekends closed (9–4 Mon–Fri)
+ if(!first)first=d; last=d;
+ html+='<div class="appt-day'+(off?' is-off':'')+(state.date===iso?' is-active':'')+'" data-iso="'+iso+'" role="option" aria-selected="'+(state.date===iso)+'"'+(off?'':' tabindex="0"')+'><div class="dow">'+dow+'</div><div class="num">'+d.getDate()+'</div></div>';
+ }
+ wrap.innerHTML=html;
+ $('.appt-range').textContent = first&&last ? first.toLocaleDateString([],{month:'short',day:'numeric'})+' – '+last.toLocaleDateString([],{month:'short',day:'numeric'}) : '';
+ $('.appt-pg[data-pg="prev"]').disabled = state.pageStart===0;
+ $('.appt-pg[data-pg="next"]').disabled = state.pageStart+7>=DAYS;
+ $$('.appt-day').forEach(function(el){
+ if(el.classList.contains('is-off')) return;
+ var pick=function(){selectDay(el.dataset.iso);};
+ el.addEventListener('click',pick);
+ el.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();pick();}});
+ });
+ }
+ $('.appt-pg[data-pg="prev"]').addEventListener('click',function(){state.pageStart=Math.max(0,state.pageStart-7);renderDays();});
+ $('.appt-pg[data-pg="next"]').addEventListener('click',function(){if(state.pageStart+7<DAYS){state.pageStart+=7;renderDays();}});
+
+ function selectDay(iso){
+ state.date=iso; state.slot=null; renderDays(); updateFoot();
+ var box=$('.appt-slots'); box.innerHTML='<p class="appt-hint">Loading open times…</p>';
+ var done=function(slots){availCache[iso]=slots;renderSlots(slots);};
+ if(availCache[iso]) return done(availCache[iso]);
+ fetch(API+'/api/appointments/availability?owner_email='+encodeURIComponent(OWNER)+'&date='+iso)
+ .then(function(r){return r.json();})
+ .then(function(j){ if(!j.ok) throw new Error(j.error||'load failed'); done(j.slots||[]); })
+ .catch(function(e){ box.innerHTML='<p class="appt-empty">Could not load times ('+e.message+'). Please try again.</p>'; });
+ }
+
+ function renderSlots(slots){
+ var box=$('.appt-slots');
+ if(!slots.length){ box.innerHTML='<p class="appt-empty">No open times that day — try another.</p>'; return; }
+ box.innerHTML = slots.map(function(s){
+ var on=state.slot&&state.slot.slot_start===s.slot_start;
+ return '<button type="button" class="appt-slot'+(on?' is-active':'')+'" data-s="'+s.slot_start+'" data-e="'+s.slot_end+'">'+fmtTime(s.slot_start)+'</button>';
+ }).join('');
+ $$('.appt-slot').forEach(function(el){el.addEventListener('click',function(){
+ state.slot={slot_start:el.dataset.s,slot_end:el.dataset.e};
+ $$('.appt-slot').forEach(function(x){x.classList.toggle('is-active',x===el);});
+ updateFoot();
+ });});
+ }
+
+ function updateFoot(){
+ var sel=$('.appt-sel'), btn=$('.appt-book');
+ if(state.slot){
+ sel.innerHTML='Selected: <strong>'+fmtLong(state.slot.slot_start)+'</strong> Pacific';
+ btn.disabled=false;
+ } else { sel.innerHTML='<em>Select a type, day and time above.</em>'; btn.disabled=true; }
+ }
+
+ // ── submit ──
+ $('.appt-form').addEventListener('submit',function(ev){
+ ev.preventDefault();
+ if(!state.slot) return;
+ var f=ev.target, msg=$('.appt-msg'); msg.textContent=''; msg.className='appt-msg';
+ var name=f.name.value.trim(), email=f.email.value.trim(), phone=f.phone.value.trim(), notes=f.notes.value.trim();
+ if(!name||!email){ msg.textContent='Please enter your name and email.'; msg.className='appt-msg is-err'; return; }
+ if(state.type==='phone'&&!phone){ msg.textContent='A phone number is required for a phone appointment.'; msg.className='appt-msg is-err'; f.phone.focus(); return; }
+ var btn=$('.appt-book'); btn.disabled=true; var prev=btn.textContent; btn.textContent='Booking…';
+ fetch(API+'/api/appointments/book',{method:'POST',headers:{'Content-Type':'application/json'},
+ body:JSON.stringify({name:name,email:email,phone:phone,notes:notes,appointment_type:state.type,
+ owner_email:OWNER,slot_start:state.slot.slot_start,slot_end:state.slot.slot_end})})
+ .then(function(r){return r.json();})
+ .then(function(j){
+ if(!j.ok) throw new Error(j.error||'Could not book');
+ var d=root.querySelector('.appt-done');
+ d.querySelector('.appt-done-when').textContent=fmtLong(state.slot.slot_start)+' Pacific · '+(state.type==='in_person'?'In person at DW':'Phone call');
+ d.querySelector('.appt-ics').setAttribute('href', j.ics_url);
+ d.querySelector('.appt-conf').setAttribute('href', j.confirmation_url);
+ root.querySelector('.appt-card').hidden=true; d.hidden=false;
+ d.scrollIntoView({behavior:'smooth',block:'center'});
+ })
+ .catch(function(e){
+ msg.textContent=e.message; msg.className='appt-msg is-err'; btn.disabled=false; btn.textContent=prev;
+ if(/taken|available/i.test(e.message)&&state.date){ delete availCache[state.date]; selectDay(state.date); }
+ });
+ });
+
+ $('.appt-again').addEventListener('click',function(){
+ state.slot=null; availCache={}; root.querySelector('.appt-done').hidden=true;
+ root.querySelector('.appt-card').hidden=false; $('.appt-form').reset();
+ $('.appt-slots').innerHTML='<p class="appt-hint">Pick a day above to see open times.</p>';
+ if(state.date) selectDay(state.date); updateFoot();
+ });
+
+ renderDays();
+})();
+</script>
+
+{% schema %}
+{
+ "name": "Appointment Booking",
+ "tag": "section",
+ "class": "section-appointment-booking",
+ "settings": [
+ { "type": "header", "content": "Backend" },
+ { "type": "text", "id": "api_base", "label": "Appointments API base URL", "default": "https://api.designerwallcoverings.com", "info": "Origin of the DW appointments service (Kamatera koroseal-quote-api behind api.designerwallcoverings.com). CORS is handled server-side." },
+ { "type": "text", "id": "owner_email", "label": "Calendar owner email", "default": "info@designerwallcoverings.com" },
+ { "type": "range", "id": "days_ahead", "min": 7, "max": 63, "step": 7, "unit": "d", "label": "Days bookable ahead", "default": 21 },
+ { "type": "header", "content": "Copy" },
+ { "type": "text", "id": "kicker", "label": "Kicker", "default": "Designer Wallcoverings" },
+ { "type": "text", "id": "heading", "label": "Heading", "default": "Book an appointment" },
+ { "type": "richtext", "id": "intro", "label": "Intro", "default": "<p>Speak with a Designer Wallcoverings consultant by phone, or visit us in person. Appointments run one hour, weekdays 9 AM–4 PM Pacific.</p>" },
+ { "type": "text", "id": "in_person_note", "label": "In-person sub-label", "default": "At our Sherman Oaks showroom · 1 hour" }
+ ],
+ "presets": [{ "name": "Appointment Booking" }]
+}
+{% endschema %}
diff --git a/sections/apps.liquid b/sections/apps.liquid
new file mode 100644
index 0000000..6e97981
--- /dev/null
+++ b/sections/apps.liquid
@@ -0,0 +1,25 @@
+<section class="product-app--container">
+ <div class="container">
+ <div class="one-whole column">
+ {% for block in section.blocks %}
+ {% render block %}
+ {% endfor %}
+ </div>
+ </div>
+</section>
+
+{% schema %}
+ {
+ "name": "App wrapper",
+ "blocks": [
+ {
+ "type": "@app"
+ }
+ ],
+ "presets": [
+ {
+ "name": "App wrapper"
+ }
+ ]
+ }
+{% endschema %}
diff --git a/sections/article.liquid b/sections/article.liquid
new file mode 100644
index 0000000..752cf30
--- /dev/null
+++ b/sections/article.liquid
@@ -0,0 +1,185 @@
+<script
+ type="application/json"
+ data-section-id="{{ section.id }}"
+ data-section-type="static-article"
+>
+</script>
+
+<section
+ class="article">
+ <h2 class="page-title">{{ blog.title }}</h2>
+
+ {% render 'breadcrumbs' %}
+
+ {% render 'section-blog-sidebar' %}
+
+ <div class="blog-post-wrapper">
+ {% render 'section-article-post' %}
+
+ {% if blog.next_article or blog.previous_article %}
+ <div class="single-post-pagination">
+ {% if blog.previous_article %}<a class="previous" href="{{ blog.previous_article }}"></a>{% endif %}
+ {% if blog.next_article %}<a class="next" href="{{ blog.next_article }}"></a>{% endif %}
+ </div>
+ {% endif %}
+
+ {% if article.comments_enabled? %}
+
+ <div class="post-comments">
+
+ {% if article.comments_count > 0 %}
+ <div class="post-comments-list">
+
+ {% if section.settings.comment-count %}
+ <h3>{{ 'blogs.article_item.comment_count' | t: count: article.comments_count }}</h3>
+ {% endif %}
+
+ {% paginate article.comments by 10 %}
+ {% for comment in article.comments %}
+ <div class="post-comment {% render 'for-looper', forloop: forloop %}" id="comment-{{ comment.id }}">
+ <span class="post-comment-date">{{ comment.created_at | date: format: 'short_month' }}</span>
+ <div class="rte">{{ comment.content }}</div>
+ <div class="post-comment-details">
+ {% if section.settings.comment-author-avatar %}
+ <img class="post-comment-author-avatar" src="http://www.gravatar.com/avatar/{{ comment.email | remove: ' ' | strip_newlines | downcase | md5 }}" />
+ {% endif %}
+ <span class="post-comment-author-name">{{ comment.author }}</span>
+ </div>
+ </div>
+ {% endfor %}
+
+ {% if paginate.previous or paginate.next %}
+ {% render 'pagination', paginate: paginate %}
+ {% endif %}
+
+ {% endpaginate %}
+ </div>
+ {% endif %}
+
+ <div class="post-comments-submit">
+ <h3>{{ 'blogs.article_item.leave_a_comment' | t }}</h3>
+
+ {% form article %}
+
+ {% if form.posted_successfully? %}
+ <p>
+ {% if blog.moderated? %}
+ {{ 'blogs.article_item.comment_pending' | t }}
+ {% else %}
+ {{ 'blogs.article_item.comment_success' | t }}
+ {% endif %}
+ </p>
+ {% endif %}
+
+ {% if form.errors %}
+ <p class="error-message">{{ 'blogs.article_item.comment_error' | t }}</p>
+ {% endif %}
+
+ <div class="input-wrapper">
+ <label class="label" for="comment[author]">{{ 'general.general.name' | t }} {{ form.errors.messages["author"] }}</label>
+ <input {% if form.errors contains 'author' %}class="error input"{% else %}class="input"{% endif %} type="text" placeholder="Name" value="{{ form.author }}" name="comment[author]" required>
+ </div>
+
+ <div class="input-wrapper">
+ <label class="label" for="comment[email]">{{ 'general.general.email' | t }} {{ form.errors.messages["email"] }}</label>
+ <input {% if form.errors contains 'email' %}class="error input"{% else %}class="input"{% endif %} type="email" placeholder="{{ 'general.general.email_placeholder' | t }}" value="{{ form.email }}" name="comment[email]" required>
+ </div>
+
+ <div class="input-wrapper">
+ <label class="label" for="comment[body]">{{ 'general.general.message' | t }} {{ form.errors.messages["body"] }}</label>
+ <textarea {% if form.errors contains 'body' %}class="error textarea"{% else %}class="textarea"{% endif %} name="comment[body]" required>{{ form.body }}</textarea>
+ </div>
+
+ <div class="input-wrapper">
+ <input type="submit" class="input" value="{{ 'blogs.article_item.submit' | t }}">
+ </div>
+
+ {% endform %}
+ </div>
+
+ </div>
+ {% endif %}
+ </div>
+
+ {%- for block in section.blocks -%}
+ {%- case block.type -%}
+ {%- when 'promotional-image' -%}
+ {% render 'block-blog-promo', block: block %}
+ {%- endcase -%}
+ {%- endfor -%}
+</section>
+
+{% schema %}
+{
+ "name": "Article",
+ "class": "shopify-section--main",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "rss-icon",
+ "label": "Show subscribe link"
+ },
+ {
+ "type": "checkbox",
+ "id": "comment-count",
+ "label": "Show comment count"
+ },
+ {
+ "type": "checkbox",
+ "id": "tags",
+ "label": "Show tags"
+ },
+ {
+ "type": "checkbox",
+ "id": "author",
+ "label": "Show post author"
+ },
+ {
+ "type": "checkbox",
+ "id": "author-avatar",
+ "label": "Show post author avatar",
+ "info": "We pull author avatars from Gravatar. [More info](http:\/\/docs.shopify.com\/manual\/settings\/account\/staff-members#change-staff-account-picture)"
+ },
+ {
+ "type": "checkbox",
+ "id": "comment-author-avatar",
+ "label": "Show avatars on post comments"
+ },
+ {
+ "type": "checkbox",
+ "id": "share-buttons",
+ "label": "Show share icons"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "promotional-image",
+ "name": "Promotional image",
+ "settings": [
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Image"
+ },
+ {
+ "type": "text",
+ "id": "heading",
+ "label": "Heading"
+ },
+ {
+ "type": "text",
+ "id": "subtitle",
+ "label": "Subheading"
+ },
+ {
+ "type": "url",
+ "id": "url",
+ "label": "Link"
+ }
+ ],
+ "limit": 1
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/blog-masonry.liquid b/sections/blog-masonry.liquid
new file mode 100644
index 0000000..3ebc9d6
--- /dev/null
+++ b/sections/blog-masonry.liquid
@@ -0,0 +1,96 @@
+<script
+ type="application/json"
+ data-section-type="static-blog-masonry"
+ data-section-id="{{ section.id }}"
+>
+</script>
+
+{% assign emphasis_first_post = false %}
+{% if section.settings.emphasis_first_post %}
+ {% assign emphasis_first_post = true %}
+{% endif %}
+
+<section>
+ <h1 class="page-title">{{ blog.title }}</h1>
+
+ {% render 'breadcrumbs' %}
+
+ <div class="blog-wrapper-masonry">
+ {% paginate blog.articles by section.settings.articles_per_page %}
+
+ {%- comment -%} DW infinite scroll: wrapper carries the next-page URL; dw-native-infinite.js appends on scroll (masonry sizer is skipped to avoid duplication). {%- endcomment -%}
+ <div
+ data-dw-infinite
+ data-dw-infinite-items=".blog-posts-masonry"
+ data-dw-infinite-next="{% if paginate.next %}{{ paginate.next.url }}{% endif %}"
+ data-dw-infinite-page="{{ paginate.current_page }}"
+ >
+ <div class="blog-posts-masonry masonry-grid" data-masonry-grid>
+ <div class="masonry-grid-sizer" data-masonry-sizer></div>
+
+ {% for article in blog.articles %}
+ {% assign is_emphasized = false %}
+
+ {%- if emphasis_first_post -%}
+ {% comment %}
+ Don't emphasize post if:
+ - is not first page
+ - if tags are active
+ - is not first in loop
+ {% endcomment %}
+ {%- if paginate.current_page == 1 and current_tags == blank and forloop.first -%}
+ {% assign is_emphasized = true %}
+ {%- endif -%}
+ {%- endif -%}
+
+ {%
+ render 'section-blog-post-masonry',
+ article: article,
+ is_emphasized: is_emphasized
+ %}
+ {% else %}
+ <div class="blog-post-masonry masonry-grid-item" data-masonry-item>
+ <span class="empty">
+ {{ 'blogs.blog.empty' | t }}
+ </span>
+ </div>
+
+ {% endfor %}
+ </div>
+
+ {% if paginate.previous or paginate.next %}
+ <div data-dw-infinite-pager>
+ {% render 'pagination', paginate: paginate %}
+ </div>
+ {% endif %}
+ </div>
+
+ {% endpaginate %}
+ </div>
+</section>
+
+<script src="{{ 'dw-native-infinite.js' | asset_url }}" defer></script>
+
+{% schema %}
+
+{
+ "name": "Blog",
+ "settings": [
+ {
+ "type": "range",
+ "id": "articles_per_page",
+ "label": "Posts per page",
+ "min": 3,
+ "max": 12,
+ "step": 3,
+ "default": 9
+ },
+ {
+ "type": "checkbox",
+ "id": "emphasis_first_post",
+ "label": "Emphasize first post"
+ }
+ ]
+}
+
+{% endschema %}
diff --git a/sections/blog.liquid b/sections/blog.liquid
new file mode 100644
index 0000000..b7cedbf
--- /dev/null
+++ b/sections/blog.liquid
@@ -0,0 +1,111 @@
+<script
+ type="application/json"
+ data-section-type="static-blog"
+ data-section-id="{{ section.id }}"
+>
+</script>
+
+<section
+ {% if section.settings.tag-filter %}data-tag-filter{% endif %}
+>
+
+ <h1 class="page-title">{{ blog.title }}</h1>
+
+ {% render 'breadcrumbs' %}
+
+ {% render 'section-blog-sidebar' %}
+
+ <div class="blog-wrapper">
+ {% paginate blog.articles by section.settings.articles_per_page %}
+
+ {%- comment -%} DW infinite scroll: wrapper carries the next-page URL; dw-native-infinite.js appends on scroll. {%- endcomment -%}
+ <div
+ data-dw-infinite
+ data-dw-infinite-items=".blog-posts"
+ data-dw-infinite-next="{% if paginate.next %}{{ paginate.next.url }}{% endif %}"
+ data-dw-infinite-page="{{ paginate.current_page }}"
+ >
+ <div class="blog-posts">
+ {% for article in blog.articles %}
+ {% render 'section-blog-post', article: article %}
+ {% else %}
+ <span class="empty">{{ 'blogs.blog.empty' | t }}</span>
+ {% endfor %}
+ </div>
+
+ {% if paginate.previous or paginate.next %}
+ <div data-dw-infinite-pager>
+ {% render 'pagination', paginate: paginate %}
+ </div>
+ {% endif %}
+ </div>
+
+ {% endpaginate %}
+
+ {%- for block in section.blocks -%}
+ {%- case block.type -%}
+ {%- when 'promotional-image' -%}
+ {% render 'block-blog-promo', block: block %}
+ {%- endcase -%}
+ {%- endfor -%}
+ </div>
+</section>
+
+<script src="{{ 'dw-native-infinite.js' | asset_url }}" defer></script>
+
+{% schema %}
+{
+ "name": "Blog",
+ "settings": [
+ {
+ "type": "range",
+ "id": "articles_per_page",
+ "label": "Posts per page",
+ "min": 2,
+ "max": 10,
+ "step": 1,
+ "default": 4
+ },
+ {
+ "type": "checkbox",
+ "id": "tag-filter",
+ "label": "Show tag filter"
+ },
+ {
+ "type": "checkbox",
+ "id": "rss-icon",
+ "label": "Show subscribe link"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "promotional-image",
+ "name": "Promotional image",
+ "settings": [
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Image"
+ },
+ {
+ "type": "text",
+ "id": "heading",
+ "label": "Heading"
+ },
+ {
+ "type": "text",
+ "id": "subtitle",
+ "label": "Subheading"
+ },
+ {
+ "type": "url",
+ "id": "url",
+ "label": "Link"
+ }
+ ],
+ "limit": 1
+ }
+ ]
+}
+
+{% endschema %}
diff --git a/sections/cart-ajax.liquid b/sections/cart-ajax.liquid
new file mode 100644
index 0000000..7db2d44
--- /dev/null
+++ b/sections/cart-ajax.liquid
@@ -0,0 +1,16 @@
+<template data-data>
+ {
+ "itemsSubtotalPrice": {{ cart.items_subtotal_price | money | json }},
+ "totalDiscount": {{ cart.total_discount | money | json }},
+ "totalPrice": {{ cart.total_price | money | json }},
+ "itemCount": {{ cart.item_count }}
+ }
+</template>
+
+<template data-html="table">
+ {% render 'cart-table' %}
+</template>
+
+<template data-html="discounts">
+ {% render 'cart-discounts' %}
+</template>
diff --git a/sections/cart.liquid b/sections/cart.liquid
new file mode 100644
index 0000000..9d32ef2
--- /dev/null
+++ b/sections/cart.liquid
@@ -0,0 +1,145 @@
+{%- capture taxes_shipping_checkout -%}
+ {%- if cart.taxes_included and shop.shipping_policy.body != blank -%}
+ {{ 'cart.general.taxes_included_and_shipping_policy_html' | t: link: shop.shipping_policy.url }}
+ {%- elsif cart.taxes_included -%}
+ {{ 'cart.general.taxes_included_but_shipping_at_checkout' | t }}
+ {%- elsif shop.shipping_policy.body != blank -%}
+ {{ 'cart.general.taxes_and_shipping_policy_at_checkout_html' | t: link: shop.shipping_policy.url }}
+ {%- else -%}
+ {{ 'cart.general.tax_and_shipping' | t }}
+ {%- endif -%}
+{%- endcapture -%}
+
+<script
+ type="application/json"
+ data-section-type="static-cart"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+ {
+ "hasShippingCalculator": {{ section.settings.shipping-calculator }}
+ }
+</script>
+
+<section
+ class="cart"
+ {% if section.settings.shipping-calculator %}data-shipping-calculator{% endif %}
+ data-section-id="{{ section.id }}"
+ data-section-type="cart">
+ <h1 class="page-title">{{ 'cart.general.header' | t }}</h1>
+
+ {% render 'breadcrumbs' %}
+
+ {% if cart.item_count > 0 %}
+
+ <form class="cart-form" action="{{ routes.cart_url }}" method="post">
+
+ {% render 'cart-table' %}
+ <div class="cart-tools {% if section.settings.shipping-calculator %}has-shipping-calculator{% endif %} {% if section.settings.special-instructions %}has-special-instructions{% endif %}">
+
+ {% if section.settings.special-instructions %}
+ <div class="cart-instructions">
+ <h2>{{ 'cart.general.special_instructions' | t }}</h2>
+ <textarea class="textarea" placeholder="{{ section.settings.special-instructions-placeholder | escape }}" name="note">{{ cart.note }}</textarea>
+ </div>
+ {% endif %}
+
+ <div class="cart-totals">
+ {% render 'cart-discounts' %}
+ <p class="cart-price"><span class="money" data-total-price>{{ cart.total_price | money }}</span></p>
+ <p class="cart-message">{{ taxes_shipping_checkout }}</p>
+ <div class="cart-buttons-container">
+ <noscript>
+ <input class="cart-update button secondary input" type="submit" name="update" value="{{ 'general.general.update' | t }}">
+ </noscript>
+ <button
+ class="cart-checkout button"
+ type="submit"
+ name="checkout"
+ value="{{ 'cart.general.submit' | t }}"
+ >
+ {% if section.settings.enable_checkout_lock_icon %}
+ {% render 'icons',
+ id: 'checkout-lock',
+ %}
+ {% endif %}
+ <span>{{ 'cart.general.submit' | t }}</span>
+ </button>
+ </div>
+ {% if additional_checkout_buttons %}
+ <div class="additional-checkout-buttons">{{ content_for_additional_checkout_buttons }}</div>
+ {% endif %}
+ </div>
+
+ </div>
+
+ </form>
+
+ {% if section.settings.shipping-calculator %}
+ {% render 'shipping-calculator' %}
+ {% endif %}
+
+ {% else %}
+
+ {%- capture continueLink -%}
+ {% assign continue_href = section.settings.continue_shopping_link | default: routes.all_products_collection_url %}
+ <a href="{{ continue_href }}">{{ 'cart.general.continue_link' | t }}</a>
+ {%- endcapture -%}
+ <p class="empty">{{ 'cart.general.empty_html' | t: continue_link: continueLink }}</p>
+
+ {% endif %}
+</section>
+
+{% schema %}
+{
+ "name": "Cart",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "enable_checkout_lock_icon",
+ "label": "Show lock icon on checkout button",
+ "default": false
+ },
+ {
+ "type": "header",
+ "content": "Order Notes"
+ },
+ {
+ "type": "checkbox",
+ "id": "special-instructions",
+ "label": "Enable"
+ },
+ {
+ "type": "text",
+ "id": "special-instructions-placeholder",
+ "label": "Placeholder text",
+ "default": "Write any special instructions for your shipment here."
+ },
+ {
+ "type": "header",
+ "content": "Shipping rate calculator"
+ },
+ {
+ "type": "checkbox",
+ "id": "shipping-calculator",
+ "label": "Enable"
+ },
+ {
+ "type": "text",
+ "id": "shipping_calculator_default_country",
+ "label": "Default country",
+ "default": "United States"
+ },
+ {
+ "type": "header",
+ "content": "Continue shopping button"
+ },
+ {
+ "type": "url",
+ "id": "continue_shopping_link",
+ "label": "Link"
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/collection-list.liquid b/sections/collection-list.liquid
new file mode 100644
index 0000000..2605c3b
--- /dev/null
+++ b/sections/collection-list.liquid
@@ -0,0 +1,168 @@
+<script
+ type="application/json"
+ data-section-id="{{ section.id }}"
+ data-section-type="static-collections-list"
+>
+</script>
+
+
+{% assign use_masonry = false %}
+
+{% if section.settings.layout == 'masonry' %}
+ {% assign use_masonry = true %}
+{% endif %}
+
+<section
+ class="collections-list-section {% unless use_masonry %}collections-list-grid{% endunless %}"
+ {% if use_masonry %}data-collection-masonry{% endif %}>
+ <h1 class="page-title">{{ 'collections.listing.header' | t }}</h1>
+
+ {% render 'breadcrumbs' %}
+
+ <!-- STICKY SHOP BY COLOR BAR -->
+ <div id="dw-color-bar" style="position:sticky;top:0;z-index:100;background:#FAF9F6;border-bottom:1px solid #e5e5e5;padding:12px 0;margin:0 -20px 24px;transition:box-shadow 0.3s;">
+ <div style="max-width:1200px;margin:0 auto;padding:0 16px;">
+ <p style="font-family:-apple-system,system-ui,sans-serif;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#999;margin:0 0 10px;text-align:center;">Shop by Color</p>
+ <div style="display:flex;flex-wrap:nowrap;overflow-x:auto;justify-content:center;gap:16px;scrollbar-width:none;-ms-overflow-style:none;padding:2px 0;">
+ <a href="/collections/blue-wallpaper" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#3B5998;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Blue</span></a>
+ <a href="/collections/green-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#4A7C59;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Green</span></a>
+ <a href="/collections/gold-wallpaper" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#C4995C;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Gold</span></a>
+ <a href="/collections/red-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#9B2335;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Red</span></a>
+ <a href="/collections/pink-wallcovering-2" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#D4768B;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Pink</span></a>
+ <a href="/collections/purple" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#6B3FA0;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Purple</span></a>
+ <a href="/collections/orange" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#D2691E;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Orange</span></a>
+ <a href="/collections/yellow-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#DAA520;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Yellow</span></a>
+ <a href="/collections/black" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#1a1a1a;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Black</span></a>
+ <a href="/collections/white-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#F5F5F0;margin:0 auto 4px;border:2px solid #ddd;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">White</span></a>
+ <a href="/collections/grey-silver" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#808080;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Gray</span></a>
+ <a href="/collections/brown-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#6B4226;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Brown</span></a>
+ <a href="/collections/beige-cream-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#C8B99A;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Beige</span></a>
+ <a href="/collections/grey-silver" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#C0C0C0,#E8E8E8);margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Silver</span></a>
+ <a href="/collections/metallic-wallpaper-collections" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#B8860B,#DAA520,#F0E68C);margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Metallic</span></a>
+ <a href="/collections/coral" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#FF6F61;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Coral</span></a>
+ <a href="/collections/turquoise" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#40B5AD;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Teal</span></a>
+ </div>
+ </div>
+ </div>
+ <style>
+ #dw-color-bar::-webkit-scrollbar{display:none}
+ #dw-color-bar div::-webkit-scrollbar{display:none}
+ #dw-color-bar a:hover div{transform:scale(1.15);transition:transform 0.2s}
+ @media(max-width:768px){#dw-color-bar>div>div{justify-content:flex-start;padding:0 8px}}
+ </style>
+ <!-- END STICKY COLOR BAR -->
+
+ {% assign using_linklist = false %}
+ {% if linklists['all-collections'] and linklists['all-collections'].links.size > 0 %}
+ {% assign using_linklist = true %}
+ {% endif %}
+
+ {% assign collections_per_page = section.settings.collections_per_row | times: section.settings.collections_number_of_rows %}
+
+ <div class="collections-list-content">
+ {%- if using_linklist -%}
+ {%- comment -%} Linklist mode is unpaginated (all links on one page) — no infinite scroll needed. {%- endcomment -%}
+ <div
+ class="rows-of-{{ section.settings.collections_per_row }} {% if use_masonry %}masonry-grid{% endif %}"
+ {% if use_masonry %}data-masonry-grid{% endif %}
+ >
+ {%- if use_masonry -%}
+ <div class="masonry-grid-sizer" data-masonry-sizer></div>
+ {%- endif -%}
+ {% for link in linklists['all-collections'].links %}
+ {%
+ render 'collection-list-item',
+ collection_list_item: 'linklist',
+ link: link,
+ use_masonry: use_masonry,
+ description: section.settings.show_description
+ %}
+ {% endfor %}
+ </div>
+ {%- else -%}
+ {%- paginate collections by collections_per_page -%}
+ {%- comment -%} DW infinite scroll: wrapper carries the next-page URL; dw-native-infinite.js appends on scroll. {%- endcomment -%}
+ <div
+ data-dw-infinite
+ data-dw-infinite-items=".dw-collections-grid"
+ data-dw-infinite-next="{% if paginate.next %}{{ paginate.next.url }}{% endif %}"
+ data-dw-infinite-page="{{ paginate.current_page }}"
+ >
+ <div
+ class="dw-collections-grid rows-of-{{ section.settings.collections_per_row }} {% if use_masonry %}masonry-grid{% endif %}"
+ {% if use_masonry %}data-masonry-grid{% endif %}
+ >
+ {%- if use_masonry -%}
+ <div class="masonry-grid-sizer" data-masonry-sizer></div>
+ {%- endif -%}
+ {%- for collection in collections -%}
+ {%-
+ render 'collection-list-item',
+ collection_list_item: 'collection',
+ collection: collection,
+ use_masonry: use_masonry,
+ description: section.settings.show_description
+ -%}
+ {%- endfor -%}
+ </div>
+
+ <div data-dw-infinite-pager>
+ {% render 'pagination', paginate: paginate %}
+ </div>
+ </div>
+ {%- endpaginate -%}
+ {% endif %}
+ </div>
+</section>
+
+<script src="{{ 'dw-native-infinite.js' | asset_url }}" defer></script>
+
+{% schema %}
+{
+ "name": "Collection list page",
+ "settings": [
+ {
+ "type": "select",
+ "id": "layout",
+ "label": "Layout",
+ "options": [
+ {
+ "value": "default",
+ "label": "Default"
+ },
+ {
+ "value": "masonry",
+ "label": "Masonry"
+ }
+ ],
+ "default": "default"
+ },
+ {
+ "type": "checkbox",
+ "id": "show_description",
+ "label": "Show description",
+ "default": false
+ },
+ {
+ "type": "range",
+ "id": "collections_per_row",
+ "label": "Collections per row",
+ "min": 2,
+ "max": 4,
+ "step": 1,
+ "default": 3
+ },
+ {
+ "type": "range",
+ "id": "collections_number_of_rows",
+ "label": "Rows",
+ "min": 2,
+ "max": 6,
+ "step": 1,
+ "default": 6
+ }
+ ]
+}
+
+{% endschema %}
+
diff --git a/sections/collection.liquid b/sections/collection.liquid
new file mode 100644
index 0000000..42515a9
--- /dev/null
+++ b/sections/collection.liquid
@@ -0,0 +1,21 @@
+{%- comment -%} DW: render the collection description server-side (theme JS never did). Respects the existing show_description setting; reversible. {%- endcomment -%}
+{%- if section.settings.show_description and collection.description != blank -%}
+ <div class="dw-collection-description rte" style="max-width:880px;margin:30px auto 4px;padding:0 26px;line-height:1.7;color:#3a342c;">
+ {{ collection.description }}
+ </div>
+{%- endif -%}
+<script type="application/json" data-section-id="{{ section.id }}" data-section-type="static-collection"></script>
+{% schema %}
+{
+ "name": "Collection pages",
+ "settings": [
+ { "type": "checkbox", "id": "show_collection_image", "label": "Show collection image" },
+ { "type": "checkbox", "id": "show_description", "label": "Show description" },
+ { "type": "checkbox", "id": "sorting", "label": "Enable sorting" },
+ { "type": "checkbox", "id": "show_filters", "label": "Enable filtering", "default": true },
+ { "type": "select", "id": "layout", "label": "Layout", "options": [{"value":"default","label":"Default"},{"value":"masonry","label":"Masonry"}], "default": "default" },
+ { "type": "range", "id": "products_per_row", "label": "Products per row", "min": 3, "max": 8, "step": 1, "default": 4 },
+ { "type": "range", "id": "number_of_rows", "label": "Rows", "min": 1, "max": 20, "step": 1, "default": 12 }
+ ]
+}
+{% endschema %}
diff --git a/sections/contact-for-price.liquid b/sections/contact-for-price.liquid
new file mode 100644
index 0000000..fd32b44
--- /dev/null
+++ b/sections/contact-for-price.liquid
@@ -0,0 +1,184 @@
+{% comment %}
+ contact-for-price.liquid
+ "Price per unit unavailable online" notice + "Contact Us About This SKU" button.
+ Renders ONLY when the product is tagged `contact-for-price` (additive tag set on
+ the sample-only cohort). Sits ALONGSIDE the existing $4.25 sample variant — the
+ customer can still buy a swatch; this block handles the roll/unit price, which is
+ not shown online (no fabricated price; in-house & to-the-trade lines).
+
+ Generalized from koroseal-quote-button.liquid. Button is PUBLIC (price is hidden
+ from everyone); the trade-discount line stays role-gated. Posts to /api/sku-inquiry.
+{% endcomment %}
+
+{% if product.tags contains 'contact-for-price' %}
+{%- assign base_sku = product.selected_or_first_available_variant.sku | remove: '-Sample' | remove: '-sample' -%}
+<div class="cfp-section" data-product-id="{{ product.id }}" data-product-title="{{ product.title | escape }}" data-sku="{{ base_sku | escape }}">
+ <div class="cfp-badge">
+ <div class="cfp-badge-content">
+ <span class="cfp-icon">●</span>
+ <div class="cfp-badge-text">
+ <p class="cfp-title">Current Item — Price Per Unit Unavailable Online</p>
+ <p class="cfp-subtitle">Order a sample below, or contact us for roll/unit pricing on this SKU.</p>
+ {% if customer and customer.tags contains 'interior_designer' or customer.tags contains 'designer' or customer.tags contains 'design_professional' or customer.tags contains 'trade' %}
+ <p class="cfp-trade">✓ Trade pricing applies — your designer discount will be reflected in the quote.</p>
+ {% endif %}
+ </div>
+ </div>
+ <button class="cfp-button" type="button" onclick="openCfpModal(event)">Contact Us About This SKU</button>
+ </div>
+
+ <div id="cfp-overlay" class="cfp-overlay" onclick="closeCfpModal(event)"></div>
+ <div id="cfp-modal" class="cfp-modal" role="dialog" aria-modal="true" aria-labelledby="cfp-modal-title">
+ <div class="cfp-modal-header">
+ <h2 id="cfp-modal-title">Contact Us About This SKU</h2>
+ <button class="cfp-close" type="button" aria-label="Close" onclick="closeCfpModal()">×</button>
+ </div>
+ <form id="cfp-form" class="cfp-form" onsubmit="handleCfpSubmit(event)">
+ <input type="hidden" id="cfp-product-id" value="{{ product.id }}">
+ <input type="hidden" id="cfp-product-title" value="{{ product.title | escape }}">
+
+ <div class="cfp-skuline">
+ <span class="cfp-skulabel">SKU</span>
+ <span class="cfp-skuval">{{ base_sku | default: product.title | escape }}</span>
+ </div>
+ <input type="hidden" id="cfp-sku" value="{{ base_sku | escape }}">
+
+ <div class="cfp-row">
+ <div class="cfp-group">
+ <label for="cfp-name">Your Name *</label>
+ <input type="text" id="cfp-name" name="name" required autocomplete="name">
+ </div>
+ <div class="cfp-group">
+ <label for="cfp-email">Email *</label>
+ <input type="email" id="cfp-email" name="email" required autocomplete="email" value="{{ customer.email }}">
+ </div>
+ </div>
+
+ <div class="cfp-row">
+ <div class="cfp-group">
+ <label for="cfp-phone">Phone</label>
+ <input type="tel" id="cfp-phone" name="phone" autocomplete="tel">
+ </div>
+ <div class="cfp-group">
+ <label for="cfp-company">Company / Business</label>
+ <input type="text" id="cfp-company" name="company" autocomplete="organization">
+ </div>
+ </div>
+
+ <div class="cfp-row">
+ <div class="cfp-group">
+ <label for="cfp-role">I am a *</label>
+ <select id="cfp-role" name="role" required>
+ <option value="">Select…</option>
+ <option value="interior_designer">Interior Designer</option>
+ <option value="trade">Trade / Dealer</option>
+ <option value="architect">Architect / Specifier</option>
+ <option value="homeowner">Homeowner</option>
+ <option value="other">Other</option>
+ </select>
+ </div>
+ <div class="cfp-group">
+ <label for="cfp-qty">Quantity Needed</label>
+ <div class="cfp-qtywrap">
+ <input type="number" id="cfp-qty" name="quantity" min="1" placeholder="e.g., 6">
+ <select id="cfp-unit" name="unit" aria-label="Unit">
+ <option value="rolls">rolls</option>
+ <option value="yards">yards</option>
+ <option value="sq_ft">sq ft</option>
+ <option value="unsure">unsure</option>
+ </select>
+ </div>
+ </div>
+ </div>
+
+ <div class="cfp-row">
+ <div class="cfp-group">
+ <label for="cfp-project">Project Name</label>
+ <input type="text" id="cfp-project" name="projectName" placeholder="e.g., Madison Ave Residence">
+ </div>
+ <div class="cfp-group">
+ <label for="cfp-city">City / Location</label>
+ <input type="text" id="cfp-city" name="city" placeholder="e.g., Los Angeles, CA">
+ </div>
+ </div>
+
+ <div class="cfp-row">
+ <div class="cfp-group">
+ <label for="cfp-timeline">Timeline</label>
+ <input type="text" id="cfp-timeline" name="timeline" placeholder="e.g., 2–3 weeks">
+ </div>
+ <div class="cfp-group">
+ <label for="cfp-budget">Budget</label>
+ <input type="text" id="cfp-budget" name="budget" placeholder="e.g., $10,000">
+ </div>
+ </div>
+
+ <div class="cfp-group">
+ <label for="cfp-notes">Additional Notes</label>
+ <textarea id="cfp-notes" name="notes" rows="3" placeholder="Anything else we should know about your project…"></textarea>
+ </div>
+
+ <button type="submit" class="cfp-submit">Send Inquiry</button>
+ <p class="cfp-reassure">We typically reply within 1 business day. No obligation.</p>
+ </form>
+ </div>
+</div>
+
+<style>
+ .cfp-section{margin:1.5rem 0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif}
+ .cfp-badge{display:flex;align-items:center;gap:1.25rem;padding:1.1rem 1.25rem;background:#faf8f4;border:1px solid #e6e0d6;border-radius:8px;flex-wrap:wrap}
+ .cfp-badge-content{display:flex;align-items:flex-start;gap:.75rem;flex:1;min-width:220px}
+ .cfp-icon{color:#b9892f;font-size:.9rem;line-height:1.6}
+ .cfp-title{margin:0;font-weight:600;font-size:.98rem;color:#2a2622;letter-spacing:.01em}
+ .cfp-subtitle{margin:.25rem 0 0;font-size:.85rem;color:#6b6357}
+ .cfp-trade{margin:.35rem 0 0;font-size:.8rem;color:#3f7d3f;font-weight:500}
+ .cfp-button{padding:.7rem 1.4rem;background:#2a2622;color:#fff;border:none;border-radius:6px;font-weight:500;cursor:pointer;white-space:nowrap;transition:all .2s}
+ .cfp-button:hover{background:#000;transform:translateY(-1px)}
+ .cfp-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:999}
+ .cfp-overlay.active{display:block}
+ .cfp-modal{display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;border-radius:12px;box-shadow:0 10px 40px rgba(0,0,0,.2);max-width:560px;width:92%;max-height:92vh;overflow-y:auto;z-index:1000}
+ .cfp-modal.active{display:block}
+ .cfp-modal-header{display:flex;justify-content:space-between;align-items:center;padding:1.25rem 1.5rem;border-bottom:1px solid #eee}
+ .cfp-modal-header h2{margin:0;font-size:1.3rem;color:#2a2622}
+ .cfp-close{background:none;border:none;font-size:1.6rem;cursor:pointer;color:#888;line-height:1}
+ .cfp-form{padding:1.25rem 1.5rem}
+ .cfp-skuline{display:flex;align-items:center;gap:.6rem;margin-bottom:1rem;padding:.5rem .75rem;background:#f6f4f0;border-radius:6px}
+ .cfp-skulabel{font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:#8a8276}
+ .cfp-skuval{font-weight:600;color:#2a2622}
+ .cfp-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
+ .cfp-group{margin-bottom:1rem}
+ .cfp-group label{display:block;margin-bottom:.4rem;font-weight:500;color:#3a352f;font-size:.9rem}
+ .cfp-group input,.cfp-group select,.cfp-group textarea{width:100%;padding:.65rem;border:1px solid #d6d0c6;border-radius:6px;font-family:inherit;font-size:.92rem;box-sizing:border-box}
+ .cfp-group input:focus,.cfp-group select:focus,.cfp-group textarea:focus{outline:none;border-color:#b9892f;box-shadow:0 0 0 3px rgba(185,137,47,.12)}
+ .cfp-qtywrap{display:flex;gap:.5rem}
+ .cfp-qtywrap input{flex:1}
+ .cfp-qtywrap select{width:auto}
+ .cfp-submit{width:100%;padding:.85rem;background:#b9892f;color:#fff;border:none;border-radius:6px;font-weight:600;font-size:.95rem;cursor:pointer;transition:background .2s}
+ .cfp-submit:hover{background:#a3781f}
+ .cfp-reassure{text-align:center;font-size:.78rem;color:#8a8276;margin:.6rem 0 0}
+ @media(max-width:640px){.cfp-badge{flex-direction:column;align-items:flex-start}.cfp-row{grid-template-columns:1fr}.cfp-modal{width:95%}}
+</style>
+
+<script>
+ function openCfpModal(e){if(e)e.preventDefault();document.getElementById('cfp-overlay').classList.add('active');document.getElementById('cfp-modal').classList.add('active');}
+ function closeCfpModal(e){if(e&&e.target&&e.target!==document.getElementById('cfp-overlay'))return;document.getElementById('cfp-overlay').classList.remove('active');document.getElementById('cfp-modal').classList.remove('active');}
+ document.addEventListener('keydown',function(e){if(e.key==='Escape')closeCfpModal();});
+ async function handleCfpSubmit(e){
+ e.preventDefault();
+ var val=function(id){var el=document.getElementById(id);return el?el.value:'';};
+ var payload={
+ productId:val('cfp-product-id'), productTitle:val('cfp-product-title'), sku:val('cfp-sku'),
+ name:val('cfp-name'), email:val('cfp-email'), phone:val('cfp-phone'), company:val('cfp-company'),
+ role:val('cfp-role'), quantity:val('cfp-qty'), unit:val('cfp-unit'),
+ projectName:val('cfp-project'), city:val('cfp-city'), timeline:val('cfp-timeline'),
+ budget:val('cfp-budget'), notes:val('cfp-notes')
+ };
+ try{
+ var r=await fetch('https://api.designerwallcoverings.com/api/sku-inquiry',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)});
+ var j=await r.json();
+ if(j.success){alert('✅ Inquiry received!\n\nWe\'ll get back to you within 1 business day.\n\nReference: '+(j.requestId||'')); document.getElementById('cfp-form').reset(); closeCfpModal();}
+ else{alert('❌ '+(j.message||'Something went wrong. Please try again.'));}
+ }catch(err){console.error('cfp submit',err);alert('❌ Could not send inquiry. Please email info@designerwallcoverings.com.');}
+ }
+</script>
+{% endif %}
diff --git a/sections/custom-liquid.liquid b/sections/custom-liquid.liquid
new file mode 100644
index 0000000..2068146
--- /dev/null
+++ b/sections/custom-liquid.liquid
@@ -0,0 +1,34 @@
+<section
+ class="custom-liquid"
+ data-section-id="{{ section.id }}"
+>
+ <div class="custom-liquid__wrapper">
+ {{ section.settings.custom_liquid }}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Custom liquid",
+ "class": "shopify-section--custom-liquid",
+ "settings": [
+ {
+ "type": "liquid",
+ "id": "custom_liquid",
+ "label": "Custom liquid"
+ }
+ ],
+ "presets": [
+ {
+ "name": "Custom liquid",
+ "category": "Content"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/dw-all-collections.liquid b/sections/dw-all-collections.liquid
new file mode 100644
index 0000000..7d49c8d
--- /dev/null
+++ b/sections/dw-all-collections.liquid
@@ -0,0 +1,6 @@
+<div id="dw-test-marker-xyz123">COLLECTIONS PAGE IS BEING FIXED - PLEASE WAIT</div>
+{% schema %}
+{
+ "name": "All Collections"
+}
+{% endschema %}
diff --git a/sections/dw-boost-filter-topbar.liquid b/sections/dw-boost-filter-topbar.liquid
new file mode 100644
index 0000000..23936cf
--- /dev/null
+++ b/sections/dw-boost-filter-topbar.liquid
@@ -0,0 +1,514 @@
+{%- comment -%}
+ DW Boost Filter Topbar — DTD verdict B (officer-yolo 2026-06-25)
+
+ A CUSTOM horizontal DROPDOWN filter toolbar that sits ABOVE Boost's grid and
+ drives Boost's pf_* URL params + sort_by. Ported UX from the left-hand filters
+ of new.designerwallcoverings.com (new-import-viewer): toggleable controls,
+ sort + density + search, all persisted to localStorage.
+
+ ── HARD ARCHITECTURE RULES (do not violate) ──
+ 1. This bar READS Boost's filter-tree DOM (option labels/counts) + the current
+ URL's pf_* params, and WRITES pf_* / sort_by params then NAVIGATES.
+ It NEVER mutates Boost's result grid DOM, never removes a Boost node, never
+ restyles Boost's React internals. Zero grid-break surface (see memory
+ reference_dw_theme_grid_init_abort: dropping a Boost DOM hook silently breaks
+ every grid — this bar only ADDS a sibling node, queries are read-only).
+ 2. Boost is the filter ENGINE. The bar is UX-only. If Boost re-renders 1000x/day
+ the bar is independent — on each Boost mutation it re-reads option values
+ (debounced) but only to repopulate its OWN dropdowns.
+ 3. Each filter field is individually toggleable ON/OFF by the user; the choice
+ persists in localStorage (dw_topbar_fields), same convention as sort/density.
+ 4. NO private-label vendor names ever surface (Brewster/York/WallQuest/Command54
+ etc.) — the Brand/Vendor dropdown is built from Boost's emitted option list,
+ which already carries house-line names; a deny-list scrub is applied as a
+ belt-and-suspenders guard before any option is rendered.
+
+ ── Boost param contract (verified on the live page 2026-06-25) ──
+ pf_t_<tag> tag-backed facets → product_type, color, style, durability,
+ historical_era (extensible: material,
+ process, pattern, contents = pf_t_*)
+ pf_v_brand vendor/brand facet
+ pf_p_price price range (pf_p_price=<min>:<max>)
+ sort_by Boost/Shopify sort (created-descending, price-ascending, …)
+ q search term
+
+ Each FIELD below maps to one Boost param. Fields whose Boost facet is not yet
+ configured in the Boost SD dashboard render their dropdown EMPTY with a
+ "configure in Boost" hint (see the accompanying runbook) — they do not break.
+
+ Revision: 2026-06-25 (officer-yolo / vp-dw-commerce)
+{%- endcomment -%}
+
+{%- liquid
+ assign accent = settings.color_accent | default: '#111111'
+-%}
+
+<div class="dw-tbf" data-section-id="{{ section.id }}" data-dw-topbar>
+ <style>
+ .dw-tbf{width:100%;padding:14px 0;margin-bottom:18px;border-bottom:1px solid var(--border-color,rgba(0,0,0,.1));
+ font-family:inherit;--dw-acc:{{ accent }}}
+ .dw-tbf__row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
+ .dw-tbf__label{font-size:10px;letter-spacing:.3em;text-transform:uppercase;font-weight:700;
+ color:var(--text-muted,rgba(0,0,0,.55));margin-right:2px;white-space:nowrap}
+ /* one dropdown unit */
+ .dw-dd{position:relative}
+ .dw-dd__btn{display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 13px;
+ font-size:11px;letter-spacing:.12em;text-transform:uppercase;font-weight:600;
+ color:var(--text-color,inherit);background:transparent;border:1px solid var(--border-color,rgba(0,0,0,.14));
+ border-radius:20px;cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s;line-height:1}
+ .dw-dd__btn:hover{border-color:var(--dw-acc)}
+ .dw-dd__btn[aria-expanded="true"]{border-color:var(--dw-acc);background:var(--bg-hover,rgba(0,0,0,.03))}
+ .dw-dd__btn .dw-caret{font-size:8px;opacity:.6;transition:transform .15s}
+ .dw-dd__btn[aria-expanded="true"] .dw-caret{transform:rotate(180deg)}
+ .dw-dd__btn .dw-cnt{font-variant-numeric:tabular-nums;background:var(--dw-acc);color:#fff;
+ border-radius:999px;font-size:9px;min-width:15px;height:15px;display:inline-flex;align-items:center;
+ justify-content:center;padding:0 4px}
+ /* active (has a selection) */
+ .dw-dd.has-sel .dw-dd__btn{background:var(--dw-acc);color:#fff;border-color:var(--dw-acc)}
+ .dw-dd.has-sel .dw-dd__btn .dw-cnt{background:#fff;color:var(--dw-acc)}
+ /* panel */
+ .dw-dd__panel{position:absolute;top:calc(100% + 6px);left:0;z-index:40;min-width:220px;max-width:300px;
+ max-height:340px;overflow:auto;background:var(--bg-color,#fff);border:1px solid var(--border-color,rgba(0,0,0,.14));
+ border-radius:12px;box-shadow:0 12px 34px rgba(0,0,0,.16);padding:8px;display:none}
+ .dw-dd.open .dw-dd__panel{display:block}
+ .dw-opt{display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:8px;cursor:pointer;
+ font-size:12.5px;color:var(--text-color,inherit);user-select:none}
+ .dw-opt:hover{background:var(--bg-hover,rgba(0,0,0,.04))}
+ .dw-opt input{width:15px;height:15px;accent-color:var(--dw-acc);margin:0;cursor:pointer;flex:0 0 auto}
+ .dw-opt .dw-sw{width:15px;height:15px;border-radius:50%;border:1px solid rgba(0,0,0,.18);flex:0 0 auto}
+ .dw-opt .dw-on{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
+ .dw-opt .dw-oc{font-size:10.5px;color:var(--text-muted,rgba(0,0,0,.45));font-variant-numeric:tabular-nums}
+ .dw-dd__empty{padding:14px 10px;font-size:11.5px;color:var(--text-muted,rgba(0,0,0,.5));line-height:1.4}
+ .dw-dd__price{display:flex;gap:8px;align-items:center;padding:10px 9px}
+ .dw-dd__price input{width:74px;height:30px;border:1px solid var(--border-color,rgba(0,0,0,.16));
+ border-radius:8px;padding:0 8px;font:inherit;font-size:12px}
+ .dw-dd__apply{margin-top:6px;width:100%;height:32px;border:0;border-radius:8px;background:var(--dw-acc);
+ color:#fff;font-size:11px;letter-spacing:.14em;text-transform:uppercase;font-weight:700;cursor:pointer}
+ /* sort + density + search reuse the same chip vocabulary */
+ .dw-tbf__sort{height:34px;padding:0 11px;border:1px solid var(--border-color,rgba(0,0,0,.14));border-radius:20px;
+ background:transparent;font:inherit;font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-weight:600;cursor:pointer;color:inherit}
+ .dw-tbf__sort:hover{border-color:var(--dw-acc)}
+ .dw-density{display:inline-flex;align-items:center;gap:9px;height:34px}
+ .dw-density input[type=range]{width:96px;accent-color:var(--dw-acc);cursor:pointer}
+ .dw-density .dw-dlabel{font-size:10px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;
+ color:var(--text-muted,rgba(0,0,0,.55));min-width:42px;text-align:right}
+ .dw-search{display:inline-flex;align-items:center;gap:7px;height:34px;border:1px solid var(--border-color,rgba(0,0,0,.14));
+ border-radius:20px;padding:0 12px;min-width:160px}
+ .dw-search input{flex:1;border:0;background:transparent;font:inherit;font-size:12px;outline:none;color:inherit}
+ .dw-search svg{width:13px;height:13px;stroke:var(--text-muted,rgba(0,0,0,.4));fill:none;stroke-width:1.6;flex:0 0 auto}
+ .dw-clear{margin-left:auto;font-size:10px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;
+ color:var(--dw-acc);background:transparent;border:0;cursor:pointer;white-space:nowrap}
+ .dw-clear:disabled{opacity:.35;cursor:default}
+ /* product-type segmented control (ports Boost's Wallcoverings/Fabrics tabs) */
+ .dw-seg{display:inline-flex;border:1px solid var(--border-color,rgba(0,0,0,.14));border-radius:20px;overflow:hidden;height:34px;margin-right:4px}
+ .dw-seg button{border:0;background:transparent;padding:0 14px;font:inherit;font-size:11px;letter-spacing:.12em;text-transform:uppercase;font-weight:600;cursor:pointer;color:inherit;white-space:nowrap;line-height:1}
+ .dw-seg button+button{border-left:1px solid var(--border-color,rgba(0,0,0,.12))}
+ .dw-seg button:hover{background:var(--bg-hover,rgba(0,0,0,.04))}
+ .dw-seg button[aria-pressed="true"]{background:var(--dw-acc);color:#fff}
+ /* live product count (ports Boost's "N products") */
+ .dw-count{font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;color:var(--text-muted,rgba(0,0,0,.55));white-space:nowrap;margin-left:2px}
+ /* REPLACE Boost's native toolbar — this topbar is the single control surface.
+ Cosmetic hide ONLY: the node stays in the DOM so Boost's own JS and our
+ read-only count-reader keep working (never removes a Boost hook). */
+ .boost-sd__toolbar{display:none!important}
+ /* the "which filters are shown" gear menu (per-field ON/OFF) */
+ .dw-gear{position:relative}
+ .dw-gear__btn{height:34px;width:34px;display:inline-flex;align-items:center;justify-content:center;
+ border:1px solid var(--border-color,rgba(0,0,0,.14));border-radius:50%;background:transparent;cursor:pointer;font-size:14px}
+ .dw-gear__btn:hover{border-color:var(--dw-acc)}
+ .dw-gear__panel{position:absolute;top:calc(100% + 6px);right:0;z-index:41;min-width:200px;background:var(--bg-color,#fff);
+ border:1px solid var(--border-color,rgba(0,0,0,.14));border-radius:12px;box-shadow:0 12px 34px rgba(0,0,0,.16);padding:8px;display:none}
+ .dw-gear.open .dw-gear__panel{display:block}
+ .dw-gear__panel .dw-gtitle{font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;font-weight:700;
+ color:var(--text-muted,rgba(0,0,0,.5));padding:5px 9px 7px}
+ @media (max-width:720px){
+ .dw-tbf__label{display:none}
+ .dw-density{display:none}
+ .dw-search{min-width:0;flex:1 1 100%;order:5}
+ .dw-dd__panel{max-width:84vw}
+ }
+ </style>
+
+ <div class="dw-tbf__row" data-tbf-row>
+ {%- comment -%} product-type segmented control (replaces Boost's native Wallcoverings/Fabrics tabs) {%- endcomment -%}
+ <span class="dw-seg" data-tbf-types role="group" aria-label="Product type">
+ <button type="button" data-ptype="" aria-pressed="false">All</button>
+ <button type="button" data-ptype="Wallcovering" aria-pressed="false">Wallcoverings</button>
+ <button type="button" data-ptype="Fabric" aria-pressed="false">Fabrics</button>
+ </span>
+
+ <span class="dw-tbf__label">Filter</span>
+ <span data-tbf-fields></span>
+
+ {%- comment -%} sort {%- endcomment -%}
+ <span class="dw-tbf__label" style="margin-left:6px">Sort</span>
+ <select class="dw-tbf__sort" data-tbf-sort aria-label="Sort products">
+ <option value="">Newest</option>
+ <option value="created-descending">Created · Newest</option>
+ <option value="created-ascending">Created · Oldest</option>
+ <option value="title-ascending">Title A→Z</option>
+ <option value="title-descending">Title Z→A</option>
+ <option value="price-ascending">Price ↑</option>
+ <option value="price-descending">Price ↓</option>
+ <option value="best-selling">Best selling</option>
+ </select>
+
+ {%- comment -%} density {%- endcomment -%}
+ <span class="dw-density" data-tbf-density-wrap>
+ <span class="dw-tbf__label">Grid</span>
+ <input type="range" min="2" max="8" value="4" data-tbf-density aria-label="Grid density">
+ <span class="dw-dlabel"><span data-tbf-dlabel>4</span> col</span>
+ </span>
+
+ {%- comment -%} search {%- endcomment -%}
+ <span class="dw-search" data-tbf-search-wrap>
+ <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path></svg>
+ <input type="text" data-tbf-search placeholder="Search pattern / sku / color…" aria-label="Search">
+ </span>
+
+ <button class="dw-clear" data-tbf-clear disabled>Clear all</button>
+ <span class="dw-count" data-tbf-count></span>
+
+ {%- comment -%} per-field ON/OFF gear {%- endcomment -%}
+ <span class="dw-gear" data-tbf-gear>
+ <button class="dw-gear__btn" data-tbf-gear-btn title="Choose which filters to show" aria-haspopup="true" aria-expanded="false">⚙</button>
+ <div class="dw-gear__panel" data-tbf-gear-panel>
+ <div class="dw-gtitle">Show filters</div>
+ <span data-tbf-gear-list></span>
+ </div>
+ </span>
+ </div>
+</div>
+
+<script>
+(function(){
+ 'use strict';
+ var root = document.currentScript.closest('[data-dw-topbar]') || document.querySelector('[data-dw-topbar]');
+ if(!root || root.__dwTbfInit) return; root.__dwTbfInit = true;
+
+ // ── FIELD MODEL ──────────────────────────────────────────────────────────
+ // key = stable id (localStorage)
+ // label= dropdown button text
+ // param= Boost URL param this field writes (the contract)
+ // kind = 'tag' (pf_t_*) | 'vendor' (pf_v_brand) | 'price' (pf_p_price)
+ // swatch=render a color dot per option (color/swatch field)
+ // The order here is the default left→right order in the bar.
+ var FIELDS = [
+ { key:'color', label:'Color', param:'pf_t_color', kind:'tag', swatch:true },
+ { key:'style', label:'Style', param:'pf_t_style', kind:'tag' },
+ { key:'material', label:'Material', param:'pf_t_material', kind:'tag' },
+ { key:'brand', label:'Brand', param:'pf_v_brand', kind:'vendor' },
+ { key:'process', label:'Process', param:'pf_t_process', kind:'tag' },
+ { key:'vendor', label:'Vendor', param:'pf_v_brand', kind:'vendor' },
+ { key:'swatch', label:'Swatch', param:'pf_t_color', kind:'tag', swatch:true },
+ { key:'contents', label:'Contents', param:'pf_t_contents', kind:'tag' },
+ { key:'pattern', label:'Pattern', param:'pf_t_pattern', kind:'tag' },
+ { key:'sku', label:'SKU', param:'pf_t_sku', kind:'tag' },
+ { key:'durability',label:'Durability',param:'pf_t_durability', kind:'tag' },
+ { key:'era', label:'Era', param:'pf_t_historical_era',kind:'tag' },
+ { key:'price', label:'Price', param:'pf_p_price', kind:'price' }
+ ];
+ // Which fields are ON by default. Data-backed only (verified 2026-06-25): color
+ // (color: tags), style/brand (global.Style/Brand facets), price (pf_p_price), and
+ // MATERIAL — backed by global.Contents (vinyl/grasscloth/raffia/paper, 78% fill);
+ // a Boost facet labeled "Material" from global.Contents emits pf_t_material to match.
+ // Process OFF (Construction/Finish empty — no data); Pattern OFF (near-unique → poor
+ // facet). All remain user-enableable via the ⚙ gear when their data lands.
+ var DEFAULT_ON = ['color','style','brand','material','price'];
+
+ // Private-label deny-list — these upstream names must NEVER reach a shopper.
+ var DENY = [/brewster/i,/\byork\b/i,/wallquest/i,/chesapeake/i,/nextwall/i,/seabrook/i,/command\s*54/i,/desima/i,/carlsten/i,/nicolette\s*mayer/i];
+ function denied(s){ s=String(s||''); return DENY.some(function(r){return r.test(s);}); }
+
+ var LS = {
+ fields:'dw_topbar_fields', density:'dw_collection_density',
+ sort:'dw_collection_sort', search:'dw_collection_search'
+ };
+ function lsGet(k,d){ try{var v=localStorage.getItem(k); return v==null?d:v;}catch(e){return d;} }
+ function lsSet(k,v){ try{localStorage.setItem(k,v);}catch(e){} }
+
+ function curParams(){ return new URLSearchParams(window.location.search); }
+ function esc(s){ return String(s==null?'':s).replace(/[&<>"']/g,function(c){return({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];}); }
+
+ // ── read which fields are enabled ────────────────────────────────────────
+ function enabledSet(){
+ var saved = lsGet(LS.fields,null);
+ if(saved){ try{ var a=JSON.parse(saved); if(Array.isArray(a)) return new Set(a); }catch(e){} }
+ return new Set(DEFAULT_ON);
+ }
+
+ // ── read Boost's emitted option values for a tag/vendor param ────────────
+ // STRICTLY READ-ONLY: we query Boost's filter-tree DOM for labels+counts.
+ // We never remove/restyle those nodes. If Boost hasn't rendered them yet
+ // (client API still loading) we fall back to the value already in the URL so
+ // the active selection is always reflected. Never throws → never breaks grid.
+ function boostOptions(field){
+ var out=[], seen={};
+ var param = field.param;
+ // 1) values already active in the URL (always show these so state is honest)
+ curParams().getAll(param).forEach(function(v){
+ v=decodeURIComponent(v); if(!seen[v]&&!denied(v)){ seen[v]=1; out.push({value:v,label:v,count:null,checked:true}); }
+ });
+ // 2) options Boost has rendered in its (possibly-hidden) native tree.
+ // Boost emits filter options as anchors/inputs carrying the pf_* param in
+ // href or data attributes. We scan defensively across known shapes.
+ try{
+ var tree = document.querySelector('.boost-sd__filter-tree') || document.querySelector('.boost-sd__sidebar');
+ if(tree){
+ tree.querySelectorAll('a[href],input[type="checkbox"]').forEach(function(el){
+ var href = el.getAttribute('href')||'';
+ var match=null;
+ if(href.indexOf(param+'=')>-1){
+ var u; try{ u=new URL(href, window.location.origin); }catch(e){ return; }
+ (u.searchParams.getAll(param)||[]).forEach(function(v){ match=v; });
+ }
+ if(!match && el.getAttribute('data-filter-value') && (el.getAttribute('data-filter-type')||'').toLowerCase().indexOf(field.key)>-1){
+ match = el.getAttribute('data-filter-value');
+ }
+ if(!match) return;
+ var lbl = (el.textContent||match).replace(/\s+\(\d[\d,]*\)\s*$/,'').trim() || match;
+ var cm = (el.textContent||'').match(/\((\d[\d,]*)\)\s*$/);
+ if(seen[match]||denied(match)||denied(lbl)) return;
+ seen[match]=1; out.push({value:match,label:lbl,count:cm?cm[1]:null,checked:false});
+ });
+ }
+ }catch(e){ /* read-only scan; ignore */ }
+ return out;
+ }
+
+ // ── swatch hex guess from a color name (cheap, named-color map) ──────────
+ var NAMED={black:'#1a1a1a',white:'#f4f4f4',grey:'#9aa0a6',gray:'#9aa0a6',silver:'#c8ccd1',red:'#c0392b',
+ pink:'#e84393',orange:'#e67e22',yellow:'#f1c40f',gold:'#caa53d',green:'#27ae60',olive:'#7d8c3e',
+ teal:'#16a085',blue:'#2980b9',navy:'#27408b',cyan:'#36c5d6',purple:'#8e44ad',violet:'#7c4dbb',
+ brown:'#8d6748',beige:'#d8c7a8',cream:'#efe6cf',taupe:'#b3a394',ivory:'#f1ebda',charcoal:'#36393f',
+ bronze:'#9c6b3c',copper:'#b87333',natural:'#d6c8af',neutral:'#cfc6b8'};
+ function swatchHex(name){
+ var n=String(name||'').toLowerCase();
+ for(var k in NAMED){ if(n.indexOf(k)>-1) return NAMED[k]; }
+ return '#cfc6b8';
+ }
+
+ // ── build a single dropdown for a field ──────────────────────────────────
+ function buildDropdown(field){
+ var opts = (field.kind==='price') ? [] : boostOptions(field);
+ var active = curParams().getAll(field.param).map(decodeURIComponent).filter(function(v){return !denied(v);});
+ var dd=document.createElement('span');
+ dd.className='dw-dd'+(active.length?' has-sel':'');
+ dd.setAttribute('data-dd', field.key);
+
+ var btn=document.createElement('button');
+ btn.type='button'; btn.className='dw-dd__btn'; btn.setAttribute('aria-expanded','false'); btn.setAttribute('aria-haspopup','true');
+ btn.innerHTML = esc(field.label) + (active.length?(' <span class="dw-cnt">'+active.length+'</span>'):'') + ' <span class="dw-caret">▾</span>';
+ dd.appendChild(btn);
+
+ var panel=document.createElement('div'); panel.className='dw-dd__panel';
+
+ if(field.kind==='price'){
+ var cur=curParams().get('pf_p_price')||''; var mn='',mx='';
+ if(cur.indexOf(':')>-1){ var pr=cur.split(':'); mn=pr[0]; mx=pr[1]; }
+ panel.innerHTML =
+ '<div class="dw-dd__price">'+
+ '<input type="number" min="0" step="1" placeholder="Min" data-pmin value="'+esc(mn)+'">'+
+ '<span style="opacity:.5">–</span>'+
+ '<input type="number" min="0" step="1" placeholder="Max" data-pmax value="'+esc(mx)+'">'+
+ '</div>'+
+ '<button class="dw-dd__apply" data-papply>Apply price</button>';
+ panel.querySelector('[data-papply]').addEventListener('click',function(){
+ var lo=panel.querySelector('[data-pmin]').value.trim(), hi=panel.querySelector('[data-pmax]').value.trim();
+ var p=curParams();
+ if(lo||hi){ p.set('pf_p_price',(lo||'0')+':'+(hi||'999999')); } else { p.delete('pf_p_price'); }
+ navTo(p);
+ });
+ } else if(!opts.length){
+ panel.innerHTML='<div class="dw-dd__empty">No <b>'+esc(field.label)+'</b> options are available for this collection yet.</div>';
+ } else {
+ var html=opts.map(function(o){
+ var sw = field.swatch ? '<span class="dw-sw" style="background:'+swatchHex(o.label)+'"></span>' : '';
+ return '<label class="dw-opt"><input type="checkbox" data-val="'+esc(o.value)+'" '+(o.checked?'checked':'')+'>'+
+ sw+'<span class="dw-on">'+esc(o.label)+'</span>'+(o.count?('<span class="dw-oc">'+esc(o.count)+'</span>'):'')+'</label>';
+ }).join('');
+ panel.innerHTML=html;
+ panel.querySelectorAll('input[type="checkbox"]').forEach(function(cb){
+ cb.addEventListener('change',function(){
+ var p=curParams(); var val=cb.getAttribute('data-val');
+ var have=p.getAll(field.param).map(decodeURIComponent);
+ p.delete(field.param);
+ if(cb.checked){ if(have.indexOf(val)<0) have.push(val); }
+ else { have=have.filter(function(v){return v!==val;}); }
+ have.forEach(function(v){ p.append(field.param,v); });
+ navTo(p);
+ });
+ });
+ }
+ dd.appendChild(panel);
+
+ btn.addEventListener('click',function(e){
+ e.stopPropagation();
+ var wasOpen=dd.classList.contains('open');
+ closeAll();
+ if(!wasOpen){ dd.classList.add('open'); btn.setAttribute('aria-expanded','true'); }
+ });
+ return dd;
+ }
+
+ // ── navigation: write params + go (resets paging so Boost re-queries) ─────
+ function navTo(params){
+ params.delete('page'); // jump back to page 1 on any filter change
+ var qs=params.toString();
+ window.location.href = window.location.pathname + (qs?('?'+qs):'');
+ }
+
+ function closeAll(){
+ root.querySelectorAll('.dw-dd.open').forEach(function(d){ d.classList.remove('open'); var b=d.querySelector('.dw-dd__btn'); if(b)b.setAttribute('aria-expanded','false'); });
+ var g=root.querySelector('[data-tbf-gear]'); if(g)g.classList.remove('open');
+ }
+ document.addEventListener('click',function(ev){ if(!root.contains(ev.target)) closeAll(); });
+
+ // ── render the field dropdowns according to enabled set ──────────────────
+ function renderFields(){
+ var host=root.querySelector('[data-tbf-fields]'); if(!host) return;
+ var en=enabledSet();
+ host.innerHTML='';
+ FIELDS.forEach(function(f){ if(en.has(f.key)) host.appendChild(buildDropdown(f)); });
+ // clear-all enabled when any pf_*/q is present
+ var anyActive=false; curParams().forEach(function(v,k){ if(k.indexOf('pf_')===0||k==='q') anyActive=true; });
+ var clr=root.querySelector('[data-tbf-clear]'); if(clr) clr.disabled=!anyActive;
+ }
+
+ // ── gear menu: per-field ON/OFF, persisted ───────────────────────────────
+ function renderGear(){
+ var list=root.querySelector('[data-tbf-gear-list]'); if(!list) return;
+ var en=enabledSet();
+ list.innerHTML=FIELDS.map(function(f){
+ return '<label class="dw-opt"><input type="checkbox" data-fkey="'+f.key+'" '+(en.has(f.key)?'checked':'')+'><span class="dw-on">'+esc(f.label)+'</span></label>';
+ }).join('');
+ list.querySelectorAll('input[data-fkey]').forEach(function(cb){
+ cb.addEventListener('change',function(){
+ var s=enabledSet();
+ if(cb.checked) s.add(cb.getAttribute('data-fkey')); else s.delete(cb.getAttribute('data-fkey'));
+ lsSet(LS.fields, JSON.stringify(Array.from(s)));
+ renderFields();
+ });
+ });
+ }
+ var gearBtn=root.querySelector('[data-tbf-gear-btn]'), gear=root.querySelector('[data-tbf-gear]');
+ if(gearBtn&&gear){ gearBtn.addEventListener('click',function(e){ e.stopPropagation(); var o=gear.classList.contains('open'); closeAll(); if(!o){gear.classList.add('open');gearBtn.setAttribute('aria-expanded','true');} else gearBtn.setAttribute('aria-expanded','false'); }); }
+
+ // ── sort ─────────────────────────────────────────────────────────────────
+ var sortSel=root.querySelector('[data-tbf-sort]');
+ if(sortSel){
+ var curSort=curParams().get('sort_by')||lsGet(LS.sort,'');
+ if(curSort){ var opt=sortSel.querySelector('option[value="'+curSort+'"]'); if(opt) sortSel.value=curSort; }
+ sortSel.addEventListener('change',function(){
+ lsSet(LS.sort,this.value); var p=curParams();
+ if(this.value) p.set('sort_by',this.value); else p.delete('sort_by');
+ navTo(p);
+ });
+ }
+
+ // ── density (drives Boost's grid var ONLY, never the grid nodes) ──────────
+ // We set the CSS custom property --dw-grid-cols that the live theme's Boost
+ // override already binds to .boost-sd__product-list. We do NOT touch list
+ // children, never set grid-template on the list directly here unless the var
+ // isn't wired — purely additive, desktop-only.
+ var dens=root.querySelector('[data-tbf-density]'), dlabel=root.querySelector('[data-tbf-dlabel]');
+ function applyDensity(n){
+ document.documentElement.style.setProperty('--dw-grid-cols', n);
+ var list=document.querySelector('.boost-sd__product-list');
+ if(list && !getComputedStyle(list).getPropertyValue('--dw-grid-cols')){
+ // fallback only if the theme var isn't bound — still never removes nodes
+ list.style.gridTemplateColumns='repeat('+n+',minmax(0,1fr))';
+ }
+ if(dlabel) dlabel.textContent=n;
+ }
+ if(dens){
+ var savedD=lsGet(LS.density,'4'); dens.value=savedD; applyDensity(parseInt(savedD,10)||4);
+ dens.addEventListener('input',function(){ var n=parseInt(this.value,10)||4; lsSet(LS.density,n); applyDensity(n); });
+ }
+
+ // ── search ────────────────────────────────────────────────────────────────
+ var srch=root.querySelector('[data-tbf-search]');
+ if(srch){
+ srch.value=curParams().get('q')||'';
+ var t; srch.addEventListener('input',function(){ clearTimeout(t); var self=this; t=setTimeout(function(){
+ lsSet(LS.search,self.value); var p=curParams();
+ if(self.value.trim()) p.set('q',self.value.trim()); else p.delete('q');
+ navTo(p);
+ },450); });
+ srch.addEventListener('keydown',function(e){ if(e.key==='Enter'){ clearTimeout(t); var p=curParams(); if(this.value.trim())p.set('q',this.value.trim());else p.delete('q'); navTo(p);} });
+ }
+
+ // ── clear all ──────────────────────────────────────────────────────────────
+ var clr=root.querySelector('[data-tbf-clear]');
+ if(clr) clr.addEventListener('click',function(){
+ var p=curParams(); var del=[];
+ p.forEach(function(v,k){ if(k.indexOf('pf_')===0||k==='q'||k==='page') del.push(k); });
+ del.forEach(function(k){ p.delete(k); });
+ navTo(p);
+ });
+
+ // ── re-read Boost options when Boost re-renders (debounced, read-only) ────
+ // Only repopulates OUR dropdowns; never writes to Boost's tree.
+ var ro; var target=document.querySelector('.boost-sd__filter-tree')||document.querySelector('.boost-sd__sidebar');
+ if(target){
+ var mo=new MutationObserver(function(){ clearTimeout(ro); ro=setTimeout(function(){ renderFields(); renderCount(); },300); });
+ mo.observe(target,{childList:true,subtree:true});
+ }
+
+ // ── product-type segmented control (ports Boost's Wallcoverings/Fabrics tabs) ─
+ var typeWrap=root.querySelector('[data-tbf-types]');
+ if(typeWrap){
+ var curType=curParams().get('pf_t_product_type')||'';
+ typeWrap.querySelectorAll('button[data-ptype]').forEach(function(b){
+ if(b.getAttribute('data-ptype')===curType) b.setAttribute('aria-pressed','true');
+ b.addEventListener('click',function(){
+ var p=curParams(); var t=b.getAttribute('data-ptype');
+ if(t) p.set('pf_t_product_type',t); else p.delete('pf_t_product_type');
+ navTo(p);
+ });
+ });
+ }
+
+ // ── live product count (ports Boost's "N products"); STRICTLY read-only ──────
+ function readCount(){
+ var sels=['.boost-sd__total-product','.boost-sd__filter-total-product','.boost-sd__total-product-count','.boost-sd__refine-total'];
+ for(var i=0;i<sels.length;i++){ var el=document.querySelector(sels[i]); if(el){ var m=(el.textContent||'').match(/[\d,]+/); if(m) return m[0]; } }
+ var tb=document.querySelector('.boost-sd__toolbar'); // hidden via CSS but present in DOM
+ if(tb){ var mm=(tb.textContent||'').match(/([\d,]+)\s*(products|results|items)/i); if(mm) return mm[1]; }
+ return null;
+ }
+ function renderCount(){ var c=root.querySelector('[data-tbf-count]'); if(!c) return; var n=readCount(); c.textContent = n ? (n+' products') : ''; }
+
+ // ── boot ──────────────────────────────────────────────────────────────────
+ renderFields(); renderGear(); renderCount();
+ // Boost loads async — retry the count a few times until it appears.
+ var _ct=0, _ci=setInterval(function(){ renderCount(); if(++_ct>8 || root.querySelector('[data-tbf-count]').textContent) clearInterval(_ci); },500);
+})();
+</script>
+
+{% schema %}
+{
+ "name": "DW Boost Filter Topbar",
+ "tag": "section",
+ "class": "dw-boost-filter-topbar",
+ "settings": [
+ {
+ "type": "header",
+ "content": "Filter Topbar"
+ },
+ {
+ "type": "paragraph",
+ "content": "Horizontal dropdown filter toolbar that drives Boost's pf_* params. Per-field show/hide is controlled by the shopper via the ⚙ menu (persisted in their browser); these defaults only seed first-visit."
+ },
+ {
+ "type": "color",
+ "id": "color_accent",
+ "label": "Accent color",
+ "default": "#111111"
+ }
+ ],
+ "presets": [
+ { "name": "DW Boost Filter Topbar" }
+ ]
+}
+{% endschema %}
diff --git a/sections/dw-collection-hero.liquid b/sections/dw-collection-hero.liquid
new file mode 100644
index 0000000..355f6b8
--- /dev/null
+++ b/sections/dw-collection-hero.liquid
@@ -0,0 +1,90 @@
+{%- comment -%}
+ DW Collection Hero — Steve standing rule (2026-06-23): every collection page
+ must have a background "bg" hero image. Renders collection.image as a full-bleed
+ cover background with the title + breadcrumbs + description on a SEMI-OPAQUE
+ CONTRASTING PANEL (dark scrim panel) so the text stays legible over any image.
+ Collections with no image fall back to a branded gradient so the page is never
+ broken; audit-collection-hero-images.py lists which collections still need one.
+
+ Also HIDES the Boost AI Search & Filter app's own collection banner (the
+ duplicate lower banner) + any legacy theme breadcrumbs, so only this hero shows.
+
+ Toggle by removing it from templates/collection.json "order".
+{%- endcomment -%}
+{%- liquid
+ assign dw_has_hero = false
+ if collection.image
+ assign dw_has_hero = true
+ endif
+-%}
+<div class="dw-collection-hero{% unless dw_has_hero %} dw-collection-hero--fallback{% endunless %}"
+ {% if dw_has_hero %}style="background-image:url({{ collection.image | img_url: '2048x' }});"{% endif %}
+ data-dw-collection-hero>
+ <div class="dw-collection-hero__inner page-width">
+ <div class="dw-collection-hero__panel">
+ <nav class="dw-collection-hero__crumbs" aria-label="Breadcrumb">
+ <a href="/">Home</a> <span aria-hidden="true">/</span>
+ <a href="/collections">Collections</a> <span aria-hidden="true">/</span>
+ <span aria-current="page">{{ collection.title }}</span>
+ </nav>
+ <h1 class="dw-collection-hero__title">{{ collection.title }}</h1>
+ {%- if section.settings.show_description and collection.description != blank -%}
+ <div class="dw-collection-hero__desc">{{ collection.description | strip_html | truncatewords: 32 }}</div>
+ {%- endif -%}
+ </div>
+ </div>
+</div>
+<style>
+ .dw-collection-hero{position:relative;min-height:clamp(80px,10.7vw,140px);display:flex;
+ align-items:center;background-size:cover;background-position:center;background-repeat:no-repeat;
+ margin:0 0 1.5rem;overflow:hidden;}
+ .dw-collection-hero--fallback{background:linear-gradient(135deg,#1c1c1c 0%,#3a3a3a 55%,#2a2320 100%);}
+ .dw-collection-hero__inner{position:relative;z-index:1;width:100%;padding:0.9rem 2.25rem;}
+ /* Semi-opaque CONTRASTING panel behind the text — dark scrim over the light
+ pattern so title/breadcrumbs/description read clearly without darkening the
+ whole image. Constrained width, left-aligned. */
+ .dw-collection-hero__panel{display:inline-block;max-width:min(640px,92%);
+ background:rgba(22,18,16,0.66);
+ -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
+ border:1px solid rgba(255,255,255,0.14);border-radius:6px;
+ padding:1.4rem 1.75rem;box-shadow:0 6px 30px rgba(0,0,0,.28);}
+ .dw-collection-hero__crumbs{font-size:.78rem;letter-spacing:.04em;text-transform:uppercase;
+ color:#fff;opacity:.92;margin:0 0 .45rem;}
+ .dw-collection-hero__crumbs a,.dw-collection-hero__crumbs span{color:#fff;text-decoration:none;}
+ .dw-collection-hero__crumbs a:hover{text-decoration:underline;}
+ .dw-collection-hero__title{color:#fff;font-size:clamp(1.8rem,3.4vw,3rem);margin:.1rem 0 0;
+ letter-spacing:.5px;line-height:1.05;}
+ .dw-collection-hero__desc{color:#fff;max-width:60ch;margin:.6rem 0 0;opacity:.96;
+ font-size:.95rem;line-height:1.55;}
+
+ /* Hide the duplicate LOWER banner drawn by the Boost AI Search & Filter app
+ (its own collection header/banner) so only this hero shows. */
+ .boost-sd__collection-header,
+ .boost-sd__page-header,
+ .boost-sd__collection-header-image,
+ .boost-sd__collection-header-content,
+ .boost-sd__collection-header-title,
+ .boost-sd__collection-header-description,
+ .boost-sd__collection-title,
+ .boost-sd__collection-description{display:none !important;}
+ /* hero now carries breadcrumbs: hide any legacy theme breadcrumbs on collection pages */
+ .template-collection .breadcrumbs,
+ .template-collection .breadcrumb{display:none;}
+</style>
+
+{% schema %}
+{
+ "name": "DW Collection Hero",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_description",
+ "label": "Show collection description in hero",
+ "default": true
+ }
+ ],
+ "presets": [
+ { "name": "DW Collection Hero" }
+ ]
+}
+{% endschema %}
diff --git a/sections/footer-group.json b/sections/footer-group.json
new file mode 100644
index 0000000..cf490ee
--- /dev/null
+++ b/sections/footer-group.json
@@ -0,0 +1,65 @@
+/*
+ * ------------------------------------------------------------
+ * IMPORTANT: The contents of this file are auto-generated.
+ *
+ * This file may be updated by the Shopify admin theme editor
+ * or related systems. Please exercise caution as any changes
+ * made to this file may be overwritten.
+ * ------------------------------------------------------------
+ */
+{
+ "type": "footer",
+ "name": "Footer",
+ "sections": {
+ "footer": {
+ "type": "footer",
+ "blocks": {
+ "1501865688783": {
+ "type": "social-links",
+ "settings": {}
+ },
+ "menu_nAnxqh": {
+ "type": "menu",
+ "settings": {
+ "menu": "footer"
+ }
+ },
+ "1522268487363": {
+ "type": "menu",
+ "settings": {
+ "menu": "resources"
+ }
+ },
+ "1502298878006": {
+ "type": "rich-text",
+ "settings": {
+ "heading": "",
+ "rich_text": "<p>For over 25 years, the nation's leading resource for architectural and luxury wallcoverings.<\/p><p>Can't find what you are looking for? We can design & print it for you. <\/p>"
+ }
+ },
+ "1588892853067": {
+ "type": "newsletter",
+ "disabled": true,
+ "settings": {}
+ }
+ },
+ "block_order": [
+ "1501865688783",
+ "menu_nAnxqh",
+ "1522268487363",
+ "1502298878006",
+ "1588892853067"
+ ],
+ "settings": {
+ "headings": false,
+ "show_follow_on_shop": false,
+ "show_locale_selector": true,
+ "show_currency_selector": true,
+ "footer-payment-options": true
+ }
+ }
+ },
+ "order": [
+ "footer"
+ ]
+}
diff --git a/sections/footer.liquid b/sections/footer.liquid
new file mode 100644
index 0000000..e9861ce
--- /dev/null
+++ b/sections/footer.liquid
@@ -0,0 +1,497 @@
+<script
+ type="application/json"
+ data-section-type="static-footer"
+ data-section-id="{{ section.id }}"
+>
+</script>
+
+{% liquid
+ assign hasNewsletter = false
+ assign blockCount = 0
+
+ for block in section.blocks
+ assign blockCount = blockCount | plus: 1
+ case block.type
+ when 'newsletter'
+ assign hasNewsletter = true
+ endcase
+ endfor
+
+ assign show_follow_on_shop = false
+ assign country_selector = section.settings.show_currency_selector
+ assign locale_selector = section.settings.show_locale_selector
+ assign show_payment_types = false
+ assign right_column_item_count = 0
+ assign total_item_count = 0
+ assign additional_sub_footer_right_class = ''
+
+ if shop.features.follow_on_shop? and section.settings.show_follow_on_shop
+ assign show_follow_on_shop = true
+ assign total_item_count = total_item_count | plus: 1
+ endif
+
+ if shop.enabled_payment_types.size > 0 and section.settings.footer-payment-options
+ assign show_payment_types = true
+ assign right_column_item_count = right_column_item_count | plus: 1
+ assign total_item_count = total_item_count | plus: 1
+ endif
+
+ if country_selector or locale_selector
+ assign right_column_item_count = right_column_item_count | plus: 1
+ assign total_item_count = total_item_count | plus: 1
+ endif
+
+ if right_column_item_count == 1
+ if country_selector or locale_selector
+ assign additional_sub_footer_right_class = 'sub-footer-right--selectors-only'
+ else
+ assign additional_sub_footer_right_class = 'sub-footer-right--payments-only'
+ endif
+ endif
+%}
+
+{% capture footer_right_column %}
+ {%- if right_column_item_count > 0 -%}
+ <div class="sub-footer-right {{ additional_sub_footer_right_class }}">
+ {%- if country_selector or locale_selector -%}
+ {% comment %}Inject @pixelunion/shopify-cross-border/cross-border begin{% endcomment %}
+ <div class="shopify-cross-border">
+ {% if locale_selector and localization.available_languages.size > 1 %}
+ {% comment %}Inject @pixelunion/shopify-cross-border/multi-language begin{% endcomment %}
+ {% comment %} Generate a "random" number so ids are unique {% endcomment %}
+ {% assign unique_id = "now" | date: "%N" | modulo: 1000 %}
+ <noscript>
+ {%- form 'localization' -%}
+ <details class="disclosure">
+ <summary>
+ <span class="disclosure__toggle">
+ {{ form.current_locale.endonym_name | capitalize }}
+ </span>
+ </summary>
+ <div class="disclosure-list disclosure-list--visible">
+ {% for locale in form.available_locales %}
+ <div class="disclosure-list__item-wrapper disclosure-list__item">
+ <input
+ type="radio"
+ id="{{ locale.iso_code }}"
+ name="locale_code"
+ value="{{ locale.iso_code }}"
+ {% if locale.iso_code == form.current_locale.iso_code %}checked{% endif %}
+ >
+ <label class="disclosure-list__item--label" for="{{ locale.iso_code }}">{{ locale.endonym_name | capitalize }}</label>
+ </div>
+ {% endfor %}
+ <button class="disclosure__submit" type="submit">{{ 'general.language.submit_button_label' | t }}</button>
+ </div>
+ </details>
+ {%- endform -%}
+ </noscript>
+
+ {%- form 'localization' -%}
+ <div class="selectors-form__item selectors-form--no-js-hidden">
+ <div class="disclosure" data-disclosure-locale>
+ <h2 class="visually-hidden" id="lang-heading-{{ unique_id }}">
+ {{ 'general.language.dropdown_label' | t }}
+ </h2>
+
+ <button
+ type="button"
+ class="disclosure__toggle"
+ aria-expanded="false"
+ aria-controls="lang-list-{{ unique_id }}"
+ aria-describedby="lang-heading-{{ unique_id }}"
+ data-disclosure-toggle
+ >
+ {{ form.current_locale.endonym_name | capitalize }}
+ </button>
+ <ul id="lang-list-{{ unique_id }}" class="disclosure-list" data-disclosure-list>
+ {% for locale in form.available_locales %}
+ <li>
+ <a class="disclosure-list__item {% if locale.iso_code == form.current_locale.iso_code %}disclosure-list__item--current{% endif %}" href="#" lang="{{ locale.iso_code }}" {% if locale.iso_code == form.current_locale.iso_code %}aria-current="true"{% endif %} data-value="{{ locale.iso_code }}" data-disclosure-option>
+ <span class="disclosure-list__option">{{ locale.endonym_name | capitalize }}</span>
+ </a>
+ </li>
+ {%- endfor -%}
+ </ul>
+ <input type="hidden" name="locale_code" id="LocaleSelector-{{ unique_id }}" value="{{ form.current_locale.iso_code }}" data-disclosure-input/>
+ </div>
+ </div>
+ {%- endform -%}
+ {% comment %}Inject @pixelunion/shopify-cross-border/multi-language end{% endcomment %}
+
+ {% endif %}
+
+ {% if country_selector and localization.available_countries.size > 1 %}
+ {% comment %}Inject @pixelunion/shopify-cross-border/multi-country begin{% endcomment %}
+ {% comment %} Generate a "random" number so ids are unique {% endcomment %}
+ {% assign unique_id = "now" | date: "%N" | modulo: 1000 %}
+ <noscript>
+ {%- form 'localization' -%}
+ <details class="disclosure">
+ <summary>
+ <span class="disclosure__toggle">
+ {{ localization.country.name }} ({{ localization.country.currency.iso_code }}{% if localization.country.currency.symbol %}{{ localization.country.currency.symbol }}{% endif %})
+ </span>
+ </summary>
+ <div class="disclosure-list disclosure-list--visible">
+ {% for country in localization.available_countries %}
+ <div class="disclosure-list__item-wrapper disclosure-list__item">
+ <input
+ type="radio"
+ id="{{ country.iso_code }}"
+ name="country_code"
+ value="{{ country.iso_code }}"
+ {% if country.iso_code == localization.country.iso_code %}checked{% endif %}
+ >
+ <label class="disclosure-list__item--label" for="{{ country.iso_code }}">{{ country.name }} ({{ country.currency.iso_code }}{%- if country.currency.symbol -%} {{ country.currency.symbol }}{%- endif -%})</label>
+ </div>
+ {% endfor %}
+ <button class="disclosure__submit" type="submit">{{ 'general.country.submit_button_label' | t }}</button>
+ </div>
+ </details>
+ {%- endform -%}
+ </noscript>
+
+ {%- form 'localization' -%}
+ <div class="selectors-form__item selectors-form--no-js-hidden">
+ <div class="disclosure" data-disclosure-country>
+ <h2 class="visually-hidden" id="country-heading-{{ unique_id }}">
+ {{ 'general.country.dropdown_label' | t }}
+ </h2>
+
+ <button
+ type="button"
+ class="disclosure__toggle"
+ aria-expanded="false"
+ aria-controls="country-list-{{ unique_id }}"
+ aria-describedby="country-heading-{{ unique_id }}"
+ data-disclosure-toggle
+ >
+ {{ localization.country.name }}
+ <span class="disclosure-list__option-code">
+ ({{ localization.country.currency.iso_code }}
+ {% if localization.country.currency.symbol %} {{ localization.country.currency.symbol }}{% endif %})
+ </span>
+ </button>
+ <ul id="country-list-{{ unique_id }}" class="disclosure-list" data-disclosure-list>
+ {% for country in localization.available_countries %}
+ <li>
+ <a class="disclosure-list__item {% if country.iso_code == localization.country.iso_code %}disclosure-list__item--current{% endif %}" href="#" {% if country.iso_code == localization.country.iso_code %}aria-current="true"{% endif %} data-value="{{ country.iso_code }}" data-disclosure-option>
+ <span class="disclosure-list__option">{{ country.name }}</span>
+ <span class="disclosure-list__option-code">
+ ({{ country.currency.iso_code }}
+ {% if country.currency.symbol %} {{ country.currency.symbol }}{%- endif -%})
+ </span>
+ </a>
+ </li>
+ {%- endfor -%}
+ </ul>
+ <input type="hidden" name="country_code" id="CountrySelector-{{ unique_id }}" value="{{ localization.country.iso_code }}" data-disclosure-input/>
+ </div>
+ </div>
+ {%- endform -%}
+ {% comment %}Inject @pixelunion/shopify-cross-border/multi-country end{% endcomment %}
+
+ {% endif %}
+ </div>
+ {% comment %}Inject @pixelunion/shopify-cross-border/cross-border end{% endcomment %}
+
+ {%- endif -%}
+
+ {%- if show_payment_types -%}
+ <div class="subfooter__payment-types">
+ {%- for type in shop.enabled_payment_types -%}
+ {{ type | payment_type_svg_tag }}
+ {%- endfor -%}
+ </div>
+ {%- endif -%}
+ </div>
+ {%- endif -%}
+{% endcapture %}
+
+<footer
+ class="
+ main-footer
+ {% if hasNewsletter %}upper-footer-has-newsletter{% endif %}
+ "
+>
+
+ {% assign linklistCount = 0 %}
+ {% for i in (1..3) %}
+ {% capture linklistOption %}footer-linklist-{{ i }}{% endcapture %}
+ {% capture linklist %}{{ section.settings[linklistOption] }}{% endcapture %}
+
+ {% if linklist.size > 0 %}
+ {% assign linklistCount = linklistCount | plus: 1 %}
+ {% endif %}
+ {% endfor %}
+
+ {% if section.blocks.size > 0 %}
+ <div class="upper-footer upper-footer-item-count-{{ blockCount }}">
+
+ {%- for block in section.blocks -%}
+ {%- case block.type -%}
+ {%- when 'rich-text' -%}
+ <div class="upper-footer-item footer-blurb">
+ {% if section.settings.headings %}
+ <h3 class="section-title">
+ {{- block.settings.heading | escape -}}
+ </h3>
+ {% endif %}
+
+ <div class="rte">{{ block.settings.rich_text }}</div>
+ </div>
+ {%- when 'social-links' -%}
+ <div class="upper-footer-item footer-linklist">
+ {% if section.settings.headings %}
+ <h3 class="section-title">
+ {{- 'layout.footer.social_heading'| t -}}
+ </h3>
+ {% endif %}
+
+ {% render 'social' %}
+ </div>
+ {%- when 'menu' -%}
+ {% assign linklist = linklists[block.settings.menu] %}
+
+ {% if linklist.links.size > 0 %}
+ <div class="upper-footer-item footer-linklist">
+ {% if section.settings.headings %}
+ <h3 class="section-title">
+ {{- linklist.title -}}
+ </h3>
+ {% endif %}
+
+ <ul>
+ {% for link in linklist.links %}
+ <li><a href="{{ link.url }}" {% if link.url contains 'http://' or link.url contains 'https://' %}target="_blank"{% endif %}>{{ link.title }}</a></li>
+ {% endfor %}
+ </ul>
+ </div>
+ {% endif %}
+ {%- when 'newsletter' -%}
+ <div class="mailing-list">
+ {% if section.settings.headings %}
+ <h3 class="section-title">
+ {{- 'general.newsletter.title' | t -}}
+ </h3>
+ {% endif %}
+
+ {% form 'customer' %}
+ {% if form.posted_successfully? %}
+ <p class="mailing-list-success">
+ {{ 'general.newsletter.success' | t }}
+ </p>
+ {% else %}
+ <p class="mailing-list-error">
+ {{ form.errors | default_errors }}
+ </p>
+ {% endif %}
+
+ <div class="mailing-list-input">
+ <input class="mailing-list-email input" name="contact[email]" type="email" placeholder="your@email.com" value="">
+ <input type="hidden" class="input" id="contact_tags" name="contact[tags]" value="prospect,newsletter"/>
+ <div class="mailing-list-submit">
+ <input class="submit input" name="subscribe" type="submit" value="{{ 'general.newsletter.subscribe' | t }}">
+ </div>
+ </div>
+ {% endform %}
+ </div>
+ {%- endcase -%}
+ {%- endfor -%}
+ </div>
+ {% endif %}
+
+ <div>
+ <img src="{{ 'Screen_Shot_2019-01-13_at_11.18.49_AM.png' | file_img_url: '125x' }}" width="125px" height="62"/>
+ <img src="{{ 'architecture_digest.png' | file_img_url: '125x' }}" width="125px" height="75"/>
+ <img src="{{ 'Screen_Shot_2019-01-13_at_4.19.27_PM.png' | file_img_url: '125x' }}" width="125px" height="46"/>
+ </div>
+
+ <div
+ class="
+ subfooter
+ {% if total_item_count == 0 %}subfooter--layout-copyright-only{% endif %}
+ {% if total_item_count == 1 %}subfooter--layout-column{% endif %}
+ "
+ >
+ {%- if right_column_item_count > 0 -%}
+ <div class="sub-footer__row sub-footer__row--first">
+ {%- if show_follow_on_shop -%}
+ {{ shop | login_button: action: 'follow' }}
+ {%- endif -%}
+ {{ footer_right_column }}
+ </div>
+ {%- endif -%}
+
+ <div
+ class="
+ sub-footer__row
+ {% if right_column_item_count > 0 %}
+ sub-footer__row--second
+ {% else %}
+ sub-footer__row--first
+ {% endif %}
+ "
+ >
+
+ {% capture year %}{{ "now" | date: "%Y" }}{% endcapture %}
+ {% capture shopName %}{{ shop.name | link_to: routes.root_url -}}{% endcapture %}
+ <p class="copyright-wrapper" role="contentinfo">
+ {{ 'general.general.copyright_html' | t: year: year, shop_name: shopName }}
+ {{ powered_by_link }}
+ </p>
+
+ {{ footer_right_column }}
+
+ {%- if show_follow_on_shop and right_column_item_count == 0 -%}
+ {{ shop | login_button: action: 'follow' }}
+ {%- endif -%}
+ </div>
+
+ </div>
+
+</footer>
+
+{%- comment -%}
+ Shop-by-Color tab handle fix (Steve 2026-07-09). The /pages/shop-by-color page
+ body links 6 color tiles to collection handles that 404 (a -wallcovering- vs
+ -wallpaper- naming mismatch). The page body needs write_content scope to edit
+ directly; until that lands, correct the 6 dead hrefs client-side on that page
+ ONLY. Inert on every other page. Remove once the page body is fixed.
+{%- endcomment -%}
+{%- if request.path contains '/pages/shop-by-color' -%}
+<script>
+(function(){
+ var FIX={
+ 'blue-wallpaper-collection':'blue-wallpaper',
+ 'yellow-wallcovering-collection':'yellow-wallpaper-collection',
+ 'orange-wallcovering-collection':'orange',
+ 'red-wallcovering-collection':'red-wallpaper-collection',
+ 'grey-wallcovering':'grey-silver',
+ 'white-wallcovering-collection':'white-wallpaper-collection'
+ };
+ function fixOne(a){
+ var h=a.getAttribute('href')||'';
+ for(var bad in FIX){
+ if(h.indexOf('/collections/'+bad)===0 || h==='/collections/'+bad){
+ a.setAttribute('href', h.replace('/collections/'+bad, '/collections/'+FIX[bad]));
+ if(a.dataset && a.dataset.handle===bad) a.dataset.handle=FIX[bad];
+ break;
+ }
+ }
+ }
+ function run(){ document.querySelectorAll('a[href*="/collections/"]').forEach(fixOne); }
+ if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',run);}else{run();}
+})();
+</script>
+{%- endif -%}
+
+{% schema %}
+{
+ "name": "Footer",
+ "max_blocks": 5,
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "headings",
+ "label": "Show footer headings",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Follow on Shop",
+ "info": "Display follow button for your storefront on the Shop app. [Learn more](https:\/\/help.shopify.com\/manual\/online-store\/themes\/customizing-themes\/follow-on-shop)"
+ },
+ {
+ "type": "checkbox",
+ "id": "show_follow_on_shop",
+ "label": "Enable Follow on Shop",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Language Selector",
+ "info": "To add a language, go to your [language settings.](/admin/settings/languages)"
+ },
+ {
+ "type": "checkbox",
+ "id": "show_locale_selector",
+ "label": "Show language selector",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Country Selector",
+ "info": "To add a country, go to your [payment settings.](/admin/settings/payments)"
+ },
+ {
+ "type": "checkbox",
+ "id": "show_currency_selector",
+ "label": "Show country selector",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Payment icons"
+ },
+ {
+ "type": "checkbox",
+ "id": "footer-payment-options",
+ "label": "Show payment icons"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "rich-text",
+ "name": "Rich text",
+ "settings": [
+ {
+ "type": "text",
+ "id": "heading",
+ "label": "Heading",
+ "default": "Rich text"
+ },
+ {
+ "type": "richtext",
+ "id": "rich_text",
+ "label": "Text",
+ "default": "<p>Use this section to welcome customers to your store, say a bit about your brand, or share news and seasonal promotions.</p>"
+ }
+ ]
+ },
+ {
+ "type": "social-links",
+ "name": "Social links",
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "Social media account settings can be found in the \"social media\" section of \"theme settings\"."
+ }
+ ],
+ "limit": 1
+ },
+ {
+ "type": "menu",
+ "name": "Menu",
+ "settings": [
+ {
+ "type": "link_list",
+ "id": "menu",
+ "label": "Menu",
+ "info": "This menu won't show dropdown items.",
+ "default": "main-menu"
+ }
+ ]
+ },
+ {
+ "type": "newsletter",
+ "name": "Newsletter",
+ "settings": [
+ ],
+ "limit": 1
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/header-group.json b/sections/header-group.json
new file mode 100644
index 0000000..9040967
--- /dev/null
+++ b/sections/header-group.json
@@ -0,0 +1,127 @@
+/*
+ * ------------------------------------------------------------
+ * IMPORTANT: The contents of this file are auto-generated.
+ *
+ * This file may be updated by the Shopify admin theme editor
+ * or related systems. Please exercise caution as any changes
+ * made to this file may be overwritten.
+ * ------------------------------------------------------------
+ */
+{
+ "type": "header",
+ "name": "Header",
+ "sections": {
+ "announcement_bar": {
+ "type": "pxs-announcement-bar",
+ "settings": {
+ "show_announcement": true,
+ "announcement_home_only": false,
+ "announcement_text": "Sign Up Today - No Charge Samples for qualified design trade professionals and 3 Free for Retail.",
+ "announcement_text_mobile": "Free trade samples · 3 for retail — Sign up",
+ "announcement_link": "#dw-signin",
+ "announcement_color": "#ffffff",
+ "announcement_background": "#262626"
+ }
+ },
+ "header": {
+ "type": "header",
+ "blocks": {
+ "header_customer_link_xeQjb3": {
+ "type": "header_customer_link",
+ "settings": {
+ "link_text": "(888) 373-4564",
+ "link_url": "tel:+18883734564"
+ }
+ },
+ "mega_menu_37rKTg": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Collections"
+ }
+ },
+ "mega_menu_xmfqGW": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Styles"
+ }
+ },
+ "mega_menu_Wxi38J": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Durable"
+ }
+ },
+ "mega_menu_AwaATJ": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Specialty"
+ }
+ },
+ "mega_menu_fb6aMJ": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "more"
+ }
+ },
+ "mega_menu_f3yKaB": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Featured"
+ }
+ },
+ "mega_menu_R7CCKD": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Showroom Lines"
+ }
+ },
+ "mega_menu_AfKBEi": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Fabrics"
+ }
+ },
+ "mega_menu_CYGBL8": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "More Lines"
+ }
+ },
+ "1517006611982": {
+ "type": "mega_menu",
+ "settings": {
+ "menu_item": "Commercial"
+ }
+ }
+ },
+ "block_order": [
+ "header_customer_link_xeQjb3",
+ "mega_menu_37rKTg",
+ "mega_menu_xmfqGW",
+ "mega_menu_Wxi38J",
+ "mega_menu_AwaATJ",
+ "mega_menu_fb6aMJ",
+ "mega_menu_f3yKaB",
+ "mega_menu_R7CCKD",
+ "mega_menu_AfKBEi",
+ "mega_menu_CYGBL8",
+ "1517006611982"
+ ],
+ "settings": {
+ "logo": "shopify://shop_images/Screen_Shot_2019-02-06_at_12.08.24_PM.png",
+ "header_layout": "compact-left",
+ "header_full_width": true,
+ "header_border": true,
+ "sticky_header": true,
+ "sticky_header_logo": true,
+ "enable_predictive_search": false,
+ "menu": "main-menu",
+ "enable_checkout_lock_icon": true
+ }
+ }
+ },
+ "order": [
+ "announcement_bar",
+ "header"
+ ]
+}
diff --git a/sections/header.liquid b/sections/header.liquid
new file mode 100644
index 0000000..1e2bf40
--- /dev/null
+++ b/sections/header.liquid
@@ -0,0 +1,589 @@
+<style>
+ .main-header .header-content-right .customer-links{ display:inline-flex !important; align-items:center; position:relative; margin:0; }
+ .main-header .header-content-right .customer-links > .header-icon-link{ display:inline-flex; align-items:center; }
+ .dw-mobile-search{ display:none; }
+ /* Mobile header: logo row, full-width search row, then a clean icon row below; hamburger top-right */
+ @media(max-width:749px){
+ /* keep the phone number (aligned-left); only hide the now-empty account slot */
+ .main-header .header-tools .aligned-right{ display:none !important; }
+ .main-header .header-tools{ justify-content:center !important; }
+ .main-header .header-main-content{ display:flex !important; flex-wrap:wrap !important; align-items:center !important; justify-content:center !important; row-gap:14px !important; padding:14px !important; position:relative !important; }
+ .main-header .header-branding{ position:static !important; transform:none !important; left:auto !important; right:auto !important; top:auto !important; margin:0 auto !important; order:1 !important; flex:0 0 100% !important; width:100% !important; display:flex !important; justify-content:center !important; }
+ .dw-mobile-search{ display:flex !important; order:2 !important; flex:0 0 100% !important; width:100% !important; align-items:center; gap:9px; background:#f4f2ee; border:1px solid #e0dcd2; border-radius:999px; padding:11px 18px; }
+ .dw-mobile-search .dw-ms-icon{ display:inline-flex; flex:0 0 auto; }
+ .dw-mobile-search .dw-ms-icon svg{ width:16px; height:16px; }
+ .dw-mobile-search input{ border:0; background:transparent; outline:none; font:inherit; font-size:14px; width:100%; color:#26241f; }
+ .main-header .header-content-right{ order:3 !important; flex:0 0 100% !important; width:100% !important; display:flex !important; align-items:center !important; justify-content:space-around !important; position:static !important; }
+ .main-header .header-content-right > *{ position:static !important; margin:0 !important; top:auto !important; }
+ .main-header .header-content-right .header-quick-search{ display:none !important; }
+ .main-header .header-content-left{ order:4 !important; position:absolute !important; top:16px !important; right:16px !important; margin:0 !important; }
+ .main-header .header-content-left .navigation-toggle-open{ display:inline-flex !important; }
+ }
+</style>
+<script
+ type="application/json"
+ data-section-type="static-header"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+ {
+ "stickyHeader": {{ section.settings.sticky_header }},
+ "compactCenter": "{{ section.settings.header_layout }}",
+ "enable_predictive_search": "{{ section.settings.enable_predictive_search }}"
+ }
+</script>
+
+{%- capture arrow_right -%}
+ {%-
+ render 'icons',
+ id: 'chevron-right'
+ -%}
+{%- endcapture -%}
+
+{% assign mega_nav_handle = section.settings.mega-nav-handle %}
+
+{%- capture header_classes -%}
+ header
+ header-layout-{{ section.settings.header_layout }}
+
+ {% if section.settings.header_full_width %}
+ header-full-width
+ {% else %}
+ header-content-width
+ {% endif %}
+
+ {% if section.settings.sticky_header and section.settings.sticky_header_logo %}
+ header-sticky-show-logo
+ {% endif %}
+
+ {% if section.settings.header_border and template != 'index' %}
+ header-border
+ {% endif %}
+{%- endcapture -%}
+
+<section
+ class="{{ header_classes | replace: ' ', ' ' | strip_newlines }}"
+ {% if section.settings.sticky_header %}data-sticky-header{% endif %}
+ {% if section.settings.header_layout == 'compact-center' %}data-header-compact-center{% endif %}
+ data-section-header
+>
+ <header
+ class="main-header"
+ role="banner"
+ data-header-main
+ >
+ <div class="header-tools-wrapper">
+ <div class="header-tools">
+
+ <div class="aligned-left">
+ <div id="coin-container"></div>
+ </div>
+
+ <div class="aligned-left">
+ {% assign customer_link_blocks = section.blocks | where: 'type', 'header_customer_link' %}
+ {% for block in customer_link_blocks %}
+ <div class="customer-links" {{ block.shopify_attributes }}>
+ <a href="{{ block.settings.link_url }}">{{ block.settings.link_text }}</a>
+ </div>
+ {% endfor %}
+ </div>
+
+ <div class="aligned-right"></div>
+
+ </div>
+ </div>
+
+ <div class="header-main-content" data-header-content>
+ {% unless section.settings.menu == blank %}
+ <div class="header-content-left">
+ <button
+ class="navigation-toggle navigation-toggle-open"
+ aria-label="{{ 'layout.header.menu' | t }}"
+ data-header-nav-toggle
+ >
+ <span class="navigation-toggle-icon">
+ {%-
+ render 'icons',
+ id: 'menu'
+ -%}
+ </span>
+ </button>
+ </div>
+ {% endunless %}
+
+ <div
+ class="
+ header-branding
+ header-branding-desktop
+ {% if section.settings.logo %}header-branding-desktop--has-logo{% endif %}
+ "
+ data-header-branding
+ >
+ <a class="logo-link" href="{{ routes.root_url }}">
+ {%- if section.settings.logo -%}
+ {%
+ render 'rimg',
+ img: section.settings.logo,
+ class: 'logo-image',
+ size: '200x100',
+ focal_point: section.settings.logo.presentation.focal_point,
+ %}
+ <span class="header-wordmark">Designer<br>Wallcoverings</span>
+ {%- else -%}
+ <h1>{{- shop.name -}}</h1>
+ {%- endif -%}
+ </a>
+ <span
+ class="navigation-toggle navigation-toggle-close"
+ data-header-nav-toggle
+ >
+ {%-
+ render 'icons',
+ id: 'close',
+ -%}
+ </span>
+ </div>
+
+ <form class="dw-mobile-search" action="{{ routes.search_url }}" method="get" role="search">
+ <span class="dw-ms-icon">{% render 'icons', id: 'search' %}</span>
+ <input type="search" name="q" placeholder="Search patterns, colors…" aria-label="{{ 'general.search.search' | t }}">
+ </form>
+
+ {% unless section.settings.menu == blank %}
+ <div class="navigation-wrapper" data-navigation-wrapper>
+ <nav class="navigation navigation-desktop navigation-has-mega-nav" data-navigation-content>
+ <ul class="navigation-menu">
+ {% for link in linklists[section.settings.menu].links %}
+ {% assign first_tier_link = link %}
+ {% assign uses_blocks = true %}
+ {% comment %}Inject is-dropdown-or-meganav begin{% endcomment %}
+ {% comment %}
+ A helper snippet for detecting if a link has a mega nav
+ or dropdown associated with it.
+
+ @param first_tier_link
+
+ @param uses_blocks
+ {% endcomment %}
+
+ {% assign is_dropdown = false %}
+ {% assign is_meganav = true %}
+
+ {% if first_tier_link.links == blank %}
+ {% assign is_meganav = false %}
+ {% else %}
+ {% assign is_dropdown = true %}
+ {% endif %}
+
+ {% for second_tier_link in first_tier_link.links %}
+ {% if second_tier_link.links == blank %}
+ {% assign is_meganav = false %}
+ {% else %}
+ {% assign is_dropdown = true %}
+ {% endif %}
+ {% endfor %}
+
+ {% if is_meganav %}
+ {% assign is_dropdown = false %}
+ {% endif %}
+
+ {% if uses_blocks %}
+ {% assign found_mega_item_handle = false %}
+ {% if section != blank and section.blocks != blank %}
+ {% for block in section.blocks %}
+ {% if block.type == 'mega_menu' %}
+ {% assign menu_item_handle = block.settings.menu_item | handle %}
+ {% if first_tier_link.handle == menu_item_handle %}
+ {% assign found_mega_item_handle = true %}
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+
+ {% if found_mega_item_handle %}
+ {% if is_dropdown %}
+ {% assign is_meganav = true %}
+ {% assign is_dropdown = false %}
+ {% endif %}
+ {% elsif found_mega_item_handle == false %}
+ {% if is_meganav %}
+ {% assign is_meganav = false %}
+ {% assign is_dropdown = true %}
+ {% endif %}
+ {% else %}
+ {% if is_meganav %}
+ {% assign is_meganav = false %}
+ {% assign is_dropdown = true %}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ {% comment %}Inject is-dropdown-or-meganav end{% endcomment %}
+
+
+ <li
+ class="{% if is_dropdown %}has-dropdown{% elsif is_meganav %}has-mega-nav{% endif %}"
+ {% if is_meganav %}data-mega-nav="true"{% endif %}
+ >
+ {% if is_dropdown or is_meganav %}
+ <details data-nav-details>
+ <summary data-href="{{ link.url }}"
+ {% else %}
+ <a href="{{ link.url }}"
+ {% endif %}
+ id="main-navigation-{{ link.handle }}"
+ class="navigation-menu-link"
+ {% if is_dropdown or is_meganav %}aria-haspopup{% endif %}
+ >
+ {{ link.title }}
+ {% if is_dropdown or is_meganav %}
+ <span
+ class="navigation-submenu-toggle"
+ tabIndex="0"
+ role="button"
+ aria-controls="navigation-{{ link.handle }}"
+ aria-expanded="false"
+ aria-label="{{ 'general.accessibility.toggle' | t }}"
+ data-subnav-toggle
+ >
+ {{- arrow_right -}}
+ </span>
+ {% endif %}
+ {% if is_dropdown or is_meganav %}
+ </summary>
+ {% else %}
+ </a>
+ {% endif %}
+
+ {% if is_dropdown %}
+ {% assign direction = 'right' %}
+ {% assign halfway = linklists[section.settings.menu].links.size | divided_by: 2 %}
+ {% if forloop.index0 > halfway %}
+ {% assign direction = 'left' %}
+ {% endif %}
+
+ {%- render 'dropdown', direction: direction, link: link -%}
+ </details>
+ {% elsif is_meganav %}
+ {%- render 'mega-nav', link: link -%}
+ {% endif %}
+ </li>
+ {% endfor %}
+
+ {% if shop.customer_accounts_enabled %}
+ {% if customer %}
+ <li class="mobile-link">
+ <a href="{{ routes.account_url }}">
+ {{ 'layout.header.my_account' | t }}
+ </a>
+ </li>
+ <li class="mobile-link">
+ {{ 'layout.header.logout' | t | customer_logout_link }}
+ </li>
+ {% else %}
+ <li class="mobile-link">
+ <a class="customer-login-link" href="{{ routes.account_login_url }}">{{ 'layout.header.account' | t }}</a>
+ </li>
+ {% endif %}
+ {% endif %}
+ </ul>
+ </nav>
+ {% render 'mobile-nav', arrow_right: arrow_right %}
+ </div>
+ {% endunless %}
+
+ <div class="header-content-right header-content-right--inline-search" data-header-content-right>
+ <div class="header-quick-search" data-quick-search>
+ <button
+ class="search-toggle header-icon-link"
+ type="button"
+ aria-label="{{ 'general.search.header' | t }}"
+ aria-expanded="false"
+ data-quick-search-toggle
+ >
+ {%
+ render 'icons',
+ id: 'search',
+ %}
+ </button>
+ {%
+ render 'search-form',
+ context: 'header',
+ %}
+ </div>
+
+ <a href="#" class="visual-search-clickable header-search-inline__visual" aria-controls="Visual Search">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="30px" height="30px" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 20 20"><path d="M10 8a3 3 0 1 0 0 6a3 3 0 0 0 0-6zm8-3h-2.4a.888.888 0 0 1-.789-.57l-.621-1.861A.89.89 0 0 0 13.4 2H6.6c-.33 0-.686.256-.789.568L5.189 4.43A.889.889 0 0 1 4.4 5H2C.9 5 0 5.9 0 7v9c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-8 11a5 5 0 0 1-5-5a5 5 0 1 1 10 0a5 5 0 0 1-5 5zm7.5-7.8a.7.7 0 1 1 0-1.4a.7.7 0 0 1 0 1.4z" fill="#000000"/></svg>
+ </a>
+
+ {% if shop.customer_accounts_enabled %}
+ <div class="customer-links">
+ {% if customer %}
+ <a href="{{ routes.account_url }}" class="header-icon-link" aria-label="{{ 'layout.header.my_account' | t }}" title="{{ 'layout.header.my_account' | t }}">{% render 'icons', id: 'person' %}</a>
+ <div class="customer-links-inner">
+ <span class="arrow"></span>
+ <ul>
+ <li><a href="{{ routes.account_url }}">{{ 'customers.general.purchases' | t }}</a></li>
+ <li><a href="{{ routes.account_addresses_url }}">{{ 'customers.addresses.header' | t }}</a></li>
+ <li>{{ 'layout.header.logout' | t | customer_logout_link }}</li>
+ </ul>
+ </div>
+ {% else %}
+ <a class="customer-login-link header-icon-link" href="{{ routes.account_login_url }}" data-dw-signin aria-label="{{ 'layout.header.account' | t }}" title="{{ 'layout.header.account' | t }}">{% render 'icons', id: 'person' %}</a>
+ {% endif %}
+ </div>
+ {% endif %}
+
+ <div class="mini-cart-wrapper">
+ <a class="cart-count header-icon-link" href="{{ routes.cart_url }}" data-cart-count aria-label="{{ 'layout.header.cart' | t }}" title="{{ 'layout.header.cart' | t }}">
+ <span class="cart-count-icon">{% render 'icons', id: 'cart' %}</span>
+ <span class="cart-count-number">{{ cart.item_count }}</span>
+ </a>
+
+ {% render 'mini-cart' %}
+ </div>
+ </div>
+
+ <div class="search-takeover" data-search-takeover>
+ <div class="search-takeover__wrapper">
+ {%
+ render 'search-form',
+ context: 'mobile',
+ %}
+
+ <button
+ class="search-takeover__close-button"
+ type="button"
+ aria-label="{{ 'general.search.close' | t }}"
+ data-search-takeover-close
+ >
+ {%
+ render 'icons',
+ id: 'close',
+ %}
+ </button>
+ </div>
+ </div>
+ </div>
+ </header>
+</section>
+
+<script>
+ (function () {
+ var wrap = document.querySelector('[data-section-header] [data-quick-search]');
+ if (!wrap) return;
+ var toggle = wrap.querySelector('[data-quick-search-toggle]');
+ if (!toggle) return;
+ function q() { return wrap.querySelector('.search-form__input'); }
+ function frm() { return wrap.querySelector('form'); }
+
+ /* ---- predictive dropdown (Shopify native /search/suggest.json) ---- */
+ var box = document.createElement('div');
+ box.className = 'hdr-suggest';
+ box.style.display = 'none';
+ document.body.appendChild(box);
+ var timer = null, lastQ = '';
+ function positionBox() {
+ var input = q(); if (!input) return;
+ var r = input.getBoundingClientRect();
+ box.style.left = Math.max(8, Math.min(r.left, window.innerWidth - 300)) + 'px';
+ box.style.top = (r.bottom + 6) + 'px';
+ box.style.width = Math.max(260, r.width) + 'px';
+ }
+ function hideBox() { box.style.display = 'none'; box.innerHTML = ''; }
+ function render(products, query) {
+ var safeQ = query.replace(/[<>]/g, '');
+ if (!products.length) {
+ box.innerHTML = '<div class="hdr-suggest__empty">No matches for “' + safeQ + '”</div>';
+ } else {
+ box.innerHTML = products.map(function (p) {
+ var img = p.image ? '<img src="' + p.image + '" alt="" loading="lazy">' : '<span class="hdr-suggest__noimg"></span>';
+ return '<a class="hdr-suggest__row" href="' + p.url + '">' + img +
+ '<span class="hdr-suggest__t">' + (p.title || '').replace(/[<>]/g, '') + '</span></a>';
+ }).join('') +
+ '<a class="hdr-suggest__all" href="/search?q=' + encodeURIComponent(query) + '">See all results →</a>';
+ }
+ positionBox();
+ box.style.display = 'block';
+ }
+ function fetchSuggest(query) {
+ var url = '/search/suggest.json?q=' + encodeURIComponent(query) +
+ '&resources[type]=product&resources[limit]=8&resources[options][unavailable_products]=last';
+ fetch(url, { headers: { 'Accept': 'application/json' } })
+ .then(function (r) { return r.json(); })
+ .then(function (d) {
+ if (query !== lastQ) return;
+ var prods = (((d.resources || {}).results || {}).products) || [];
+ render(prods.map(function (p) {
+ return { title: p.title, url: p.url, image: (p.featured_image && p.featured_image.url) || p.image || '' };
+ }), query);
+ }).catch(function () {});
+ }
+ function onInput() {
+ var input = q(); if (!input) return;
+ var val = input.value.trim(); lastQ = val;
+ clearTimeout(timer);
+ if (val.length < 2) { hideBox(); return; }
+ timer = setTimeout(function () { fetchSuggest(val); }, 160);
+ }
+ wrap.addEventListener('input', function (e) {
+ if (e.target && e.target.classList && e.target.classList.contains('search-form__input')) onInput();
+ });
+ window.addEventListener('resize', function () { if (box.style.display === 'block') positionBox(); });
+ window.addEventListener('scroll', function () { if (box.style.display === 'block') positionBox(); }, true);
+
+ function close() {
+ wrap.classList.remove('search-open');
+ toggle.setAttribute('aria-expanded', 'false');
+ hideBox();
+ }
+ toggle.addEventListener('click', function (e) {
+ e.preventDefault();
+ var input = q(), form = frm();
+ if (wrap.classList.contains('search-open')) {
+ if (input && input.value.trim() && form) { form.submit(); return; }
+ close();
+ return;
+ }
+ wrap.classList.add('search-open');
+ toggle.setAttribute('aria-expanded', 'true');
+ if (input) { setTimeout(function () { input.focus(); }, 60); }
+ });
+ document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
+ document.addEventListener('click', function (e) { if (!wrap.contains(e.target) && !box.contains(e.target)) close(); });
+ })();
+</script>
+
+{% schema %}
+{
+ "name": "Header",
+ "settings": [
+ {
+ "type": "header",
+ "content": "Logo"
+ },
+ {
+ "type": "image_picker",
+ "id": "logo",
+ "label": "Logo image",
+ "info": "200px tall recommended"
+ },
+ {
+ "type": "header",
+ "content": "Header"
+ },
+ {
+ "type": "select",
+ "id": "header_layout",
+ "label": "Logo layout",
+ "info": "Logo layouts are only active on screens wider than 1080px",
+ "options": [
+ {
+ "value": "default",
+ "label": "Default"
+ },
+ {
+ "value": "compact-center",
+ "label": "Compact center"
+ },
+ {
+ "value": "compact-left",
+ "label": "Compact left"
+ }
+ ],
+ "default": "compact-left"
+ },
+ {
+ "type": "checkbox",
+ "id": "header_full_width",
+ "label": "Enable full width header ",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "header_border",
+ "label": "Show header border",
+ "default": true,
+ "info": "This will appear on all pages except the home page."
+ },
+ {
+ "type": "checkbox",
+ "id": "sticky_header",
+ "label": "Enable sticky header"
+ },
+ {
+ "type": "checkbox",
+ "id": "sticky_header_logo",
+ "default": true,
+ "label": "Show logo image in sticky header"
+ },
+ {
+ "type": "header",
+ "content": "Search behavior"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_predictive_search",
+ "label": "Enable predictive search",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Navigation"
+ },
+ {
+ "type": "link_list",
+ "id": "menu",
+ "label": "Menu",
+ "default": "main-menu"
+ },
+ {
+ "type": "header",
+ "content": "Mini Cart"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_checkout_lock_icon",
+ "label": "Show lock icon on checkout button in mini cart",
+ "default": false
+ }
+ ],
+ "blocks": [
+ {
+ "type": "mega_menu",
+ "name": "Mega menu",
+ "settings": [
+ {
+ "type": "text",
+ "id": "menu_item",
+ "label": "Menu item",
+ "info": "Enter menu item to apply a mega menu dropdown. [Learn more](https://support.pixelunion.net/hc/en-us/articles/360022052534-How-to-set-up-your-store-s-navigation)"
+ },
+ {
+ "type": "image_picker",
+ "id": "menu_image",
+ "label": "Featured image",
+ "info": "480 x 1000px recommended"
+ }
+ ]
+ },
+ {
+ "type": "header_customer_link",
+ "name": "Header customer link",
+ "settings": [
+ {
+ "type": "text",
+ "id": "link_text",
+ "label": "Link text",
+ "default": "Contact us: (888) 373-4564"
+ },
+ {
+ "type": "url",
+ "id": "link_url",
+ "label": "Link URL"
+ }
+ ]
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-blog.liquid b/sections/home-blog.liquid
new file mode 100644
index 0000000..45e50d8
--- /dev/null
+++ b/sections/home-blog.liquid
@@ -0,0 +1,92 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-blog"
+ data-section-id="{{ section.id }}"
+></script>
+
+{% assign post_count = section.settings.number_of_rows | times: section.settings.number_of_columns %}
+{% assign onboard = true %}
+{% assign blog = blogs[section.settings.blog] %}
+
+{% if section.settings.blog != 'none' and blog.articles.size > 0 %}
+ {% assign onboard = false %}
+{% endif %}
+
+<section
+ class="home-blog home-blog-columns-{{ section.settings.number_of_columns }}"
+ data-section-id="{{ section.id }}"
+ data-section-type="home-blog">
+
+ {%- if section.settings.title != blank -%}
+ <h2 class="section-title">{{ section.settings.title | escape }}</h2>
+ {%- endif -%}
+
+ <div class="home-blog-list" {% if blog.articles.size > 1 or onboard %}data-blog-container{% endif %}>
+ {%- unless onboard -%}
+ {%- for article in blog.articles limit: post_count -%}
+ {%- assign publishedAt = article.published_at | time_tag: '%b %d, %Y' -%}
+ {%-
+ render 'home-blog-post',
+ article: article,
+ -%}
+ {%- endfor -%}
+ {%- else -%}
+ {%- for i in (1..post_count) -%}
+ {%-
+ render 'home-blog-post',
+ -%}
+ {%- endfor -%}
+ {%- endunless -%}
+ </div>
+
+</section>
+
+{% schema %}
+{
+ "name": "Blog posts",
+ "class": "shopify-section--blog-posts",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Blog posts"
+ },
+ {
+ "type": "blog",
+ "id": "blog",
+ "label": "Blog"
+ },
+ {
+ "type": "range",
+ "id": "number_of_columns",
+ "label": "Blog posts per row",
+ "min": 1,
+ "max": 4,
+ "step": 1,
+ "default": 3
+ },
+ {
+ "type": "range",
+ "id": "number_of_rows",
+ "label": "Number of rows",
+ "min": 1,
+ "max": 4,
+ "step": 1,
+ "default": 1
+ }
+ ],
+ "presets": [
+ {
+ "category": "Blog",
+ "name": "Blog posts"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-collections.liquid b/sections/home-collections.liquid
new file mode 100644
index 0000000..2a0387c
--- /dev/null
+++ b/sections/home-collections.liquid
@@ -0,0 +1,174 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-collections-list"
+ data-section-id="{{ section.id }}"
+>
+</script>
+
+{% comment %}
+ Determine if there is an uneven amount of blocks
+ If there are no blocks, 3 onboarding blocks will be shown
+{% endcomment %}
+
+{% assign block_count = 3 %}
+{% if section.blocks.size != 0 %}
+ {% assign block_count = section.blocks.size %}
+{% endif %}
+
+{% assign has_remainder = true %}
+{% assign block_remainder = block_count | modulo: 2 %}
+{% if block_remainder == 0 %}
+ {% assign has_remainder = false %}
+{% endif %}
+
+{% capture section_clases %}
+ home-collections
+ home-collections-columns-{{ section.settings.columns_range }}
+
+ {% if has_remainder %}
+ home-collections-has-remainder
+ {% endif %}
+{% endcapture %}
+
+<section
+ class="{{ section_clases | strip_newlines }}"
+ data-section-id="{{ section.id }}"
+ data-section-type="home-collection-list"
+>
+ {% if section.settings.title %}
+ <h2 class="section-title">
+ {{ section.settings.title | escape }}
+ </h2>
+ {% endif %}
+
+ <div class="home-collections-content" data-collections>
+ {% unless section.blocks.size == 0 %}
+ {% for block in section.blocks %}
+ {% case block.type %}
+ {% when 'collection' %}
+ {% assign collectionIndex = collectionIndex | plus: 1 %}
+ {% assign collectionImageIndex = collectionIndex | modulo: 6 | plus: 1 %}
+ {% assign collectionImage = 'collection-' | append: collectionImageIndex %}
+ {% assign collection = collections[block.settings.collection] %}
+ {% assign image = collectionImage | placeholder_svg_tag: 'placeholder-svg' %}
+
+ {% if forloop.first == true %}
+ {% if collection.image %}
+ {% assign aspect_ratio = collection.image.aspect_ratio %}
+ {% elsif collection.products.first.featured_media.preview_image %}
+ {% assign aspect_ratio = collection.products.first.featured_media.preview_image.aspect_ratio %}
+ {% endif %}
+ {% endif %}
+
+ {%
+ render 'home-collection',
+ block: block,
+ aspect_ratio: aspect_ratio,
+ collection: collection,
+ onboard_image: image,
+ %}
+ {% endcase %}
+ {% endfor %}
+ {% else %}
+ {% for i in (1..block_count) %}
+ {% assign collectionIndex = collectionIndex | plus: 1 %}
+ {% assign collectionImageIndex = collectionIndex | modulo: 6 | plus: 1 %}
+ {% assign collectionImage = 'collection-' | append: i %}
+ {% assign image = collectionImage | placeholder_svg_tag: 'placeholder-svg' %}
+
+ {%
+ render 'home-collection',
+ onboard_image: image,
+ %}
+ {% endfor %}
+ {% endunless %}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Collection list",
+ "class": "shopify-section--collection-list",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Collection list"
+ },
+ {
+ "type": "range",
+ "id": "columns_range",
+ "label": "Columns",
+ "min": 1,
+ "max": 3,
+ "step": 1,
+ "default": 3
+ }
+ ],
+ "blocks": [
+ {
+ "type": "collection",
+ "name": "Collection",
+ "settings": [
+ {
+ "type": "collection",
+ "id": "collection",
+ "label": "Collection"
+ },
+ {
+ "type": "select",
+ "id": "overlay-color",
+ "label": "Overlay text color",
+ "options": [
+ {
+ "value": "black",
+ "label": "Black"
+ },
+ {
+ "value": "white",
+ "label": "White"
+ }
+ ],
+ "default": "black"
+ },
+ {
+ "type": "text",
+ "id": "subheading",
+ "label": "Subheading",
+ "default": "Collection subtitle"
+ },
+ {
+ "type": "richtext",
+ "id": "description",
+ "label": "Text",
+ "default": "<p>Help guide customers to the products they're looking for by featuring collections on your homepage.</p>"
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Collection",
+ "name": "Collection list",
+ "blocks": [
+ {
+ "type": "collection"
+ },
+ {
+ "type": "collection"
+ },
+ {
+ "type": "collection"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-masonry.liquid b/sections/home-masonry.liquid
new file mode 100644
index 0000000..6791a75
--- /dev/null
+++ b/sections/home-masonry.liquid
@@ -0,0 +1,235 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-masonry"
+ data-section-id="{{ section.id }}">
+</script>
+<section>
+ {% render 'home-masonry' %}
+</section>
+
+{% schema %}
+{
+ "name": "Masonry",
+ "class": "shopify-section--masonry",
+ "max_blocks": 6,
+ "settings": [
+ {
+ "type": "select",
+ "id": "layout",
+ "label": "Layout",
+ "options": [
+ {
+ "value": "content-width",
+ "label": "Content width"
+ },
+ {
+ "value": "full-width",
+ "label": "Full width"
+ }
+ ],
+ "default": "content-width"
+ },
+ {
+ "type": "checkbox",
+ "id": "gutters",
+ "label": "Enable gutters",
+ "default": true
+ },
+ {
+ "type": "checkbox",
+ "id": "hover",
+ "label": "Enable text hover",
+ "info": "Desktop only.",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "hover-animation",
+ "label": "Enable hover animation",
+ "default": true
+ }
+ ],
+ "blocks": [
+ {
+ "type": "image_feature",
+ "name": "Image feature",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Masonry feature"
+ },
+ {
+ "type": "text",
+ "id": "subheading",
+ "label": "Subheading",
+ "default": "Showcase up to six features with overlaying text"
+ },
+ {
+ "type": "url",
+ "id": "url",
+ "label": "Link"
+ },
+ {
+ "type": "select",
+ "id": "color",
+ "label": "Text color",
+ "options": [
+ {
+ "value": "white",
+ "label": "White"
+ },
+ {
+ "value": "black",
+ "label": "Black"
+ }
+ ],
+ "default": "black"
+ },
+ {
+ "type": "checkbox",
+ "id": "mobile",
+ "label": "Show on mobile",
+ "default": true
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Image",
+ "info": "1400 x 640px recommended"
+ },
+ {
+ "type": "header",
+ "content": "Overlay"
+ },
+ {
+ "type": "checkbox",
+ "id": "show_overlay",
+ "label": "Show overlay",
+ "default": false
+ },
+ {
+ "type": "color",
+ "id": "overlay_color",
+ "label": "Color",
+ "default": "#000000"
+ },
+ {
+ "type": "range",
+ "id": "opacity",
+ "label": "Opacity",
+ "min": 1,
+ "max": 100,
+ "step": 1,
+ "unit": "%",
+ "default": 50
+ }
+ ]
+ },
+ {
+ "type": "video_feature",
+ "name": "Video feature",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Video feature"
+ },
+ {
+ "type": "text",
+ "id": "subheading",
+ "label": "Subheading",
+ "default": "Showcase up to six features with overlaying text"
+ },
+ {
+ "type": "select",
+ "id": "color",
+ "label": "Text color",
+ "options": [
+ {
+ "value": "white",
+ "label": "White"
+ },
+ {
+ "value": "black",
+ "label": "Black"
+ }
+ ],
+ "default": "black"
+ },
+ {
+ "type": "video_url",
+ "id": "video_url",
+ "label": "YouTube or Vimeo link",
+ "accept": [
+ "youtube",
+ "vimeo"
+ ]
+ },
+ {
+ "type": "select",
+ "id": "aspect_ratio",
+ "label": "Aspect ratio",
+ "options": [
+ {
+ "value": "16/9",
+ "label": "16:9"
+ },
+ {
+ "value": "4/3",
+ "label": "4:3"
+ }
+ ],
+ "default": "16/9"
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Image",
+ "info": "1400 x 700px recommended"
+ },
+ {
+ "type": "checkbox",
+ "id": "mobile",
+ "label": "Show on mobile",
+ "default": true
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Image",
+ "name": "Masonry",
+ "blocks": [
+ {
+ "type": "image_feature"
+ },
+ {
+ "type": "image_feature"
+ },
+ {
+ "type": "image_feature"
+ },
+ {
+ "type": "image_feature"
+ },
+ {
+ "type": "image_feature"
+ },
+ {
+ "type": "image_feature"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-message.liquid b/sections/home-message.liquid
new file mode 100644
index 0000000..6231c07
--- /dev/null
+++ b/sections/home-message.liquid
@@ -0,0 +1,94 @@
+{%- assign heading = section.settings.heading | escape -%}
+
+{%- for block in section.blocks -%}
+ {%- case block.type -%}
+ {%- when 'rich-text' -%}
+ {%- assign caption = block.settings.rich_text -%}
+ {%- when 'page' -%}
+ {%- assign caption = pages[block.settings.page].content -%}
+ {%- endcase -%}
+{%- endfor -%}
+
+{%- if section.blocks.size == 0 -%}
+ {%- assign heading = 'onboarding.message.title' | t -%}
+ {%- assign caption = 'onboarding.message.caption' | t -%}
+{%- endif -%}
+
+<section
+ class="home-message"
+ data-section-id="{{ section.id }}"
+ data-section-type="home-message">
+ <div class="home-message-content {% if section.settings.border %}home-message-content-border{% endif %}">
+ {% if heading != blank %}
+ <h2>{{ heading }}</h2>
+ {% endif %}
+
+ {% if caption != blank %}
+ <div class="rte">{{ caption }}</div>
+ {% endif %}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Rich text",
+ "class": "shopify-section--rich-text",
+ "max_blocks": 1,
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "border",
+ "label": "Show border",
+ "default": true
+ },
+ {
+ "type": "text",
+ "id": "heading",
+ "label": "Heading",
+ "default": "Rich text"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "rich-text",
+ "name": "Rich text",
+ "settings": [
+ {
+ "type": "richtext",
+ "id": "rich_text",
+ "label": "Text",
+ "default": "<p>Use this section to welcome customers to your store, say a bit about your brand, or share news and seasonal promotions</p>"
+ }
+ ]
+ },
+ {
+ "type": "page",
+ "name": "Page",
+ "settings": [
+ {
+ "type": "page",
+ "id": "page",
+ "label": "Page"
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Text",
+ "name": "Rich text",
+ "blocks": [
+ {
+ "type": "rich-text"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-product.liquid b/sections/home-product.liquid
new file mode 100644
index 0000000..7241f57
--- /dev/null
+++ b/sections/home-product.liquid
@@ -0,0 +1,298 @@
+{% assign product = nil %}
+
+{% if section.settings.product_handle != blank %}
+ {% assign product = all_products[section.settings.product_handle] %}
+{% endif %}
+
+{% assign show_social_media_icons = section.settings.show_social_media_icons %}
+{% assign show_payment_button = section.settings.show_payment_button %}
+{% assign images_layout = section.settings.images_layout %}
+{% assign enable_zoom = section.settings.enable_zoom %}
+{% assign enable_cart_redirection = section.settings.enable_cart_redirection %}
+{% assign enable_video_autoplay = section.settings.enable_video_autoplay %}
+{% assign enable_video_looping = section.settings.enable_video_looping %}
+
+
+<script
+ type="application/json"
+ data-section-type="product"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+ {
+ "product": {{ product | json }},
+ "product_settings": {
+ "addToCartText": {{ 'products.product.add_to_cart' | t | json }},
+ "enableHistory": false,
+ "processingText": {{ 'products.product.processing' | t | json }},
+ "setQuantityText": {{ 'products.product.set_quantity' | t | json }},
+ "soldOutText": {{ 'products.product.sold_out' | t | json }},
+ "unavailableText": {{ 'products.product.unavailable' | t | json }}
+ },
+ "images_layout": {{ images_layout | json }},
+ "enable_zoom": {{ enable_zoom | json }},
+ "enable_video_autoplay": {{ enable_video_autoplay | json }},
+ "enable_video_looping": {{ enable_video_looping | json }},
+ "enable_cart_redirection": {{ enable_cart_redirection | json }},
+ "enable_fixed_positioning": false
+ }
+</script>
+
+{% render 'product-success-labels' %}
+
+<section class="product-container">
+ {%
+ render 'product',
+ product: product,
+ show_social_media_icons: show_social_media_icons,
+ images_layout: images_layout,
+ enable_zoom: enable_zoom,
+ enable_linked_options: true,
+ show_payment_button: show_payment_button,
+ %}
+</section>
+
+{% schema %}
+{
+ "name": "Featured product",
+ "class": "shopify-section--featured-product",
+ "settings": [
+ {
+ "type": "product",
+ "id": "product_handle",
+ "label": "Product"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_cart_redirection",
+ "label": "Enable cart redirection",
+ "info": "Automatically sends users to the Cart page after adding a product.",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "show_payment_button",
+ "label": "Show dynamic checkout button",
+ "info": "Each customer will see their preferred payment method from those available on your store, such as PayPal or Apple Pay. [Learn more](https://help.shopify.com/manual/using-themes/change-the-layout/dynamic-checkout)",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Media"
+ },
+ {
+ "type": "paragraph",
+ "content": "Learn more about [media types](https://help.shopify.com/en/manual/products/product-media/product-media-types)"
+ },
+ {
+ "type": "select",
+ "id": "images_layout",
+ "label": "Layout",
+ "options": [
+ {
+ "label": "Slideshow",
+ "value": "slideshow"
+ },
+ {
+ "label": "List",
+ "value": "list"
+ },
+ {
+ "label": "Masonry",
+ "value": "masonry"
+ }
+ ],
+ "default": "slideshow"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_zoom",
+ "label": "Enable image zoom",
+ "info": "Zoom only works with the slideshow image layout"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_video_autoplay",
+ "label": "Enable video autoplay",
+ "default": true
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_video_looping",
+ "label": "Enable video looping"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "@app"
+ },
+ {
+ "type": "collapsible-tab",
+ "name": "Collapsible tab",
+ "settings": [
+ {
+ "type": "text",
+ "id": "collapsible_tab_heading",
+ "label": "Heading",
+ "default": "Collapsible tab"
+ },
+ {
+ "type": "richtext",
+ "id": "collapsible_tab_text",
+ "label": "Text",
+ "default": "<p>Use this text to share information about your product.</p>"
+ }
+ ]
+ },
+ {
+ "type": "custom-liquid",
+ "name": "Custom liquid",
+ "settings": [
+ {
+ "type": "liquid",
+ "id": "custom_liquid",
+ "label": "Custom liquid",
+ "info": "Add app snippets or other Liquid code to create advanced customizations."
+ }
+ ]
+ },
+ {
+ "type": "tabs",
+ "name": "Tabs",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_product_description",
+ "label": "Show product description",
+ "default": false
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_1",
+ "label": "Heading",
+ "default": "Tab 1"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_1",
+ "label": "Text",
+ "default": "<p>Tab 1 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_2",
+ "label": "Heading",
+ "default": "Tab 2"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_2",
+ "label": "Text",
+ "default": "<p>Tab 2 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_3",
+ "label": "Heading",
+ "default": "Tab 3"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_3",
+ "label": "Text",
+ "default": "<p>Tab 3 content goes here.</p>"
+ }
+ ]
+ },
+ {
+ "type": "title",
+ "name": "Title",
+ "limit": 1
+ },
+ {
+ "type": "vendor",
+ "name": "Vendor",
+ "limit": 1
+ },
+ {
+ "type": "social",
+ "name": "Social",
+ "limit": 1
+ },
+ {
+ "type": "description",
+ "name": "Description",
+ "limit": 1
+ },
+ {
+ "type": "price",
+ "name": "Price",
+ "limit": 1
+ },
+ {
+ "type": "form",
+ "name": "Form",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "Customize form features for the product in the products portion of the theme settings."
+ }
+ ]
+ },
+ {
+ "type": "rating",
+ "name": "Product rating",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "To display a rating, add a product rating app. [Learn more](https://apps.shopify.com/product-reviews)"
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Product",
+ "name": "Featured product",
+ "blocks": [
+ {
+ "type": "vendor"
+ },
+ {
+ "type": "title"
+ },
+ {
+ "type": "price"
+ },
+ {
+ "type": "form"
+ },
+ {
+ "type": "description"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-products.liquid b/sections/home-products.liquid
new file mode 100644
index 0000000..63a53b6
--- /dev/null
+++ b/sections/home-products.liquid
@@ -0,0 +1,91 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-featured-collection"
+ data-section-id="{{ section.id }}"
+></script>
+
+{%- assign product_count = section.settings.product-columns | times: section.settings.product-rows -%}
+
+<section
+ class="home-products home-products-columns-{{ section.settings.product-columns }}"
+ data-section-id="{{ section.id }}"
+ data-section-type="home-featured-collection"
+ data-product-hover="{{ settings.product_hover }}"
+>
+ {% if section.settings.title != blank %}
+ <h2 class="section-title">{{ section.settings.title | escape }}</h2>
+ {% endif %}
+
+ <div class="home-products-content" data-products-container>
+ {%- assign collection = collections[section.settings.collection] -%}
+
+ {%- unless section.settings.collection == blank or collection.all_products_count == 0 -%}
+ {%- for product in collection.products limit: product_count -%}
+ {%
+ render 'product-list-item',
+ collection: collection,
+ product: product,
+ %}
+ {%- endfor -%}
+ {%- else -%}
+ {%- for i in (1..product_count) -%}
+ {%- capture productImage -%}
+ {%- cycle 'product-1', 'product-2', 'product-3' -%}
+ {%- endcapture -%}
+ {%- assign image = productImage | placeholder_svg_tag: 'placeholder-svg' -%}
+
+ {%- render 'home-onboard-product', image: image -%}
+ {%- endfor -%}
+ {%- endunless -%}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Featured collection",
+ "class": "shopify-section--featured-collection",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Featured collection"
+ },
+ {
+ "id": "collection",
+ "type": "collection",
+ "label": "Collection"
+ },
+ {
+ "type": "range",
+ "id": "product-columns",
+ "label": "Products per row",
+ "min": 2,
+ "max": 4,
+ "step": 1,
+ "default": 3
+ },
+ {
+ "type": "range",
+ "id": "product-rows",
+ "label": "Number of rows",
+ "min": 1,
+ "max": 12,
+ "step": 1,
+ "default": 3
+ }
+ ],
+ "presets": [
+ {
+ "category": "Collection",
+ "name": "Featured collection"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-promotion.liquid b/sections/home-promotion.liquid
new file mode 100644
index 0000000..f51dac1
--- /dev/null
+++ b/sections/home-promotion.liquid
@@ -0,0 +1,196 @@
+{% assign has_cta = false %}
+{% if section.settings.button_text != blank and section.settings.button_url != blank %}
+ {% assign has_cta = true %}
+{% endif %}
+
+{% assign has_content = false %}
+{% if section.settings.title != blank or section.settings.subtitle != blank or has_cta %}
+ {% assign has_content = true %}
+{% endif %}
+
+{% assign has_image = false %}
+{% assign has_retina_image = false %}
+{% assign image_url = '' %}
+{% assign image_retina_url = '' %}
+{% if section.settings.image %}
+ {% assign has_image = true %}
+ {% assign image_url = section.settings.image | img_url: '1440x640' %}
+
+ {% if section.settings.image.width >= 2880 %}
+ {% assign has_retina_image = true %}
+ {% assign image_retina_url = section.settings.image | img_url: '1440x640', scale: 2 %}
+ {% endif %}
+{% endif %}
+
+<script
+ type="application/json"
+ data-section-type="dynamic-promotion"
+ data-section-id="{{ section.id }}"
+ data-section-data>
+ {
+ "layout": "{{ section.settings.layout }}"
+ }
+</script>
+
+<section>
+
+ {%- capture classes -%}
+ home-promotion
+ home-promotion-{{ section.id }}
+ home-promotion-layout-{{ section.settings.layout }}
+ home-promotion-align-{{ section.settings.text_alignment }}
+
+ {%- if has_content -%}
+ home-promotion-has-content
+ {%- endif -%}
+ {%- endcapture -%}
+
+ <article class="{{ classes }}" data-promotion-wrapper>
+ {%- if has_image -%}
+ <div
+ class="home-promotion-image-container"
+ data-promotion-image-container
+ >
+ <img
+ class="home-promotion-image"
+ src="{{ image_url }}"
+ {%- if has_retina_image -%}
+ srcset="{{ image_retina_url }} 2x"
+ {%- endif -%}
+ alt="{{ section.settings.image.alt | escape }}"
+ data-promotion-image
+ >
+ </div>
+ {%- endif -%}
+
+ {%- if has_content -%}
+ <div class="home-promotion-content" data-promotion-content>
+ {%- if section.settings.title != blank -%}
+ <h2 class="home-promotion-title">
+ {{ section.settings.title | escape }}
+ </h2>
+ {%- endif -%}
+
+ {%- if section.settings.subtitle != blank -%}
+ <p class="home-promotion-subtitle">
+ {{ section.settings.subtitle | escape }}
+ </p>
+ {%- endif -%}
+
+ {% if has_cta %}
+ <a
+ class="home-promotion-button button"
+ href="{{ section.settings.button_url }}"
+ >
+ {{ section.settings.button_text | escape }}
+ </a>
+ {% endif %}
+ </div>
+ {% endif %}
+ </article>
+
+ <style>
+ .home-promotion-{{ section.id }} .home-promotion-title,
+ .home-promotion-{{ section.id }} .home-promotion-subtitle {
+ color: {{ section.settings.text_color }};
+ }
+
+ {% if has_content and has_image %}
+ .home-promotion-{{ section.id }} .home-promotion-image-container {
+ background-image: url('{{ image_url }}');
+ background-position: {{ section.settings.image.presentation.focal_point }};
+ }
+
+ {% if has_retina_image %}
+ @media (-webkit-min-device-pixel-ratio: 1.5) and (min-width: 1024px),
+ (min-resolution: 144dpi) and (min-width: 1024px) {
+ .home-promotion-{{ section.id }} .home-promotion-image-container {
+ background-image: url('{{ image_retina_url }}');
+ background-position: {{ section.settings.image.presentation.focal_point }};
+ }
+ }
+ {% endif %}
+ {% endif %}
+ </style>
+</section>
+
+{% schema %}
+{
+ "name": "Promotion",
+ "class": "shopify-section--promotion",
+ "settings": [
+ {
+ "type": "select",
+ "id": "layout",
+ "label": "Layout",
+ "options": [
+ {
+ "value": "content-width",
+ "label": "Content width"
+ },
+ {
+ "value": "full-width",
+ "label": "Full width"
+ },
+ {
+ "value": "full-screen",
+ "label": "Full screen"
+ }
+ ],
+ "default": "full-width"
+ },
+ {
+ "type": "text_alignment",
+ "id": "text_alignment",
+ "label": "Text alignment",
+ "default": "center"
+ },
+ {
+ "type": "color",
+ "id": "text_color",
+ "label": "Text color",
+ "default": "#000000"
+ },
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Promotion"
+ },
+ {
+ "type": "text",
+ "id": "subtitle",
+ "label": "Subheading",
+ "default": "Draw attention to sales, new products and other great offers"
+ },
+ {
+ "type": "text",
+ "id": "button_text",
+ "label": "Button text"
+ },
+ {
+ "type": "url",
+ "id": "button_url",
+ "label": "Button link"
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Background image",
+ "info": "2880 x 1280px recommended"
+ }
+ ],
+ "presets": [
+ {
+ "category": "Promotional",
+ "name": "Promotion"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-slideshow.liquid b/sections/home-slideshow.liquid
new file mode 100644
index 0000000..5849d95
--- /dev/null
+++ b/sections/home-slideshow.liquid
@@ -0,0 +1,281 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-slideshow"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+{
+ "autoplay": {{ section.settings.autoplay }},
+ "autoplayDelay": {{ section.settings.autoplay_delay }},
+ "autoplayHoverPause": {{ section.settings.autoplay-hover-pause }}
+ }
+</script>
+
+{%- assign slideIndex = 0 -%}
+{%- assign slide_count = section.blocks.size -%}
+
+<section
+ class="home-slideshow home-slideshow-layout-{{ section.settings.layout }}"
+ data-slideshow
+ data-slideshow-layout="{{ section.settings.layout }}"
+ data-slideshow-slides="{{ slide_count }}"
+>
+ {%- unless section.blocks.size == 0 -%}
+ {%- for block in section.blocks -%}
+ {%- case block.type -%}
+ {%- when 'slide' -%}
+ {%- assign slideIndex = slideIndex | plus: 1 -%}
+ {%- assign lifestyleIndex = slideIndex | modulo: 2 | plus: 1 -%}
+ {%- assign lifestyleImage = 'lifestyle-' | append: lifestyleIndex -%}
+ {%- capture image -%}
+ {{ lifestyleImage | placeholder_svg_tag: 'placeholder-svg' }}
+ {%- endcapture -%}
+
+ {%-
+ render 'home-slideshow-slide',
+ block: block,
+ slideIndex: slideIndex,
+ onboard_image: image,
+ -%}
+ {%- endcase -%}
+ {%- endfor -%}
+ {%- else -%}
+ {%- for i in (1..slide_count) -%}
+ {%- assign slideIndex = slideIndex | plus: 1 -%}
+ {%- assign lifestyleIndex = slideIndex | modulo: 2 | plus: 1 -%}
+ {%- assign lifestyleImage = 'lifestyle-' | append: lifestyleIndex -%}
+ {%- capture image -%}
+ <canvas class="home-slideshow-svg-ie11-fix" width="50" height="19"></canvas>
+ {{ lifestyleImage | placeholder_svg_tag: 'placeholder-svg' }}
+ {%- endcapture -%}
+ {%- capture contentAlignment -%}
+ {%- cycle 'left', 'center', 'right' -%}
+ {%- endcapture -%}
+
+ {%-
+ render 'home-slideshow-slide',
+ slideIndex: slideIndex,
+ contentAlignment: contentAlignment,
+ onboard_image: image,
+ -%}
+ {%- endfor -%}
+ {%- endunless -%}
+
+ <style>
+ #shopify-section-{{ section.id }} .home-slideshow .flickity-prev-next-button .arrow {
+ fill: {{ section.settings.controls-color | default: '#000' }};
+ }
+
+ #shopify-section-{{ section.id }} .home-slideshow .flickity-page-dots .dot {
+ background: {{ section.settings.controls-color | default: '#000' }};
+ }
+
+ /* DW front-page sprint 2026-06-23: hero legibility scrim + mobile text overlay (vp-dw-commerce) */
+ #shopify-section-{{ section.id }} .home-slideshow-slide { position: relative; }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-image { position: relative; }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-image::after {
+ content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
+ background: linear-gradient(to top, rgba(0,0,0,.42) 0%, rgba(0,0,0,.16) 32%, rgba(0,0,0,0) 62%);
+ }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-content { z-index: 2; }
+
+ /* DW restrained secondary CTA — luxury "Book a consultation" hairline pill (DTD verdict C, 2026-06-29).
+ Deliberately quieter than the primary .home-slideshow-slide-cta: lighter weight, smaller, wider
+ tracking, hairline outline, ample whitespace — a premium secondary, never a competing banner. */
+ /* Wrapper forces the secondary onto its own row beneath the primary button and inherits the
+ slide's text-align (left/center/right) so the pill stays aligned with the heading. The primary
+ .home-slideshow-slide-cta is an inline text-button, so without this the secondary would sit
+ beside it as a visual peer — the opposite of the restrained, subordinate treatment we want. */
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2-row {
+ display: block;
+ margin-top: 18px;
+ }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2 {
+ display: inline-block;
+ padding: 9px 26px;
+ font-family: Lora, serif;
+ font-style: normal;
+ font-weight: 400;
+ font-size: 0.7857142857rem; /* ~11px — well below the ~16px primary */
+ line-height: 1;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ text-decoration: none;
+ border: 1px solid currentColor; /* hairline pill, inherits overlay text color */
+ border-radius: 999px;
+ /* Faint dark backing + soft shadow so the small pill text always clears contrast over a
+ variable hero photo (APCA), without becoming a loud solid block like the primary button. */
+ background: rgba(0,0,0,0.46); /* APCA Lc>=75 worst-case over a light photo region; still translucent vs the opaque primary */
+ -webkit-backdrop-filter: blur(6px);
+ backdrop-filter: blur(6px);
+ text-shadow: 0 1px 6px rgba(0,0,0,0.45);
+ opacity: 0.95;
+ transition: opacity 0.25s ease, background-color 0.25s ease;
+ }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2:hover,
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2:focus {
+ opacity: 1;
+ background: rgba(0,0,0,0.55);
+ }
+ @media (min-width: 770px) {
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2-row { margin-top: 24px; }
+ }
+
+ @media (max-width: 768px) {
+ #shopify-section-{{ section.id }} .home-slideshow-slide { display: block; }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-content {
+ position: absolute; inset: 0; display: flex; flex-direction: column;
+ align-items: center; justify-content: flex-end; text-align: center; padding: 0 18px 34px;
+ }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-content-inner { width: 100%; max-width: 92%; }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-heading { color: #fff !important; text-shadow: 0 1px 14px rgba(0,0,0,.5); }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-subheading { color: #fff !important; text-shadow: 0 1px 10px rgba(0,0,0,.45); }
+ /* On mobile the photo sits directly behind the text — force the hairline pill light + give it a faint backing for legibility. */
+ #shopify-section-{{ section.id }} .home-slideshow-slide-cta2 { color: #fff !important; border-color: rgba(255,255,255,.7) !important; }
+ #shopify-section-{{ section.id }} .home-slideshow-slide-image::after {
+ background: linear-gradient(to top, rgba(0,0,0,.58) 0%, rgba(0,0,0,.24) 42%, rgba(0,0,0,0) 78%);
+ }
+ }
+ </style>
+</section>
+
+{% schema %}
+{
+ "name": "Slideshow",
+ "class": "shopify-section--slideshow",
+ "max_blocks": 6,
+ "settings": [
+ {
+ "type": "select",
+ "id": "layout",
+ "label": "Layout",
+ "options": [
+ {
+ "value": "content-width",
+ "label": "Content width"
+ },
+ {
+ "value": "full-width",
+ "label": "Full width"
+ }
+ ],
+ "default": "full-width"
+ },
+ {
+ "type": "color",
+ "id": "controls-color",
+ "label": "Controls",
+ "default": "#000"
+ },
+ {
+ "type": "checkbox",
+ "id": "autoplay",
+ "label": "Auto-rotate slides",
+ "default": false
+ },
+ {
+ "type": "range",
+ "id": "autoplay_delay",
+ "label": "Rotation interval",
+ "min": 2,
+ "max": 10,
+ "step": 1,
+ "unit": "sec",
+ "default": 3
+ },
+ {
+ "type": "checkbox",
+ "id": "autoplay-hover-pause",
+ "label": "Pause auto-rotate on hover",
+ "default": false
+ }
+ ],
+ "blocks": [
+ {
+ "type": "slide",
+ "name": "Slide",
+ "settings": [
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "Image",
+ "info": "2880 x 1280px recommended"
+ },
+ {
+ "type": "text_alignment",
+ "id": "content-alignment",
+ "label": "Text alignment",
+ "default": "center"
+ },
+ {
+ "type": "color",
+ "id": "overlay-color",
+ "label": "Overlay text",
+ "default": "#262626"
+ },
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Slide"
+ },
+ {
+ "type": "text",
+ "id": "subheading",
+ "label": "Subheading",
+ "default": "Introduce customers to your shop with lifestyle imagery and product photography"
+ },
+ {
+ "type": "text",
+ "id": "cta",
+ "label": "Button",
+ "default": "Button"
+ },
+ {
+ "type": "url",
+ "id": "url",
+ "label": "Link"
+ },
+ {
+ "type": "header",
+ "content": "Secondary link (optional)"
+ },
+ {
+ "type": "text",
+ "id": "cta2",
+ "label": "Secondary button",
+ "info": "Restrained hairline link shown beneath the main button (e.g. Book an Appointment)."
+ },
+ {
+ "type": "url",
+ "id": "url2",
+ "label": "Secondary link"
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Image",
+ "name": "Slideshow",
+ "blocks": [
+ {
+ "type": "slide"
+ },
+ {
+ "type": "slide"
+ },
+ {
+ "type": "slide"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-testimonials.liquid b/sections/home-testimonials.liquid
new file mode 100644
index 0000000..bbd7a02
--- /dev/null
+++ b/sections/home-testimonials.liquid
@@ -0,0 +1,142 @@
+<script
+ type="application/json"
+ data-section-type="dynamic-testimonials"
+ data-section-id="{{ section.id }}"
+>
+</script>
+
+{%- assign section_class = 'home-testimonials' -%}
+{%- assign section_class = section_class | append: ' style-' | append: section.settings.style -%}
+{%- assign section_class = section_class | append: ' rows-of-' | append: section.settings.per_row -%}
+
+<section
+ class="{{ section_class }}"
+>
+
+ {%- if section.settings.title != blank -%}
+ <h2 class="section-title">{{ section.settings.title | escape }}</h2>
+ {%- endif -%}
+
+ <div class="home-testimonials-list" {% if section.blocks.size > 0 %}data-testimonials-container{% endif %}>
+ {%- for block in section.blocks -%}
+ <article class="home-testimonials-item" {{ block.shopify_attributes }} data-testimonial-item data-index="{{ forloop.index0 }}">
+ <span class="home-testimonials-icon">
+ {%-
+ render 'icons',
+ id: 'quote'
+ %}
+ </span>
+
+ {%- if block.settings.quote != blank -%}
+ <div class="home-testimonials-content rte">
+ <p>
+ {{- block.settings.quote | escape -}}
+ </p>
+ </div>
+ {%- endif -%}
+
+ {%- if block.settings.title != blank -%}
+ <span class="home-testimonials-name">
+ {{- block.settings.title | escape -}}
+ </span>
+ {%- endif -%}
+
+ {%- if block.settings.role != blank -%}
+ <span class="home-testimonials-role">
+ {{- block.settings.role | escape -}}
+ </span>
+ {%- endif -%}
+ </article>
+ {%- endfor -%}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Testimonials",
+ "class": "shopify-section--testimonials",
+ "max_blocks": 8,
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Heading",
+ "default": "Testimonials"
+ },
+ {
+ "type": "range",
+ "id": "per_row",
+ "label": "Testimonials per row",
+ "min": 2,
+ "max": 4,
+ "step": 1,
+ "default": 3
+ },
+ {
+ "type": "select",
+ "id": "style",
+ "label": "Style",
+ "options": [
+ {
+ "value": "filled",
+ "label": "Filled"
+ },
+ {
+ "value": "bordered",
+ "label": "Bordered"
+ }
+ ],
+ "default": "filled"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "testimonial",
+ "name": "Testimonial",
+ "settings": [
+ {
+ "type": "textarea",
+ "id": "quote",
+ "label": "Quote",
+ "default": "Showcase up to eight testimonials to build trust with potential customers."
+ },
+ {
+ "type": "text",
+ "id": "title",
+ "label": "Name",
+ "default": "Name"
+ },
+ {
+ "type": "text",
+ "id": "role",
+ "label": "Role",
+ "default": "Role"
+ }
+ ]
+ }
+ ],
+ "presets": [
+ {
+ "category": "Text",
+ "name": "Testimonials",
+ "blocks": [
+ {
+ "type": "testimonial"
+ },
+ {
+ "type": "testimonial"
+ },
+ {
+ "type": "testimonial"
+ }
+ ]
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/home-video.liquid b/sections/home-video.liquid
new file mode 100644
index 0000000..694aa31
--- /dev/null
+++ b/sections/home-video.liquid
@@ -0,0 +1,495 @@
+{% liquid
+ assign section_id = section.id
+ assign section_subheading = section.settings.text
+ assign overlay_heading = section.settings.overlay_heading | escape
+ assign overlay_text = section.settings.overlay_text
+ assign overlay_text_position = section.settings.overlay_header_position
+ assign overlay_image = section.settings.overlay_image
+ assign overlay_text_color = section.settings.overlay_text_color
+ assign video = section.settings.video
+ assign autoplay = section.settings.autoplay
+ assign aspect_ratio = section.settings.aspect_ratio
+ assign show_headings_above_video = false
+ assign show_overlay = true
+ assign overlay_opacity = 0
+
+ if section.settings.video_layout == 'full-width'
+ assign treat_as_banner = true
+ endif
+
+ if overlay_image
+ assign placeholder_image = true
+ else
+ assign placeholder_image = false
+ endif
+
+ assign play_button_style = 'primary'
+
+ if section.settings.overlay_color != blank and section.settings.overlay_color != 'rgba(0,0,0,0)'
+ assign overlay_color = section.settings.overlay_color
+ endif
+
+ if section.settings.overlay_opacity > 0
+ assign overlay_opacity = section.settings.overlay_opacity | times: 0.01
+ endif
+
+ if overlay_color
+ assign overlay_color = overlay_color | color_modify: 'alpha', overlay_opacity
+ endif
+%}
+
+{%- capture video_classes -%}
+ video-section--{{ section.settings.video_layout }}
+{%- endcapture -%}
+
+{%- capture wrapper_classes -%}
+ video-section__wrapper--aspect-ratio-{{ aspect_ratio }}
+ video-section__wrapper--show-text-while-playing-{{ show_headings_above_video }}
+{%- endcapture -%}
+
+{% comment %}Inject @pixelunion/pxs-video/video begin{% endcomment %}
+{%- comment -%}
+
+ # General
+ @param video_classes {String}
+ A space separated list of classnames to add to the video section element
+
+ @param wrapper_classes {String}
+ A space separated list of classnames to add to the video internal wrapper element
+
+ @param section_id {String}
+ The id for the section or block
+
+ # Section Settings
+
+ @param show_headings_above_video {Boolean}
+ If set to true, the headings will appear above the video
+
+ @param section_heading {String} Optional
+ Section heading
+
+ @param section_subheading {String} Optional
+ Section subheading
+
+ @param treat_as_banner {Boolean} Optional
+ If this is set to true an attribute will be added to treat this as a banner. Usually important for the header if it is transparent.
+
+ # Video Settings
+
+ @param video {Object}
+ The video object for the YouTube or Vimeo video url entered
+
+ @param html5_video {String}
+ The HTML5 video url for media uploaded to the settings admin
+
+ @param autoplay {Boolean}
+ If set to true, the video will play automatically
+
+ @param start_muted {Boolean}
+ If set to true, the video will start with the sound turned off
+
+ @param loop_video {Boolean}
+ If set to true, the video will loop
+
+ @param aspect_ratio {String}
+ Updates the aspect ratio for the video player
+
+ # Overlay Settings
+
+ @param show_overlay {Boolean}
+ If set to true, an image will be placed over the video.
+ If no image is uploaded then a placeholder image will be used.
+ This also affects if the overlay color is added.
+
+ @param overlay_image {Object}
+ The overlay image to be used
+
+ @param overlay_color {String}
+ Overlay color used for inline style
+
+ @param overlay_text_color {String}
+ Overlay text color used for inline style
+
+ @param overlay_opacity {Number}
+ Overlay opacity used for inline style
+
+ @param overlay_heading {String}
+ The video heading to appear in the overlay
+
+ @param overlay_text {String}
+ The video subheading to appear in the overlay
+
+ @param overlay_text_position {String}
+ Sets the text position of the overlay header content
+
+ # Text Settings
+
+ @param preheading {String}
+ Preheading to show above the video
+
+ @param heading {String}
+ Heading to show above the video
+
+ @param subheading {String}
+ Subheading to show above the video
+
+ # Button Settings
+
+ @param play_button_style {String}
+ Class added to the play button
+
+ @param call_to_action_text {String}
+ This will add a call to action link inside the overlay
+
+ @param call_to_action_link {String}
+ This will populate the href of the call to action link
+
+{%- endcomment -%}
+
+{% liquid
+ assign treat_as_banner = treat_as_banner | default: false
+
+ if section_id == blank
+ assign section_id = section.id
+ endif
+
+ if video != blank
+ assign video_type = video.type
+ assign video_id = video.id
+ elsif html5_video != blank
+ assign video_type = 'html5'
+ assign video_id = html5_video.id
+ else
+ assign video_type = 'youtube'
+ assign video_id ='_9VUPq3SxOc'
+ endif
+%}
+
+<script
+ type="application/json"
+ data-section-type="pxs-video"
+ data-section-id="{{ section_id }}"
+ data-section-data
+>
+ {
+ "autoplay": {{ autoplay | default: false | json }},
+ "startMuted": {{ start_muted | default: false | json }},
+ "loopVideo": {{ loop_video | default: false | json }},
+ "aspectRatio": {{ aspect_ratio | json }}
+ }
+</script>
+
+<section
+ class="
+ video-section
+ {{ video_classes }}
+ "
+ aria-label="{{ 'sections.video.video' | t }}"
+ data-banner="{{ treat_as_banner }}"
+>
+
+ {%- if section_heading != blank or section_subheading != blank -%}
+ <div class="section__header section__header--video">
+ {%- if section_heading != blank -%}
+ <h2 class="section__heading section__heading--video">
+ {{ section_heading }}
+ </h2>
+ {%- endif -%}
+
+ {%- if section_subheading != blank -%}
+ <div class="section__subheading section__subheading--video rte">
+ {{ section_subheading }}
+ </div>
+ {%- endif -%}
+ </div>
+ {%- endif -%}
+
+ {% if show_headings_above_video %}
+ {%
+ if heading != blank or subheading != blank or preheading != blank
+ %}
+ <div class="video-section__header">
+ {% if preheading != blank %}
+ <div class="video-section__preheading">
+ {{ preheading }}
+ </div>
+ {% endif %}
+
+ {% if heading != blank %}
+ <h2 class="video-section__heading">
+ {{ heading }}
+ </h2>
+ {% endif %}
+
+ {% if subheading != blank %}
+ <div class="video-section__subheading">
+ {{ subheading }}
+ </div>
+ {% endif %}
+ </div>
+ {% endif %}
+ {% endif %}
+ <div
+ class="
+ video-section__wrapper
+ {{ wrapper_classes }}
+ "
+ >
+ {% if show_overlay %}
+ <div
+ class="video-section__overlay"
+ {%
+ if overlay_color != blank
+ or overlay_opacity != 0
+ or overlay_text_color != blank
+ %}
+ style="
+ {%- if overlay_color != blank -%}
+ --overlay-color: {{ overlay_color }};
+ {%- endif -%}
+ {%- if overlay_opacity != 0 -%}
+ --overlay-opacity: {{ overlay_opacity }};
+ {%- endif -%}
+ {%- if overlay_text_color != blank -%}
+ --overlay-text-color: {{ overlay_text_color }};
+ {%- endif -%}
+ "
+ {% endif %}
+ >
+ {% if overlay_image %}
+ <div class="video-section__overlay-image-wrapper">
+ {%
+ render 'rimg',
+ img: overlay_image,
+ size: '1400x',
+ class: 'video-section__overlay-image',
+ canvas: true,
+ lazy: true,
+ focal_point: overlay_image.presentation.focal_point,
+ %}
+ </div>
+ {% elsif video == blank and html5_video == blank %}
+ {{ 'lifestyle-1' | placeholder_svg_tag: 'video-section__overlay-image video-section__overlay-placeholder' }}
+ {% endif %}
+
+ <div class="
+ video-section__overlay-header
+ video-section__overlay-header--text-position-{{ overlay_text_position }}
+ ">
+ {% if overlay_heading != blank %}
+ <p class="video-section__overlay-heading">{{ overlay_heading }}</p>
+ {% endif %}
+
+ {% if overlay_text != blank %}
+ <div class="video-section__overlay-subheading">{{ overlay_text }}</div>
+ {% endif %}
+
+ <div class="video-section__button-wrapper">
+ <button
+ class="
+ video-section__play-button
+ {% if play_button_style != blank %}
+ video-section__play-button--{{ play_button_style }}
+ {% endif %}
+ "
+ data-video-play-button
+ aria-label="{{ 'sections.video.play_button' | t }}"
+ >
+ <span class="video-section__play-icon">
+ <svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M0 18.1958C0 18.9812 0.863951 19.46 1.53 19.0438L14.6432 10.848C15.2699 10.4563 15.2699 9.54367 14.6432 9.152L1.53 0.956248C0.863949 0.539968 0 1.01881 0 1.80425L0 18.1958Z" fill="white"/>
+ </svg>
+ </span>
+
+ <span class="video-section__play-button-text">
+ {{ 'sections.video.play_button' | t }}
+ </span>
+
+ <svg
+ class="video-section__loading-icon"
+ xmlns="http://www.w3.org/2000/svg"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ >
+ <g fill="currentColor" fill-rule="evenodd">
+ <path class="video-loading-icon-phalange" d="M11,2 L11,6 C11,6.55228475 11.4477153,7 12,7 C12.5522847,7 13,6.55228475 13,6 L13,2 C13,1.44771525 12.5522847,1 12,1 C11.4477153,1 11,1.44771525 11,2 Z"/>
+ <path class="video-loading-icon-phalange" d="M16.9471068,8.46710678 L19.7771068,5.63710678 C20.1676311,5.24658249 20.1676311,4.61341751 19.7771068,4.22289322 C19.3865825,3.83236893 18.7534175,3.83236893 18.3628932,4.22289322 L15.5328932,7.05289322 C15.1423689,7.44341751 15.1423689,8.07658249 15.5328932,8.46710678 C15.9234175,8.85763107 16.5565825,8.85763107 16.9471068,8.46710678 Z"/>
+ <path class="video-loading-icon-phalange" d="M18,13 L22,13 C22.5522847,13 23,12.5522847 23,12 C23,11.4477153 22.5522847,11 22,11 L18,11 C17.4477153,11 17,11.4477153 17,12 C17,12.5522847 17.4477153,13 18,13 Z"/>
+ <path class="video-loading-icon-phalange" d="M15.5328932,16.9471068 L18.3628932,19.7771068 C18.7534175,20.1676311 19.3865825,20.1676311 19.7771068,19.7771068 C20.1676311,19.3865825 20.1676311,18.7534175 19.7771068,18.3628932 L16.9471068,15.5328932 C16.5565825,15.1423689 15.9234175,15.1423689 15.5328932,15.5328932 C15.1423689,15.9234175 15.1423689,16.5565825 15.5328932,16.9471068 Z"/>
+ <path class="video-loading-icon-phalange" d="M11,18 L11,22 C11,22.5522847 11.4477153,23 12,23 C12.5522847,23 13,22.5522847 13,22 L13,18 C13,17.4477153 12.5522847,17 12,17 C11.4477153,17 11,17.4477153 11,18 Z"/>
+ <path class="video-loading-icon-phalange" d="M5.63710678,19.7771068 L8.46710678,16.9471068 C8.85763107,16.5565825 8.85763107,15.9234175 8.46710678,15.5328932 C8.07658249,15.1423689 7.44341751,15.1423689 7.05289322,15.5328932 L4.22289322,18.3628932 C3.83236893,18.7534175 3.83236893,19.3865825 4.22289322,19.7771068 C4.61341751,20.1676311 5.24658249,20.1676311 5.63710678,19.7771068 Z"/>
+ <path class="video-loading-icon-phalange" d="M2,13 L6,13 C6.55228475,13 7,12.5522847 7,12 C7,11.4477153 6.55228475,11 6,11 L2,11 C1.44771525,11 1,11.4477153 1,12 C1,12.5522847 1.44771525,13 2,13 Z"/>
+ <path class="video-loading-icon-phalange" d="M4.22289322,5.63710678 L7.05289322,8.46710678 C7.44341751,8.85763107 8.07658249,8.85763107 8.46710678,8.46710678 C8.85763107,8.07658249 8.85763107,7.44341751 8.46710678,7.05289322 L5.63710678,4.22289322 C5.24658249,3.83236893 4.61341751,3.83236893 4.22289322,4.22289322 C3.83236893,4.61341751 3.83236893,5.24658249 4.22289322,5.63710678 Z"/>
+ </g>
+ </svg>
+ </button>
+
+ {% if call_to_action_text != blank and call_to_action_link != blank %}
+ <a class="video-section__call-to-action" href="{{ call_to_action_link }}">
+ {{ call_to_action_text }}
+ </a>
+ {% endif %}
+ </div>
+ </div>
+ </div>
+ {% endif %}
+
+ <div
+ class="
+ video-section__video
+ video-section__video--{{ video_type }}
+ {% if show_overlay %}
+ video-section__video--with-overlay
+ {% endif %}
+ "
+ data-video="{{ video_type }}"
+ data-video-id="{{ video_id }}"
+ tabindex="0"
+ >
+ {% if video == blank and html5_video != blank %}
+ <video
+ class="video-section__html5-video"
+ data-html5-video
+ playsinline
+ >
+ <source src="{{ html5_video }}">
+ </video>
+ {% endif %}
+ </div>
+ </div>
+</section>
+{% comment %}Inject @pixelunion/pxs-video/video end{% endcomment %}
+
+
+{% schema %}
+{
+ "name": "Video",
+ "class": "shopify-section--video",
+ "settings": [
+ {
+ "type": "select",
+ "id": "video_layout",
+ "label": "Layout",
+ "options": [
+ {
+ "value": "content-width",
+ "label": "Content width"
+ },
+ {
+ "value": "full-width",
+ "label": "Full width"
+ }
+ ],
+ "default": "full-width"
+ },
+ {
+ "type": "select",
+ "id": "aspect_ratio",
+ "label": "Aspect ratio",
+ "options": [
+ {
+ "label": "16:9",
+ "value": "16-9"
+ },
+ {
+ "label": "21:9",
+ "value": "21-9"
+ }
+ ],
+ "default": "16-9"
+ },
+ {
+ "type": "checkbox",
+ "id": "autoplay",
+ "label": "Autoplay video",
+ "default": false
+ },
+ {
+ "type": "video_url",
+ "id": "video",
+ "label": "Video link",
+ "accept": [
+ "youtube",
+ "vimeo"
+ ],
+ "default": "https://www.youtube.com/watch?v=_9VUPq3SxOc"
+ },
+ {
+ "type": "header",
+ "content": "Content"
+ },
+ {
+ "type": "image_picker",
+ "id": "overlay_image",
+ "label": "Image"
+ },
+ {
+ "type": "header",
+ "content": "Overlay"
+ },
+ {
+ "type": "text",
+ "id": "overlay_heading",
+ "label": "Heading",
+ "default": "Video"
+ },
+ {
+ "type": "richtext",
+ "id": "overlay_text",
+ "label": "Subheading",
+ "default": "<p>Enhance your home page with a video that relates to your process, products, or story.</p>"
+ },
+ {
+ "type": "select",
+ "id": "overlay_header_position",
+ "label": "Text position",
+ "options": [
+ {
+ "label": "Above button",
+ "value": "above-button"
+ },
+ {
+ "label": "Below button",
+ "value": "below-button"
+ }
+ ],
+ "default": "above-button"
+ },
+ {
+ "type": "range",
+ "id": "overlay_opacity",
+ "label": "Overlay opacity",
+ "step": 5,
+ "min": 0,
+ "max": 100,
+ "default": 70,
+ "unit": "%"
+ },
+ {
+ "type": "color",
+ "id": "overlay_color",
+ "label": "Overlay color",
+ "default": "#000000"
+ },
+ {
+ "type": "color",
+ "id": "overlay_text_color",
+ "label": "Overlay text color",
+ "default": "#FFFFFF"
+ }
+ ],
+ "presets": [
+ {
+ "category": "Video",
+ "name": "Video"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/main-product-high-variant.liquid b/sections/main-product-high-variant.liquid
new file mode 100644
index 0000000..1ef0cf5
--- /dev/null
+++ b/sections/main-product-high-variant.liquid
@@ -0,0 +1,50 @@
+{% render 'breadcrumbs' %}
+
+{% capture slot_gallery %}
+ {% content_for 'block', type: '_section-flex-pdp-media-gallery', id: 'section-flex-pdp-media-gallery' %}
+{% endcapture %}
+
+{% capture slot_details %}
+ {% content_for 'blocks' %}
+{% endcapture %}
+
+{%- render 'section.flex-pdp', slot_gallery: slot_gallery, slot_details: slot_details -%}
+
+{% schema %}
+{
+ "name": "t:flex_pdp.section.high_variant.name",
+ "blocks": [
+ {"type": "@app"},
+ {"type": "@theme"},
+ {"type": "_section-flex-pdp-buy-buttons"},
+ {"type": "_section-flex-pdp-description"},
+ {"type": "_section-flex-pdp-divider"},
+ {"type": "_section-flex-pdp-policies"},
+ {"type": "_section-flex-pdp-price"},
+ {"type": "_section-flex-pdp-quantity-picker"},
+ {"type": "_section-flex-pdp-sku"},
+ {"type": "_section-flex-pdp-title"},
+ {"type": "_section-flex-pdp-variant-picker"},
+ {"type": "_section-flex-pdp-vendor"},
+ {"type": "_section-flex-pdp-pick-up"},
+ {"type": "_section-flex-pdp-installments"}
+ ],
+ "presets": [
+ {
+ "name": "t:flex_pdp.section.high_variant.name",
+ "blocks": [
+ {"type": "_section-flex-pdp-title"},
+ {"type": "_section-flex-pdp-vendor"},
+ {"type": "_section-flex-pdp-price"},
+ {"type": "_section-flex-pdp-installments"},
+ {"type": "_section-flex-pdp-divider"},
+ {"type": "_section-flex-pdp-variant-picker"},
+ {"type": "_section-flex-pdp-quantity-picker"},
+ {"type": "_section-flex-pdp-buy-buttons"},
+ {"type": "_section-flex-pdp-pick-up"},
+ {"type": "_section-flex-pdp-description"}
+ ]
+ }
+ ]
+}
+{% endschema %}
\ No newline at end of file
diff --git a/sections/mini-ajax.liquid b/sections/mini-ajax.liquid
new file mode 100644
index 0000000..382acbe
--- /dev/null
+++ b/sections/mini-ajax.liquid
@@ -0,0 +1,12 @@
+<template data-data>
+ {
+ "itemsSubtotalPrice": {{ cart.items_subtotal_price | money | json }},
+ "totalDiscount": {{ cart.total_discount | money | json }},
+ "totalPrice": {{ cart.total_price | money | json }},
+ "itemCount": {{ cart.item_count }}
+ }
+</template>
+
+<template data-html="miniCart">
+ {% render 'mini-cart' %}
+</template>
diff --git a/sections/natural-wallcoverings.liquid b/sections/natural-wallcoverings.liquid
new file mode 100644
index 0000000..8116b47
--- /dev/null
+++ b/sections/natural-wallcoverings.liquid
@@ -0,0 +1,77 @@
+{%- comment -%}
+ Natural Wallcoverings — 4 category squares (Grasscloth, Paperweave, Sisal, Mica).
+ Horizontal row of squares on desktop; 2-up on mobile. Editable via blocks;
+ ships with high-end fallback imagery so it renders correctly on install.
+{%- endcomment -%}
+{%- liquid
+ assign rid = section.id
+ assign fb_img = 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5002800-1.jpg,https://cdn.shopify.com/s/files/1/0015/4117/7456/products/79afbadaeacc2b2228b00e232f1e84dc.jpg,https://cdn.shopify.com/s/files/1/0015/4117/7456/products/dce4bafa8834f67c25990248c6743eb3.jpg,https://cdn.shopify.com/s/files/1/0015/4117/7456/products/86c999e57ca94ffa6d42d7b55020cc1c.jpg' | split: ','
+-%}
+<style>
+ .nw-{{ rid }}{ padding:64px 24px; text-align:center; background:{{ section.settings.bg }}; }
+ .nw-{{ rid }} .nw-eyebrow{ font-size:12px; letter-spacing:2.5px; color:{{ section.settings.accent }}; font-weight:600; margin:0 0 10px; }
+ .nw-{{ rid }} h2{ font-family:'Playfair Display',Georgia,serif; font-weight:600; font-size:clamp(26px,3.4vw,38px); color:{{ section.settings.heading_color }}; margin:0 0 32px; }
+ .nw-{{ rid }} .nw-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:18px; max-width:1280px; margin:0 auto; }
+ .nw-{{ rid }} .nw-sq{ position:relative; display:block; aspect-ratio:1/1; overflow:hidden; border-radius:6px; isolation:isolate; }
+ .nw-{{ rid }} .nw-sq img{ width:100%; height:100%; object-fit:cover; transition:transform .5s ease; }
+ .nw-{{ rid }} .nw-sq:hover img{ transform:scale(1.05); }
+ .nw-{{ rid }} .nw-sq::after{ content:""; position:absolute; inset:0; background:linear-gradient(rgba(0,0,0,.05),rgba(30,25,18,.6)); }
+ .nw-{{ rid }} .nw-sq .lbl{ position:absolute; left:0; right:0; bottom:0; z-index:2; padding:18px; color:#fff;
+ font-family:'Playfair Display',Georgia,serif; font-weight:600; font-size:clamp(17px,1.6vw,22px); letter-spacing:.3px; }
+ @media(max-width:749px){
+ .nw-{{ rid }}{ padding:44px 16px; }
+ .nw-{{ rid }} .nw-grid{ grid-template-columns:repeat(2,1fr); gap:12px; }
+ }
+</style>
+<section class="nw-{{ rid }}">
+ {%- if section.settings.eyebrow != blank -%}<p class="nw-eyebrow">{{ section.settings.eyebrow }}</p>{%- endif -%}
+ <h2>{{ section.settings.title }}</h2>
+ <div class="nw-grid">
+ {%- for block in section.blocks -%}
+ {%- assign img = block.settings.image | image_url: width: 800 -%}
+ {%- if block.settings.image == blank -%}{%- assign img = fb_img[forloop.index0] | default: fb_img.first -%}{%- endif -%}
+ <a class="nw-sq" href="{{ block.settings.link | default: '#' }}" {{ block.shopify_attributes }}>
+ <img src="{{ img }}" alt="{{ block.settings.label }}" loading="lazy">
+ <span class="lbl">{{ block.settings.label }}</span>
+ </a>
+ {%- endfor -%}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Natural Wallcoverings",
+ "tag": "section",
+ "class": "section-natural-wallcoverings",
+ "settings": [
+ { "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "THE NATURALS" },
+ { "type": "text", "id": "title", "label": "Heading", "default": "Natural Wallcoverings" },
+ { "type": "color", "id": "bg", "label": "Background", "default": "#f6f2ea" },
+ { "type": "color", "id": "heading_color", "label": "Heading color", "default": "#26241f" },
+ { "type": "color", "id": "accent", "label": "Eyebrow accent", "default": "#a9773f" }
+ ],
+ "blocks": [
+ {
+ "type": "category",
+ "name": "Category square",
+ "settings": [
+ { "type": "text", "id": "label", "label": "Label", "default": "Grasscloth" },
+ { "type": "url", "id": "link", "label": "Link" },
+ { "type": "image_picker", "id": "image", "label": "Image (high-end line only)" }
+ ]
+ }
+ ],
+ "max_blocks": 8,
+ "presets": [
+ {
+ "name": "Natural Wallcoverings",
+ "blocks": [
+ { "type": "category", "settings": { "label": "Grasscloth", "link": "/collections/grasscloth" } },
+ { "type": "category", "settings": { "label": "Paperweave", "link": "/search?q=paperweave" } },
+ { "type": "category", "settings": { "label": "Sisal", "link": "/collections/sisal" } },
+ { "type": "category", "settings": { "label": "Mica", "link": "/collections/mica" } }
+ ]
+ }
+ ]
+}
+{% endschema %}
diff --git a/sections/new-arrivals-banner.liquid b/sections/new-arrivals-banner.liquid
new file mode 100644
index 0000000..de5532f
--- /dev/null
+++ b/sections/new-arrivals-banner.liquid
@@ -0,0 +1,55 @@
+{%- comment -%}
+ New Arrivals banner — full-width statement banner over high-end imagery,
+ links to the New Arrivals collection. Editable via settings; ships with a
+ luxe fallback image (Maya Romanoff glass-bead).
+{%- endcomment -%}
+{%- liquid
+ assign rid = section.id
+ assign fb = 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/mr-abh-1177-Maya_Romanoff_3.jpg'
+ assign bg = fb
+ if section.settings.image != blank
+ assign bg = section.settings.image | image_url: width: 2400
+ endif
+-%}
+<style>
+ .na-{{ rid }}{ position:relative; min-height:{{ section.settings.height }}px; display:flex; flex-direction:column;
+ align-items:center; justify-content:center; text-align:center; gap:16px; padding:64px 24px;
+ background:url('{{ bg }}') center/cover no-repeat; isolation:isolate; }
+ .na-{{ rid }}::before{ content:""; position:absolute; inset:0; z-index:-1; background:{{ section.settings.veil }}; }
+ .na-{{ rid }} .ey{ font-size:13px; letter-spacing:4px; font-weight:600; color:{{ section.settings.accent }}; margin:0; }
+ .na-{{ rid }} h2{ font-family:'Playfair Display',Georgia,serif; font-weight:700; font-size:clamp(34px,5vw,64px);
+ line-height:1.04; color:{{ section.settings.text_color }}; margin:0; max-width:760px; }
+ .na-{{ rid }} p{ color:{{ section.settings.text_color }}; opacity:.9; font-size:16px; max-width:520px; margin:0; }
+ .na-{{ rid }} .cta{ margin-top:8px; display:inline-block; background:{{ section.settings.cta_bg }}; color:{{ section.settings.cta_text }};
+ border-radius:999px; padding:15px 34px; font-size:13px; font-weight:600; letter-spacing:1.5px; text-decoration:none; }
+ @media(max-width:749px){ .na-{{ rid }}{ min-height:{{ section.settings.height | times: 0.72 | round }}px; padding:48px 20px; } }
+</style>
+<a class="na-{{ rid }}" href="{{ section.settings.cta_link | default: '/collections/new-arrivals' }}" style="text-decoration:none;">
+ {%- if section.settings.eyebrow != blank -%}<span class="ey">{{ section.settings.eyebrow }}</span>{%- endif -%}
+ <h2>{{ section.settings.heading }}</h2>
+ {%- if section.settings.subheading != blank -%}<p>{{ section.settings.subheading }}</p>{%- endif -%}
+ {%- if section.settings.cta_label != blank -%}<span class="cta">{{ section.settings.cta_label }}</span>{%- endif -%}
+</a>
+
+{% schema %}
+{
+ "name": "New Arrivals Banner",
+ "tag": "section",
+ "class": "section-new-arrivals-banner",
+ "settings": [
+ { "type": "image_picker", "id": "image", "label": "Background image (high-end line only)" },
+ { "type": "range", "id": "height", "min": 300, "max": 640, "step": 20, "unit": "px", "label": "Height", "default": 460 },
+ { "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "JUST IN" },
+ { "type": "text", "id": "heading", "label": "Heading", "default": "New Arrivals" },
+ { "type": "text", "id": "subheading", "label": "Subheading", "default": "The season's latest luxury walls & fabrics." },
+ { "type": "text", "id": "cta_label", "label": "Button label", "default": "SHOP NEW ARRIVALS" },
+ { "type": "url", "id": "cta_link", "label": "Button link" },
+ { "type": "color", "id": "text_color", "label": "Text color", "default": "#ffffff" },
+ { "type": "color", "id": "accent", "label": "Eyebrow accent", "default": "#e4c88a" },
+ { "type": "color_background", "id": "veil", "label": "Image veil (legibility)", "default": "linear-gradient(rgba(30,25,18,.35),rgba(30,25,18,.62))" },
+ { "type": "color", "id": "cta_bg", "label": "Button background", "default": "#ffffff" },
+ { "type": "color", "id": "cta_text", "label": "Button text", "default": "#26241f" }
+ ],
+ "presets": [ { "name": "New Arrivals Banner" } ]
+}
+{% endschema %}
diff --git a/sections/page-contact.liquid b/sections/page-contact.liquid
new file mode 100644
index 0000000..4a05ba2
--- /dev/null
+++ b/sections/page-contact.liquid
@@ -0,0 +1,38 @@
+<h1 class="page-title">{{ page.title }}</h1>
+
+{% render 'breadcrumbs' %}
+
+<div class="page-content rte">
+ {{ page.content }}
+
+ {% form 'contact' %}
+
+ {% if form.errors %}
+ <div class="error-message"><span>{{ 'general.contact.error' | t }}</span></div>
+ {% endif %}
+
+ {% if form.posted_successfully? %}
+ <div class="success-message">{{ 'general.contact.success' | t }}</div>
+ {% else %}
+ <div class="field-wrap name">
+ <label class="label" for="contact[name]">{{ 'general.general.name' | t }}</label>
+ <input type="text" placeholder="{{ 'general.general.name_placeholder' | t }}" value="" name="contact[name]" class="{% if form.errors contains "author" %}error{% endif %} input">
+ </div>
+
+ <div class="field-wrap email">
+ <label class="label" for="contact[email]">{{ 'general.general.email' | t }}</label>
+ <input type="text" placeholder="{{ 'general.general.email_placeholder' | t }}" value="" name="contact[email]" class="{% if form.errors contains "email" %}error{% endif %} input">
+ </div>
+
+ <div class="field-wrap message">
+ <label class="label" for="contact[body]">{{ 'general.general.message' | t }}</label>
+ <textarea name="contact[body]" class="{% if form.errors contains "body" %}error{% endif %} textarea"></textarea>
+ </div>
+
+ <input type="hidden" class="comment-check input" value="" />
+ <input type="submit" class="input" value="{{ 'general.contact.submit' | t }}">
+ {% endif %}
+
+ {% endform %}
+
+</div>
diff --git a/sections/page-inquiry.liquid b/sections/page-inquiry.liquid
new file mode 100644
index 0000000..e2d741f
--- /dev/null
+++ b/sections/page-inquiry.liquid
@@ -0,0 +1,364 @@
+<style>
+ .inquiry-section {
+ max-width: 900px;
+ margin: 0 auto;
+ padding: 40px 20px 60px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
+ }
+
+ .inquiry-section h1.page-title {
+ font-size: 2rem;
+ font-weight: 600;
+ color: #1a1a1a;
+ margin-bottom: 8px;
+ letter-spacing: -0.02em;
+ text-align: center;
+ }
+
+ .inquiry-section .page-content {
+ color: #4a4a4a;
+ font-size: 1.05rem;
+ line-height: 1.7;
+ margin-bottom: 40px;
+ padding-bottom: 32px;
+ border-bottom: 1px solid #e5e1dc;
+ text-align: center;
+ }
+
+ .inquiry-section .page-content p {
+ margin-bottom: 1em;
+ }
+
+ .inquiry-form-wrapper {
+ max-width: 750px;
+ margin: 0 auto;
+ }
+
+ .inquiry-form-heading {
+ font-size: 1.4rem;
+ font-weight: 600;
+ color: #2c2420;
+ margin-bottom: 6px;
+ text-align: center;
+ }
+
+ .inquiry-form-subheading {
+ font-size: 0.95rem;
+ color: #7a7a7a;
+ text-align: center;
+ margin-bottom: 32px;
+ }
+
+ .inquiry-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px 24px;
+ }
+
+ .inquiry-field {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .inquiry-field.full-width {
+ grid-column: 1 / -1;
+ }
+
+ .inquiry-field label {
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: #2c2420;
+ margin-bottom: 6px;
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+ }
+
+ .inquiry-field label .required {
+ color: #c0392b;
+ margin-left: 2px;
+ }
+
+ .inquiry-field input,
+ .inquiry-field select,
+ .inquiry-field textarea {
+ padding: 12px 14px;
+ font-size: 0.95rem;
+ color: #333;
+ background: #fff;
+ border: 1px solid #d4d0cb;
+ border-radius: 6px;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ font-family: inherit;
+ appearance: none;
+ -webkit-appearance: none;
+ }
+
+ .inquiry-field input:focus,
+ .inquiry-field select:focus,
+ .inquiry-field textarea:focus {
+ outline: none;
+ border-color: #2c2420;
+ box-shadow: 0 0 0 3px rgba(44, 36, 32, 0.08);
+ }
+
+ .inquiry-field input::placeholder,
+ .inquiry-field textarea::placeholder {
+ color: #b0aaa4;
+ }
+
+ .inquiry-field select {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%232c2420' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-position: right 14px center;
+ padding-right: 36px;
+ cursor: pointer;
+ }
+
+ .inquiry-field textarea {
+ min-height: 130px;
+ resize: vertical;
+ line-height: 1.5;
+ }
+
+ .inquiry-submit-row {
+ grid-column: 1 / -1;
+ margin-top: 12px;
+ }
+
+ .inquiry-submit-btn {
+ display: block;
+ width: 100%;
+ padding: 16px 32px;
+ font-size: 1rem;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: #fff;
+ background-color: #2c2420;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.2s ease, transform 0.1s ease;
+ font-family: inherit;
+ }
+
+ .inquiry-submit-btn:hover {
+ background-color: #3d332e;
+ }
+
+ .inquiry-submit-btn:active {
+ transform: translateY(1px);
+ }
+
+ .inquiry-success {
+ grid-column: 1 / -1;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 20px 24px;
+ background-color: #ecf9f1;
+ border: 1px solid #b8e6c8;
+ border-radius: 8px;
+ color: #1a6b3c;
+ font-size: 1rem;
+ line-height: 1.5;
+ }
+
+ .inquiry-success svg {
+ flex-shrink: 0;
+ }
+
+ .inquiry-errors {
+ grid-column: 1 / -1;
+ padding: 16px 20px;
+ background-color: #fef2f2;
+ border: 1px solid #f5c6c6;
+ border-radius: 8px;
+ color: #991b1b;
+ font-size: 0.9rem;
+ line-height: 1.5;
+ }
+
+ @media (max-width: 600px) {
+ .inquiry-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .inquiry-section {
+ padding: 24px 16px 40px;
+ }
+
+ .inquiry-section h1.page-title {
+ font-size: 1.6rem;
+ }
+
+ .inquiry-submit-btn {
+ padding: 14px 24px;
+ }
+ }
+</style>
+
+<div class="inquiry-section">
+ <h1 class="page-title">{{ page.title }}</h1>
+
+ {% render 'breadcrumbs' %}
+
+ {% if page.content != blank %}
+ <div class="page-content rte">
+ {{ page.content }}
+ </div>
+ {% endif %}
+
+ <div class="inquiry-form-wrapper">
+ <h2 class="inquiry-form-heading">Submit an Inquiry</h2>
+ <p class="inquiry-form-subheading">Fill out the form below and a member of our team will be in touch shortly.</p>
+
+ {% form 'contact' %}
+
+ <div class="inquiry-grid">
+
+ {% if form.posted_successfully? %}
+ <div class="inquiry-success">
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#1a6b3c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
+ <polyline points="22 4 12 14.01 9 11.01"/>
+ </svg>
+ <div>
+ <strong>Thank you for your inquiry.</strong><br>
+ We have received your submission and will respond within one business day.
+ </div>
+ </div>
+ {% endif %}
+
+ {% if form.errors %}
+ <div class="inquiry-errors">
+ {{ form.errors | default_errors }}
+ </div>
+ {% endif %}
+
+ <input type="hidden" name="contact[subject]" value="Vendor Inquiry: {{ page.title }}">
+
+ {%- comment -%} Row 1: Name + Email {%- endcomment -%}
+ <div class="inquiry-field">
+ <label for="inquiry-name">Name <span class="required">*</span></label>
+ <input
+ type="text"
+ id="inquiry-name"
+ name="contact[name]"
+ placeholder="Full name"
+ required
+ autocomplete="name"
+ >
+ </div>
+
+ <div class="inquiry-field">
+ <label for="inquiry-email">Email <span class="required">*</span></label>
+ <input
+ type="email"
+ id="inquiry-email"
+ name="contact[email]"
+ placeholder="you@example.com"
+ required
+ autocomplete="email"
+ >
+ </div>
+
+ {%- comment -%} Row 2: Phone + Design Firm {%- endcomment -%}
+ <div class="inquiry-field">
+ <label for="inquiry-phone">Phone</label>
+ <input
+ type="tel"
+ id="inquiry-phone"
+ name="contact[phone]"
+ placeholder="(555) 123-4567"
+ autocomplete="tel"
+ >
+ </div>
+
+ <div class="inquiry-field">
+ <label for="inquiry-firm">Design Firm</label>
+ <input
+ type="text"
+ id="inquiry-firm"
+ name="contact[design_firm]"
+ placeholder="Firm or studio name"
+ autocomplete="organization"
+ >
+ </div>
+
+ {%- comment -%} Row 3: Project Name + Location {%- endcomment -%}
+ <div class="inquiry-field">
+ <label for="inquiry-project">Project Name</label>
+ <input
+ type="text"
+ id="inquiry-project"
+ name="contact[project_name]"
+ placeholder="e.g. Residence at Park Ave"
+ >
+ </div>
+
+ <div class="inquiry-field">
+ <label for="inquiry-location">Location of Job</label>
+ <input
+ type="text"
+ id="inquiry-location"
+ name="contact[job_location]"
+ placeholder="City, State"
+ >
+ </div>
+
+ {%- comment -%} Row 4: Budget + Architect {%- endcomment -%}
+ <div class="inquiry-field">
+ <label for="inquiry-budget">Budget</label>
+ <select id="inquiry-budget" name="contact[budget]">
+ <option value="" disabled selected>Select a range</option>
+ <option value="Under $5,000">Under $5,000</option>
+ <option value="$5,000 - $15,000">$5,000 - $15,000</option>
+ <option value="$15,000 - $50,000">$15,000 - $50,000</option>
+ <option value="$50,000 - $100,000">$50,000 - $100,000</option>
+ <option value="$100,000+">$100,000+</option>
+ </select>
+ </div>
+
+ <div class="inquiry-field">
+ <label for="inquiry-architect">Design Architect</label>
+ <input
+ type="text"
+ id="inquiry-architect"
+ name="contact[design_architect]"
+ placeholder="Architect or designer on the project"
+ >
+ </div>
+
+ {%- comment -%} Full-width: Scope {%- endcomment -%}
+ <div class="inquiry-field full-width">
+ <label for="inquiry-scope">Scope of Project</label>
+ <textarea
+ id="inquiry-scope"
+ name="contact[scope]"
+ placeholder="Describe the project scope, materials of interest, timeline, and any other relevant details..."
+ ></textarea>
+ </div>
+
+ {%- comment -%} Submit {%- endcomment -%}
+ <div class="inquiry-submit-row">
+ <button type="submit" class="inquiry-submit-btn">Submit Inquiry</button>
+ </div>
+
+ </div>
+
+ {% endform %}
+ </div>
+</div>
+
+{% schema %}
+{
+ "name": "Vendor Inquiry Page",
+ "settings": [],
+ "presets": [
+ {
+ "name": "Vendor Inquiry Page"
+ }
+ ]
+}
+{% endschema %}
\ No newline at end of file
diff --git a/sections/page.liquid b/sections/page.liquid
new file mode 100644
index 0000000..c3a1cbe
--- /dev/null
+++ b/sections/page.liquid
@@ -0,0 +1,11 @@
+<h1 class="page-title">{{ page.title }}</h1>
+
+{% render 'breadcrumbs' %}
+
+<div class="page-content rte">
+ {{ page.content }}
+</div>
+
+{% if settings.dw_enable_recently_viewed %}
+ {% render 'recently-viewed' %}
+{% endif %}
\ No newline at end of file
diff --git a/sections/password.liquid b/sections/password.liquid
new file mode 100644
index 0000000..7f45b27
--- /dev/null
+++ b/sections/password.liquid
@@ -0,0 +1,112 @@
+<script
+ type="application/json"
+ data-section-type="password"
+ data-section-id="{{ section.id }}"
+></script>
+
+<div class="password-page main-content">
+ <div class="password-page-header">
+ <div class="password-page-inner">
+ <a href="#modal-login" class="admin-login-modal">
+ {{ 'general.password_page.password_link' | t }}
+ </a>
+ </div>
+ </div>
+
+ <div class="password-page-content">
+ <div class="password-page-inner">
+ <div class="password-page-logo">
+ <header class="main-header" role="banner">
+ <div class="password-branding">
+ <a class="logo-link" href="{{ routes.root_url }}">
+ <h1>{{ shop.name }}</h1>
+ </a>
+ </div>
+ </header>
+ </div>
+ <div class="password-page-signup-form">
+ <div class="password-page-form-header">
+ <h2>{{ 'general.password_page.opening_soon' | t }}</h2>
+
+ {% unless shop.password_message == blank %}
+ <p class="password-page-message">
+ {{ shop.password_message }}
+ </p>
+ {% endunless %}
+ </div>
+
+ {% form 'customer', class: 'newsletter-signup' %}
+ {{ form.errors | default_errors }}
+
+ {% if form.posted_successfully? %}
+ <p class="form-success">{{ 'general.password_page.signup_form_success' | t }}</p>
+ {% else %}
+ {% if section.settings.newsletter_text != blank %}
+ {{ section.settings.newsletter_text }}
+ {% endif %}
+
+ <div class="password-page-field-wrap">
+ <input class="password-page-input input" type="text" name="contact[email]" id="email" placeholder="{{ 'general.password_page.signup_form_email_placeholder' | t }}">
+ <input class="submit input" name="commit" type="submit" value="{{ 'general.password_page.signup_form_submit' | t }}">
+ <input type="hidden" class="input" name="contact[tags]" value="prospect, password page">
+ </div>
+ {% endif %}
+ {% endform %}
+ </div>
+ </div>
+ </div>
+
+ <div class="password-page-footer" role="contentinfo">
+ <div class="password-page-inner">
+ {% capture shopify %}
+ <a
+ class="shopify-link"
+ href="//www.shopify.com/"
+ rel="nofollow"
+ target="_blank"
+ title="Create your own online store with Shopify"
+ >
+ <span class="shopify-name">Shopify</span>
+ </a>
+ {% endcapture %}
+ {{ 'general.password_page.powered_by_shopify_html' | t: shopify: shopify }}
+ </div>
+ </div>
+
+</div>
+
+<div id="modal-login" class="password-page-modal-wrapper">
+ <div class="password-page-modal">
+ <div class="module header">
+ <p class="form-title">{{ 'general.password_page.login_form_heading' | t }}</p>
+ </div>
+
+ {% form 'storefront_password' %}
+ {{ form.errors | default_errors }}
+ <div class="password-page-field-wrap" {% if form.errors %}data-open-modal{% endif %}>
+ <input class="password-page-input input" type="password" name="password" id="password" placeholder="{{ 'general.password_page.login_form_password_label' | t }}" autofocus>
+ <input class="submit input" name="submit" type="submit" value="{{ 'general.password_page.login_form_submit' | t }}">
+ </div>
+ {% endform %}
+ </div>
+</div>
+
+{% schema %}
+{
+ "name": "Password pages",
+ "class": "section-password",
+ "settings": [
+ {
+ "type": "header",
+ "content": "Newsletter"
+ },
+ {
+ "id": "newsletter_text",
+ "type": "richtext",
+ "label": "Text",
+ "default": "<p>Find out when we open:</p>"
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/predictive-search.liquid b/sections/predictive-search.liquid
new file mode 100644
index 0000000..c9f01c2
--- /dev/null
+++ b/sections/predictive-search.liquid
@@ -0,0 +1,219 @@
+{%- if predictive_search.performed -%}
+ {% liquid
+ assign search_results = false
+
+ if predictive_search.resources.products.size > 0 or predictive_search.resources.collections.size > 0 or predictive_search.resources.articles.size > 0 or predictive_search.resources.pages.size > 0
+ assign search_results = true
+ endif
+ %}
+
+ <div
+ class="
+ predictive-search-results
+ {% if predictive_search.resources.products.size > 0 and predictive_search.resources.pages.size > 0 or predictive_search.resources.articles.size > 0 %}
+ predictive-search-results--multi-column
+ {% endif %}
+ "
+ >
+ {%- if predictive_search.resources.queries.size > 0 or predictive_search.resources.collections.size > 0 -%}
+ <div class="predictive-search-query-suggestions">
+ <h2 class="predictive-search-heading">
+ {{- 'general.predictive_search.query_suggestions_heading' | t -}}
+ </h2>
+
+ <ul class="predictive-search-results-list" role="listbox">
+ {%- for query in predictive_search.resources.queries -%}
+ <li class="predictive-search-results-list__item" role="option">
+ <a class="predictive-search-results-list__item-result" href="{{ query.url }}">
+ {{- query.styled_text -}}
+ </a>
+ </li>
+ {%- endfor -%}
+
+ {%- for collection in predictive_search.resources.collections -%}
+ <li class="predictive-search-results-list__item" role="option">
+ <a class="predictive-search-results-list__item-result" href="{{ collection.url }}">
+ {{- collection.title | escape -}}
+ </a>
+ </li>
+ {%- endfor -%}
+ </ul>
+ </div>
+ {%- endif -%}
+
+ {%- if predictive_search.resources.products.size > 0 -%}
+ <div class="predictive-search-product-suggestions" data-predictive-search-product-suggestions>
+ <h2 class="predictive-search-heading">
+ {{- 'general.predictive_search.product_suggestions_heading' | t -}}
+ </h2>
+
+ <ul class="predictive-search-results-list" role="listbox">
+ {%- for product in predictive_search.resources.products -%}
+ <li class="predictive-search-results-list__item" role="option">
+ <a class="predictive-search-results-list__item-result" href="{{ product.url }}">
+ <div class="predictive-search-results-list__item-result-container">
+ <div class="predictive-search-results-list__product-item-image-container">
+ <figure>
+ {%- if product.featured_media != blank -%}
+ {%
+ render 'rimg',
+ img: product.featured_media.preview_image,
+ alt: product.featured_media.preview_image.alt,
+ size: '300x',
+ lazy: true,
+ %}
+ {%- else -%}
+ {{- 'product-1' | placeholder_svg_tag: 'placeholder-svg' -}}
+ {%- endif -%}
+ </figure>
+ </div>
+
+ <div class="predictive-search-results-list__product-item-content">
+ <span class="predictive-search-results-list__product-item-vendor">
+ {{- product.vendor -}}
+ </span>
+
+ <h3 class="predictive-search-results-list__product-item-heading">
+ {{- product.title | escape -}}
+ </h3>
+
+ <p class="predictive-search-results-list__product-item-price">
+ {%- if product.price_varies -%}
+ {{- 'products.product.from' | t -}}
+
+ {%- if product.compare_at_price_min > product.price_min -%}
+ <span class="money">
+ {{- product.price_min | money -}}
+ </span>
+
+ <span class="original money">
+ {{- product.compare_at_price_min | money -}}
+ </span>
+ {%- else -%}
+ <span class="money">
+ {{- product.price_min | money -}}
+ </span>
+ {%- endif -%}
+ {%- else -%}
+ {%- if product.compare_at_price_min > product.price_min -%}
+ <span class="money">
+ {{- product.price_min | money -}}
+ </span>
+
+ <span class="original money">
+ {{- product.compare_at_price_min | money -}}
+ </span>
+ {%- else -%}
+ <span class="money">
+ {{- product.price_min | money -}}
+ </span>
+ {%- endif -%}
+ {%- endif -%}
+ </p>
+
+ {%- assign variant_for_unit_price = product.variants | sort: 'price' | first -%}
+
+ {%- if variant_for_unit_price.unit_price -%}
+ {% comment %}Inject unit-price begin{% endcomment %}
+ {% comment %}
+ @param variant_for_unit_price
+ Product variant for price
+ @param tax_text
+ String containing 'tax included' text
+ {% endcomment %}
+
+ {% capture total_quantity %}
+ <span class="product-price__unit-price-total-quantity" data-unit-price-quantity>
+ {{ variant_for_unit_price.unit_price_measurement.quantity_value }}{{ variant_for_unit_price.unit_price_measurement.quantity_unit }}
+ </span>
+ {% endcapture %}
+
+
+ {% capture unit_price %}
+ <span class="product-price__unit-price-amount money" data-unit-price-amount>
+ {{ variant_for_unit_price.unit_price | money }}
+ </span>
+ {% endcapture %}
+ {% capture unit_measure %}
+ <span class="product-price__unit-price-measure" data-unit-price-measure>
+ {%- if variant_for_unit_price.unit_price_measurement.reference_value != 1 -%}
+ {{ variant_for_unit_price.unit_price_measurement.reference_value }}
+ {%- endif %}
+ {{ variant_for_unit_price.unit_price_measurement.reference_unit }}
+ </span>
+ {% endcapture %}
+
+ <div
+ class="
+ product-price__unit-price
+ {% unless variant_for_unit_price.unit_price_measurement %}hidden{% endunless %}
+ "
+ data-unit-price
+ >
+ {{ 'products.product.price_per_unit_html' | t: total_quantity: total_quantity, unit_price: unit_price, unit_measure: unit_measure | strip_newlines }}
+ </div>
+
+ {% assign variant_for_unit_price = blank %}
+ {% comment %}Inject unit-price end{% endcomment %}
+
+ {%- endif -%}
+ </div>
+ </div>
+ </a>
+ </li>
+ {%- endfor -%}
+ </ul>
+ </div>
+ {%- endif -%}
+
+ {%- if predictive_search.resources.pages.size > 0 or predictive_search.resources.articles.size > 0 -%}
+ <div class="predictive-search-page-and-post-suggestions">
+ <h2 class="predictive-search-heading">
+ {% if predictive_search.resources.articles.size > 0 and predictive_search.resources.pages.size > 0 %}
+ {{- 'general.predictive_search.pages_and_posts_suggestions_heading' | t -}}
+ {% elsif predictive_search.resources.articles.size > 0 %}
+ {{- 'general.predictive_search.posts_suggestions_heading' | t -}}
+ {% elsif predictive_search.resources.pages.size > 0 %}
+ {{- 'general.predictive_search.pages_suggestions_heading' | t -}}
+ {% endif %}
+ </h2>
+
+ <ul class="predictive-search-results-list" role="listbox">
+ {%- for article in predictive_search.resources.articles -%}
+ <li class="predictive-search-results-list__item" role="option">
+ <a class="predictive-search-results-list__item-result" href="{{ article.url }}">
+ {{- article.title | escape -}}
+ </a>
+ </li>
+ {%- endfor -%}
+
+ {%- for page in predictive_search.resources.pages -%}
+ <li class="predictive-search-results-list__item" role="option">
+ <a class="predictive-search-results-list__item-result" href="{{ page.url }}">
+ {{- page.title | escape -}}
+ </a>
+ </li>
+ {%- endfor -%}
+ </ul>
+ </div>
+ {%- endif -%}
+
+ {%- unless search_results -%}
+ <div class="predictive-search-no-results">
+ <p class="predictive-search-no-results__text">
+ {{- 'general.predictive_search.no_results_text' | t -}}
+ </p>
+ </div>
+ {%- endunless -%}
+
+ <div class="predictive-search-footer">
+ <button
+ class="predictive-search-footer__button"
+ type="submit"
+ data-predictive-search-button
+ >
+ {{- 'general.predictive_search.search_button_label' | t: search_terms: predictive_search.terms -}}
+ </button>
+ </div>
+ </div>
+{%- endif -%}
\ No newline at end of file
diff --git a/sections/product-ajax.liquid b/sections/product-ajax.liquid
new file mode 100644
index 0000000..c1e6ab7
--- /dev/null
+++ b/sections/product-ajax.liquid
@@ -0,0 +1,274 @@
+{% liquid
+ assign enable_zoom = section.settings.quickshop_enable_zoom
+ assign enable_video_autoplay = section.settings.quickshop_enable_video_autoplay
+ assign enable_video_looping = section.settings.quickshop_enable_video_looping
+ assign enable_cart_redirection = section.settings.quickshop_enable_cart_redirection
+ assign images_layout = section.settings.quickshop_images_layout
+ assign show_payment_button = section.settings.quickshop_show_payment_button
+ assign isQuickshop = true
+ assign product_json = product | json
+%}
+
+{% capture settings_string %}
+ {{ enable_zoom }}
+ {{ enable_cart_redirection }}
+ {{ images_layout }}
+ {{ show_payment_button }}
+ {{ enable_video_autoplay }}
+ {{ enable_video_looping }}
+ {{ isQuickshop }}
+{% endcapture %}
+
+<script
+ type="application/json"
+ data-section-type="product"
+ data-section-id="{{ section.id }}"
+ data-section-data
+ data-product-options
+>
+ {
+ "product": {{ product_json }},
+ "product_settings": {
+ "addToCartText": {{ 'products.product.add_to_cart' | t | json }},
+ "enableHistory": false,
+ "processingText": {{ 'products.product.processing' | t | json }},
+ "setQuantityText": {{ 'products.product.set_quantity' | t | json }},
+ "soldOutText": {{ 'products.product.sold_out' | t | json }},
+ "unavailableText": {{ 'products.product.unavailable' | t | json }}
+ },
+ "images_layout": {{ images_layout | json }},
+ "enable_zoom": {{ enable_zoom | json }},
+ "enable_video_autoplay": {{ enable_video_autoplay | json }},
+ "enable_video_looping": {{ enable_video_looping | json }},
+ "enable_cart_redirection": {{ enable_cart_redirection | json }},
+ "enable_fixed_positioning": false,
+ "isQuickshop": true
+ }
+</script>
+
+
+
+<section data-product-html>
+ {%
+ render 'product',
+ product: product,
+ enable_zoom: enable_zoom,
+ images_layout: images_layout,
+ enable_linked_options: true,
+ show_social_media_icons: show_social_media_icons,
+ show_payment_button: show_payment_button,
+ link_to: true,
+ %}
+</section>
+
+{% schema %}
+{
+ "name": "Quick shop",
+ "class": "shopify-section--quick-shop",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "quickshop_enable_cart_redirection",
+ "label": "Enable cart redirection",
+ "info": "Automatically sends users to the Cart page after adding a product.",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "quickshop_show_payment_button",
+ "label": "Show dynamic checkout button",
+ "info": "Each customer will see their preferred payment method from those available on your store, such as PayPal or Apple Pay. [Learn more](https://help.shopify.com/manual/using-themes/change-the-layout/dynamic-checkout)",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Media"
+ },
+ {
+ "type": "paragraph",
+ "content": "Learn more about [media types](https://help.shopify.com/en/manual/products/product-media/product-media-types)"
+ },
+ {
+ "type": "select",
+ "id": "quickshop_images_layout",
+ "label": "Layout",
+ "options": [
+ {
+ "label": "Slideshow",
+ "value": "slideshow"
+ },
+ {
+ "label": "List",
+ "value": "list"
+ },
+ {
+ "label": "Masonry",
+ "value": "masonry"
+ }
+ ],
+ "default": "slideshow"
+ },
+ {
+ "type": "checkbox",
+ "id": "quickshop_enable_zoom",
+ "label": "Enable image zoom",
+ "info": "Zoom only works with the slideshow image layout"
+ },
+ {
+ "type": "checkbox",
+ "id": "quickshop_enable_video_autoplay",
+ "label": "Enable video autoplay",
+ "default": true
+ },
+ {
+ "type": "checkbox",
+ "id": "quickshop_enable_video_looping",
+ "label": "Enable video looping"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "@app"
+ },
+ {
+ "type": "collapsible-tab",
+ "name": "Collapsible tab",
+ "settings": [
+ {
+ "type": "text",
+ "id": "collapsible_tab_heading",
+ "label": "Heading",
+ "default": "Collapsible tab"
+ },
+ {
+ "type": "richtext",
+ "id": "collapsible_tab_text",
+ "label": "Text",
+ "default": "<p>Use this text to share information about your product.</p>"
+ }
+ ]
+ },
+ {
+ "type": "custom-liquid",
+ "name": "Custom liquid",
+ "settings": [
+ {
+ "type": "liquid",
+ "id": "custom_liquid",
+ "label": "Custom liquid",
+ "info": "Add app snippets or other Liquid code to create advanced customizations."
+ }
+ ]
+ },
+ {
+ "type": "tabs",
+ "name": "Tabs",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_product_description",
+ "label": "Show product description",
+ "default": false
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_1",
+ "label": "Heading",
+ "default": "Tab 1"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_1",
+ "label": "Text",
+ "default": "<p>Tab 1 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_2",
+ "label": "Heading",
+ "default": "Tab 2"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_2",
+ "label": "Text",
+ "default": "<p>Tab 2 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_3",
+ "label": "Heading",
+ "default": "Tab 3"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_3",
+ "label": "Text",
+ "default": "<p>Tab 3 content goes here.</p>"
+ }
+ ]
+ },
+ {
+ "type": "title",
+ "name": "Title",
+ "limit": 1
+ },
+ {
+ "type": "vendor",
+ "name": "Vendor",
+ "limit": 1
+ },
+ {
+ "type": "social",
+ "name": "Social",
+ "limit": 1
+ },
+ {
+ "type": "description",
+ "name": "Description",
+ "limit": 1
+ },
+ {
+ "type": "price",
+ "name": "Price",
+ "limit": 1
+ },
+ {
+ "type": "form",
+ "name": "Form",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "Customize form features for the product in the products portion of the theme settings."
+ }
+ ]
+ },
+ {
+ "type": "rating",
+ "name": "Product rating",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "To display a rating, add a product rating app. [Learn more](https://apps.shopify.com/product-reviews)"
+ }
+ ]
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/product.liquid b/sections/product.liquid
new file mode 100644
index 0000000..ed86f01
--- /dev/null
+++ b/sections/product.liquid
@@ -0,0 +1,712 @@
+{% render 'breadcrumbs' %}
+
+{% liquid
+ assign enable_zoom = section.settings.enable_zoom
+ assign enable_cart_redirection = section.settings.enable_cart_redirection
+ assign images_layout = section.settings.images_layout
+ assign enable_video_autoplay = section.settings.enable_video_autoplay
+ assign enable_video_looping = section.settings.enable_video_looping
+ assign enable_linked_options = true
+ assign show_vendor = settings.show_vendor
+ assign show_social_media_icons = section.settings.show_social_media_icons
+ assign show_payment_button = section.settings.show_payment_button
+
+ for block in section.blocks
+ if block.type == 'complementary_products'
+ assign product_recommendation_limit = block.settings.product_recommendation_limit
+ break
+ endif
+ endfor
+%}
+
+{% if images_layout == 'masonry' %}
+ {% comment %}Related products in masonry grid must be below product{% endcomment %}
+ {% assign related_products_position_right = false %}
+{% endif %}
+
+<script
+ type="application/json"
+ data-section-type="product"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+ {
+ "product": {{ product | json }},
+ "product_settings": {
+ "addToCartText": {{ 'products.product.add_to_cart' | t | json }},
+ "enableHistory": true,
+ "processingText": {{ 'products.product.processing' | t | json }},
+ "setQuantityText": {{ 'products.product.set_quantity' | t | json }},
+ "soldOutText": {{ 'products.product.sold_out' | t | json }},
+ "unavailableText": {{ 'products.product.unavailable' | t | json }}
+ },
+ "images_layout": {{ images_layout | json }},
+ "enable_zoom": {{ enable_zoom | json }},
+ "enable_video_autoplay": {{ enable_video_autoplay | json }},
+ "enable_video_looping": {{ enable_video_looping | json }},
+ "enable_cart_redirection": {{ enable_cart_redirection | json }},
+ "enable_fixed_positioning": true,
+ "product_recommendation_limit": {{ product_recommendation_limit | json }}
+ }
+</script>
+
+{% render 'product-success-labels' %}
+<section class="product-container">
+ {%
+ render 'product',
+ product: product,
+ enable_zoom: enable_zoom,
+ images_layout: images_layout,
+ enable_linked_options: enable_linked_options,
+ show_vendor: show_vendor,
+ show_social_media_icons: show_social_media_icons,
+ show_payment_button: show_payment_button,
+ %}
+
+ {%- comment -%}
+ Design Coordinate v6 — Steve's spec:
+ • Catalog grid: 24 stripe/plaid/check coordinates that use the source palette
+ • Density slider 3-12 cols (default 8), localStorage-persisted
+ • AI Generated Coordinates: 24 SVG-poster placeholders seeded from palette
+ • Vendor picker: SW / DE / BM / F&B (default on) + Behr / PPG / RAL (opt-in)
+ • Each card shows palette dots + selected vendors' paint chips
+ Service: https://pairs.designerwallcoverings.com (commit history at ~/Projects/dw-pairs-well)
+ CSS namespace kept as .pairs-well__* — only the button TEXT is "Design Coordinate".
+ {%- endcomment -%}
+ <section
+ id="pairs-well-with"
+ class="dc-section"
+ data-pairs-endpoint="https://pairs.designerwallcoverings.com/api/pairs"
+ data-ai-endpoint="https://pairs.designerwallcoverings.com/api/ai-coordinates"
+ data-product-handle="{{ product.handle }}"
+ {%- comment -%}
+ 2026-06-27 (vp-dw-commerce): data-product-sku must be the DW sku (the
+ shopify_products.dw_sku key), NOT custom.manufacturer_sku — the MFR sku
+ never matches the pairs DB and was returning "source not found",
+ breaking the Design Coordinate panel. Use the variant's DW sku (strip the
+ -Sample suffix); the pairs API also resolves by handle as a fallback.
+ {%- endcomment -%}
+ {%- assign dc_sku = product.selected_or_first_available_variant.sku | default: product.variants.first.sku | replace: '-Sample', '' | replace: '-SAMPLE', '' -%}
+ data-product-sku="{{ dc_sku | escape }}"
+ style="margin: 1.5em 0 2em; clear: both;"
+ hidden
+ >
+ <button type="button" class="pairs-well__cta" aria-expanded="false">
+ <span class="pairs-well__cta-text">Design Coordinate</span>
+ <span class="pairs-well__cta-icon" aria-hidden="true">+</span>
+ </button>
+
+ <div class="pairs-well__source-palette" id="pairs-well-source-palette" hidden></div>
+
+ <div class="pairs-well__vendor-picker" id="pairs-well-vendor-picker" hidden>
+ <h4>Paint brands</h4>
+ <div class="chips">
+ <label><input type="checkbox" value="sw" checked> Sherwin-Williams</label>
+ <label><input type="checkbox" value="de" checked> Dunn-Edwards</label>
+ <label><input type="checkbox" value="bm" checked> Benjamin Moore</label>
+ <label><input type="checkbox" value="fb" checked> Farrow & Ball</label>
+ <label><input type="checkbox" value="behr" > Behr</label>
+ <label><input type="checkbox" value="ppg" > PPG</label>
+ <label><input type="checkbox" value="ral" > RAL</label>
+ </div>
+ </div>
+
+ <div class="pairs-well__catalog" id="pairs-well-catalog" hidden>
+ <div class="pairs-well__panel-head">
+ <h3>Stripes & Plaids from our catalog <span class="count" id="pairs-well-catalog-count"></span></h3>
+ <div class="pairs-well__controls">
+ <label for="pairs-well-cols-catalog">Columns</label>
+ <input id="pairs-well-cols-catalog" type="range" min="3" max="12" value="8" step="1">
+ <span class="pairs-well__cols-val" id="pairs-well-cols-catalog-val">8</span>
+ </div>
+ </div>
+ <div id="pairs-well-grid" class="pairs-well__grid"></div>
+ </div>
+
+ <div class="pairs-well__ai" id="pairs-well-ai" hidden>
+ <div class="pairs-well__panel-head">
+ <h3>AI Generated Coordinates <span class="ai-badge">Preview · 24 options</span></h3>
+ <div class="pairs-well__controls">
+ <label for="pairs-well-cols-ai">Columns</label>
+ <input id="pairs-well-cols-ai" type="range" min="3" max="12" value="8" step="1">
+ <span class="pairs-well__cols-val" id="pairs-well-cols-ai-val">8</span>
+ </div>
+ </div>
+ <div id="pairs-well-ai-grid" class="pairs-well__grid pairs-well__grid--ai"></div>
+ </div>
+ </section>
+
+ <style>
+ #pairs-well-with { font-family: inherit; --cols-catalog: 8; --cols-ai: 8; }
+ .pairs-well__cta {
+ display: flex; align-items: center; justify-content: space-between;
+ width: 100%; padding: 18px 24px; margin: 0;
+ background: #111; color: #fff;
+ border: 0; border-radius: 999px;
+ font-size: 15px; font-weight: 500; letter-spacing: 0.06em;
+ text-transform: uppercase; cursor: pointer;
+ transition: background 160ms ease, transform 120ms ease;
+ }
+ .pairs-well__cta:hover { background: #2a2a2a; }
+ .pairs-well__cta:active { transform: scale(0.995); }
+ .pairs-well__cta[aria-expanded="true"] .pairs-well__cta-icon { transform: rotate(45deg); }
+ .pairs-well__cta-icon { display: inline-block; font-size: 22px; line-height: 1; transition: transform 200ms ease; }
+
+ .pairs-well__source-palette { margin: 18px 0 0; }
+ .pairs-well__source-palette h4 { margin: 0 0 8px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #777; }
+ .pairs-well__source-palette table { border-collapse: collapse; width: 100%; font-size: 12px; }
+ .pairs-well__source-palette th, .pairs-well__source-palette td { text-align: left; padding: 6px 8px; border-bottom: 1px solid #f0ebe2; }
+ .pairs-well__source-palette th { font-weight: 500; color: #777; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
+ .pairs-well__source-palette td.swatch { width: 28px; }
+
+ .pw-dot { display: inline-block; width: 18px; height: 18px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.12); vertical-align: middle; }
+ .pw-square { display: inline-block; width: 13px; height: 13px; border-radius: 3px; border: 1px solid rgba(0,0,0,0.12); vertical-align: middle; margin-right: 4px; }
+ .pw-code { color: #888; font-variant-numeric: tabular-nums; font-size: 11px; }
+
+ .pairs-well__vendor-picker { margin: 18px 0 0; }
+ .pairs-well__vendor-picker h4 { margin: 0 0 8px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #777; }
+ .pairs-well__vendor-picker .chips { display: flex; flex-wrap: wrap; gap: 6px; }
+ .pairs-well__vendor-picker label {
+ font-size: 12px; padding: 5px 10px; border: 1px solid #e7e7e7; border-radius: 999px;
+ cursor: pointer; background: #fff; user-select: none;
+ }
+ .pairs-well__vendor-picker label:has(input:checked) { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
+ .pairs-well__vendor-picker input { display: none; }
+
+ .pairs-well__panel-head {
+ display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
+ gap: 12px; margin: 24px 0 12px;
+ }
+ .pairs-well__panel-head h3 { margin: 0; font: 500 18px/1.2 ui-serif, Georgia, serif; }
+ .pairs-well__panel-head .count { color: #888; font-size: 12px; margin-left: 6px; font-family: -apple-system, sans-serif; font-weight: 400; }
+ .pairs-well__panel-head .ai-badge {
+ display: inline-block; padding: 3px 8px; background: #2a2a2a; color: #fff;
+ border-radius: 999px; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
+ margin-left: 8px; font-family: -apple-system, sans-serif; font-weight: 600;
+ }
+ .pairs-well__controls {
+ display: flex; align-items: center; gap: 10px;
+ font-size: 11px; color: #777; text-transform: uppercase; letter-spacing: 0.06em;
+ }
+ .pairs-well__controls input[type=range] { width: 160px; accent-color: #1a1a1a; }
+ .pairs-well__cols-val { font-variant-numeric: tabular-nums; color: #1a1a1a; min-width: 1.5em; text-align: right; font-weight: 600; }
+
+ .pairs-well__grid {
+ display: grid; gap: 14px; margin-top: 6px;
+ grid-template-columns: repeat(var(--cols-catalog), minmax(0, 1fr));
+ }
+ .pairs-well__grid--ai { grid-template-columns: repeat(var(--cols-ai), minmax(0, 1fr)); }
+ @media (max-width: 1100px) { .pairs-well__grid { grid-template-columns: repeat(min(6, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(6, var(--cols-ai)), minmax(0, 1fr)); } }
+ @media (max-width: 900px) { .pairs-well__grid { grid-template-columns: repeat(min(4, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(4, var(--cols-ai)), minmax(0, 1fr)); } }
+ @media (max-width: 600px) { .pairs-well__grid { grid-template-columns: repeat(min(2, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(2, var(--cols-ai)), minmax(0, 1fr)); } }
+
+ .pairs-well__card {
+ display: block; text-decoration: none; color: inherit;
+ background: #fff; border: 1px solid #e7e7e7; border-radius: 6px;
+ overflow: hidden; transition: box-shadow 160ms ease, transform 160ms ease;
+ }
+ .pairs-well__card:hover { box-shadow: 0 6px 20px rgba(0,0,0,0.08); transform: translateY(-2px); }
+ .pairs-well__card--ai { border-style: dashed; border-color: #d9c7a8; }
+ .pairs-well__img-wrap { aspect-ratio: 1 / 1; background: #f4f4f4; overflow: hidden; }
+ .pairs-well__img { width: 100%; height: 100%; object-fit: cover; display: block; }
+ .pairs-well__meta { padding: 10px 12px 12px; }
+ .pairs-well__title { margin: 0 0 4px; font-size: 13px; font-weight: 600; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
+ .pairs-well__vendor { margin: 0 0 6px; font-size: 10px; color: #777; letter-spacing: 0.04em; text-transform: uppercase; }
+ .pairs-well__why { display: inline-block; padding: 2px 7px; background: #f4ede4; color: #5a4628; border-radius: 999px; font-size: 10px; line-height: 1.4; margin-bottom: 8px; }
+ .pairs-well__card--ai .pairs-well__why { background: #efe6f5; color: #5b3478; }
+ .pairs-well__palette { display: flex; gap: 3px; margin: 0 0 8px; flex-wrap: wrap; }
+ .pairs-well__palette .pw-dot { width: 12px; height: 12px; }
+ .pairs-well__paints { border-top: 1px dashed #ebe4d8; margin-top: 4px; padding-top: 6px; font-size: 10px; line-height: 1.5; color: #444; }
+ .pairs-well__paints .label { color: #888; font-weight: 600; margin-right: 4px; letter-spacing: 0.04em; }
+ .pairs-well__paints .row { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+
+ .pairs-well__skeleton { background: linear-gradient(90deg, #eee 0%, #f6f6f6 50%, #eee 100%); background-size: 200% 100%; animation: pwShim 1.2s linear infinite; aspect-ratio: 1 / 1; border-radius: 6px; }
+ @keyframes pwShim { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
+ .pairs-well__empty { padding: 18px; color: #777; font-size: 14px; grid-column: 1 / -1; }
+ </style>
+
+ <script>
+ (function () {
+ var root = document.getElementById('pairs-well-with');
+ if (!root) return;
+
+ var endpointPairs = root.getAttribute('data-pairs-endpoint');
+ var endpointAi = root.getAttribute('data-ai-endpoint');
+ var handle = root.getAttribute('data-product-handle');
+ var sku = root.getAttribute('data-product-sku');
+ if (!(sku && sku.length) && !(handle && handle.length)) return;
+ root.hidden = false;
+
+ var cta = root.querySelector('.pairs-well__cta');
+ var catalogPanel = document.getElementById('pairs-well-catalog');
+ var catalogGrid = document.getElementById('pairs-well-grid');
+ var catalogCols = document.getElementById('pairs-well-cols-catalog');
+ var catalogColsVal = document.getElementById('pairs-well-cols-catalog-val');
+ var catalogCount = document.getElementById('pairs-well-catalog-count');
+ var aiPanel = document.getElementById('pairs-well-ai');
+ var aiGrid = document.getElementById('pairs-well-ai-grid');
+ var aiCols = document.getElementById('pairs-well-cols-ai');
+ var aiColsVal = document.getElementById('pairs-well-cols-ai-val');
+ var sourcePalette = document.getElementById('pairs-well-source-palette');
+ var vendorPicker = document.getElementById('pairs-well-vendor-picker');
+ var vendorChecks = vendorPicker.querySelectorAll('input[type=checkbox]');
+ var loaded = false;
+ var cachedPairs = null, cachedAi = null, cachedSource = null;
+
+ var VENDOR_LABEL = { sw:'Sherwin-Williams', de:'Dunn-Edwards', bm:'Benjamin Moore', fb:'Farrow & Ball', behr:'Behr', ppg:'PPG', ral:'RAL' };
+ var VENDOR_SHORT = { sw:'SW', de:'DE', bm:'BM', fb:'F&B', behr:'Behr', ppg:'PPG', ral:'RAL' };
+ var DEFAULT_VENDORS = ['sw','de','bm','fb'];
+
+ function selectedVendors() {
+ var out = [];
+ vendorChecks.forEach(function (cb) { if (cb.checked) out.push(cb.value); });
+ return out.length ? out : DEFAULT_VENDORS.slice();
+ }
+ try {
+ var stored = JSON.parse(localStorage.getItem('pw.vendors') || 'null');
+ if (Array.isArray(stored) && stored.length) {
+ vendorChecks.forEach(function (cb) { cb.checked = stored.indexOf(cb.value) !== -1; });
+ }
+ } catch (_) {}
+ function persistVendors() {
+ try { localStorage.setItem('pw.vendors', JSON.stringify(selectedVendors())); } catch (_) {}
+ }
+ vendorChecks.forEach(function (cb) {
+ cb.addEventListener('change', function () {
+ persistVendors();
+ if (cachedSource) renderSourcePalette(cachedSource.palette);
+ if (cachedPairs && !catalogPanel.hidden) renderGrid(catalogGrid, cachedPairs, false);
+ });
+ });
+
+ function wireSlider(input, valEl, gridEl, varName, storageKey) {
+ function apply() {
+ var n = Math.max(3, Math.min(12, parseInt(input.value, 10) || 8));
+ valEl.textContent = n;
+ gridEl.parentNode.parentNode.style.setProperty('--' + varName, n);
+ root.style.setProperty('--' + varName, n);
+ try { localStorage.setItem(storageKey, n); } catch (_) {}
+ }
+ try {
+ var s = parseInt(localStorage.getItem(storageKey), 10);
+ if (!isNaN(s) && s >= 3 && s <= 12) input.value = s;
+ } catch (_) {}
+ input.addEventListener('input', apply);
+ apply();
+ }
+ wireSlider(catalogCols, catalogColsVal, catalogGrid, 'cols-catalog', 'pw.cols.catalog');
+ wireSlider(aiCols, aiColsVal, aiGrid, 'cols-ai', 'pw.cols.ai');
+
+ function esc(s) {
+ return String(s == null ? '' : s)
+ .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
+ .replace(/"/g, '"').replace(/'/g, ''');
+ }
+ function renderSkeletons(grid, n) {
+ var html = '';
+ for (var i = 0; i < n; i++) html += '<div class="pairs-well__skeleton"></div>';
+ grid.innerHTML = html;
+ }
+
+ function renderSourcePalette(palette) {
+ if (!palette || !palette.length) { sourcePalette.hidden = true; vendorPicker.hidden = true; return; }
+ var vendors = selectedVendors();
+ var head = '<th></th>' + vendors.map(function (v) { return '<th>' + esc(VENDOR_LABEL[v]) + '</th>'; }).join('');
+ var body = palette.map(function (c) {
+ var hex = typeof c === 'string' ? c : c.hex;
+ var cells = '<td class="swatch"><span class="pw-dot" style="background:' + esc(hex) + '"></span></td>';
+ vendors.forEach(function (v) {
+ var p = c && c.paints && c.paints[v];
+ cells += '<td>' + (p
+ ? '<span class="pw-square" style="background:' + esc(p.hex) + '"></span>' + esc(p.name) + ' <span class="pw-code">' + esc(p.code) + '</span>'
+ : '—') + '</td>';
+ });
+ return '<tr>' + cells + '</tr>';
+ }).join('');
+ sourcePalette.innerHTML = '<h4>Color story</h4><table><thead><tr>' + head + '</tr></thead><tbody>' + body + '</tbody></table>';
+ sourcePalette.hidden = false;
+ vendorPicker.hidden = false;
+ }
+
+ function renderCard(p, isAi) {
+ var img = p.image_url ? esc(p.image_url) : '';
+ var why = (p.why && p.why[0]) ? esc(p.why[0]) : (p.motif ? 'AI ' + esc(p.motif) : '');
+ var palette = (p.palette || []).map(function (c) {
+ var hex = typeof c === 'string' ? c : c.hex;
+ var sw = c && c.paints && c.paints.sw, de = c && c.paints && c.paints.de;
+ var tip = (sw ? 'SW ' + sw.name + ' ' + sw.code : '') + (de ? ' · DE ' + de.name + ' ' + de.code : '');
+ return '<span class="pw-dot" style="background:' + esc(hex) + '" title="' + esc(tip) + '"></span>';
+ }).join('');
+ var dom = (p.palette && p.palette[0]) || null;
+ var paintsBlock = '';
+ if (dom && dom.paints) {
+ var vendors = selectedVendors();
+ var rows = vendors.map(function (v) {
+ var paint = dom.paints[v];
+ if (!paint) return '';
+ return '<span class="row"><span class="label">' + esc(VENDOR_SHORT[v]) + '</span>'
+ + '<span class="pw-square" style="background:' + esc(paint.hex) + '"></span>'
+ + esc(paint.name) + ' <span class="pw-code">' + esc(paint.code) + '</span></span>';
+ }).filter(Boolean).join('');
+ if (rows) paintsBlock = '<div class="pairs-well__paints">' + rows + '</div>';
+ }
+ var href = p.url ? esc(p.url) : (p.handle ? '/products/' + esc(p.handle) : '#');
+ return '<a class="pairs-well__card' + (isAi ? ' pairs-well__card--ai' : '') + '" href="' + href + '" title="' + esc((p.why || []).join(' · ')) + '">'
+ + '<div class="pairs-well__img-wrap">' + (img ? '<img class="pairs-well__img" src="' + img + '" alt="' + esc(p.title) + '" loading="lazy">' : '') + '</div>'
+ + '<div class="pairs-well__meta">'
+ + '<p class="pairs-well__title">' + esc(p.title || '') + '</p>'
+ + '<p class="pairs-well__vendor">' + esc(p.vendor || (isAi ? 'AI-Generated' : '')) + '</p>'
+ + (why ? '<span class="pairs-well__why">' + why + '</span>' : '')
+ + (palette ? '<div class="pairs-well__palette">' + palette + '</div>' : '')
+ + paintsBlock
+ + '</div>'
+ + '</a>';
+ }
+ function renderGrid(grid, items, isAi) {
+ if (!items || !items.length) { grid.innerHTML = '<div class="pairs-well__empty">No coordinates found for this pattern.</div>'; return; }
+ grid.innerHTML = items.map(function (p) { return renderCard(p, isAi); }).join('');
+ }
+
+ function buildUrl(base, limit) {
+ var qs = [];
+ if (sku) qs.push('dw_sku=' + encodeURIComponent(sku));
+ if (handle) qs.push('handle=' + encodeURIComponent(handle));
+ if (limit) qs.push('limit=' + limit);
+ return base + '?' + qs.join('&');
+ }
+
+ function load() {
+ if (loaded) return Promise.resolve();
+ loaded = true;
+ renderSkeletons(catalogGrid, 12);
+ catalogPanel.hidden = false;
+ aiPanel.hidden = true; /* Option B (Steve 2026-07-12): hide AI-generated placeholder half */
+
+ var pairsPromise = fetch(buildUrl(endpointPairs, 24), { credentials: 'omit' })
+ .then(function (r) { return r.ok ? r.json() : Promise.reject(new Error('http ' + r.status)); })
+ .then(function (d) {
+ if (!d || d.ok === false) throw new Error((d && d.error) || 'bad payload');
+ cachedSource = d.source || null;
+ cachedPairs = d.pairs || [];
+ if (cachedSource) renderSourcePalette(cachedSource.palette || []);
+ renderGrid(catalogGrid, cachedPairs, false);
+ catalogCount.textContent = '(' + cachedPairs.length + ')';
+ if (!cachedPairs.length && (!cachedSource || !cachedSource.palette || !cachedSource.palette.length)) {
+ root.hidden = true;
+ }
+ })
+ .catch(function () { catalogGrid.innerHTML = '<div class="pairs-well__empty">Could not load coordinates right now.</div>'; });
+
+ /* Option B (Steve 2026-07-12): AI-generated coordinate half removed from the customer PDP.
+ Those cards were generated SVG placeholders with url:null -> dead href="#" (~50% of the
+ grid = the reported "no images / bad links"). Only REAL catalog coordinates (/api/pairs,
+ actual products with images + working links) render now. */
+ return pairsPromise;
+ }
+
+ cta.addEventListener('click', function () {
+ var open = cta.getAttribute('aria-expanded') === 'true';
+ if (open) {
+ cta.setAttribute('aria-expanded', 'false');
+ sourcePalette.hidden = true;
+ vendorPicker.hidden = true;
+ catalogPanel.hidden = true;
+ aiPanel.hidden = true;
+ return;
+ }
+ cta.setAttribute('aria-expanded', 'true');
+ load();
+ });
+ })();
+ </script>
+
+ <div
+ class="product-recommendations-wrapper--right"
+ data-product-recommendations-right
+ >
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "Product pages",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "enable_cart_redirection",
+ "label": "Enable cart redirection",
+ "info": "Automatically sends users to the Cart page after adding a product.",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "show_payment_button",
+ "label": "Show dynamic checkout button",
+ "info": "Each customer will see their preferred payment method from those available on your store, such as PayPal or Apple Pay. [Learn more](https://help.shopify.com/manual/using-themes/change-the-layout/dynamic-checkout)",
+ "default": true
+ },
+ {
+ "type": "header",
+ "content": "Media"
+ },
+ {
+ "type": "paragraph",
+ "content": "Learn more about [media types](https://help.shopify.com/en/manual/products/product-media/product-media-types)"
+ },
+ {
+ "type": "select",
+ "id": "images_layout",
+ "label": "Layout",
+ "options": [
+ {
+ "label": "Slideshow",
+ "value": "slideshow"
+ },
+ {
+ "label": "List",
+ "value": "list"
+ },
+ {
+ "label": "Masonry",
+ "value": "masonry"
+ }
+ ],
+ "default": "slideshow"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_zoom",
+ "label": "Enable image zoom",
+ "info": "Zoom only works with the slideshow image layout"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_video_autoplay",
+ "label": "Enable video autoplay",
+ "default": true
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_video_looping",
+ "label": "Enable video looping"
+ }
+ ],
+ "blocks": [
+ {
+ "type": "@app"
+ },
+ {
+ "type": "collapsible-tab",
+ "name": "Collapsible tab",
+ "settings": [
+ {
+ "type": "text",
+ "id": "collapsible_tab_heading",
+ "label": "Heading",
+ "default": "Collapsible tab"
+ },
+ {
+ "type": "richtext",
+ "id": "collapsible_tab_text",
+ "label": "Text",
+ "default": "<p>Use this text to share information about your product.</p>"
+ }
+ ]
+ },
+ {
+ "type": "custom-liquid",
+ "name": "Custom liquid",
+ "settings": [
+ {
+ "type": "liquid",
+ "id": "custom_liquid",
+ "label": "Custom liquid",
+ "info": "Add app snippets or other Liquid code to create advanced customizations."
+ }
+ ]
+ },
+ {
+ "type": "tabs",
+ "name": "Tabs",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_product_description",
+ "label": "Show product description",
+ "default": false
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_1",
+ "label": "Heading",
+ "default": "Tab 1"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_1",
+ "label": "Text",
+ "default": "<p>Tab 1 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_2",
+ "label": "Heading",
+ "default": "Tab 2"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_2",
+ "label": "Text",
+ "default": "<p>Tab 2 content goes here.</p>"
+ },
+ {
+ "type": "header",
+ "content": "Tab"
+ },
+ {
+ "type": "text",
+ "id": "tab_heading_3",
+ "label": "Heading",
+ "default": "Tab 3"
+ },
+ {
+ "type": "richtext",
+ "id": "tab_text_3",
+ "label": "Text",
+ "default": "<p>Tab 3 content goes here.</p>"
+ }
+ ]
+ },
+ {
+ "type": "title",
+ "name": "Title",
+ "limit": 1
+ },
+ {
+ "type": "vendor",
+ "name": "Vendor",
+ "limit": 1
+ },
+ {
+ "type": "social",
+ "name": "Social",
+ "limit": 1
+ },
+ {
+ "type": "description",
+ "name": "Description",
+ "limit": 1
+ },
+ {
+ "type": "price",
+ "name": "Price",
+ "limit": 1
+ },
+ {
+ "type": "form",
+ "name": "Form",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "Customize form features for the product in the products portion of the theme settings."
+ },
+ {
+ "type": "checkbox",
+ "id": "show_gift_card_recipient_form",
+ "label": "t:sections.product.blocks.form.show_gift_card_recipient_form.label",
+ "info": "t:sections.product.blocks.form.show_gift_card_recipient_form.info",
+ "default": false
+ }
+ ]
+ },
+ {
+ "type": "rating",
+ "name": "Product rating",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "To display a rating, add a product rating app. [Learn more](https://apps.shopify.com/product-reviews)"
+ }
+ ]
+ },
+ {
+ "type": "complementary_products",
+ "name": "Complementary products",
+ "limit": 1,
+ "settings": [
+ {
+ "type": "paragraph",
+ "content": "To select complementary products, add the Search & Discovery app. [Learn more](https:\/\/shopify.dev\/themes\/product-merchandising\/recommendations)"
+ },
+ {
+ "type": "text",
+ "id": "heading",
+ "label": "Heading",
+ "default": "Pairs well with"
+ },
+ {
+ "type": "range",
+ "id": "product_recommendation_limit",
+ "label": "Maximum products to show",
+ "min": 1,
+ "max": 10,
+ "default": 5
+ },
+ {
+ "type": "range",
+ "id": "products_per_slide",
+ "label": "Number of products per page",
+ "min": 1,
+ "max": 3,
+ "default": 2
+ }
+ ]
+ }
+ ]
+}
+
+{% endschema %}
+
+<div class="keywords-desktop" style="padding-left: 0ch; max-width: 80ch; line-height: 1.6;">
+ <h4 style="padding-left: 3ch; margin-bottom: 0;">KEYWORDS:</h4>
+ <div style="padding-left: 3ch;">
+ {% assign line = "" %}
+ {% assign char_limit = 96 %}
+ {% assign separator = ", " %}
+ {% assign plain_line = "" %}
+ {% for tag in product.tags %}
+ {% unless tag == "display_variant" %}
+ {% assign tag_link = '<a href="/search?q=' | append: tag | append: '">' | append: tag | append: '</a>' %}
+ {% assign tag_text = tag | append: separator %}
+ {% assign test_line = plain_line | append: tag_text %}
+ {% assign test_size = test_line | size %}
+ {% if test_size > char_limit %}
+ {{ line }}<br>
+ {% assign line = tag_link | append: separator %}
+ {% assign plain_line = tag_text %}
+ {% else %}
+ {% assign line = line | append: tag_link | append: separator %}
+ {% assign plain_line = test_line %}
+ {% endif %}
+ {% endunless %}
+ {% endfor %}
+ {{ line }}
+ </div>
+</div>
+
+{% comment %} Recently Viewed Products — tracks current product + shows carousel {% endcomment %}
+{% if settings.dw_enable_recently_viewed %}
+
+ {% render 'recently-viewed' %}
+{% endif %}
diff --git a/sections/pxs-announcement-bar.liquid b/sections/pxs-announcement-bar.liquid
new file mode 100644
index 0000000..68f130a
--- /dev/null
+++ b/sections/pxs-announcement-bar.liquid
@@ -0,0 +1,101 @@
+<script
+ type="application/json"
+ data-section-type="pxs-announcement-bar"
+ data-section-id="{{ section.id }}"
+></script>
+
+{% assign enable_announcement = section.settings.show_announcement %}
+{% assign homepage_only = section.settings.announcement_home_only %}
+{% assign show_announcement = false %}
+
+{% if enable_announcement and homepage_only == false %}
+ {% assign show_announcement = true %}
+{% endif %}
+
+{% if enable_announcement and homepage_only and template.name == 'index' %}
+ {% assign show_announcement = true %}
+{% endif %}
+
+{% if section.settings.announcement_text == blank %}
+ {% assign show_announcement = false %}
+{% endif %}
+
+{% unless show_announcement %}
+ {% break %}
+{% endunless %}
+
+<a
+ class="pxs-announcement-bar"
+ style="
+ color: {{ section.settings.announcement_color }};
+ background-color: {{ section.settings.announcement_background }}
+ "
+ {% if section.settings.announcement_link != blank %}
+ href="{{ section.settings.announcement_link }}"
+ {% endif %}
+>
+ {% if section.settings.announcement_text_mobile != blank %}
+ <span class="pxs-announcement-bar-text-mobile">
+ {{ section.settings.announcement_text_mobile | escape }}
+ </span>
+ {% endif %}
+
+ {% if section.settings.announcement_text != blank %}
+ <span class="pxs-announcement-bar-text-desktop">
+ {{ section.settings.announcement_text | escape }}
+ </span>
+ {% endif %}
+</a>
+
+
+
+{% schema %}
+{
+ "name": "Announcement bar",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_announcement",
+ "label": "Show announcement",
+ "default": false
+ },
+ {
+ "type": "checkbox",
+ "id": "announcement_home_only",
+ "label": "Show on home page only",
+ "default": false
+ },
+ {
+ "id": "announcement_text",
+ "type": "textarea",
+ "label": "Text",
+ "default": "Call attention to a special discount, feature, or promotion here."
+ },
+ {
+ "id": "announcement_text_mobile",
+ "type": "textarea",
+ "label": "Text (mobile)",
+ "default": "Use less text on mobile!",
+ "info": "Use this option if you want to display alternate text in mobile. Recommended for shortening announcement text to make suitable for mobile."
+ },
+ {
+ "id": "announcement_link",
+ "type": "url",
+ "label": "Link"
+ },
+ {
+ "id": "announcement_color",
+ "type": "color",
+ "label": "Text color",
+ "default": "#ffffff"
+ },
+ {
+ "id": "announcement_background",
+ "type": "color",
+ "label": "Background color",
+ "default": "#000000"
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/pxs-image-with-text-overlay.liquid b/sections/pxs-image-with-text-overlay.liquid
new file mode 100644
index 0000000..98d1795
--- /dev/null
+++ b/sections/pxs-image-with-text-overlay.liquid
@@ -0,0 +1,238 @@
+{% assign onboarding = false %}
+
+{% if section.settings.image == blank %}
+ {% assign onboarding = true %}
+{% endif %}
+
+<section
+ class="
+ pxs-image-with-text
+ pxs-image-with-text-section-height-{{ section.settings.section_height }}
+ "
+>
+ <div class="pxs-image-with-text-wrapper">
+ <div
+ class="pxs-image-with-text-background"
+ {% if section.settings.image != blank %}
+ {% capture background_style %}
+ {% if section.settings.section_height == 'original' %}
+ padding-bottom: {{- 100 | divided_by: section.settings.image.aspect_ratio -}}%;
+ {% endif %}
+ {% endcapture %}
+
+ {%
+ render 'rimg',
+ img: section.settings.image,
+ size: '1400x',
+ style: background_style,
+ lazy: true,
+ background: true,
+ focal_point: section.settings.image.presentation.focal_point,
+ %}
+ {% endif %}
+ >
+ {% if onboarding %}
+ {{ 'lifestyle-1' | placeholder_svg_tag }}
+ {% endif %}
+ </div>
+
+ {% if section.settings.overlay_opacity != 0 and section.settings.overlay_background != 'rgba(0,0,0,0)' %}
+ {% assign opacity = section.settings.overlay_opacity | times: 0.01 %}
+ {% assign overlay = section.settings.overlay_background | color_modify: 'alpha', opacity %}
+
+ <div
+ class="pxs-image-with-text-overlay"
+ style="background-color: {{ overlay }};"
+ ></div>
+ {% endif %}
+
+ <div
+ class="
+ pxs-image-with-text-content-wrapper
+ pxs-image-with-text-content-position-y-{{ section.settings.content_position | split: '-' | first }}
+ pxs-image-with-text-content-position-x-{{ section.settings.content_position | split: '-' | last }}
+ "
+ >
+ <div
+ class="pxs-image-with-text-content"
+ style="color: {{ section.settings.color }};"
+ >
+ {% if section.settings.title != blank %}
+ <h2
+ class="pxs-image-with-text-heading"
+ >
+ {{ section.settings.title | escape }}
+ </h2>
+ {% endif %}
+
+ {% if section.settings.text != blank %}
+ <div
+ class="pxs-image-with-text-subheading rte"
+ >
+ {{ section.settings.text }}
+ </div>
+ {% endif %}
+
+ {% if section.settings.button_text != blank %}
+ <span class="pxs-image-with-text-button">
+ {{ section.settings.button_text | escape }}
+ </span>
+ {% endif %}
+
+ {% if section.settings.link != blank %}
+ <a
+ class="pxs-image-with-text-link"
+ href="{{ section.settings.link }}"
+ ></a>
+ {% endif %}
+ </div>
+ </div>
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "t:sections.image_with_text_overlay.name",
+ "class": "pxs-image-with-text-section",
+ "settings": [
+ {
+ "type": "select",
+ "id": "section_height",
+ "label": "t:sections.image_with_text_overlay.section_height.label",
+ "options": [
+ {
+ "value": "small",
+ "label": "t:sections.image_with_text_overlay.section_height.option_1"
+ },
+ {
+ "value": "medium",
+ "label": "t:sections.image_with_text_overlay.section_height.option_2"
+ },
+ {
+ "value": "large",
+ "label": "t:sections.image_with_text_overlay.section_height.option_3"
+ },
+ {
+ "value": "original",
+ "label": "t:sections.image_with_text_overlay.section_height.option_4"
+ }
+ ],
+ "default": "medium"
+ },
+ {
+ "type": "header",
+ "content": "t:sections.image_with_text_overlay.header_1.content"
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "t:sections.image_with_text_overlay.image.label"
+ },
+ {
+ "type": "header",
+ "content": "t:sections.image_with_text_overlay.header_2.content"
+ },
+ {
+ "type": "text",
+ "id": "title",
+ "label": "t:sections.image_with_text_overlay.title.label",
+ "default": "Image with text overlay"
+ },
+ {
+ "type": "richtext",
+ "id": "text",
+ "label": "t:sections.image_with_text_overlay.text.label",
+ "default": "<p>Say a bit about your brand, a specific product, or promotion.</p>"
+ },
+ {
+ "type": "select",
+ "id": "content_position",
+ "label": "t:sections.image_with_text_overlay.content_position.label",
+ "options": [
+ {
+ "value": "top-left",
+ "label": "t:sections.image_with_text_overlay.content_position.option_1"
+ },
+ {
+ "value": "top-center",
+ "label": "t:sections.image_with_text_overlay.content_position.option_2"
+ },
+ {
+ "value": "top-right",
+ "label": "t:sections.image_with_text_overlay.content_position.option_3"
+ },
+ {
+ "value": "center-left",
+ "label": "t:sections.image_with_text_overlay.content_position.option_4"
+ },
+ {
+ "value": "center-center",
+ "label": "t:sections.image_with_text_overlay.content_position.option_5"
+ },
+ {
+ "value": "center-right",
+ "label": "t:sections.image_with_text_overlay.content_position.option_6"
+ },
+ {
+ "value": "bottom-left",
+ "label": "t:sections.image_with_text_overlay.content_position.option_7"
+ },
+ {
+ "value": "bottom-center",
+ "label": "t:sections.image_with_text_overlay.content_position.option_8"
+ },
+ {
+ "value": "bottom-right",
+ "label": "t:sections.image_with_text_overlay.content_position.option_9"
+ }
+ ],
+ "default": "center-center"
+ },
+ {
+ "type": "color",
+ "id": "color",
+ "label": "t:sections.image_with_text_overlay.color.label",
+ "default": "#ffffff"
+ },
+ {
+ "type": "color",
+ "id": "overlay_background",
+ "label": "t:sections.image_with_text_overlay.overlay_background.label",
+ "default": "#000000"
+ },
+ {
+ "type": "range",
+ "id": "overlay_opacity",
+ "label": "t:sections.image_with_text_overlay.overlay_opacity.label",
+ "min": 0,
+ "max": 100,
+ "step": 1,
+ "unit": "%",
+ "default": 50
+ },
+ {
+ "type": "url",
+ "id": "link",
+ "label": "t:sections.image_with_text_overlay.link.label"
+ },
+ {
+ "type": "text",
+ "id": "button_text",
+ "label": "t:sections.image_with_text_overlay.button_text.label",
+ "default": "Button"
+ }
+ ],
+ "presets": [
+ {
+ "category": "t:sections.image_with_text_overlay.presets.category",
+ "name": "t:sections.image_with_text_overlay.presets.name"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/pxs-map.liquid b/sections/pxs-map.liquid
new file mode 100644
index 0000000..6a61cb0
--- /dev/null
+++ b/sections/pxs-map.liquid
@@ -0,0 +1,343 @@
+<script
+ type="application/json"
+ data-section-type="pxs-map"
+ data-section-id="{{ section.id }}"
+ data-section-data
+>
+ {
+ {% if section.settings.enable_custom_colors %}
+ {% assign background_color = section.settings.background_color %}
+ {% assign foreground_color = section.settings.foreground_color %}
+ "colors": {
+ "a": {{ foreground_color | json }},
+ "b": {{ background_color | color_mix: foreground_color, 30 | json }},
+ "c": {{ background_color | color_mix: foreground_color, 50 | json }},
+ "d": {{ background_color | color_mix: foreground_color, 70 | json }},
+ "e": {{ background_color | color_mix: '#ffffff', 98 | json }},
+ "f": {{ background_color | color_mix: '#000000', 50 | json }}
+ },
+ {% endif %}
+ "api_key": {{ section.settings.api_key | default: false | json }},
+ "address": {{ section.settings.address | json }},
+ "zoom": {{ section.settings.zoom | json }}
+ }
+</script>
+
+<script type="application/pxs-animation-mapping+json">
+ {
+ "blocks": [
+ ".pxs-map"
+ ],
+ "elements": [
+ ".pxs-map-wrapper"
+ ]
+ }
+</script>
+
+{% assign layout = section.settings.layout | split: '-' %}
+
+<div
+ class="
+ pxs-map
+ pxs-map-section-layout-{{ layout[0] }}
+ pxs-map-section-layout-y-{{ layout[0] }}-{{ layout[1] }}
+ pxs-map-section-layout-x-{{ layout[0] }}-{{ layout[2] }}
+ pxs-map-section-layout-mobile-{{ section.settings.layout_mobile }}
+ "
+>
+ <div
+ class="
+ pxs-map-wrapper
+ pxs-map-wrapper-height-{{ section.settings.section_height }}
+ "
+ {% if section.settings.image %}
+ {%
+ render 'rimg',
+ img: section.settings.image,
+ size: '1400x',
+ lazy: true,
+ background: true,
+ focal_point: section.settings.image.presentation.focal_point,
+ %}
+ {% endif %}
+ data-map
+ >
+ {% if section.settings.image %}
+ {%
+ render 'rimg',
+ img: section.settings.image,
+ size: '1400x',
+ class: 'pxs-map-image',
+ lazy: true,
+ canvas: true,
+ focal_point: section.settings.image.presentation.focal_point,
+ %}
+ {% endif %}
+
+ <div class="pxs-map-container" data-map-container></div>
+
+ {% if section.settings.opacity != 0 and section.settings.overlay_color != 'rgba(0,0,0,0)' %}
+ {% assign opacity = section.settings.opacity | times: 0.01 %}
+ {% assign overlay = section.settings.overlay_color | color_modify: 'alpha', opacity %}
+
+ <div
+ class="pxs-map-overlay"
+ style="background-color: {{ overlay }}"
+ >
+ </div>
+ {% endif %}
+ </div>
+
+ {% if
+ section.settings.title != blank or
+ section.settings.content != blank
+ %}
+ <div class="pxs-map-card-wrapper">
+ <div
+ class="
+ pxs-map-card
+ pxs-map-card-text-alignment-{{ section.settings.text_alignment }}
+ "
+ >
+ {% if section.settings.title != blank %}
+ <h2 class="pxs-map-card-heading">{{ section.settings.title | escape }}</h2>
+ {% endif %}
+
+ {% if section.settings.content != blank %}
+ <div class="pxs-map-card-content rte">{{ section.settings.content }}</div>
+ {% endif %}
+ </div>
+ </div>
+ {% endif %}
+</div>
+
+{% schema %}
+{
+ "name": "t:sections.map.name",
+ "class": "pxs-map-section",
+ "settings": [
+ {
+ "type": "select",
+ "id": "section_height",
+ "label": "t:sections.map.section_height.label",
+ "options": [
+ {
+ "value": "small",
+ "label": "t:sections.map.section_height.option_1"
+ },
+ {
+ "value": "medium",
+ "label": "t:sections.map.section_height.option_2"
+ },
+ {
+ "value": "large",
+ "label": "t:sections.map.section_height.option_3"
+ }
+ ],
+ "default": "medium"
+ },
+ {
+ "type": "header",
+ "content": "t:sections.map.header_1.content"
+ },
+ {
+ "type": "text",
+ "id": "title",
+ "label": "t:sections.map.title.label",
+ "default": "Location"
+ },
+ {
+ "type": "richtext",
+ "id": "content",
+ "label": "t:sections.map.content.label",
+ "default": "<p>1221 Broad St<br>Victoria, BC</p>"
+ },
+ {
+ "type": "text_alignment",
+ "id": "text_alignment",
+ "label": "t:sections.map.text_alignment.label",
+ "default": "center"
+ },
+ {
+ "type": "select",
+ "id": "layout",
+ "label": "t:sections.map.layout.label",
+ "options": [
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-top-left",
+ "label": "t:sections.map.layout.option_1"
+ },
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-center-left",
+ "label": "t:sections.map.layout.option_2"
+ },
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-bottom-left",
+ "label": "t:sections.map.layout.option_3"
+ },
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-top-right",
+ "label": "t:sections.map.layout.option_4"
+ },
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-center-right",
+ "label": "t:sections.map.layout.option_5"
+ },
+ {
+ "group": "t:sections.map.layout.group_1",
+ "value": "outside-bottom-right",
+ "label": "t:sections.map.layout.option_6"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-top-left",
+ "label": "t:sections.map.layout.option_7"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-top-center",
+ "label": "t:sections.map.layout.option_8"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-top-right",
+ "label": "t:sections.map.layout.option_9"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-center-left",
+ "label": "t:sections.map.layout.option_10"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-center-center",
+ "label": "t:sections.map.layout.option_11"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-center-right",
+ "label": "t:sections.map.layout.option_12"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-bottom-left",
+ "label": "t:sections.map.layout.option_13"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-bottom-center",
+ "label": "t:sections.map.layout.option_14"
+ },
+ {
+ "group": "t:sections.map.layout.group_2",
+ "value": "overlay-bottom-right",
+ "label": "t:sections.map.layout.option_15"
+ }
+ ],
+ "default": "overlay-center-center"
+ },
+ {
+ "type": "select",
+ "id": "layout_mobile",
+ "label": "t:sections.map.layout_mobile.label",
+ "options": [
+ {
+ "value": "above",
+ "label": "t:sections.map.layout_mobile.option_1"
+ },
+ {
+ "value": "below",
+ "label": "t:sections.map.layout_mobile.option_2"
+ }
+ ],
+ "default": "below"
+ },
+ {
+ "type": "header",
+ "content": "t:sections.map.header_2.content"
+ },
+ {
+ "type": "text",
+ "id": "address",
+ "label": "t:sections.map.address.label",
+ "default": "1221 Broad St, Victoria, BC"
+ },
+ {
+ "type": "text",
+ "id": "api_key",
+ "label": "t:sections.map.api_key.label",
+ "info": "t:sections.map.api_key.info"
+ },
+ {
+ "type": "checkbox",
+ "id": "enable_custom_colors",
+ "label": "t:sections.map.enable_custom_colors.label"
+ },
+ {
+ "type": "color",
+ "id": "foreground_color",
+ "label": "t:sections.map.foreground_color.label",
+ "default": "#292929"
+ },
+ {
+ "type": "color",
+ "id": "background_color",
+ "label": "t:sections.map.background_color.label",
+ "default": "#ffffff"
+ },
+ {
+ "type": "range",
+ "id": "zoom",
+ "label": "t:sections.map.zoom.label",
+ "min": 1,
+ "max": 6,
+ "step": 1,
+ "unit": "x",
+ "default": 2
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "t:sections.map.image.label",
+ "info": "t:sections.map.image.info"
+ },
+ {
+ "type": "header",
+ "content": "t:sections.map.header_3.content"
+ },
+ {
+ "type": "color",
+ "id": "overlay_color",
+ "label": "t:sections.map.overlay_color.label",
+ "default": "#000000"
+ },
+ {
+ "type": "range",
+ "id": "opacity",
+ "label": "t:sections.map.opacity.label",
+ "min": 0,
+ "max": 100,
+ "step": 1,
+ "unit": "%",
+ "default": 10
+ }
+ ],
+ "presets": [
+ {
+ "name": "t:sections.map.presets.name",
+ "category": "t:sections.map.presets.category"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/pxs-newsletter.liquid b/sections/pxs-newsletter.liquid
new file mode 100644
index 0000000..c680341
--- /dev/null
+++ b/sections/pxs-newsletter.liquid
@@ -0,0 +1,144 @@
+{% liquid
+ assign pxs_newsletter_form_success = 'form.success' | t
+ assign pxs_newsletter_form_placeholder = 'form.placeholder' | t
+ assign pxs_newsletter_form_submit = 'form.submit' | t
+ assign pxs_newsletter_form_id = 'pxs-newsletter-' | append: section.id
+ assign pxs_newsletter_email_id = 'pxs-newsletter-email-' | append: section.id
+%}
+
+<section
+ class="
+ pxs-newsletter
+ pxs-newsletter-desktop-alignment-{{ section.settings.desktop_alignment }}
+ pxs-newsletter-mobile-alignment-{{ section.settings.mobile_alignment }}
+ "
+>
+ {% if section.settings.image %}
+ <figure
+ class="pxs-newsletter-figure"
+ {%
+ render 'rimg',
+ img: section.settings.image,
+ size: '500x',
+ background: true,
+ lazy: true,
+ focal_point: section.settings.image.presentation.focal_point,
+ %}
+ >
+ {%
+ render 'rimg',
+ img: section.settings.image,
+ class: 'pxs-newsletter-image',
+ size: '500x',
+ canvas: true,
+ lazy: true,
+ focal_point: section.settings.image.presentation.focal_point,
+ %}
+ </figure>
+ {% endif %}
+
+ <div class="pxs-newsletter-content">
+ <div class="pxs-newsletter-header">
+ {% if section.settings.title != blank %}
+ <h2 class="pxs-newsletter-heading">
+ {{ section.settings.title | escape }}
+ </h2>
+ {% endif %}
+
+ {% if section.settings.text != blank %}
+ <div class="pxs-newsletter-text">
+ {{ section.settings.text }}
+ </div>
+ {% endif %}
+ </div>
+
+ {%
+ render 'newsletter',
+ pxs_newsletter_image: pxs_newsletter_image,
+ pxs_newsletter_form_success: pxs_newsletter_form_success,
+ pxs_newsletter_form_placeholder: pxs_newsletter_form_placeholder,
+ pxs_newsletter_form_submit: pxs_newsletter_form_submit,
+ pxs_newsletter_form_id: pxs_newsletter_form_id,
+ pxs_newsletter_email_id: pxs_newsletter_email_id,
+ %}
+ </div>
+</section>
+
+{% schema %}
+{
+ "name": "t:sections.newsletter.name",
+ "class": "pxs-newsletter-section",
+ "settings": [
+ {
+ "type": "text",
+ "id": "title",
+ "label": "t:sections.newsletter.title.label",
+ "default": "Newsletter"
+ },
+ {
+ "type": "richtext",
+ "id": "text",
+ "label": "t:sections.newsletter.text.label",
+ "default": "<p>Invite customers to join your mailing list.</p>"
+ },
+ {
+ "type": "image_picker",
+ "id": "image",
+ "label": "t:sections.newsletter.image.label"
+ },
+ {
+ "type": "select",
+ "id": "desktop_alignment",
+ "label": "t:sections.newsletter.desktop_alignment.label",
+ "options": [
+ {
+ "label": "t:sections.newsletter.desktop_alignment.option_1",
+ "value": "left"
+ },
+ {
+ "label": "t:sections.newsletter.desktop_alignment.option_2",
+ "value": "right"
+ }
+ ],
+ "default": "left"
+ },
+ {
+ "type": "select",
+ "id": "mobile_alignment",
+ "label": "t:sections.newsletter.mobile_alignment.label",
+ "options": [
+ {
+ "label": "t:sections.newsletter.mobile_alignment.option_1",
+ "value": "top"
+ },
+ {
+ "label": "t:sections.newsletter.mobile_alignment.option_2",
+ "value": "bottom"
+ }
+ ],
+ "default": "top"
+ }
+ ],
+ "presets": [
+ {
+ "name": "t:sections.newsletter.presets.name",
+ "category": "t:sections.newsletter.presets.category"
+ }
+ ],
+ "disabled_on": {
+ "groups": [
+ "*"
+ ]
+ },
+ "locales": {
+ "en": {
+ "form": {
+ "placeholder": "Email address",
+ "submit": "Subscribe",
+ "success": "Thanks for subscribing!"
+ }
+ }
+ }
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/recently-viewed.liquid b/sections/recently-viewed.liquid
new file mode 100644
index 0000000..223616b
--- /dev/null
+++ b/sections/recently-viewed.liquid
@@ -0,0 +1,143 @@
+{% comment %}
+ Recently Viewed Products — 8 square cards with centered text, horizontal scroll with arrows
+{% endcomment %}
+
+<div
+ id="dw-recently-viewed"
+ data-section-id="{{ section.id }}"
+ data-max-products="{{ section.settings.max_products }}"
+ data-current-handle="{{ product.handle | default: '' }}"
+ style="display:none;max-width:1200px;margin:0 auto;padding:32px 20px 48px;"
+>
+ <h2 style="font-family:-apple-system,system-ui,sans-serif;font-size:22px;font-weight:600;text-align:center;margin:0 0 4px;color:#1a1a1a;">Recently Viewed</h2>
+ <p style="text-align:center;color:#888;font-size:13px;margin:0 0 20px;">Products you've browsed</p>
+ <div style="position:relative;">
+ <button id="rv-prev" onclick="document.getElementById('dw-rv-grid').scrollBy({left:-260,behavior:'smooth'})" style="position:absolute;left:-16px;top:50%;transform:translateY(-70%);z-index:2;width:36px;height:36px;border-radius:50%;border:1px solid #ddd;background:#fff;cursor:pointer;font-size:18px;color:#333;box-shadow:0 2px 6px rgba(0,0,0,0.1);display:none;">‹</button>
+ <div id="dw-rv-grid" style="display:flex;gap:16px;overflow-x:auto;scroll-behavior:smooth;scrollbar-width:none;-ms-overflow-style:none;padding:4px 0;"></div>
+ <button id="rv-next" onclick="document.getElementById('dw-rv-grid').scrollBy({left:260,behavior:'smooth'})" style="position:absolute;right:-16px;top:50%;transform:translateY(-70%);z-index:2;width:36px;height:36px;border-radius:50%;border:1px solid #ddd;background:#fff;cursor:pointer;font-size:18px;color:#333;box-shadow:0 2px 6px rgba(0,0,0,0.1);display:none;">›</button>
+ </div>
+</div>
+
+<style>
+ #dw-rv-grid::-webkit-scrollbar{display:none}
+ .rv-card{text-decoration:none;color:inherit;display:flex;flex-direction:column;align-items:center;min-width:140px;max-width:140px;flex-shrink:0;}
+ .rv-card-img{width:140px;height:140px;object-fit:cover;display:block;border-radius:8px;background:#f5f5f0;}
+ .rv-card-info{padding:8px 4px;text-align:center;width:100%;}
+ .rv-card-vendor{font-size:10px;font-weight:500;color:#999;text-transform:uppercase;letter-spacing:0.04em;margin:0 0 2px;}
+ .rv-card-title{font-size:12px;font-weight:500;color:#333;margin:0;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
+ .rv-card:hover .rv-card-img{box-shadow:0 4px 12px rgba(0,0,0,0.12);transform:scale(1.03);transition:all 0.2s;}
+ @media(max-width:768px){.rv-card{min-width:120px;max-width:120px;}.rv-card-img{width:120px;height:120px;}}
+</style>
+
+<script>
+(function() {
+ var STORAGE_KEY = 'dw_recently_viewed';
+ var MAX_STORED = 20;
+ var container = document.getElementById('dw-recently-viewed');
+ var grid = document.getElementById('dw-rv-grid');
+ if (!container || !grid) return;
+
+ var maxShow = parseInt(container.dataset.maxProducts) || 8;
+ var currentHandle = container.dataset.currentHandle || '';
+
+ // Track current product
+ if (currentHandle && currentHandle.length > 0) {
+ try {
+ var stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
+ stored = stored.filter(function(h) { return h !== currentHandle; });
+ stored.unshift(currentHandle);
+ if (stored.length > MAX_STORED) stored = stored.slice(0, MAX_STORED);
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
+ } catch(e) {}
+ }
+
+ // Render
+ try {
+ var handles = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
+ handles = handles.filter(function(h) { return h !== currentHandle; });
+ handles = handles.slice(0, maxShow);
+ if (handles.length < 1) return;
+
+ container.style.display = 'block';
+ var loaded = 0;
+ var total = handles.length;
+ var cards = {};
+
+ handles.forEach(function(handle, index) {
+ fetch('/products/' + handle + '.js')
+ .then(function(r) { return r.ok ? r.json() : null; })
+ .then(function(product) {
+ loaded++;
+ if (!product || !product.featured_image) { checkDone(); return; }
+ var img = product.featured_image || '';
+ if (img && !img.startsWith('http')) img = 'https:' + img;
+ if (img) img = img.replace(/(\.[^.]+)$/, '_300x300$1');
+ var vendor = product.vendor || '';
+ var title = product.title || '';
+ if (vendor && title.includes(' | ' + vendor)) title = title.split(' | ' + vendor)[0];
+
+ var card = document.createElement('a');
+ card.href = '/products/' + handle;
+ card.className = 'rv-card';
+
+ var imgEl = document.createElement('img');
+ imgEl.className = 'rv-card-img';
+ imgEl.src = img;
+ imgEl.alt = title;
+ imgEl.loading = 'lazy';
+ card.appendChild(imgEl);
+
+ var info = document.createElement('div');
+ info.className = 'rv-card-info';
+ var vendorEl = document.createElement('p');
+ vendorEl.className = 'rv-card-vendor';
+ vendorEl.textContent = vendor;
+ info.appendChild(vendorEl);
+ var titleEl = document.createElement('p');
+ titleEl.className = 'rv-card-title';
+ titleEl.textContent = title;
+ info.appendChild(titleEl);
+ card.appendChild(info);
+
+ cards[index] = card;
+ checkDone();
+ })
+ .catch(function() { loaded++; checkDone(); });
+ });
+
+ function checkDone() {
+ if (loaded < total) return;
+ for (var i = 0; i < total; i++) {
+ if (cards[i]) grid.appendChild(cards[i]);
+ }
+ // Show arrows if scrollable
+ if (grid.scrollWidth > grid.clientWidth) {
+ document.getElementById('rv-prev').style.display = 'block';
+ document.getElementById('rv-next').style.display = 'block';
+ }
+ }
+ } catch(e) {}
+})();
+</script>
+
+{% schema %}
+{
+ "name": "Recently Viewed Products",
+ "settings": [
+ {
+ "type": "range",
+ "id": "max_products",
+ "label": "Max products to show",
+ "min": 2,
+ "max": 12,
+ "step": 1,
+ "default": 8
+ }
+ ],
+ "presets": [
+ {
+ "name": "Recently Viewed Products"
+ }
+ ]
+}
+{% endschema %}
\ No newline at end of file
diff --git a/sections/static-product-recommendations.liquid b/sections/static-product-recommendations.liquid
new file mode 100644
index 0000000..522fc7c
--- /dev/null
+++ b/sections/static-product-recommendations.liquid
@@ -0,0 +1,99 @@
+{% if section.settings.show_product_recommendations %}
+ {% assign product_limit = 4 %}
+ {% assign product_limit_masonry = 4 %}
+
+ <script
+ type="application/json"
+ data-section-type="static-product-recommendations"
+ data-section-id="{{ section.id }}"
+ data-section-data
+ >
+ {
+ "productId": {{ product.id | json }},
+ "positionRight": {{ section.settings.related_products_position_right | json }}
+ }
+ </script>
+
+ <section
+ class="product-recommendations-wrapper--section"
+ data-product-recommendations-section
+ data-product-hover="{{ settings.product_hover }}"
+ >
+ </section>
+
+ {% if recommendations.products_count > 0 %}
+ <template data-html="common">
+ {%- unless section.settings.product_recommendations_heading == blank -%}
+ <h2 class="section-title">{{ section.settings.product_recommendations_heading }}</h2>
+ {%- endunless -%}
+
+ <div
+ class="product-recommendations rows-of-4"
+ data-masonry-products
+ >
+ </div>
+ </template>
+
+ <template data-html="below">
+ <div class="product-grid-masonry-sizer" data-masonry-products-sizer></div>
+
+ {% for product in recommendations.products limit: product_limit_masonry %}
+ {% assign product_attributes = blank %}
+
+ {% if forloop.index > product_limit %}
+ {% assign product_attributes = 'data-masonry-only' %}
+ {% endif %}
+
+ {%
+ render 'product-list-item',
+ product: product,
+ product_attributes: product_attributes,
+ %}
+ {% endfor %}
+ </template>
+
+ <template data-html="right">
+ {% for product in recommendations.products limit: product_limit %}
+ <a title="{{ product.title }}" href="{{ product.url }}">
+ {%
+ render 'rimg',
+ img: product.featured_media.preview_image,
+ alt: product.title,
+ size: '480x480',
+ lazy: true,
+ %}
+ </a>
+ {% endfor %}
+ </template>
+ {% endif %}
+{% endif %}
+
+{% schema %}
+{
+ "name": "Related products",
+ "class": "static-product-recommendations",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_product_recommendations",
+ "label": "Show dynamic recommendations",
+ "info": "Dynamic recommendations change and improve with time. [Learn more](https://help.shopify.com/en/themes/development/recommended-products)",
+ "default": true
+ },
+ {
+ "type": "text",
+ "id": "product_recommendations_heading",
+ "label": "Heading",
+ "default": "You may also like"
+ },
+ {
+ "type": "checkbox",
+ "id": "related_products_position_right",
+ "label": "Display related products to the right of product info",
+ "default": false,
+ "info": "Only works with slideshow and list product image layouts"
+ }
+ ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/surface-pick-up.liquid b/sections/surface-pick-up.liquid
new file mode 100644
index 0000000..406063e
--- /dev/null
+++ b/sections/surface-pick-up.liquid
@@ -0,0 +1,141 @@
+<template data-html="surface-pick-up-embed">
+ {% comment %}Inject @pixelunion/shopify-surface-pick-up/surface-pick-up-embed begin{% endcomment %}
+ {% assign pick_up_availabilities = product_variant.store_availabilities | where: 'pick_up_enabled', true %}
+ {% if product_variant.available and pick_up_availabilities.size > 0 %}
+ {% assign closest_location = pick_up_availabilities.first %}
+
+ <div class="surface-pick-up-embed surface-pick-up-embed--{% if closest_location.available %}available{% else %}unavailable{% endif %}">
+ {% if closest_location.available %}
+ <svg
+ class="
+ surface-pick-up-embed__in-stock-icon
+ surface-pick-up-embed__svg-placeholder
+ "
+ width="13"
+ height="13"
+ viewBox="0 0 13 13"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ focusable="false"
+ aria-hidden="true"
+ >
+ <path d="M4.33346 10.5625L3.80311 11.0928L4.33344 11.6232L4.86379 11.0928L4.33346 10.5625ZM0.191824 7.48134L3.80311 11.0928L4.8638 10.0322L1.25251 6.4207L0.191824 7.48134ZM4.86379 11.0928L12.9888 2.96783L11.9281 1.90717L3.80313 10.0322L4.86379 11.0928Z"/>
+ </svg>
+ {% else %}
+ <svg class="surface-pick-up-embed__out-of-stock-icon surface-pick-up-embed__svg-placeholder" width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg" focusable=”false” aria-hidden=”true”>
+ <path d="M1.46967 2.53033L5.96967 7.03033L7.03033 5.96967L2.53033 1.46967L1.46967 2.53033ZM5.96967 7.03033L10.4697 11.5303L11.5303 10.4697L7.03033 5.96967L5.96967 7.03033ZM7.03033 7.03033L11.5303 2.53033L10.4697 1.46967L5.96967 5.96967L7.03033 7.03033ZM10.4697 1.46967L1.46967 10.4697L2.53033 11.5303L11.5303 2.53033L10.4697 1.46967Z"/>
+ </svg>
+ {% endif %}
+
+ <div class="surface-pick-up-embed__location-info">
+ {% if closest_location.available %}
+ <p class="surface-pick-up-embed__location-availability">
+ {{- 'store_availability.general.available_for_pick_up_at_html' | t: location_name: closest_location.location.name -}}
+ </p>
+ <small class="surface-pick-up-embed__location-pick-up-time">{{ closest_location.pick_up_time }}</small>
+ {% else %}
+ <p class="surface-pick-up-embed__location-availability">
+ {{- 'store_availability.general.unavailable_for_pick_up_at_html' | t: location_name: closest_location.location.name -}}
+ </p>
+ {% endif %}
+ </div>
+
+ <button
+ class="surface-pick-up-embed__modal-btn"
+ type="button"
+ aria-haspopup="dialog"
+ data-surface-pick-up-embed-modal-btn
+ >
+ {% if pick_up_availabilities.size > 1 %}
+ {{ 'store_availability.general.check_other_stores' | t }}
+ {% else %}
+ {{ 'store_availability.general.view_store_info' | t }}
+ {% endif %}
+ </button>
+ </div>
+ {% endif %}
+ {% comment %}Inject @pixelunion/shopify-surface-pick-up/surface-pick-up-embed end{% endcomment %}
+
+</template>
+
+<template data-html="surface-pick-up-items">
+ {% assign pick_up_availabilities = product_variant.store_availabilities | where: 'pick_up_enabled', true %}
+ {% if product_variant.available and pick_up_availabilities.size > 0 %}
+ {%- assign closest_location_country_code = pick_up_availabilities.first.location.address.country_code -%}
+ {%- assign imperialSystemCountries = 'US,MM,LR' | split: ',' -%}
+ {%- if imperialSystemCountries contains closest_location_country_code -%}
+ {%- assign unit_system = 'imperial' -%}
+ {%- else -%}
+ {%- assign unit_system = 'metric' -%}
+ {%- endif -%}
+ <ul class="surface-pick-up-items" role="list">
+ {% for location in pick_up_availabilities %}
+ {% comment %}Inject @pixelunion/shopify-surface-pick-up/surface-pick-up-item begin{% endcomment %}
+ <li
+ class="surface-pick-up-item surface-pick-up-item--{% if location.available %}available{% else %}unavailable{% endif %}"
+ data-surface-pick-up-item
+ >
+ <div class="surface-pick-up-item__header">
+ <h3 class="surface-pick-up-item__pick-up-location">{{ location.location.name }}</h3>
+ <p
+ class="surface-pick-up-item__pick-up-distance"
+ >
+ <span
+ data-distance
+ data-latitude="{{ location.location.latitude }}"
+ data-longitude="{{ location.location.longitude }}"
+ >
+ </span>
+ <span
+ data-distance-unit="{{ unit_system }}"
+ >
+ {%- if unit_system == 'imperial' -%}
+ {{ 'store_availability.general.miles' | t }}
+ {%- else -%}
+ {{ 'store_availability.general.kilometers' | t }}
+ {%- endif -%}
+ </span>
+ </p>
+ </div>
+
+ {% if location.available %}
+ <svg class="surface-pick-up-item__in-stock-icon surface-pick-up-item__svg-placeholder" width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg" focusable=”false” aria-hidden=”true”>
+ <path d="M4.33346 10.5625L3.80311 11.0928L4.33344 11.6232L4.86379 11.0928L4.33346 10.5625ZM0.191824 7.48134L3.80311 11.0928L4.8638 10.0322L1.25251 6.4207L0.191824 7.48134ZM4.86379 11.0928L12.9888 2.96783L11.9281 1.90717L3.80313 10.0322L4.86379 11.0928Z"/>
+ </svg>
+ {% else %}
+ <svg class="surface-pick-up-item__out-of-stock-icon surface-pick-up-item__svg-placeholder" width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg" focusable=”false” aria-hidden=”true”>
+ <path d="M1.46967 2.53033L5.96967 7.03033L7.03033 5.96967L2.53033 1.46967L1.46967 2.53033ZM5.96967 7.03033L10.4697 11.5303L11.5303 10.4697L7.03033 5.96967L5.96967 7.03033ZM7.03033 7.03033L11.5303 2.53033L10.4697 1.46967L5.96967 5.96967L7.03033 7.03033ZM10.4697 1.46967L1.46967 10.4697L2.53033 11.5303L11.5303 2.53033L10.4697 1.46967Z"/>
+ </svg>
+ {% endif %}
+
+ <div class="surface-pick-up-item__availability">
+ {% if location.available %}
+ {% assign pick_up_time = location.pick_up_time | downcase %}
+ {{ 'store_availability.general.available_for_pick_up_at_time_html' | t: pick_up_time: pick_up_time }}
+ {% else %}
+ {{ 'store_availability.general.unavailable_for_pick_up_at_time_html' | t }}
+ {% endif %}
+ </div>
+
+ <address class="surface-pick-up-item__address-info">
+ {{ location.location.address | format_address }}
+ {%- if location.location.phone.size > 0 %}
+ <a href="tel:{{ location.location.phone }}">{{ location.location.phone }}</a>
+ {%- endif -%}
+ </address>
+ </li>
+ {% comment %}Inject @pixelunion/shopify-surface-pick-up/surface-pick-up-item end{% endcomment %}
+
+ {% endfor %}
+ </ul>
+ {% endif %}
+</template>
+
+{% schema %}
+{
+ "name": "Surface pick up",
+ "settings": [],
+ "presets": []
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/sections/template-search.liquid b/sections/template-search.liquid
new file mode 100644
index 0000000..9e8a559
--- /dev/null
+++ b/sections/template-search.liquid
@@ -0,0 +1,7 @@
+{% render "dw-boost-overrides" %}
+{% schema %}
+{
+ "name": "Search results",
+ "settings": []
+}
+{% endschema %}
diff --git a/templates/index.json b/templates/index.json
new file mode 100644
index 0000000..4b5a459
--- /dev/null
+++ b/templates/index.json
@@ -0,0 +1,382 @@
+/*
+ * ------------------------------------------------------------
+ * IMPORTANT: The contents of this file are auto-generated.
+ *
+ * This file may be updated by the Shopify admin theme editor
+ * or related systems. Please exercise caution as any changes
+ * made to this file may be overwritten.
+ * ------------------------------------------------------------
+ */
+{
+ "sections": {
+ "home_slideshow_EXmkyD": {
+ "type": "home-slideshow",
+ "blocks": {
+ "slide_8gwUz8": {
+ "type": "slide",
+ "settings": {
+ "image": "shopify://shop_images/HomeHero.jpg",
+ "content-alignment": "center",
+ "overlay-color": "#ffffff",
+ "title": "Phyllis Morris",
+ "subheading": "Designer Selections",
+ "cta": "View Collection",
+ "url": "shopify://collections/phyllis-morris-classic-wallcovering",
+ "cta2": "Book an Appointment",
+ "url2": "/pages/book-appointment"
+ }
+ }
+ },
+ "block_order": [
+ "slide_8gwUz8"
+ ],
+ "name": "Slideshow",
+ "settings": {
+ "layout": "content-width",
+ "controls-color": "#000000",
+ "autoplay": false,
+ "autoplay_delay": 3,
+ "autoplay-hover-pause": false
+ }
+ },
+ "home_masonry": {
+ "type": "home-masonry",
+ "blocks": {
+ "block_1": {
+ "type": "image_feature",
+ "settings": {
+ "title": "Shop Body",
+ "subheading": "",
+ "url": "",
+ "color": "white",
+ "mobile": true,
+ "show_overlay": false,
+ "overlay_color": "#000000",
+ "opacity": 1
+ }
+ },
+ "block_2": {
+ "type": "image_feature",
+ "settings": {
+ "title": "Shop Serums",
+ "subheading": "",
+ "url": "",
+ "color": "white",
+ "mobile": true,
+ "show_overlay": false,
+ "overlay_color": "#000000",
+ "opacity": 50
+ }
+ },
+ "block_3": {
+ "type": "image_feature",
+ "settings": {
+ "title": "Shop Toner & Masks",
+ "subheading": "",
+ "url": "",
+ "color": "white",
+ "mobile": true,
+ "show_overlay": false,
+ "overlay_color": "#000000",
+ "opacity": 15
+ }
+ },
+ "block_4": {
+ "type": "image_feature",
+ "settings": {
+ "title": "Shop Dryness",
+ "subheading": "",
+ "url": "",
+ "color": "white",
+ "mobile": true,
+ "show_overlay": false,
+ "overlay_color": "#000000",
+ "opacity": 100
+ }
+ },
+ "block_5": {
+ "type": "image_feature",
+ "settings": {
+ "title": "Shop Face",
+ "subheading": "",
+ "url": "",
+ "color": "white",
+ "mobile": true,
+ "show_overlay": false,
+ "overlay_color": "#000000",
+ "opacity": 50
+ }
+ }
+ },
+ "block_order": [
+ "block_1",
+ "block_2",
+ "block_3",
+ "block_4",
+ "block_5"
+ ],
+ "disabled": true,
+ "settings": {
+ "layout": "full-width",
+ "gutters": true,
+ "hover": true,
+ "hover-animation": true
+ }
+ },
+ "home_blog": {
+ "type": "home-blog",
+ "disabled": true,
+ "settings": {
+ "title": "Latest from Our Blog",
+ "blog": "designer-wallcoverings-news",
+ "number_of_columns": 3,
+ "number_of_rows": 1
+ }
+ },
+ "home_products-2": {
+ "type": "home-products",
+ "disabled": true,
+ "settings": {
+ "title": "Hollywood Hospitality Wallcoverings",
+ "collection": "hollywood-wallpaper-commercial-wallpaper",
+ "product-columns": 4,
+ "product-rows": 1
+ }
+ },
+ "home_products_98xHPG": {
+ "type": "home-products",
+ "disabled": true,
+ "name": "Featured collection",
+ "settings": {
+ "title": "Yeeha Cowboy Wallpaper",
+ "collection": "the-original-yeeha-cowboy-wallpaper",
+ "product-columns": 3,
+ "product-rows": 1
+ }
+ },
+ "home_product": {
+ "type": "home-product",
+ "blocks": {
+ "204ade9d-9c3b-4554-87aa-d454b0538034": {
+ "type": "vendor",
+ "settings": {}
+ },
+ "title": {
+ "type": "title",
+ "settings": {}
+ },
+ "price": {
+ "type": "price",
+ "settings": {}
+ },
+ "form": {
+ "type": "form",
+ "settings": {}
+ },
+ "description": {
+ "type": "description",
+ "settings": {}
+ }
+ },
+ "block_order": [
+ "204ade9d-9c3b-4554-87aa-d454b0538034",
+ "title",
+ "price",
+ "form",
+ "description"
+ ],
+ "disabled": true,
+ "settings": {
+ "product_handle": "",
+ "enable_cart_redirection": false,
+ "show_payment_button": true,
+ "images_layout": "slideshow",
+ "enable_zoom": true,
+ "enable_video_autoplay": false,
+ "enable_video_looping": false
+ }
+ },
+ "home_testimonials": {
+ "type": "home-testimonials",
+ "blocks": {
+ "testimonial-block-1": {
+ "type": "testimonial",
+ "settings": {
+ "quote": "Showcase up to eight testimonials to build trust with potential customers.",
+ "title": "Name",
+ "role": "Role"
+ }
+ },
+ "testimonial-block-2": {
+ "type": "testimonial",
+ "settings": {
+ "quote": "Showcase up to eight testimonials to build trust with potential customers.",
+ "title": "Name",
+ "role": "Role"
+ }
+ }
+ },
+ "block_order": [
+ "testimonial-block-1",
+ "testimonial-block-2"
+ ],
+ "disabled": true,
+ "settings": {
+ "title": "",
+ "per_row": 2,
+ "style": "filled"
+ }
+ },
+ "home_map": {
+ "type": "pxs-map",
+ "disabled": true,
+ "settings": {
+ "section_height": "small",
+ "title": "Local Curbside Pickup",
+ "content": "<p>After placing your order, we will contact you with a time and date to pick up your order anywhere from Monday-Friday!</p><p><span style=\"text-decoration:underline\"><strong>Contact us with any questions</strong></span></p>",
+ "text_alignment": "center",
+ "layout": "overlay-center-center",
+ "layout_mobile": "below",
+ "address": "1221 Broad St, Victoria, BC",
+ "api_key": "",
+ "enable_custom_colors": false,
+ "foreground_color": "#292929",
+ "background_color": "#ffffff",
+ "zoom": 1,
+ "overlay_color": "#000000",
+ "opacity": 10
+ }
+ },
+ "home_slideshow_Vz6PJq": {
+ "type": "home-slideshow",
+ "blocks": {
+ "slide_pDkNtC": {
+ "type": "slide",
+ "settings": {
+ "image": "shopify://shop_images/1386_Shot_14_763_rt_1440x640_1440x640_c5f2ddc0-f346-4be6-9f6c-35593680a9d0.webp",
+ "content-alignment": "center",
+ "overlay-color": "#ffffff",
+ "title": "Trade-Only Benefits",
+ "subheading": "Benefits for professionals and help from specialists",
+ "cta": "Apply Now",
+ "url": "https://www.designerwallcoverings.com/pages/trade-only-benefits"
+ }
+ }
+ },
+ "block_order": [
+ "slide_pDkNtC"
+ ],
+ "name": "Slideshow",
+ "settings": {
+ "layout": "content-width",
+ "controls-color": "#000000",
+ "autoplay": false,
+ "autoplay_delay": 3,
+ "autoplay-hover-pause": false
+ }
+ },
+ "home_slideshow_CHqc8a": {
+ "type": "home-slideshow",
+ "blocks": {
+ "slide_zex9hw": {
+ "type": "slide",
+ "settings": {
+ "image": "shopify://shop_images/digital_725x414_1440x640_1833146d-744e-447f-8d4c-693abe45e203.jpg",
+ "content-alignment": "center",
+ "overlay-color": "#262626",
+ "title": "Custom Walls and Fabrics",
+ "subheading": "Bring your vision to life with help from our design team",
+ "cta": "Learn More",
+ "url": "https://www.designerwallcoverings.com/pages/custom"
+ }
+ }
+ },
+ "block_order": [
+ "slide_zex9hw"
+ ],
+ "disabled": true,
+ "name": "Slideshow",
+ "settings": {
+ "layout": "content-width",
+ "controls-color": "#000000",
+ "autoplay": false,
+ "autoplay_delay": 3,
+ "autoplay-hover-pause": false
+ }
+ },
+ "home_image_with_text_overlay": {
+ "type": "pxs-image-with-text-overlay",
+ "settings": {
+ "section_height": "medium",
+ "image": "shopify://shop_images/Screenshot_2020-01-03_06.03.03_41380f97-3448-489e-82f4-abbb850ef39f.png",
+ "title": "",
+ "text": "",
+ "content_position": "center-center",
+ "color": "#ffffff",
+ "overlay_background": "#ffffff",
+ "overlay_opacity": 50,
+ "link": "",
+ "button_text": ""
+ }
+ },
+ "new_arrivals_banner": {
+ "type": "new-arrivals-banner",
+ "settings": {}
+ },
+ "natural_wallcoverings": {
+ "type": "natural-wallcoverings",
+ "blocks": {
+ "g": {
+ "type": "category",
+ "settings": {
+ "label": "Grasscloth",
+ "link": "/collections/grasscloth"
+ }
+ },
+ "p": {
+ "type": "category",
+ "settings": {
+ "label": "Paperweave",
+ "link": "/search?q=paperweave"
+ }
+ },
+ "s": {
+ "type": "category",
+ "settings": {
+ "label": "Sisal",
+ "link": "/collections/sisal"
+ }
+ },
+ "m": {
+ "type": "category",
+ "settings": {
+ "label": "Mica",
+ "link": "/collections/mica"
+ }
+ }
+ },
+ "block_order": [
+ "g",
+ "p",
+ "s",
+ "m"
+ ],
+ "settings": {}
+ }
+ },
+ "order": [
+ "home_slideshow_EXmkyD",
+ "home_masonry",
+ "new_arrivals_banner",
+ "natural_wallcoverings",
+ "home_blog",
+ "home_products-2",
+ "home_products_98xHPG",
+ "home_product",
+ "home_testimonials",
+ "home_map",
+ "home_slideshow_Vz6PJq",
+ "home_slideshow_CHqc8a",
+ "home_image_with_text_overlay"
+ ]
+}
\ No newline at end of file
(oldest)
·
back to Dw Theme Frontpage Cta
·
front page: remove View Collection button, relabel hero pill 62ce8ae →