-
+ {iconNode ?? (
+
+ )}
{author.isLoading ? (
@@ -1962,7 +2034,17 @@ export function EventActionHeader({
)}
- {action}
+ {actionHref ? (
+ e.stopPropagation()}
+ >
+ {verbContent}
+
+ ) : (
+ verbContent
+ )}
{noun && nounRoute && (
<>
{" "}
diff --git a/src/components/PeopleListDetailContent.tsx b/src/components/PeopleListDetailContent.tsx
index bd47e936..bc0feb2e 100644
--- a/src/components/PeopleListDetailContent.tsx
+++ b/src/components/PeopleListDetailContent.tsx
@@ -164,6 +164,7 @@ export function PeopleListFeedTab({ pubkeys, tabKey }: { pubkeys: string[]; tabK
key={item.repostedBy ? `repost-${item.repostedBy}-${item.event.id}` : item.event.id}
event={item.event}
repostedBy={item.repostedBy}
+ repostEvent={item.repostEvent}
/>
))}
{hasNextPage && (
diff --git a/src/contexts/AppContext.ts b/src/contexts/AppContext.ts
index e81edbf9..7eb0038b 100644
--- a/src/contexts/AppContext.ts
+++ b/src/contexts/AppContext.ts
@@ -44,6 +44,10 @@ export interface FeedSettings {
feedIncludeReposts: boolean;
/** Include generic reposts (kind 16) in the feed */
feedIncludeGenericReposts: boolean;
+ /** Include reactions (kind 7) in the feed, rendered as "X reacted to" overlays on the target event. Default: false. */
+ feedIncludeReactions: boolean;
+ /** Include zaps (Lightning kind 9735 + on-chain kind 8333) in the feed, rendered as "X zapped" overlays on the target event. Default: false. */
+ feedIncludeZaps: boolean;
/** Include long-form articles (kind 30023) in the feed */
feedIncludeArticles: boolean;
/** Show Articles (kind 30023) link in sidebar */
diff --git a/src/hooks/useFeed.ts b/src/hooks/useFeed.ts
index 73f64a11..60ff904f 100644
--- a/src/hooks/useFeed.ts
+++ b/src/hooks/useFeed.ts
@@ -7,10 +7,18 @@ import { useFollowList } from './useFollowActions';
import { useMutedAuthorFilter } from './useMutedAuthorFilter';
import { parseAuthorEvent } from './useAuthor';
import { getEnabledFeedKinds } from '@/lib/extraKinds';
-import { getPaginationCursor, parseRepostContent, isRepostKind, type FeedItem } from '@/lib/feedUtils';
+import {
+ getPaginationCursor,
+ parseRepostContent,
+ isRepostKind,
+ isReactionKind,
+ isZapKind,
+ type FeedItem,
+} from '@/lib/feedUtils';
import { isReplyEvent } from '@/lib/nostrEvents';
import { setProfileCached } from '@/lib/profileCache';
import { getStorageKey } from '@/lib/storageKey';
+import { getZapAmountSats, getZapSenderPubkey, getTargetEventId } from '@/lib/zapHelpers';
import type { NostrEvent } from '@nostrify/nostrify';
const PAGE_SIZE = 15;
@@ -106,6 +114,151 @@ export function useFeed(tab: 'follows' | 'global' | 'communities', options?: Use
}
}
+ /**
+ * Turn a list of raw events into FeedItems, unwrapping reposts /
+ * reactions / zaps so that the target event becomes the FeedItem's
+ * primary `event` and the wrapper is surfaced as an overlay
+ * (repostedBy / reactedBy / zappedBy). Any wrapper whose target
+ * isn't in `events` is fetched in a single batched query.
+ */
+ async function buildFeedItems(events: NostrEvent[]): Promise {
+ const items: FeedItem[] = [];
+
+ // Map of target-event id → list of wrappers that need it. A single
+ // target can have multiple wrappers (e.g. several reactions to one
+ // post), so we store an array.
+ type PendingWrapper =
+ | { type: 'repost'; event: NostrEvent }
+ | { type: 'reaction'; event: NostrEvent }
+ | { type: 'zap'; event: NostrEvent };
+ const missingTargets = new Map();
+
+ const queueMissing = (id: string, wrapper: PendingWrapper) => {
+ const existing = missingTargets.get(id);
+ if (existing) existing.push(wrapper);
+ else missingTargets.set(id, [wrapper]);
+ };
+
+ // Index events by id so we can resolve targets that arrived in the
+ // same page without an extra query.
+ const eventsById = new Map();
+ for (const ev of events) eventsById.set(ev.id, ev);
+
+ for (const ev of events) {
+ if (isRepostKind(ev.kind)) {
+ // Kind 6 / 16 — repost. Prefer the embedded JSON; fall back to
+ // resolving the `e` tag.
+ const embedded = parseRepostContent(ev);
+ if (embedded && embedded.created_at <= now) {
+ items.push({ event: embedded, repostedBy: ev.pubkey, repostEvent: ev, sortTimestamp: ev.created_at });
+ continue;
+ }
+ const targetId = getTargetEventId(ev);
+ if (!targetId) continue;
+ const resolved = eventsById.get(targetId);
+ if (resolved && resolved.created_at <= now) {
+ items.push({ event: resolved, repostedBy: ev.pubkey, repostEvent: ev, sortTimestamp: ev.created_at });
+ } else {
+ queueMissing(targetId, { type: 'repost', event: ev });
+ }
+ } else if (isReactionKind(ev.kind)) {
+ // Kind 7 — reaction. The target is in the last `e` tag (NIP-25).
+ const eTags = ev.tags.filter(([n]) => n === 'e');
+ const targetId = eTags[eTags.length - 1]?.[1];
+ if (!targetId) continue;
+ const resolved = eventsById.get(targetId);
+ if (resolved && resolved.created_at <= now) {
+ items.push({
+ event: resolved,
+ reactedBy: { event: ev, pubkey: ev.pubkey },
+ sortTimestamp: ev.created_at,
+ });
+ } else {
+ queueMissing(targetId, { type: 'reaction', event: ev });
+ }
+ } else if (isZapKind(ev.kind)) {
+ // Kind 9735 Lightning receipt or kind 8333 on-chain attestation.
+ const targetId = getTargetEventId(ev);
+ if (!targetId) continue;
+ const senderPubkey = getZapSenderPubkey(ev);
+ const sats = getZapAmountSats(ev);
+ const resolved = eventsById.get(targetId);
+ if (resolved && resolved.created_at <= now) {
+ items.push({
+ event: resolved,
+ zappedBy: { event: ev, pubkey: senderPubkey, sats },
+ sortTimestamp: ev.created_at,
+ });
+ } else {
+ queueMissing(targetId, { type: 'zap', event: ev });
+ }
+ } else {
+ // Direct post — kind 1, 1068, 34236, etc.
+ items.push({ event: ev, sortTimestamp: ev.created_at });
+ }
+ }
+
+ // Single batched fetch for all missing target events.
+ if (missingTargets.size > 0) {
+ try {
+ const ids = [...missingTargets.keys()];
+ const originals = await nostr.query(
+ [{ ids, limit: ids.length }],
+ { signal },
+ );
+ for (const original of originals) {
+ if (original.created_at > now) continue;
+ const wrappers = missingTargets.get(original.id);
+ if (!wrappers) continue;
+ for (const w of wrappers) {
+ if (w.type === 'repost') {
+ items.push({ event: original, repostedBy: w.event.pubkey, repostEvent: w.event, sortTimestamp: w.event.created_at });
+ } else if (w.type === 'reaction') {
+ items.push({
+ event: original,
+ reactedBy: { event: w.event, pubkey: w.event.pubkey },
+ sortTimestamp: w.event.created_at,
+ });
+ } else {
+ items.push({
+ event: original,
+ zappedBy: {
+ event: w.event,
+ pubkey: getZapSenderPubkey(w.event),
+ sats: getZapAmountSats(w.event),
+ },
+ sortTimestamp: w.event.created_at,
+ });
+ }
+ }
+ }
+ } catch {
+ // timeout or abort — just skip wrappers whose targets couldn't be fetched
+ }
+ }
+
+ return items;
+ }
+
+ /**
+ * Deduplicate FeedItems by event id. Direct posts win over any
+ * overlay (repost / reaction / zap), so the user sees the original
+ * once with full action buttons rather than as a passive overlay.
+ */
+ function dedupeFeedItems(items: FeedItem[]): FeedItem[] {
+ const seen = new Map();
+ for (const item of items) {
+ const existing = seen.get(item.event.id);
+ const isDirect = !item.repostedBy && !item.reactedBy && !item.zappedBy;
+ if (!existing) {
+ seen.set(item.event.id, item);
+ } else if (isDirect && (existing.repostedBy || existing.reactedBy || existing.zappedBy)) {
+ seen.set(item.event.id, item);
+ }
+ }
+ return Array.from(seen.values()).sort((a, b) => b.sortTimestamp - a.sortTimestamp);
+ }
+
if (tab === 'communities' && communityPubkeys.length > 0) {
// Communities feed — posts from community members with NIP-05 verification
const fetchLimit = !feedSettings.followsFeedShowReplies ? PAGE_SIZE * OVER_FETCH_MULTIPLIER : PAGE_SIZE;
@@ -180,64 +333,17 @@ export function useFeed(tab: 'follows' | 'global' | 'communities', options?: Use
const validFilteredEvents = filteredEvents.filter((ev) => ev.created_at <= now);
const oldestQueryTimestamp = getPaginationCursor(validFilteredEvents);
- // Process reposts same as follows feed
- const items: FeedItem[] = [];
- const repostMissingIds: string[] = [];
- const repostMap = new Map();
+ // Unwrap reposts / reactions / zaps so the target event renders
+ // with the wrapper as an overlay header.
+ const items = await buildFeedItems(validFilteredEvents);
- for (const ev of validFilteredEvents) {
- if (isRepostKind(ev.kind)) {
- // Handle reposts (kind 6 for notes, kind 16 for generic)
- const embedded = parseRepostContent(ev);
- if (embedded && embedded.created_at <= now) {
- items.push({ event: embedded, repostedBy: ev.pubkey, sortTimestamp: ev.created_at });
- } else {
- const repostedId = ev.tags.find(([name]) => name === 'e')?.[1];
- if (repostedId) {
- repostMissingIds.push(repostedId);
- repostMap.set(repostedId, ev);
- }
- }
- } else {
- // Kind 1 and extra kinds — direct post
- items.push({ event: ev, sortTimestamp: ev.created_at });
- }
- }
-
- // Fetch any missing reposted events in a single query
- if (repostMissingIds.length > 0) {
- try {
- const originals = await nostr.query(
- [{ ids: repostMissingIds, limit: repostMissingIds.length }],
- { signal },
- );
- for (const original of originals) {
- const repost = repostMap.get(original.id);
- if (repost && original.created_at <= now) {
- items.push({ event: original, repostedBy: repost.pubkey, sortTimestamp: repost.created_at });
- }
- }
- } catch {
- // timeout or abort — just skip the missing reposts
- }
- }
-
- // Deduplicate
- const seen = new Map();
- for (const item of items) {
- const existing = seen.get(item.event.id);
- if (!existing) {
- seen.set(item.event.id, item);
- } else if (!item.repostedBy && existing.repostedBy) {
- seen.set(item.event.id, item);
- }
- }
-
- let dedupedItems = Array.from(seen.values()).sort((a, b) => b.sortTimestamp - a.sortTimestamp);
+ let dedupedItems = dedupeFeedItems(items);
// Filter replies if the user has disabled them
if (!feedSettings.followsFeedShowReplies) {
- dedupedItems = dedupedItems.filter((item) => item.repostedBy || !isReplyEvent(item.event));
+ dedupedItems = dedupedItems.filter(
+ (item) => item.repostedBy || item.reactedBy || item.zappedBy || !isReplyEvent(item.event),
+ );
}
// Seed event cache so embedded note previews resolve instantly.
@@ -268,63 +374,17 @@ export function useFeed(tab: 'follows' | 'global' | 'communities', options?: Use
const validEvents = rawEvents.filter((ev) => ev.created_at <= now);
const oldestQueryTimestamp = getPaginationCursor(validEvents);
- const items: FeedItem[] = [];
- const repostMissingIds: string[] = [];
- const repostMap = new Map();
+ // Unwrap reposts / reactions / zaps so the target event renders
+ // with the wrapper as an overlay header.
+ const items = await buildFeedItems(validEvents);
- for (const ev of validEvents) {
- if (isRepostKind(ev.kind)) {
- // Handle reposts (kind 6 for notes, kind 16 for generic)
- const embedded = parseRepostContent(ev);
- if (embedded && embedded.created_at <= now) {
- items.push({ event: embedded, repostedBy: ev.pubkey, sortTimestamp: ev.created_at });
- } else {
- const repostedId = ev.tags.find(([name]) => name === 'e')?.[1];
- if (repostedId) {
- repostMissingIds.push(repostedId);
- repostMap.set(repostedId, ev);
- }
- }
- } else {
- // Kind 1, 1068, 3367, 34236, 37516, etc. — direct post / extra kinds
- items.push({ event: ev, sortTimestamp: ev.created_at });
- }
- }
-
- // Fetch any missing reposted events in a single query
- if (repostMissingIds.length > 0) {
- try {
- const originals = await nostr.query(
- [{ ids: repostMissingIds, limit: repostMissingIds.length }],
- { signal },
- );
- for (const original of originals) {
- const repost = repostMap.get(original.id);
- if (repost && original.created_at <= now) {
- items.push({ event: original, repostedBy: repost.pubkey, sortTimestamp: repost.created_at });
- }
- }
- } catch {
- // timeout or abort — just skip the missing reposts
- }
- }
-
- // Deduplicate
- const seen = new Map();
- for (const item of items) {
- const existing = seen.get(item.event.id);
- if (!existing) {
- seen.set(item.event.id, item);
- } else if (!item.repostedBy && existing.repostedBy) {
- seen.set(item.event.id, item);
- }
- }
-
- let dedupedItems = Array.from(seen.values()).sort((a, b) => b.sortTimestamp - a.sortTimestamp);
+ let dedupedItems = dedupeFeedItems(items);
// Filter replies if the user has disabled them
if (!feedSettings.followsFeedShowReplies) {
- dedupedItems = dedupedItems.filter((item) => item.repostedBy || !isReplyEvent(item.event));
+ dedupedItems = dedupedItems.filter(
+ (item) => item.repostedBy || item.reactedBy || item.zappedBy || !isReplyEvent(item.event),
+ );
}
// Seed event cache so embedded note previews resolve instantly.
@@ -332,8 +392,10 @@ export function useFeed(tab: 'follows' | 'global' | 'communities', options?: Use
return { items: dedupedItems, oldestQueryTimestamp, rawCount: validEvents.length };
} else {
- // Global feed — all enabled kinds except reposts (too noisy without author filter)
- const globalKinds = allKinds.filter((k) => !isRepostKind(k));
+ // Global feed — all enabled kinds except reposts / reactions / zaps,
+ // which are too noisy without an author filter and require an extra
+ // unwrap step. Users will see those overlays on the Follows tab.
+ const globalKinds = allKinds.filter((k) => !isRepostKind(k) && !isReactionKind(k) && !isZapKind(k));
const filter: Record = { kinds: globalKinds, limit: PAGE_SIZE, ...tagFilters };
// Use hot sorting on the homepage Global tab for better content quality,
// but not on kind-specific pages that pass custom kinds.
diff --git a/src/hooks/useProfileFeed.ts b/src/hooks/useProfileFeed.ts
index 2ab25b4e..27483719 100644
--- a/src/hooks/useProfileFeed.ts
+++ b/src/hooks/useProfileFeed.ts
@@ -149,7 +149,7 @@ export function useProfileFeed(pubkey: string | undefined, activeTab: ProfileTab
// Handle reposts (kind 6 for notes, kind 16 for generic)
const embedded = parseRepostContent(ev);
if (embedded && embedded.created_at <= now) {
- items.push({ event: embedded, repostedBy: ev.pubkey, sortTimestamp: ev.created_at });
+ items.push({ event: embedded, repostedBy: ev.pubkey, repostEvent: ev, sortTimestamp: ev.created_at });
} else {
const repostedId = ev.tags.find(([name]) => name === 'e')?.[1];
if (repostedId) {
@@ -173,7 +173,7 @@ export function useProfileFeed(pubkey: string | undefined, activeTab: ProfileTab
for (const original of originals) {
const repost = repostMap.get(original.id);
if (repost && original.created_at <= now) {
- items.push({ event: original, repostedBy: repost.pubkey, sortTimestamp: repost.created_at });
+ items.push({ event: original, repostedBy: repost.pubkey, repostEvent: repost, sortTimestamp: repost.created_at });
}
}
} catch {
@@ -360,7 +360,7 @@ export function useTabFeed(
if (isRepostKind(ev.kind)) {
const embedded = parseRepostContent(ev);
if (embedded && embedded.created_at <= now) {
- items.push({ event: embedded, repostedBy: ev.pubkey, sortTimestamp: ev.created_at });
+ items.push({ event: embedded, repostedBy: ev.pubkey, repostEvent: ev, sortTimestamp: ev.created_at });
} else {
const repostedId = ev.tags.find(([name]) => name === 'e')?.[1];
if (repostedId) {
@@ -382,7 +382,7 @@ export function useTabFeed(
for (const original of originals) {
const repost = repostMap.get(original.id);
if (repost && original.created_at <= now) {
- items.push({ event: original, repostedBy: repost.pubkey, sortTimestamp: repost.created_at });
+ items.push({ event: original, repostedBy: repost.pubkey, repostEvent: repost, sortTimestamp: repost.created_at });
}
}
} catch {
diff --git a/src/lib/extraKinds.ts b/src/lib/extraKinds.ts
index bf62c6d4..98ca2ddd 100644
--- a/src/lib/extraKinds.ts
+++ b/src/lib/extraKinds.ts
@@ -119,6 +119,29 @@ export const EXTRA_KINDS: ExtraKindDef[] = [
section: 'feed',
feedOnly: true,
},
+ {
+ kind: 7,
+ id: 'reactions',
+ feedKey: 'feedIncludeReactions',
+ label: 'Reactions',
+ description: 'People reacting to posts (likes and emoji reactions). Disabled by default.',
+ addressable: false,
+ section: 'feed',
+ feedOnly: true,
+ },
+ {
+ kind: 9735,
+ id: 'zaps',
+ feedKey: 'feedIncludeZaps',
+ // Combine Lightning (9735) and on-chain Bitcoin (8333) zaps into a single
+ // toggle so users don't have to think about which rail was used.
+ extraFeedKinds: [8333],
+ label: 'Zaps',
+ description: 'People zapping posts (Lightning and on-chain Bitcoin). Disabled by default.',
+ addressable: false,
+ section: 'feed',
+ feedOnly: true,
+ },
{
kind: 30023,
id: 'articles',
diff --git a/src/lib/feedUtils.ts b/src/lib/feedUtils.ts
index bbf633f7..46847a85 100644
--- a/src/lib/feedUtils.ts
+++ b/src/lib/feedUtils.ts
@@ -48,6 +48,22 @@ export function isRepostKind(kind: number): boolean {
return REPOST_KINDS.has(kind);
}
+/** The set of kind numbers that represent reactions. */
+export const REACTION_KINDS = new Set([7]);
+
+/** Check if a kind number is a reaction kind (7). */
+export function isReactionKind(kind: number): boolean {
+ return REACTION_KINDS.has(kind);
+}
+
+/** The set of kind numbers that represent zap events (Lightning + on-chain). */
+export const ZAP_KINDS = new Set([9735, 8333]);
+
+/** Check if a kind number is a zap kind (9735 Lightning or 8333 on-chain). */
+export function isZapKind(kind: number): boolean {
+ return ZAP_KINDS.has(kind);
+}
+
/**
* Returns the correct repost kind for a given event.
* Kind 6 is only for reposting kind 1 text notes; kind 16 is for everything else.
@@ -56,16 +72,52 @@ export function getRepostKind(originalEventKind: number): number {
return originalEventKind === 1 ? 6 : 16;
}
-/** A feed item — either a direct post or a repost wrapping the original event. */
+/** Overlay describing a reaction (kind 7) made to a target event. */
+export interface ReactionOverlay {
+ /** The reaction event itself (used for linking to the underlying nevent). */
+ event: NostrEvent;
+ /** Pubkey of the person who reacted. */
+ pubkey: string;
+}
+
+/** Overlay describing a zap (kind 9735 Lightning or kind 8333 on-chain). */
+export interface ZapOverlay {
+ /** The zap event itself (used for linking to the underlying nevent). */
+ event: NostrEvent;
+ /** Pubkey of the sender (resolved through P-tag / description / event.pubkey). */
+ pubkey: string;
+ /** Zap amount in sats. May be 0 if unparseable. */
+ sats: number;
+}
+
+/** A feed item — either a direct post, a repost, a reaction, or a zap wrapping the original event. */
export interface FeedItem {
- /** The event to display (original note). */
+ /** The event to display (original note / target event). */
event: NostrEvent;
/** If this item is a repost, the pubkey of the person who reposted it. */
repostedBy?: string;
- /** Sort timestamp — uses the repost timestamp when present for correct ordering. */
+ /** If this item is a repost and we have the wrapper event, the kind 6 / 16 repost event itself (used for linking "reposted" to its nevent). */
+ repostEvent?: NostrEvent;
+ /** If this item is a reaction overlay, the reaction event + actor pubkey. */
+ reactedBy?: ReactionOverlay;
+ /** If this item is a zap overlay, the zap event + sender pubkey + amount. */
+ zappedBy?: ZapOverlay;
+ /** Sort timestamp — uses the wrapper event's timestamp when present for correct ordering. */
sortTimestamp: number;
}
+/**
+ * Compute a stable React key / dedup key for a feed item. The same target
+ * event can appear with multiple wrappers (a repost AND a reaction AND a
+ * zap), so the key incorporates the wrapper event id when present.
+ */
+export function feedItemKey(item: FeedItem): string {
+ if (item.reactedBy) return `reaction-${item.reactedBy.event.id}-${item.event.id}`;
+ if (item.zappedBy) return `zap-${item.zappedBy.event.id}-${item.event.id}`;
+ if (item.repostedBy) return `repost-${item.repostedBy}-${item.event.id}`;
+ return item.event.id;
+}
+
/** d-tags reserved by NIP-51 for other purposes — hide these kind 30000 events from feeds. */
const DEPRECATED_DTAGS = new Set(['mute', 'pin', 'bookmark', 'communities']);
diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts
index 37d0be47..c04206aa 100644
--- a/src/lib/schemas.ts
+++ b/src/lib/schemas.ts
@@ -137,6 +137,8 @@ export const FeedSettingsSchema = z.looseObject({
feedIncludeComments: z.boolean().optional(),
feedIncludeReposts: z.boolean().optional(),
feedIncludeGenericReposts: z.boolean().optional(),
+ feedIncludeReactions: z.boolean().optional(),
+ feedIncludeZaps: z.boolean().optional(),
feedIncludeArticles: z.boolean().optional(),
showArticles: z.boolean().optional(),
showHighlights: z.boolean().optional(),
diff --git a/src/lib/sidebarItems.tsx b/src/lib/sidebarItems.tsx
index c7e11e3f..cb42af6a 100644
--- a/src/lib/sidebarItems.tsx
+++ b/src/lib/sidebarItems.tsx
@@ -38,6 +38,7 @@ import {
Stars,
TrendingUp,
User,
+ Zap,
} from "lucide-react";
import { CardsIcon } from "@/components/icons/CardsIcon";
import { ChestIcon } from "@/components/icons/ChestIcon";
@@ -214,6 +215,8 @@ export const CONTENT_KIND_ICONS: Record = {
comments: MessageSquareMore,
reposts: Repeat2,
"generic-reposts": Repeat2,
+ reactions: SmilePlus,
+ zaps: Zap,
voice: Mic,
"custom-emojis": Smile,
statuses: SmilePlus,
diff --git a/src/pages/FollowPage.tsx b/src/pages/FollowPage.tsx
index e6ada370..118ae5a7 100644
--- a/src/pages/FollowPage.tsx
+++ b/src/pages/FollowPage.tsx
@@ -155,6 +155,7 @@ function ProfileFeed({ pubkey }: { pubkey: string }) {
key={item.repostedBy ? `repost-${item.repostedBy}-${item.event.id}` : item.event.id}
event={item.event}
repostedBy={item.repostedBy}
+ repostEvent={item.repostEvent}
compact
/>
))}
diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx
index 1501ffe0..a80aed71 100644
--- a/src/pages/ProfilePage.tsx
+++ b/src/pages/ProfilePage.tsx
@@ -2645,6 +2645,7 @@ type EditableTab = { label: string; isCore: boolean; tab?: ProfileTab };
key={item.repostedBy ? `repost-${item.repostedBy}-${item.event.id}` : item.event.id}
event={item.event}
repostedBy={item.repostedBy}
+ repostEvent={item.repostEvent}
/>
))}
@@ -3151,6 +3152,7 @@ function ProfileSavedFeedContent({ feed, vars, ownerPubkey }: {
key={item.repostedBy ? `repost-${item.repostedBy}-${item.event.id}` : item.event.id}
event={item.event}
repostedBy={item.repostedBy}
+ repostEvent={item.repostEvent}
/>
))}
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index fad83e12..56551c86 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -805,7 +805,7 @@ export function SearchPage() {
if (isRepostKind(event.kind)) {
const embedded = parseRepostContent(event);
if (embedded) {
- return ;
+ return ;
}
return null;
}
diff --git a/src/test/TestApp.tsx b/src/test/TestApp.tsx
index ff3aa5f3..8c170b14 100644
--- a/src/test/TestApp.tsx
+++ b/src/test/TestApp.tsx
@@ -38,6 +38,8 @@ export function TestApp({ children }: TestAppProps) {
feedIncludeComments: true,
feedIncludeReposts: true,
feedIncludeGenericReposts: true,
+ feedIncludeReactions: false,
+ feedIncludeZaps: false,
feedIncludeArticles: false,
showArticles: false,
showHighlights: false,