aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-05 21:11:32 -0700
committerAdam Soltys <[email protected]>2026-10-05 21:11:32 -0700
commita08f48d67ad61eba5077fdb1a01d19fe5eea0fdb (patch)
tree36a16e9662f6b337e81976fc4f61dff553da0576
parent690a3c177778bdbdee61da5285745e39cfc2be33 (diff)
downloadcoinosv3-a08f48d67ad61eba5077fdb1a01d19fe5eea0fdb.tar.gz
coinosv3-a08f48d67ad61eba5077fdb1a01d19fe5eea0fdb.zip
A quote inside a quote shows as a one-line preview (author + start of the text) instead of a bare 'view note' link
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
-rw-r--r--src/features/messages.js20
-rw-r--r--src/style.css5
2 files changed, 24 insertions, 1 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index e97fa37..7f71264 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -6901,6 +6901,24 @@ export function messagesFeature(ctx) {
return out;
}
+ // A quote inside a quote: one line of who and what, never a third level
+ // of cards (a bare "view note" link said nothing about where it leads).
+ function quoteMini(ref) {
+ let c = feedPaint ? feedPaint.quotes.get(ref.id) : null;
+ if (!c?.ev) {
+ c = quotedNote(ref);
+ if (feedPaint && c.ev) feedPaint.quotes.set(ref.id, { ...c });
+ }
+ const open = (e) => { e.preventDefault(); e.stopPropagation(); if (c.ev) openNoteThread(c.ev); else openNoteRef(ref); };
+ if (!c.ev || hidden(c.ev)) return h('a', { href: '#', class: 'quote-mini small', onClick: open },
+ t(c.status === 'loading' ? 'noteRefLoading' : 'noteRefLink'));
+ const words = plainExcerpt(c.ev.content.replace(/https?:\/\/\S+|nostr:(note|nevent|naddr)1[a-z0-9]+/gi, ' '));
+ return h('div', { class: 'quote-mini clickable', onClick: open },
+ avatar(c.ev.pubkey, 'chat-avatar mini', false),
+ h('span', { class: 'quote-name' }, displayName(c.ev.pubkey)),
+ h('span', { class: 'small muted quote-mini-text' }, words || '\u2026'));
+ }
+
// One URL, rendered as whatever it points at. `isImage` is markdown saying
// so outright — plenty of perfectly good picture URLs carry no extension
// (a CDN path, a /media/ route), and ![…] is the author telling us what it
@@ -7280,7 +7298,7 @@ export function messagesFeature(ctx) {
if (ref && ref.type === 'event') {
// the note they're quoting, shown inside what they said about it —
// except one level down, where it goes back to being a link
- out.push(depth ? h('a', {
+ out.push(depth === 1 ? quoteMini(ref) : depth ? h('a', {
href: '#', onClick: (e) => { e.preventDefault(); e.stopPropagation(); openNoteRef(ref); },
}, t('noteRefLink')) : quoteCard(ref, depth));
} else out.push(h('span', { class: 'faint' }, part.slice(6, 18) + '…'));
diff --git a/src/style.css b/src/style.css
index 0515a7e..c0edfac 100644
--- a/src/style.css
+++ b/src/style.css
@@ -811,6 +811,11 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; }
.quote-card.clickable { cursor: pointer; }
.quote-card.clickable:hover { border-color: var(--line-strong); }
.quote-loading { flex-direction: row; align-items: center; gap: 8px; }
+/* a quote inside a quote: one line */
+.quote-mini { display: flex; align-items: center; gap: 6px; margin-top: 6px; padding: 5px 8px; min-width: 0;
+ border: 1px solid var(--line); border-radius: 8px; white-space: nowrap; overflow: hidden; }
+.quote-mini .quote-name { flex-shrink: 0; }
+.quote-mini-text { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* An audio link as a player (a podcast on Blossom, a voice note). */
.note-audio { margin: 8px 0; padding: 10px; border: 1px solid var(--line); border-radius: 12px;
background: var(--surface2); display: flex; flex-direction: column; gap: 6px; white-space: normal; }