|
|
|
|
@ -2,21 +2,27 @@
@@ -2,21 +2,27 @@
|
|
|
|
|
import Comment from './Comment.svelte'; |
|
|
|
|
import CommentForm from './CommentForm.svelte'; |
|
|
|
|
import ZapReceiptReply from '../feed/ZapReceiptReply.svelte'; |
|
|
|
|
import FeedPost from '../feed/FeedPost.svelte'; |
|
|
|
|
import { nostrClient } from '../../services/nostr/nostr-client.js'; |
|
|
|
|
import { relayManager } from '../../services/nostr/relay-manager.js'; |
|
|
|
|
import { onMount } from 'svelte'; |
|
|
|
|
import type { NostrEvent } from '../../types/nostr.js'; |
|
|
|
|
|
|
|
|
|
interface Props { |
|
|
|
|
threadId: string; // The kind 11 thread event ID |
|
|
|
|
threadId: string; // The event ID |
|
|
|
|
event?: NostrEvent; // The event itself (optional, used to determine reply types) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let { threadId }: Props = $props(); |
|
|
|
|
let { threadId, event }: Props = $props(); |
|
|
|
|
|
|
|
|
|
let comments = $state<NostrEvent[]>([]); |
|
|
|
|
let kind1Replies = $state<NostrEvent[]>([]); |
|
|
|
|
let yakBacks = $state<NostrEvent[]>([]); |
|
|
|
|
let zapReceipts = $state<NostrEvent[]>([]); |
|
|
|
|
let loading = $state(true); |
|
|
|
|
let replyingTo = $state<NostrEvent | null>(null); |
|
|
|
|
|
|
|
|
|
const isKind1 = $derived(event?.kind === 1); |
|
|
|
|
|
|
|
|
|
onMount(async () => { |
|
|
|
|
await nostrClient.initialize(); |
|
|
|
|
@ -28,29 +34,47 @@
@@ -28,29 +34,47 @@
|
|
|
|
|
try { |
|
|
|
|
const config = nostrClient.getConfig(); |
|
|
|
|
const relays = relayManager.getCommentReadRelays(); |
|
|
|
|
const feedRelays = relayManager.getFeedReadRelays(); |
|
|
|
|
const allRelays = [...new Set([...relays, ...feedRelays])]; |
|
|
|
|
|
|
|
|
|
// First, fetch comments (kind 1111) that directly reference this thread |
|
|
|
|
// NIP-22: Comments use K tag for kind and E tag for event |
|
|
|
|
const directCommentFilters = [ |
|
|
|
|
{ |
|
|
|
|
kinds: [1111], |
|
|
|
|
'#K': ['11'], // Comments on kind 11 threads |
|
|
|
|
'#E': [threadId] // Comments on this specific thread |
|
|
|
|
} |
|
|
|
|
const replyFilters: any[] = [ |
|
|
|
|
{ kinds: [9735], '#e': [threadId] }, // Zap receipts |
|
|
|
|
{ kinds: [1244], '#e': [threadId] }, // Yak backs (voice replies) |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
let directComments = await nostrClient.fetchEvents( |
|
|
|
|
directCommentFilters, |
|
|
|
|
relays, |
|
|
|
|
|
|
|
|
|
// For kind 1 events, also fetch kind 1 replies |
|
|
|
|
if (isKind1) { |
|
|
|
|
replyFilters.push({ kinds: [1], '#e': [threadId] }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// For all events, fetch kind 1111 comments |
|
|
|
|
// For kind 11 threads, use #E and #K tags (NIP-22) |
|
|
|
|
// For other events, use #e tag |
|
|
|
|
if (event?.kind === 11) { |
|
|
|
|
replyFilters.push( |
|
|
|
|
{ kinds: [1111], '#E': [threadId], '#K': ['11'] }, // NIP-22 standard (uppercase) |
|
|
|
|
{ kinds: [1111], '#e': [threadId] } // Fallback (lowercase) |
|
|
|
|
); |
|
|
|
|
} else { |
|
|
|
|
replyFilters.push({ kinds: [1111], '#e': [threadId] }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const allReplies = await nostrClient.fetchEvents( |
|
|
|
|
replyFilters, |
|
|
|
|
allRelays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
comments = directComments; |
|
|
|
|
|
|
|
|
|
// Separate by type |
|
|
|
|
comments = allReplies.filter(e => e.kind === 1111); |
|
|
|
|
kind1Replies = allReplies.filter(e => e.kind === 1); |
|
|
|
|
yakBacks = allReplies.filter(e => e.kind === 1244); |
|
|
|
|
zapReceipts = allReplies.filter(e => e.kind === 9735); |
|
|
|
|
|
|
|
|
|
// Recursively fetch all nested replies |
|
|
|
|
await fetchNestedReplies(); |
|
|
|
|
|
|
|
|
|
// Fetch zap receipts that reference this thread or any comment |
|
|
|
|
// Fetch zap receipts that reference this thread or any comment/reply |
|
|
|
|
await fetchZapReceipts(); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Error loading comments:', error); |
|
|
|
|
@ -61,69 +85,63 @@
@@ -61,69 +85,63 @@
|
|
|
|
|
|
|
|
|
|
async function fetchNestedReplies() { |
|
|
|
|
const relays = relayManager.getCommentReadRelays(); |
|
|
|
|
let hasNewComments = true; |
|
|
|
|
const feedRelays = relayManager.getFeedReadRelays(); |
|
|
|
|
const allRelays = [...new Set([...relays, ...feedRelays])]; |
|
|
|
|
let hasNewReplies = true; |
|
|
|
|
let iterations = 0; |
|
|
|
|
const maxIterations = 10; // Prevent infinite loops |
|
|
|
|
|
|
|
|
|
// Keep fetching until we have all nested replies |
|
|
|
|
while (hasNewComments && iterations < maxIterations) { |
|
|
|
|
while (hasNewReplies && iterations < maxIterations) { |
|
|
|
|
iterations++; |
|
|
|
|
hasNewComments = false; |
|
|
|
|
const allCommentIds = new Set(comments.map(c => c.id)); |
|
|
|
|
hasNewReplies = false; |
|
|
|
|
const allReplyIds = new Set([ |
|
|
|
|
...comments.map(c => c.id), |
|
|
|
|
...kind1Replies.map(r => r.id), |
|
|
|
|
...yakBacks.map(y => y.id) |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
if (allCommentIds.size > 0) { |
|
|
|
|
// Fetch comments that reference any comment we have (replies to replies) |
|
|
|
|
const replyToCommentsFilters = [ |
|
|
|
|
{ |
|
|
|
|
kinds: [1111], |
|
|
|
|
'#K': ['11'], // Comments on kind 11 threads |
|
|
|
|
'#E': Array.from(allCommentIds) // Comments that reference any of our comments |
|
|
|
|
if (allReplyIds.size > 0) { |
|
|
|
|
const nestedFilters: any[] = [ |
|
|
|
|
{ kinds: [9735], '#e': Array.from(allReplyIds) }, // Zap receipts |
|
|
|
|
{ kinds: [1244], '#e': Array.from(allReplyIds) }, // Yak backs |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
// For kind 1 events, also fetch nested kind 1 replies |
|
|
|
|
if (isKind1) { |
|
|
|
|
nestedFilters.push({ kinds: [1], '#e': Array.from(allReplyIds) }); |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
const replyToComments = await nostrClient.fetchEvents( |
|
|
|
|
replyToCommentsFilters, |
|
|
|
|
relays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Add new comments that are replies to our comments |
|
|
|
|
for (const reply of replyToComments) { |
|
|
|
|
if (!allCommentIds.has(reply.id)) { |
|
|
|
|
comments.push(reply); |
|
|
|
|
hasNewComments = true; |
|
|
|
|
|
|
|
|
|
// Fetch nested comments |
|
|
|
|
if (event?.kind === 11) { |
|
|
|
|
nestedFilters.push( |
|
|
|
|
{ kinds: [1111], '#E': Array.from(allReplyIds), '#K': ['11'] }, |
|
|
|
|
{ kinds: [1111], '#e': Array.from(allReplyIds) } |
|
|
|
|
); |
|
|
|
|
} else { |
|
|
|
|
nestedFilters.push({ kinds: [1111], '#e': Array.from(allReplyIds) }); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Also fetch missing parent comments that are referenced but not loaded |
|
|
|
|
const missingReplyIds = new Set<string>(); |
|
|
|
|
for (const comment of comments) { |
|
|
|
|
const eTag = comment.tags.find((t) => t[0] === 'E') || comment.tags.find((t) => t[0] === 'e' && t[1] !== comment.id); |
|
|
|
|
if (eTag && eTag[1] && eTag[1] !== threadId) { |
|
|
|
|
const parentExists = comments.some(c => c.id === eTag[1]); |
|
|
|
|
if (!parentExists) { |
|
|
|
|
missingReplyIds.add(eTag[1]); |
|
|
|
|
|
|
|
|
|
const nestedReplies = await nostrClient.fetchEvents( |
|
|
|
|
nestedFilters, |
|
|
|
|
allRelays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Add new replies by type |
|
|
|
|
for (const reply of nestedReplies) { |
|
|
|
|
if (reply.kind === 1111 && !comments.some(c => c.id === reply.id)) { |
|
|
|
|
comments.push(reply); |
|
|
|
|
hasNewReplies = true; |
|
|
|
|
} else if (reply.kind === 1 && !kind1Replies.some(r => r.id === reply.id)) { |
|
|
|
|
kind1Replies.push(reply); |
|
|
|
|
hasNewReplies = true; |
|
|
|
|
} else if (reply.kind === 1244 && !yakBacks.some(y => y.id === reply.id)) { |
|
|
|
|
yakBacks.push(reply); |
|
|
|
|
hasNewReplies = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (missingReplyIds.size > 0) { |
|
|
|
|
const replyComments = await nostrClient.fetchEvents( |
|
|
|
|
[{ kinds: [1111], ids: Array.from(missingReplyIds) }], |
|
|
|
|
relays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Add new parent comments |
|
|
|
|
for (const reply of replyComments) { |
|
|
|
|
const exists = comments.some(c => c.id === reply.id); |
|
|
|
|
if (!exists) { |
|
|
|
|
comments.push(reply); |
|
|
|
|
hasNewComments = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -131,24 +149,32 @@
@@ -131,24 +149,32 @@
|
|
|
|
|
async function fetchZapReceipts() { |
|
|
|
|
const config = nostrClient.getConfig(); |
|
|
|
|
const relays = relayManager.getCommentReadRelays(); |
|
|
|
|
const feedRelays = relayManager.getFeedReadRelays(); |
|
|
|
|
const allRelays = [...new Set([...relays, ...feedRelays])]; |
|
|
|
|
|
|
|
|
|
// Keep fetching until we have all zaps |
|
|
|
|
let previousCount = -1; |
|
|
|
|
while (zapReceipts.length !== previousCount) { |
|
|
|
|
previousCount = zapReceipts.length; |
|
|
|
|
const allEventIds = new Set([threadId, ...comments.map(c => c.id), ...zapReceipts.map(z => z.id)]); |
|
|
|
|
const allEventIds = new Set([ |
|
|
|
|
threadId, |
|
|
|
|
...comments.map(c => c.id), |
|
|
|
|
...kind1Replies.map(r => r.id), |
|
|
|
|
...yakBacks.map(y => y.id), |
|
|
|
|
...zapReceipts.map(z => z.id) |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
// Fetch zap receipts that reference thread or any comment/zap |
|
|
|
|
// Fetch zap receipts that reference thread or any comment/reply/yak/zap |
|
|
|
|
const zapFilters = [ |
|
|
|
|
{ |
|
|
|
|
kinds: [9735], |
|
|
|
|
'#e': Array.from(allEventIds) // Zap receipts for thread and all comments/zaps |
|
|
|
|
'#e': Array.from(allEventIds) // Zap receipts for thread and all replies |
|
|
|
|
} |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
const zapEvents = await nostrClient.fetchEvents( |
|
|
|
|
zapFilters, |
|
|
|
|
relays, |
|
|
|
|
allRelays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
@ -170,43 +196,54 @@
@@ -170,43 +196,54 @@
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check if any zaps reference comments we don't have |
|
|
|
|
const missingCommentIds = new Set<string>(); |
|
|
|
|
// Check if any zaps reference events we don't have |
|
|
|
|
const missingEventIds = new Set<string>(); |
|
|
|
|
for (const zap of validZaps) { |
|
|
|
|
const eTag = zap.tags.find((t) => t[0] === 'e'); |
|
|
|
|
if (eTag && eTag[1] && eTag[1] !== threadId) { |
|
|
|
|
if (!comments.some(c => c.id === eTag[1])) { |
|
|
|
|
missingCommentIds.add(eTag[1]); |
|
|
|
|
const exists = comments.some(c => c.id === eTag[1]) |
|
|
|
|
|| kind1Replies.some(r => r.id === eTag[1]) |
|
|
|
|
|| yakBacks.some(y => y.id === eTag[1]); |
|
|
|
|
if (!exists) { |
|
|
|
|
missingEventIds.add(eTag[1]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fetch missing comments |
|
|
|
|
if (missingCommentIds.size > 0) { |
|
|
|
|
const missingComments = await nostrClient.fetchEvents( |
|
|
|
|
[{ kinds: [1111], ids: Array.from(missingCommentIds) }], |
|
|
|
|
relays, |
|
|
|
|
// Fetch missing events (could be comments, replies, or yak backs) |
|
|
|
|
if (missingEventIds.size > 0) { |
|
|
|
|
const missingEvents = await nostrClient.fetchEvents( |
|
|
|
|
[ |
|
|
|
|
{ kinds: [1111], ids: Array.from(missingEventIds) }, |
|
|
|
|
{ kinds: [1], ids: Array.from(missingEventIds) }, |
|
|
|
|
{ kinds: [1244], ids: Array.from(missingEventIds) } |
|
|
|
|
], |
|
|
|
|
allRelays, |
|
|
|
|
{ useCache: true, cacheResults: true } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
for (const comment of missingComments) { |
|
|
|
|
if (!comments.some(c => c.id === comment.id)) { |
|
|
|
|
comments.push(comment); |
|
|
|
|
for (const event of missingEvents) { |
|
|
|
|
if (event.kind === 1111 && !comments.some(c => c.id === event.id)) { |
|
|
|
|
comments.push(event); |
|
|
|
|
} else if (event.kind === 1 && !kind1Replies.some(r => r.id === event.id)) { |
|
|
|
|
kind1Replies.push(event); |
|
|
|
|
} else if (event.kind === 1244 && !yakBacks.some(y => y.id === event.id)) { |
|
|
|
|
yakBacks.push(event); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fetch nested replies to newly found comments |
|
|
|
|
// Fetch nested replies to newly found events |
|
|
|
|
await fetchNestedReplies(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sortThreadItems(items: Array<{ event: NostrEvent; type: 'comment' | 'zap' }>): Array<{ event: NostrEvent; type: 'comment' | 'zap' }> { |
|
|
|
|
function sortThreadItems(items: Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }>): Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }> { |
|
|
|
|
// Build thread structure similar to feed |
|
|
|
|
const eventMap = new Map<string, { event: NostrEvent; type: 'comment' | 'zap' }>(); |
|
|
|
|
const eventMap = new Map<string, { event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }>(); |
|
|
|
|
const replyMap = new Map<string, string[]>(); // parentId -> childIds[] |
|
|
|
|
const rootItems: Array<{ event: NostrEvent; type: 'comment' | 'zap' }> = []; |
|
|
|
|
const rootItems: Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }> = []; |
|
|
|
|
const allEventIds = new Set<string>(); |
|
|
|
|
|
|
|
|
|
// First pass: build event map and collect all event IDs |
|
|
|
|
@ -217,19 +254,19 @@
@@ -217,19 +254,19 @@
|
|
|
|
|
|
|
|
|
|
// Second pass: determine parent-child relationships |
|
|
|
|
for (const item of items) { |
|
|
|
|
// Check if this is a reply |
|
|
|
|
// Check if this is a reply - check both uppercase E (NIP-22) and lowercase e tags |
|
|
|
|
const eTag = item.event.tags.find((t) => t[0] === 'E') || item.event.tags.find((t) => t[0] === 'e' && t[1] !== item.event.id); |
|
|
|
|
const parentId = eTag?.[1]; |
|
|
|
|
|
|
|
|
|
if (parentId) { |
|
|
|
|
// Check if parent is the thread or another comment/zap we have |
|
|
|
|
// Check if parent is the thread or another reply we have |
|
|
|
|
if (parentId === threadId || allEventIds.has(parentId)) { |
|
|
|
|
// This is a reply |
|
|
|
|
if (!replyMap.has(parentId)) { |
|
|
|
|
replyMap.set(parentId, []); |
|
|
|
|
} |
|
|
|
|
replyMap.get(parentId)!.push(item.event.id); |
|
|
|
|
} else { |
|
|
|
|
// This is a reply |
|
|
|
|
if (!replyMap.has(parentId)) { |
|
|
|
|
replyMap.set(parentId, []); |
|
|
|
|
} |
|
|
|
|
replyMap.get(parentId)!.push(item.event.id); |
|
|
|
|
} else { |
|
|
|
|
// Parent not found - treat as root item (might be a missing parent) |
|
|
|
|
rootItems.push(item); |
|
|
|
|
} |
|
|
|
|
@ -240,10 +277,10 @@
@@ -240,10 +277,10 @@
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Third pass: recursively collect all items in thread order |
|
|
|
|
const result: Array<{ event: NostrEvent; type: 'comment' | 'zap' }> = []; |
|
|
|
|
const result: Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }> = []; |
|
|
|
|
const processed = new Set<string>(); |
|
|
|
|
|
|
|
|
|
function addThread(item: { event: NostrEvent; type: 'comment' | 'zap' }) { |
|
|
|
|
function addThread(item: { event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }) { |
|
|
|
|
if (processed.has(item.event.id)) return; |
|
|
|
|
processed.add(item.event.id); |
|
|
|
|
|
|
|
|
|
@ -253,7 +290,7 @@
@@ -253,7 +290,7 @@
|
|
|
|
|
const replies = replyMap.get(item.event.id) || []; |
|
|
|
|
const replyItems = replies |
|
|
|
|
.map(id => eventMap.get(id)) |
|
|
|
|
.filter((item): item is { event: NostrEvent; type: 'comment' | 'zap' } => item !== undefined) |
|
|
|
|
.filter((item): item is { event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' } => item !== undefined) |
|
|
|
|
.sort((a, b) => a.event.created_at - b.event.created_at); // Sort replies chronologically |
|
|
|
|
|
|
|
|
|
for (const reply of replyItems) { |
|
|
|
|
@ -270,9 +307,11 @@
@@ -270,9 +307,11 @@
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getThreadItems(): Array<{ event: NostrEvent; type: 'comment' | 'zap' }> { |
|
|
|
|
const items: Array<{ event: NostrEvent; type: 'comment' | 'zap' }> = [ |
|
|
|
|
function getThreadItems(): Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }> { |
|
|
|
|
const items: Array<{ event: NostrEvent; type: 'comment' | 'reply' | 'yak' | 'zap' }> = [ |
|
|
|
|
...comments.map(c => ({ event: c, type: 'comment' as const })), |
|
|
|
|
...kind1Replies.map(r => ({ event: r, type: 'reply' as const })), |
|
|
|
|
...yakBacks.map(y => ({ event: y, type: 'yak' as const })), |
|
|
|
|
...zapReceipts.map(z => ({ event: z, type: 'zap' as const })) |
|
|
|
|
]; |
|
|
|
|
return sortThreadItems(items); |
|
|
|
|
@ -282,8 +321,11 @@
@@ -282,8 +321,11 @@
|
|
|
|
|
// NIP-22: E tag (uppercase) points to parent event, or lowercase e tag |
|
|
|
|
const eTag = event.tags.find((t) => t[0] === 'E') || event.tags.find((t) => t[0] === 'e' && t[1] !== event.id); |
|
|
|
|
if (eTag && eTag[1]) { |
|
|
|
|
// Find parent in comments or zap receipts |
|
|
|
|
const parent = comments.find((c) => c.id === eTag[1]) || zapReceipts.find((z) => z.id === eTag[1]); |
|
|
|
|
// Find parent in comments, replies, yak backs, or zap receipts |
|
|
|
|
const parent = comments.find((c) => c.id === eTag[1]) |
|
|
|
|
|| kind1Replies.find((r) => r.id === eTag[1]) |
|
|
|
|
|| yakBacks.find((y) => y.id === eTag[1]) |
|
|
|
|
|| zapReceipts.find((z) => z.id === eTag[1]); |
|
|
|
|
if (parent) return parent; |
|
|
|
|
|
|
|
|
|
// If parent not found, it might be the thread itself |
|
|
|
|
@ -307,8 +349,8 @@
@@ -307,8 +349,8 @@
|
|
|
|
|
|
|
|
|
|
{#if loading} |
|
|
|
|
<p class="text-fog-text-light dark:text-fog-dark-text-light">Loading comments...</p> |
|
|
|
|
{:else if comments.length === 0 && zapReceipts.length === 0} |
|
|
|
|
<p class="text-fog-text-light dark:text-fog-dark-text-light">No comments yet. Be the first to comment!</p> |
|
|
|
|
{:else if comments.length === 0 && kind1Replies.length === 0 && yakBacks.length === 0 && zapReceipts.length === 0} |
|
|
|
|
<p class="text-fog-text-light dark:text-fog-dark-text-light">No replies yet. Be the first to reply!</p> |
|
|
|
|
{:else} |
|
|
|
|
<div class="comments-list"> |
|
|
|
|
{#each getThreadItems() as item (item.event.id)} |
|
|
|
|
@ -319,6 +361,16 @@
@@ -319,6 +361,16 @@
|
|
|
|
|
parentEvent={parent} |
|
|
|
|
onReply={handleReply} |
|
|
|
|
/> |
|
|
|
|
{:else if item.type === 'reply'} |
|
|
|
|
<!-- Kind 1 reply - render as FeedPost --> |
|
|
|
|
<div class="kind1-reply mb-4"> |
|
|
|
|
<FeedPost post={item.event} /> |
|
|
|
|
</div> |
|
|
|
|
{:else if item.type === 'yak'} |
|
|
|
|
<!-- Yak back (kind 1244) - render as FeedPost --> |
|
|
|
|
<div class="yak-back mb-4"> |
|
|
|
|
<FeedPost post={item.event} /> |
|
|
|
|
</div> |
|
|
|
|
{:else if item.type === 'zap'} |
|
|
|
|
<ZapReceiptReply |
|
|
|
|
zapReceipt={item.event} |
|
|
|
|
|