aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-05 10:07:30 -0700
committerAdam Soltys <[email protected]>2026-10-05 10:07:30 -0700
commit0611d3b3b3e94089218da867e4530234f9248d3f (patch)
treeb823ab750741c1c88a1b03e99559aa5e4b016c15 /src
parent3208a406171f88eb151b95ad8755ed2d847dcc24 (diff)
downloadcoinosv3-0611d3b3b3e94089218da867e4530234f9248d3f.tar.gz
coinosv3-0611d3b3b3e94089218da867e4530234f9248d3f.zip
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 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js16
1 files changed, 14 insertions, 2 deletions
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)),