From 73de36a5440f83caba6d6a9eb7d4f5a3da7ba80b Mon Sep 17 00:00:00 2001 From: Alejandro Date: Mon, 12 Jan 2026 17:46:41 +0100 Subject: [PATCH] Render NIP-29 group metadata as links (#63) * feat: add GroupMetadataRenderer for NIP-29 group metadata (kind 39000) Render kind 39000 events with group name, picture, description, and an "Open Chat" link that opens the NIP-29 group in the chat viewer. * feat: add kind names for NIP-29 group events and simplify renderer - Add kind 39000 (Group), 39001 (Group Admins), 39002 (Group Members) to EVENT_KINDS so kind badge displays proper names - Simplify GroupMetadataRenderer to show only title, description, and Open Chat CTA (remove group picture) --------- Co-authored-by: Claude --- .../nostr/kinds/GroupMetadataRenderer.tsx | 66 +++++++++++++++++++ src/components/nostr/kinds/index.tsx | 2 + src/constants/kinds.ts | 21 ++++++ 3 files changed, 89 insertions(+) create mode 100644 src/components/nostr/kinds/GroupMetadataRenderer.tsx diff --git a/src/components/nostr/kinds/GroupMetadataRenderer.tsx b/src/components/nostr/kinds/GroupMetadataRenderer.tsx new file mode 100644 index 0000000..461d8f6 --- /dev/null +++ b/src/components/nostr/kinds/GroupMetadataRenderer.tsx @@ -0,0 +1,66 @@ +import type { NostrEvent } from "@/types/nostr"; +import { getTagValue } from "applesauce-core/helpers"; +import { getSeenRelays } from "applesauce-core/helpers/relays"; +import { BaseEventContainer, ClickableEventTitle } from "./BaseEventRenderer"; +import { useGrimoire } from "@/core/state"; +import { MessageSquare } from "lucide-react"; + +interface GroupMetadataRendererProps { + event: NostrEvent; +} + +/** + * Renderer for NIP-29 Group Metadata events (kind 39000) + * Displays group info and links to chat + */ +export function GroupMetadataRenderer({ event }: GroupMetadataRendererProps) { + const { addWindow } = useGrimoire(); + + // Extract group metadata + const groupId = getTagValue(event, "d") || ""; + const name = getTagValue(event, "name") || groupId; + const about = getTagValue(event, "about"); + + // Get relay URL from where we saw this event + const seenRelaysSet = getSeenRelays(event); + const relayUrl = seenRelaysSet?.values().next().value; + + const handleOpenChat = () => { + if (!relayUrl) return; + + addWindow("chat", { + protocol: "nip-29", + identifier: { + type: "group", + value: groupId, + relays: [relayUrl], + }, + }); + }; + + const canOpenChat = !!relayUrl && !!groupId; + + return ( + +
+ + {name} + + + {about && ( +

{about}

+ )} + + {canOpenChat && ( + + )} +
+
+ ); +} diff --git a/src/components/nostr/kinds/index.tsx b/src/components/nostr/kinds/index.tsx index 2af9d0f..a5833b0 100644 --- a/src/components/nostr/kinds/index.tsx +++ b/src/components/nostr/kinds/index.tsx @@ -61,6 +61,7 @@ import { ZapstoreAppSetRenderer } from "./ZapstoreAppSetRenderer"; import { ZapstoreAppSetDetailRenderer } from "./ZapstoreAppSetDetailRenderer"; import { ZapstoreReleaseRenderer } from "./ZapstoreReleaseRenderer"; import { ZapstoreReleaseDetailRenderer } from "./ZapstoreReleaseDetailRenderer"; +import { GroupMetadataRenderer } from "./GroupMetadataRenderer"; import { NostrEvent } from "@/types/nostr"; import { BaseEventContainer, type BaseEventProps } from "./BaseEventRenderer"; @@ -116,6 +117,7 @@ const kindRenderers: Record> = { 31989: HandlerRecommendationRenderer, // Handler Recommendation (NIP-89) 31990: ApplicationHandlerRenderer, // Application Handler (NIP-89) 32267: ZapstoreAppRenderer, // Zapstore App + 39000: GroupMetadataRenderer, // Group Metadata (NIP-29) 39701: Kind39701Renderer, // Web Bookmarks (NIP-B0) }; diff --git a/src/constants/kinds.ts b/src/constants/kinds.ts index 9bc78e6..fd62988 100644 --- a/src/constants/kinds.ts +++ b/src/constants/kinds.ts @@ -1415,6 +1415,27 @@ export const EVENT_KINDS: Record = { nip: "51", icon: Play, }, + 39000: { + kind: 39000, + name: "Group", + description: "Group Metadata", + nip: "29", + icon: Users, + }, + 39001: { + kind: 39001, + name: "Group Admins", + description: "Group Admins List", + nip: "29", + icon: UserCheck, + }, + 39002: { + kind: 39002, + name: "Group Members", + description: "Group Members List", + nip: "29", + icon: Users, + }, 39701: { kind: 39701, name: "Web Bookmark",