← back to Wallpapercanada
wallpapercanada: also hide cards that would fall back to the generic hero
34669bb97ec303d977d4d632f9654540e8d659e0 · 2026-09-22 10:45:47 -0700 · Steve Abrams
cardImg() returns a 404 sentinel for any non-allowlisted/empty image_url so
the onerror->imgFail path hides the card. Grid, list, rail, and detail modal.
0 products affected in the current catalog (all 600 allow-listed) — defensive.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZB4e67U2DRKnZu3SVFk1m
Files touched
Diff
commit 34669bb97ec303d977d4d632f9654540e8d659e0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 22 10:45:47 2026 -0700
wallpapercanada: also hide cards that would fall back to the generic hero
cardImg() returns a 404 sentinel for any non-allowlisted/empty image_url so
the onerror->imgFail path hides the card. Grid, list, rail, and detail modal.
0 products affected in the current catalog (all 600 allow-listed) — defensive.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZB4e67U2DRKnZu3SVFk1m
---
public/index.html | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/public/index.html b/public/index.html
index 9b39bbf..a59e349 100644
--- a/public/index.html
+++ b/public/index.html
@@ -793,6 +793,10 @@ function safeImg(u) { u = u || ''; return (/^\/img\//.test(u) || /^https:\/\/(?:
// Steve rule: never show a non-loading image. On <img> load failure, hide the
// whole card/rail-tile/modal-image-wrap so a broken-image box never renders.
function imgFail(el) { var w = el && el.closest && el.closest('.card, .rail-card, .d-img-wrap'); if (w) w.style.display = 'none'; else if (el) el.style.display = 'none'; }
+// Card image source: only a real, allow-listed image renders. Anything that
+// would otherwise fall back to the generic hero returns a 404 sentinel, so the
+// existing onerror->imgFail path hides the card (no generic-hero placeholders).
+function cardImg(u) { u = (u || '').trim(); return (/^\/img\//.test(u) || /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u)) ? u : '/__no-image__'; }
// USD → CAD conversion (cosmetic; final price confirmed at checkout)
const USD_CAD = 1.36;
function cadPrice(usd) {
@@ -803,7 +807,7 @@ function cadPrice(usd) {
function cardHTML(p) {
const eager = state.page === 1;
const cad = cadPrice(p.max_price);
- return '<img onerror="imgFail(this)" data-f="image" loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+ return '<img onerror="imgFail(this)" data-f="image" loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(cardImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+ '<div class="overlay">'
+ '<div class="pat" data-f="pattern">' + escAttr(p.pattern_name || p.title) + '</div>'
+ '<div class="ven" data-f="vendor">Designer Wallcoverings' + (cad ? ' · <span class="cad-price">from ' + cad + ' CAD</span>' : '') + '</div>'
@@ -818,7 +822,7 @@ function rowHTML(p) {
const mp = Number(p.max_price);
const price = (p.max_price != null && !isNaN(mp) && mp > 0) ? '$' + mp.toFixed(2) : '—';
const aes = LABELS[p.aesthetic] || p.aesthetic || '—';
- return '<img onerror="imgFail(this)" data-f="image" loading="lazy" src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+ return '<img onerror="imgFail(this)" data-f="image" loading="lazy" src="' + escAttr(cardImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+ '<div class="r-pat" data-f="pattern">' + escAttr(p.pattern_name || p.title) + '</div>'
+ '<div class="r-col r-sku" data-f="vendor">' + escAttr(cleanSku(p.sku || p.handle_display || p.handle) || '—') + '</div>'
+ '<div class="r-col r-aes" data-f="color">' + (p.aesthetic ? sfDrill(p.aesthetic, String(aes).replace(/-/g, ' '), 'span') : escAttr(String(aes).replace(/-/g, ' '))) + '</div>'
@@ -845,7 +849,7 @@ function openDetails(p) {
const dImg = m.querySelector('[data-d-img]');
const dWrap = dImg.closest('.d-img-wrap'); if (dWrap) dWrap.style.display = ''; // reset (element is reused across opens)
dImg.onerror = function () { imgFail(this); };
- dImg.src = safeP.image_url;
+ dImg.src = cardImg(safeP.image_url);
dImg.alt = safeP.title;
m.querySelector('[data-d-pat]').textContent = safeP.pattern;
m.querySelector('[data-d-brand]').textContent = 'Designer Wallcoverings' + (cleanSku(safeP.sku) ? ' · ' + cleanSku(safeP.sku) : '');
@@ -1522,7 +1526,7 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
const cad = (typeof cadPrice === 'function') ? cadPrice(p.max_price) : '';
return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle_display || p.handle || p.sku) + '">' +
- '<img onerror="imgFail(this)" src="' + url + '" alt="' + (p.title || '').replace(/"/g, '"') + '" loading="lazy">' +
+ '<img onerror="imgFail(this)" src="' + cardImg(url) + '" alt="' + (p.title || '').replace(/"/g, '"') + '" loading="lazy">' +
'<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
'<div class="rc-meta">Designer Wallcoverings' + (cad ? ' · ' + cad + ' CAD' : '') + '</div>' +
'</a>';
← a5322e0 wallpapercanada: never show non-loading images (hide card/ra
·
back to Wallpapercanada
·
front-page-steward: ux-primitives bundle (silent) TK-12031 847b96c →