[object Object]

← back to Dw Marketing Reels

colorwheel: canonical /pages/shop-by-color body (new wheel, replaces static swatch page); /pages/colors 301→shop-by-color

907a60da1deaf317cfae1c58b7ba9819df3a3743 · 2026-07-16 11:26:05 -0700 · Steve

Files touched

Diff

commit 907a60da1deaf317cfae1c58b7ba9819df3a3743
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jul 16 11:26:05 2026 -0700

    colorwheel: canonical /pages/shop-by-color body (new wheel, replaces static swatch page); /pages/colors 301→shop-by-color
---
 colorwheel/shop-by-color.page-body.html | 207 ++++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)

diff --git a/colorwheel/shop-by-color.page-body.html b/colorwheel/shop-by-color.page-body.html
new file mode 100644
index 0000000..980ef4f
--- /dev/null
+++ b/colorwheel/shop-by-color.page-body.html
@@ -0,0 +1,207 @@
+<style>
+  #dw-recently-viewed, .recently-viewed-section.rv-index { display:none !important; }
+  .page-title { display:none !important; }
+  .breadcrumbs, .breadcrumb { display:none !important; }
+  .page-content.rte { max-width:100% !important; padding:0 !important; }
+  .template-page .page-content { max-width:100% !important; }
+  .template-page .wrapper, .template-page .container { max-width:100% !important; width:100% !important; padding:0 !important; }
+  .template-page .main-content { max-width:100% !important; width:100% !important; padding:0 !important; margin-left:0 !important; margin-right:0 !important; }
+  .template-page .grid, .template-page .grid__item { max-width:100% !important; width:100% !important; padding:0 !important; }
+</style>
+<!-- Designer Wallcoverings · Shop by Color — self-contained widget for /pages/colors.
+     Everything scoped under #sbc; JS in an IIFE; talks to the public color-widen API. -->
+<style>
+#sbc{--ink:#1a1a1a;--line:#e6e0d6;--gold:#b9892f;color:var(--ink);
+  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;
+  max-width:1220px;margin:0 auto;padding:6px 0 44px}
+#sbc *{box-sizing:border-box}
+#sbc .sbc-head{text-align:center;padding:14px 16px 4px}
+#sbc .sbc-head h2{margin:0;font-weight:300;letter-spacing:.18em;text-transform:uppercase;font-size:22px}
+#sbc .sbc-head p{margin:6px 0 0;color:#7a7266;font-size:13px;letter-spacing:.04em}
+#sbc .sbc-stage{display:flex;gap:40px;align-items:center;justify-content:center;flex-wrap:wrap;padding:22px 16px 8px}
+#sbc .sbc-wheelcol{display:flex;flex-direction:column;align-items:center;gap:16px}
+#sbc .sbc-wheelwrap{position:relative;width:340px;height:340px;flex:0 0 auto}
+#sbc .sbc-spin{position:absolute;inset:0;animation:sbcspin 40s linear infinite}
+#sbc .sbc-wheelwrap.sbc-dragging .sbc-spin{animation-play-state:paused}
+#sbc .sbc-wheel{width:100%;height:100%;border-radius:50%;cursor:crosshair;
+  box-shadow:0 10px 40px rgba(0,0,0,.18),inset 0 0 0 1px rgba(0,0,0,.06)}
+@keyframes sbcspin{to{transform:rotate(360deg)}}
+#sbc .sbc-pick{position:absolute;width:34px;height:34px;border-radius:50%;border:3px solid #fff;
+  box-shadow:0 2px 10px rgba(0,0,0,.35),0 0 0 1px rgba(0,0,0,.25);transform:translate(-50%,-50%);
+  left:50%;top:14%;pointer-events:none}
+#sbc .sbc-hub{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:118px;height:118px;
+  border-radius:50%;background:#fff;box-shadow:0 6px 22px rgba(0,0,0,.16),inset 0 0 0 1px var(--line);
+  display:flex;align-items:center;justify-content:center}
+#sbc .sbc-sw{width:78px;height:78px;border-radius:50%;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12);
+  transition:background .2s;background:#8aa}
+#sbc .sbc-side{max-width:300px}
+#sbc .sbc-side h3{font-weight:400;font-size:15px;letter-spacing:.06em;text-transform:uppercase;margin:0 0 8px}
+#sbc .sbc-side p{color:#7a7266;font-size:13px;line-height:1.6;margin:0}
+#sbc .sbc-palette{display:flex;align-items:center;justify-content:center;gap:14px}
+#sbc .sbc-nav{border:1px solid var(--line);background:#fff;color:var(--ink);width:32px;height:32px;
+  border-radius:50%;font-size:20px;line-height:1;cursor:pointer;display:flex;align-items:center;
+  justify-content:center;box-shadow:0 1px 4px rgba(0,0,0,.08);transition:transform .12s,box-shadow .12s}
+#sbc .sbc-nav:hover{transform:translateY(-2px);box-shadow:0 5px 14px rgba(0,0,0,.16)}
+#sbc .sbc-nav:disabled{opacity:.28;cursor:default;transform:none;box-shadow:none}
+#sbc .sbc-dots{display:flex;gap:14px}
+#sbc .sbc-pdot{width:34px;height:34px;border-radius:50%;cursor:pointer;
+  box-shadow:inset 0 0 0 1px rgba(0,0,0,.14),0 1px 4px rgba(0,0,0,.12);
+  transition:transform .14s,box-shadow .14s}
+#sbc .sbc-pdot:hover{transform:translateY(-3px) scale(1.1)}
+#sbc .sbc-pdot.sbc-on{box-shadow:0 0 0 3px var(--gold),inset 0 0 0 1px rgba(0,0,0,.14)}
+#sbc .sbc-grid{margin:16px auto 20px;padding:0 6px;display:grid;
+  grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:18px}
+#sbc .sbc-card{position:relative;text-decoration:none;color:inherit;background:#fff;border:1px solid var(--line);
+  border-radius:12px;overflow:hidden;opacity:0;transform:translateY(14px) scale(.98);
+  animation:sbcpop .5s forwards;box-shadow:0 1px 0 rgba(0,0,0,.03)}
+@keyframes sbcpop{to{opacity:1;transform:none}}
+#sbc .sbc-card:hover{box-shadow:0 12px 30px rgba(0,0,0,.12)}
+#sbc .sbc-card .sbc-im{aspect-ratio:1/1;width:100%;object-fit:cover;display:block;background:#f2efe9}
+#sbc .sbc-card .sbc-cap{padding:10px 12px;font-size:12.5px;line-height:1.35}
+#sbc .sbc-card .sbc-cap i{display:block;color:#9a9276;font-style:normal;font-size:11px;margin-top:3px}
+#sbc .sbc-card .sbc-cdot{position:absolute;top:8px;right:8px;width:14px;height:14px;border-radius:50%;
+  box-shadow:0 0 0 2px #fff,inset 0 0 0 1px rgba(0,0,0,.15)}
+#sbc .sbc-empty{grid-column:1/-1;text-align:center;color:#9a9276;padding:40px;font-size:14px}
+#sbc .sbc-loading{grid-column:1/-1;text-align:center;color:var(--gold);padding:40px;font-size:13px;letter-spacing:.1em}
+</style>
+
+<div id="sbc">
+  <div class="sbc-head">
+    <h2>Shop by Color</h2>
+    <p>Spin the wheel · click a hue · discover every wallcovering in that color</p>
+  </div>
+  <div class="sbc-stage">
+    <div class="sbc-wheelcol">
+      <div class="sbc-wheelwrap" id="sbc-ww">
+        <div class="sbc-spin" id="sbc-spin">
+          <canvas class="sbc-wheel" id="sbc-wheel" width="680" height="680"></canvas>
+          <div class="sbc-pick" id="sbc-pick"></div>
+        </div>
+        <div class="sbc-hub"><div class="sbc-sw" id="sbc-sw"></div></div>
+      </div>
+      <div class="sbc-palette">
+        <button class="sbc-nav" id="sbc-prev" aria-label="Previous colors">&lsaquo;</button>
+        <div class="sbc-dots" id="sbc-dots"></div>
+        <button class="sbc-nav" id="sbc-next" aria-label="More colors">&rsaquo;</button>
+      </div>
+    </div>
+    <div class="sbc-side">
+      <h3>Curated by hue</h3>
+      <p>Every color on the wheel maps to the actual dominant colors extracted from our
+         full catalog. Pick a shade and we surface the closest perceptual matches — the
+         same color intelligence behind each product page.</p>
+    </div>
+  </div>
+  <div class="sbc-grid" id="sbc-grid"></div>
+</div>
+
+<script>
+(function(){
+  var API='https://photo.designerwallcoverings.com/apps/color-widen';
+  var cv=document.getElementById('sbc-wheel'); if(!cv||cv.dataset.sbcInit) return; cv.dataset.sbcInit='1';
+  var ctx=cv.getContext('2d'), R=cv.width/2;
+  function hsl2rgb(h,s,l){h/=360;var r,g,b;if(s===0){r=g=b=l;}else{
+    var q=l<.5?l*(1+s):l+s-l*s,p=2*l-q;var t=function(a){if(a<0)a+=1;if(a>1)a-=1;
+      if(a<1/6)return p+(q-p)*6*a;if(a<1/2)return q;if(a<2/3)return p+(q-p)*(2/3-a)*6;return p;};
+    r=t(h+1/3);g=t(h);b=t(h-1/3);}return[Math.round(r*255),Math.round(g*255),Math.round(b*255)];}
+  function rgbHex(r,g,b){return '#'+[r,g,b].map(function(x){return x.toString(16).padStart(2,'0');}).join('');}
+  (function paint(){
+    var img=ctx.createImageData(cv.width,cv.height),d=img.data;
+    for(var y=0;y<cv.height;y++)for(var x=0;x<cv.width;x++){
+      var dx=x-R,dy=y-R,r=Math.sqrt(dx*dx+dy*dy),i=(y*cv.width+x)*4;
+      if(r>R){d[i+3]=0;continue;}
+      var h=Math.atan2(dy,dx)*180/Math.PI;if(h<0)h+=360;
+      var rgb=hsl2rgb(h,Math.min(1,r/R),0.5);
+      d[i]=rgb[0];d[i+1]=rgb[1];d[i+2]=rgb[2];d[i+3]=255;
+    }
+    ctx.putImageData(img,0,0);
+  })();
+  var ww=document.getElementById('sbc-ww'),spin=document.getElementById('sbc-spin'),
+    pick=document.getElementById('sbc-pick'),sw=document.getElementById('sbc-sw'),
+    grid=document.getElementById('sbc-grid');
+  var curHue=140,curSat=0.45;
+  function place(hue,sat){
+    var ang=hue*Math.PI/180,rad=sat*48;
+    pick.style.left=(50+Math.cos(ang)*rad)+'%';
+    pick.style.top=(50+Math.sin(ang)*rad)+'%';
+    var rgb=hsl2rgb(hue,sat,0.5),hx=rgbHex(rgb[0],rgb[1],rgb[2]);
+    pick.style.background=hx;sw.style.background=hx;
+    return hx;
+  }
+  function spinDeg(){
+    var tr=getComputedStyle(spin).transform;
+    if(!tr||tr==='none')return 0;
+    var m=new DOMMatrixReadOnly(tr);
+    var d=Math.atan2(m.b,m.a)*180/Math.PI;if(d<0)d+=360;return d;
+  }
+  function fromEvent(e){
+    var rect=cv.getBoundingClientRect();
+    var cx=e.touches?e.touches[0].clientX:e.clientX,cy=e.touches?e.touches[0].clientY:e.clientY;
+    var dx=cx-(rect.left+rect.width/2),dy=cy-(rect.top+rect.height/2);
+    var scr=Math.atan2(dy,dx)*180/Math.PI;if(scr<0)scr+=360;
+    var h=(scr-spinDeg()+360)%360;
+    var s=Math.min(1,Math.sqrt(dx*dx+dy*dy)/(rect.width/2));
+    curHue=h;curSat=Math.max(.12,s);return place(curHue,curSat);
+  }
+  var t=null;
+  function selected(hx){clearTimeout(t);t=setTimeout(function(){load(hx);},140);}
+  ww.addEventListener('pointerdown',function(e){ww.classList.add('sbc-dragging');selected(fromEvent(e));
+    var mv=function(ev){selected(fromEvent(ev));};
+    var up=function(){ww.classList.remove('sbc-dragging');
+      window.removeEventListener('pointermove',mv);window.removeEventListener('pointerup',up);};
+    window.addEventListener('pointermove',mv);window.addEventListener('pointerup',up);});
+
+  var PALETTE=[
+    [0,.62],[22,.62],[42,.6],[60,.58],[85,.55],[110,.55],
+    [140,.55],[165,.55],[190,.58],[210,.6],[232,.6],[255,.58],
+    [280,.56],[300,.56],[322,.58],[345,.6],[10,.34],[200,.34],
+    [320,.3],[45,.14],[150,.14],[220,.14],[0,.06],[0,0]
+  ];
+  var PAGE=6,dotsEl=document.getElementById('sbc-dots'),
+    prevB=document.getElementById('sbc-prev'),nextB=document.getElementById('sbc-next');
+  var pStart=0,activeDot=-1;
+  function renderDots(){
+    dotsEl.innerHTML='';
+    PALETTE.slice(pStart,pStart+PAGE).forEach(function(pr,k){
+      var h=pr[0],s=pr[1],idx=pStart+k,el=document.createElement('div');el.className='sbc-pdot';
+      var rgb=hsl2rgb(h,s,0.5),hx=rgbHex(rgb[0],rgb[1],rgb[2]);
+      el.style.background=hx;el.title=hx.toUpperCase();
+      if(idx===activeDot)el.classList.add('sbc-on');
+      el.onclick=function(){activeDot=idx;curHue=h;curSat=Math.max(.12,s);place(h,s);load(hx);renderDots();};
+      dotsEl.appendChild(el);
+    });
+    prevB.disabled=pStart<=0;
+    nextB.disabled=pStart+PAGE>=PALETTE.length;
+  }
+  prevB.onclick=function(){pStart=Math.max(0,pStart-PAGE);renderDots();};
+  nextB.onclick=function(){pStart=Math.min(Math.max(0,PALETTE.length-PAGE),pStart+PAGE);renderDots();};
+  renderDots();
+
+  function load(hex){
+    grid.innerHTML='<div class="sbc-loading">Finding wallcoverings in this color</div>';
+    fetch(API,{method:'POST',headers:{'Content-Type':'application/json'},
+      body:JSON.stringify({hex:hex,ceiling:15,k:300})})
+      .then(function(r){return r.json();})
+      .then(function(j){
+        var res=(j.results||[]);
+        if(!res.length){grid.innerHTML='<div class="sbc-empty">No close matches for this shade yet — try a neighboring hue.</div>';return;}
+        grid.innerHTML='';
+        res.forEach(function(p,i){
+          if(!p.handle||!p.image)return;
+          var a=document.createElement('a');a.className='sbc-card';
+          a.href='/products/'+encodeURIComponent(p.handle);a.target='_blank';a.rel='noopener';
+          a.style.animationDelay=Math.min(i*12,700)+'ms';
+          var im=document.createElement('img');im.className='sbc-im';im.loading='lazy';im.src=p.image;
+          im.onerror=function(){a.remove();};
+          var dot=document.createElement('span');dot.className='sbc-cdot';dot.style.background=p.hex||hex;
+          var cap=document.createElement('div');cap.className='sbc-cap';
+          cap.textContent=(p.title||'').replace(/\s*\|\s*.*$/,'');
+          if(p.vendor){var v=document.createElement('i');v.textContent=p.vendor;cap.appendChild(v);}
+          a.appendChild(im);a.appendChild(dot);a.appendChild(cap);grid.appendChild(a);
+        });
+      })
+      .catch(function(e){grid.innerHTML='<div class="sbc-empty">Could not load right now. '+e.message+'</div>';});
+  }
+  load(place(curHue,curSat));
+})();
+</script>

← 1dfe5d5 colorwheel: Shopify /pages/colors widget (scoped inline buil  ·  back to Dw Marketing Reels  ·  shop-by-color wheel: -50% wheel+dots, mobile+touch, >=80 SKU f7b3987 →