[object Object]

← back to New Import Viewer

viewer: clean 'no image' placeholder on broken vendor image URLs (e.g. timorous logo-404 bug)

a368e81f61b7ac642dc0b8c9dc4e4c458f5a4b2d · 2026-06-09 15:54:55 -0700 · SteveStudio2

Files touched

Diff

commit a368e81f61b7ac642dc0b8c9dc4e4c458f5a4b2d
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Tue Jun 9 15:54:55 2026 -0700

    viewer: clean 'no image' placeholder on broken vendor image URLs (e.g. timorous logo-404 bug)
---
 public/index.html | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/public/index.html b/public/index.html
index a12a025..8a1b079 100644
--- a/public/index.html
+++ b/public/index.html
@@ -16,7 +16,9 @@ input[type=text]{min-width:180px}
 input[type=range]{accent-color:var(--acc)}
 .grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:12px;padding:16px}
 .card{background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden;display:flex;flex-direction:column}
-.card img{width:100%;aspect-ratio:1/1;object-fit:cover;object-position:center 12%;background:#0a0b0f;display:block}
+.imgwrap{position:relative;width:100%;aspect-ratio:1/1;background:#0a0b0f}
+.imgwrap img{width:100%;height:100%;object-fit:cover;object-position:center 12%;display:block}
+.imgwrap.noimg::after{content:'no image';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#3a4150;font-size:11px;letter-spacing:.5px}
 .card .b{padding:9px 10px;display:flex;flex-direction:column;gap:4px}
 .vend{font-size:11px;color:var(--acc);font-weight:700;text-transform:uppercase;letter-spacing:.4px}
 .ttl{font-weight:600;line-height:1.25}
@@ -63,8 +65,8 @@ document.documentElement.style.setProperty('--cols',dens);
 function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));}
 function card(p){
   const title=esc(p.pattern||p.sku||'(untitled)')+(p.color?(', '+esc(p.color)):'');
-  const img=p.image?`<img loading="lazy" src="${esc(p.image)}" alt="${title}" onerror="this.style.opacity=.15">`
-                    :`<div style="aspect-ratio:1/1;background:#0a0b0f;display:flex;align-items:center;justify-content:center;color:#333">no image</div>`;
+  const img=p.image?`<div class="imgwrap"><img loading="lazy" src="${esc(p.image)}" alt="${title}" onerror="this.style.display='none';this.parentNode.classList.add('noimg')"></div>`
+                    :`<div class="imgwrap noimg"></div>`;
   const crawled=p.crawled?`🕓 ${esc(p.crawled)}`:'🕓 (no crawl date)';
   const seen=p.firstSeen?` · first seen ${esc(p.firstSeen)}`:'';
   return `<div class="card">${img}<div class="b">

← f6b1300 fix: strip psql trailing newline from final field (stats new  ·  back to New Import Viewer  ·  viewer: select-and-launch — per-product checkboxes, select-a 039ba4a →