aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/messages.js33
1 files changed, 26 insertions, 7 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 801ad28..490ac6f 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -491,6 +491,18 @@ export function messagesFeature(ctx) {
}
// what a feed or a profile lists: notes, and polls (NIP-88)
const FEED_KINDS = [1, 1068];
+ // A profile shows its articles (NIP-23) among the notes, as Amethyst does.
+ const PROFILE_KINDS = [...FEED_KINDS, 30023];
+ // An edited article is a new event at the same address: keep the newest.
+ const newestArticles = (evs) => {
+ const best = new Map();
+ for (const e of evs) {
+ if (e.kind !== 30023) continue;
+ const k = e.pubkey + ':' + ((e.tags.find((x) => x[0] === 'd') || [])[1] || '');
+ if (!best.has(k) || best.get(k).created_at < e.created_at) best.set(k, e);
+ }
+ return evs.filter((e) => e.kind !== 30023 || best.get(e.pubkey + ':' + ((e.tags.find((x) => x[0] === 'd') || [])[1] || '')) === e);
+ };
const myPubkeys = () => {
const pks = [];
const id = hook('nostrLoginIdentity');
@@ -3488,11 +3500,18 @@ export function messagesFeature(ctx) {
wallet.saveFeatureState(PROF_PAGE_CACHE, c);
} catch {}
}
- const slimNote = (ev) => ({
+ // (an article keeps its kind, its card's tags and, near enough, all of
+ // itself: a tap opens it to read)
+ const ARTICLE_TAGS = ['d', 'title', 'summary', 'image', 'published_at'];
+ const slimNote = (ev) => ev.kind === 30023 ? {
+ id: ev.id, pubkey: ev.pubkey, kind: 30023, created_at: ev.created_at,
+ content: String(ev.content || '').slice(0, 30000),
+ tags: (ev.tags || []).filter((x) => ARTICLE_TAGS.includes(x[0])),
+ } : {
id: ev.id, pubkey: ev.pubkey, kind: 1, created_at: ev.created_at,
content: String(ev.content || '').slice(0, 3000),
tags: (ev.tags || []).filter((x) => x[0] === 'e' || x[0] === 'p'),
- });
+ };
function fetchFullProfile(pk) {
if (!fullProfiles.has(pk)) {
@@ -4061,7 +4080,7 @@ export function messagesFeature(ctx) {
function fetchNotes(pk, c) {
c.fetching = true;
(async () => {
- const evs = await queryOn(await notesRelays(pk), { kinds: FEED_KINDS, authors: [pk], limit: 30 }, 4500);
+ const evs = await queryOn(await notesRelays(pk), { kinds: PROFILE_KINDS, authors: [pk], limit: 30 }, 4500);
// Merged with what's already on the page, never swapped for it: the
// relays answer unevenly (primal held 2 of Joe Nakamoto's posts, ours
// 18, the archives 30), and a thin answer used to erase a full page.
@@ -4069,7 +4088,7 @@ export function messagesFeature(ctx) {
let added = 0;
for (const e of evs || []) if (!byId.has(e.id)) { byId.set(e.id, e); added++; }
if (!added && c.notes.length) return;
- const merged = [...byId.values()].sort((a, b) => b.created_at - a.created_at);
+ const merged = newestArticles([...byId.values()]).sort((a, b) => b.created_at - a.created_at);
await notesReady(merged.slice(0, FEED_PAGE)); // the first screen arrives whole
c.notes = merged;
c.end = false;
@@ -4117,12 +4136,12 @@ export function messagesFeature(ctx) {
render();
try {
const evs = await queryOn(await notesRelays(pk),
- { kinds: FEED_KINDS, authors: [pk], limit: 30, until: oldest.created_at - 1 }, 4500);
+ { kinds: PROFILE_KINDS, authors: [pk], limit: 30, until: oldest.created_at - 1 }, 4500);
const seen = new Set(c.notes.map((e) => e.id));
const older = (evs || [])
.filter((e) => !seen.has(e.id) && seen.add(e.id))
.sort((a, b) => b.created_at - a.created_at);
- if (older.length) { await notesReady(older); c.notes = [...c.notes, ...older]; }
+ if (older.length) { await notesReady(older); c.notes = newestArticles([...c.notes, ...older]); }
else c.end = true; // the relays have nothing older
} catch {} finally {
c.loadingMore = false;
@@ -8515,7 +8534,7 @@ export function messagesFeature(ctx) {
}, '\u22ef')),
foreign
? h('div', { class: 'note-text small muted', style: 'white-space:pre-wrap;overflow-wrap:anywhere' }, (ev.kind === 64 ? '\u265f ' : '') + altText)
- : h('div', { class: 'note-text', style: 'white-space:pre-wrap;overflow-wrap:anywhere' }, ...(ev.kind === ARTICLE ? articleBody(ev) : noteBody(ev.content, 0, emojiTagMap(ev.tags)))),
+ : h('div', { class: 'note-text', style: 'white-space:pre-wrap;overflow-wrap:anywhere' }, ...(ev.kind === ARTICLE ? (open ? [articleCard(ev)] : articleBody(ev)) : noteBody(ev.content, 0, emojiTagMap(ev.tags)))),
ev.kind === POLL ? pollBox(ev) : null,
pending ? null : noteActions(pk, ev, { canZap }),
!pending && whoOpen(ev.id) ? whoPanel(ev) : null));