← 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>