From f470732c2cd55fb2f6318ffb3036d18b4e4cfe95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lohrer?= Date: Wed, 15 Apr 2026 17:21:44 +0200 Subject: [PATCH] spa(task 13): reactions-loader mit aggregation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loadReactions(dtag) sammelt kind:7-Events mit #a-Filter auf den Post, gruppiert nach content (emoji oder +/-), zählt und sortiert nach Häufigkeit. Leerer content wird als + interpretiert (NIP-25- Konvention für Like-Default). Co-Authored-By: Claude Opus 4.6 (1M context) --- app/src/lib/nostr/loaders.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/src/lib/nostr/loaders.ts b/app/src/lib/nostr/loaders.ts index fb8213d..c77f446 100644 --- a/app/src/lib/nostr/loaders.ts +++ b/app/src/lib/nostr/loaders.ts @@ -144,3 +144,31 @@ export async function loadReplies( ); return events.sort((a, b) => a.created_at - b.created_at); } + +export interface ReactionSummary { + /** Emoji oder "+"/"-" */ + content: string; + count: number; +} + +/** + * Aggregiert kind:7-Reactions auf einen Post. + * Gruppiert nach content, zählt Anzahl. + */ +export async function loadReactions(dtag: string): Promise { + const relays = get(readRelays); + const address = eventAddress(AUTHOR_PUBKEY_HEX, dtag); + const events = await collectEvents(relays, { + kinds: [7], + '#a': [address], + limit: 500 + }); + const counts = new Map(); + for (const ev of events) { + const key = ev.content || '+'; + counts.set(key, (counts.get(key) ?? 0) + 1); + } + return [...counts.entries()] + .map(([content, count]) => ({ content, count })) + .sort((a, b) => b.count - a.count); +}