aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-10 10:28:12 -0700
committerAdam Soltys <[email protected]>2026-10-10 10:28:12 -0700
commite253cbd16d502cd382a6f7632d2851db4ae1a6ae (patch)
treebfb8caefb7dc4853e334e955fd915b38e2432274 /src
parent0262af2885831f67b7025fff84d4987fed4857c6 (diff)
downloadcoinosv3-e253cbd16d502cd382a6f7632d2851db4ae1a6ae.tar.gz
coinosv3-e253cbd16d502cd382a6f7632d2851db4ae1a6ae.zip
Notifications: a custom-emoji reaction shows its picture. djmeistro's :peepoClap: read as the bare text "reacted :peepoClap:" — the notification row kept the reaction's content but not its NIP-30 emoji tag (and cut shortcodes at 12 characters). Rows now keep the tag's picture and the whole :name:, draw it like the reaction chips do, and a row saved the old way gets its picture when the relay hands the reaction again. tools/notif-custom-emoji-test.js.
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js28
1 files changed, 22 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 0a14b9c..cedd8db 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -13706,8 +13706,11 @@ export function messagesFeature(ctx) {
if (my.includes(ev.pubkey)) return null;
if (ev.kind === 7) {
if (!lastE) return null;
- const emoji = !ev.content || ev.content === '+' ? '\u2764\ufe0f' : ev.content.slice(0, 12);
- return { id: ev.id, what: 'react', actor: ev.pubkey, target: lastE, hint, emoji, ts: ev.created_at };
+ // a :shortcode: keeps its whole name and the picture its NIP-30 tag names
+ const code = shortcodeOf(ev.content || '');
+ const tag = code && (ev.tags || []).find((x) => x[0] === 'emoji' && x[1] === code && /^https?:\/\//.test(x[2] || ''));
+ const emoji = !ev.content || ev.content === '+' ? '\u2764\ufe0f' : code ? ev.content.slice(0, 64) : ev.content.slice(0, 12);
+ return { id: ev.id, what: 'react', actor: ev.pubkey, target: lastE, hint, emoji, emojiUrl: tag ? tag[2] : undefined, ts: ev.created_at };
}
if (ev.kind === 6) return lastE ? { id: ev.id, what: 'boost', actor: ev.pubkey, target: lastE, hint, ts: ev.created_at } : null;
if (ev.kind === COMMENT) {
@@ -13727,9 +13730,16 @@ export function messagesFeature(ctx) {
const c = notifNow();
const known = new Set(c.items.map((x) => x.id));
for (const ev of evs) noteForSpam(ev);
- const add = evs.map((ev) => ((ev.kind === 1 || ev.kind === COMMENT) && hidden(ev) ? null : notifItem(ev)))
- .filter((x) => x && !hiddenPk(x.actor) && !known.has(x.id) && known.add(x.id));
- if (!add.length) return false;
+ const items = evs.map((ev) => ((ev.kind === 1 || ev.kind === COMMENT) && hidden(ev) ? null : notifItem(ev)));
+ // a custom-emoji reaction saved before rows kept its picture gets it now
+ let healed = false;
+ for (const x of items) {
+ if (!x || !x.emojiUrl || !known.has(x.id)) continue;
+ const old = c.items.find((y) => y.id === x.id);
+ if (old && !old.emojiUrl) { old.emojiUrl = x.emojiUrl; old.emoji = x.emoji; healed = true; }
+ }
+ const add = items.filter((x) => x && !hiddenPk(x.actor) && !known.has(x.id) && known.add(x.id));
+ if (!add.length) { if (healed) persistNotifs(); return healed; }
warmNotifFaces(add);
// One zap, two receipts: a coinos zap publishes its own (9737) beside the
// LNURL server's (9735). The same person, post and amount within a few
@@ -13822,7 +13832,13 @@ export function messagesFeature(ctx) {
}
function notifLabel(x) {
if (x.what === 'zap') return t('alertZap', { sats: fmtSats(x.sats) + ' sats' });
- if (x.what === 'react') return t('alertReact', { emoji: x.emoji });
+ if (x.what === 'react') {
+ const code = shortcodeOf(x.emoji);
+ const url = code && (x.emojiUrl || emojiUrl(code));
+ if (!url) return t('alertReact', { emoji: x.emoji });
+ const [a, b = ''] = t('alertReact', { emoji: '\u0000' }).split('\u0000');
+ return h('span', {}, a, reactImg(code, url), b);
+ }
if (x.what === 'boost') return t('alertBoost');
if (x.what === 'reply') return t('alertReply');
return t('alertMention');