From 0611d3b3b3e94089218da867e4530234f9248d3f Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 5 Oct 2026 10:07:30 -0700 Subject: Article cards: a dead cover falls back to the body's first picture, else no cover (no grey box) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi --- src/features/messages.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/features') diff --git a/src/features/messages.js b/src/features/messages.js index 490ac6f..d18a0b2 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -6856,11 +6856,23 @@ export function messagesFeature(ctx) { h('div', { class: 'small muted' }, title || alt || t('noteForeignKind', { kind: ev.kind }))); } // An article as a card: its cover, title and summary; a tap opens it to read. + // Its cover: the image tag, else the first pictures in its body. Covers + // die (a Blossom host drops the file and no other server has it): a dead + // one is remembered for the session and the next candidate takes its + // place, or the card goes without — never a grey box with a broken icon. + const deadCovers = new Set(); + function articleCover(ev) { + const cands = [tagStr(ev, 'image').trim(), ...noteMediaUrls(ev.content).slice(0, 3)]; + return cands.find((u) => /^https:\/\/\S+$/.test(u) && !deadCovers.has(u)) || null; + } function articleCard(ev) { - const img = tagStr(ev, 'image'); + const img = articleCover(ev); const summary = tagStr(ev, 'summary'); return h('div', { class: 'quote-card clickable addr-article', onClick: (e) => { e.stopPropagation(); openNoteThread(ev); } }, - /^https:\/\//.test(img) ? h('img', { class: 'addr-cover', src: img, alt: '', loading: 'lazy' }) : null, + img ? h('img', { + class: 'addr-cover', src: img, alt: '', loading: 'lazy', 'data-key': 'cover:' + img, + onError: (e) => { deadCovers.add(img); e.target.style.display = 'none'; scheduleRepaint(); }, + }) : null, h('div', { class: 'row gap6', style: 'align-items:center;min-width:0' }, avatar(ev.pubkey, 'chat-avatar mini', false), h('span', { class: 'quote-name' }, displayName(ev.pubkey)), -- cgit v1.2.3