diff --git a/AGENTS.md b/AGENTS.md index 87b2be74..7409667d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -289,16 +289,14 @@ When adding support for a new Nostr event kind to the application, the kind must - Add the kind number to an existing feed definition's `extraFeedKinds` array, or create a new `ExtraKindDef` entry 5. **Kind label registries** -- these are separate maps that resolve kind numbers to human-readable strings. All must be updated: - - `getKindLabel()` in `src/components/CommentContext.tsx` -- used for "Commenting on an nsite" text + - `KIND_LABELS` and `KIND_ICONS` in `src/components/CommentContext.tsx` -- used for "Commenting on an nsite" text and inline icons - `WELL_KNOWN_KIND_LABELS` in `src/components/ExternalContentHeader.tsx` -- used in addressable event preview headers - The icon fallback in `AddressableEventPreview` in the same file -6. **Inline embeds / quote posts** -- events can be quoted inline via `nostr:nevent1...` or `nostr:naddr1...` URIs in note content: - - `src/components/EmbeddedNote.tsx` -- for non-addressable kinds: add to `NOTECARD_KINDS` set so it renders the full NoteCard (with your card component inside) instead of trying to show `event.content` as text - - `src/components/EmbeddedNaddr.tsx` -- for addressable kinds: same pattern, add to `NOTECARD_KINDS` +6. **Inline embeds / quote posts** -- events can be quoted inline via `nostr:nevent1...` or `nostr:naddr1...` URIs in note content. Both `EmbeddedNote` and `EmbeddedNaddr` render a compact card (author + title/content preview) for all kinds automatically — no per-kind registration needed. The same components are reused by CommentContext hover cards and the reply composer. 7. **Reply composer** (`src/components/ReplyComposeModal.tsx`): - - Add a kind check in the `EmbeddedPost` component so the reply-to preview shows the card component instead of empty/raw content + - The `EmbeddedPost` component delegates to the shared `EmbeddedNote`/`EmbeddedNaddr` components — no per-kind registration needed #### Why so many places? diff --git a/src/components/EmbeddedNaddr.tsx b/src/components/EmbeddedNaddr.tsx index 8adfaf43..7948c2ca 100644 --- a/src/components/EmbeddedNaddr.tsx +++ b/src/components/EmbeddedNaddr.tsx @@ -6,7 +6,6 @@ import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { getAvatarShape } from '@/lib/avatarShape'; import { Skeleton } from '@/components/ui/skeleton'; import { EmojifiedText } from '@/components/CustomEmoji'; -import { NoteCard } from '@/components/NoteCard'; import { parseBadgeDefinition } from '@/components/BadgeContent'; import { useAddrEvent, type AddrCoords } from '@/hooks/useEvent'; import { useAuthor } from '@/hooks/useAuthor'; @@ -15,9 +14,6 @@ import { timeAgo } from '@/lib/timeAgo'; import { cn } from '@/lib/utils'; import type { NostrEvent } from '@nostrify/nostrify'; -/** Kinds that render as a full NoteCard instead of a generic embed. */ -const NOTECARD_KINDS = new Set([30000, 39089, 35128]); - interface EmbeddedNaddrProps { /** The decoded naddr coordinates. */ addr: AddrCoords; @@ -72,15 +68,6 @@ export function EmbeddedNaddr({ addr, className }: EmbeddedNaddrProps) { return ; } - // For follow packs / starter packs, render the same NoteCard used in feeds (without actions) - if (NOTECARD_KINDS.has(event.kind)) { - return ( -
e.stopPropagation()}> - -
- ); - } - // Badge definitions get a compact showcase instead of a link-preview card if (event.kind === 30009) { return ; diff --git a/src/components/EmbeddedNote.tsx b/src/components/EmbeddedNote.tsx index 4e3ce7b6..d46e6add 100644 --- a/src/components/EmbeddedNote.tsx +++ b/src/components/EmbeddedNote.tsx @@ -6,7 +6,6 @@ import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { getAvatarShape } from '@/lib/avatarShape'; import { Skeleton } from '@/components/ui/skeleton'; import { EmojifiedText } from '@/components/CustomEmoji'; -import { NoteCard } from '@/components/NoteCard'; import { ProfileHoverCard } from '@/components/ProfileHoverCard'; import { VanishCardCompact } from '@/components/VanishEventContent'; import { useEvent } from '@/hooks/useEvent'; @@ -21,9 +20,6 @@ import { IMAGE_URL_REGEX, IMETA_MEDIA_URL_REGEX, extractVideoUrls, extractAudioU /** NIP-62 Request to Vanish. */ const VANISH_KIND = 62; -/** Kinds that render as a full NoteCard instead of the generic embed card. */ -const NOTECARD_KINDS = new Set([30000, 39089, 15128]); - /** Bech32 charset used by NIP-19 identifiers. */ const B32 = '023456789acdefghjklmnpqrstuvwxyz'; @@ -95,15 +91,6 @@ export function EmbeddedNote({ eventId, relays, authorHint, className, disableHo return ; } - // For follow packs / lists, render the same rich NoteCard used in feeds - if (NOTECARD_KINDS.has(event.kind)) { - return ( -
e.stopPropagation()}> - -
- ); - } - // NIP-62 vanish events get their own dramatic inline card if (event.kind === VANISH_KIND) { return ; @@ -149,6 +136,16 @@ function EmbeddedNoteCard({ return cleaned.slice(0, MAX_CONTENT_LENGTH).trimEnd() + '…'; }, [event.content]); + // For non-text kinds with empty content, extract title/description from tags + const tagMeta = useMemo(() => { + if (truncatedContent) return undefined; + const getTag = (name: string) => event.tags.find(([n]) => n === name)?.[1]; + const title = getTag('title') || getTag('name') || getTag('d'); + const description = getTag('summary') || getTag('description'); + if (!title && !description) return undefined; + return { title, description }; + }, [truncatedContent, event.tags]); + // Extract first image for a small thumbnail const firstImage = useMemo(() => { return event.content.match(IMAGE_URL_REGEX)?.[0] ?? null; @@ -255,13 +252,22 @@ function EmbeddedNoteCard({ - {/* Content warning notice or text preview */} + {/* Content warning notice or text preview or tag-based metadata */} {hasCW && config.contentWarningPolicy === 'blur' ? (

Content warning{cwTag?.[1] ? <>{' '}“{cwTag[1]}” : ''}

) : truncatedContent ? ( + ) : tagMeta ? ( + <> + {tagMeta.title && ( +

{tagMeta.title}

+ )} + {tagMeta.description && ( +

{tagMeta.description}

+ )} + ) : null} {/* Attachment indicators for stripped media/links */}