← back to Newmor Onboard

data/live-2026-09-09/theme/snippets/dw-hover-meta.liquid

86 lines

{%- comment -%}
  dw-hover-meta — hover ANY product chip/card to reveal its SKU + product type
  (Steve 2026-07-28). Universal + delegated so it works on every card variant:
  Boost collection cards (.boost-sd__product-item), the custom infinite-scroll cards
  (.dw-if-card), and the PDP CLIP chips (.dw-similar__card, .dw-color-index__card,
  .pairs-well__card) — including cards injected after load. Data is pulled ONCE per
  handle from Shopify's own /products/{handle}.js ($0) and cached.
{%- endcomment -%}
<style>
  .dw-hovermeta{position:absolute;z-index:9999;display:flex;flex-direction:column;gap:3px;pointer-events:none;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;}
  .dw-hovermeta[hidden]{display:none;}
  .dw-hovermeta__sku{background:rgba(17,17,17,.92);color:#fff;font-size:12px;font-weight:700;letter-spacing:.03em;padding:4px 9px;border-radius:4px;align-self:flex-start;font-variant-numeric:tabular-nums;box-shadow:0 2px 8px rgba(0,0,0,.25);}
  .dw-hovermeta__type{background:rgba(17,17,17,.72);color:#fff;font-size:10px;letter-spacing:.09em;text-transform:uppercase;padding:3px 9px;border-radius:4px;align-self:flex-start;box-shadow:0 2px 8px rgba(0,0,0,.18);}
</style>
<script>
(function(){
  if(window.__dwHoverMeta) return; window.__dwHoverMeta = true;
  /* Touch devices have no hover: a tap fires mouseover but mouseout never
     comes, so the chip sticks over the first card forever (TK-10040 mobile). */
  if(!(window.matchMedia && matchMedia('(hover: hover) and (pointer: fine)').matches)) return;
  /* every "chip"/product-card variant across the store */
  var CARD_SEL = '.boost-sd__product-item, .dw-if-card, .dw-similar__card, .dw-color-index__card, .pairs-well__card, .dwsm-card__product';
  var cache = {};          // handle -> {sku,type}
  var tip = null, curCard = null;

  function ensureTip(){
    if(tip) return tip;
    tip = document.createElement('div'); tip.className = 'dw-hovermeta'; tip.hidden = true;
    document.body.appendChild(tip); return tip;
  }
  function handleOf(card){
    var a = card.matches('a[href*="/products/"]') ? card : card.querySelector('a[href*="/products/"]');
    if(!a) return '';
    var m = (a.getAttribute('href')||'').split('?')[0].match(/\/products\/([^\/?#]+)/);
    return m ? m[1] : '';
  }
  function load(h){
    if(cache[h]) return Promise.resolve(cache[h]);
    return fetch('/products/'+encodeURIComponent(h)+'.js', {headers:{'Accept':'application/json'}})
      .then(function(r){ return r.ok ? r.json() : null; })
      .then(function(p){
        var d = {sku:'', type:''};
        if(p){
          var vs = p.variants || [];
          // prefer the sellable (non-Sample) variant's SKU
          var v = vs.filter(function(x){ return x && x.sku && !/sample/i.test(x.sku) && !/sample/i.test(x.title||''); })[0] || vs[0] || {};
          d.sku = v.sku || '';
          d.type = p.type || '';
        }
        cache[h] = d; return d;
      })
      .catch(function(){ cache[h] = {sku:'',type:''}; return cache[h]; });
  }
  function position(card){
    var t = ensureTip(), r = card.getBoundingClientRect();
    t.style.left = Math.round(window.pageXOffset + r.left + 8) + 'px';
    t.style.top  = Math.round(window.pageYOffset + r.top  + 8) + 'px';
  }
  function show(card){
    var h = handleOf(card); if(!h) return;
    curCard = card; var t = ensureTip();
    load(h).then(function(d){
      if(curCard !== card) return;                 // moved off before fetch resolved
      if(!d || (!d.sku && !d.type)){ t.hidden = true; return; }
      t.innerHTML = (d.sku ? '<span class="dw-hovermeta__sku">'+d.sku+'</span>' : '')
                  + (d.type ? '<span class="dw-hovermeta__type">'+d.type+'</span>' : '');
      position(card); t.hidden = false;
    });
  }
  function hide(){ curCard = null; if(tip) tip.hidden = true; }

  document.addEventListener('mouseover', function(e){
    var card = e.target.closest && e.target.closest(CARD_SEL);
    if(card && card !== curCard) show(card);
  }, true);
  document.addEventListener('mouseout', function(e){
    var card = e.target.closest && e.target.closest(CARD_SEL);
    if(!card) return;
    var to = e.relatedTarget;
    if(!to || !(to.closest && to.closest(CARD_SEL))) hide();       // left the card entirely
  }, true);
  // keep the tip glued to the card while scrolling
  window.addEventListener('scroll', function(){ if(curCard && tip && !tip.hidden) position(curCard); }, {passive:true});
})();
</script>