diff --git a/src/components/CommentContext.tsx b/src/components/CommentContext.tsx
index ccc24ee6..9bc1abd4 100644
--- a/src/components/CommentContext.tsx
+++ b/src/components/CommentContext.tsx
@@ -60,14 +60,14 @@ function getEventDisplayName(event: NostrEvent): string {
const title = event.tags.find(([name]) => name === 'title')?.[1];
if (title) return title;
+ // Try name tag (used by communities, emoji packs, etc.)
+ const name = event.tags.find(([name]) => name === 'name')?.[1];
+ if (name) return name;
+
// Try d tag (addressable events use this as an identifier)
const dTag = event.tags.find(([name]) => name === 'd')?.[1];
if (dTag) return dTag;
- // Try name tag (used by some events)
- const name = event.tags.find(([name]) => name === 'name')?.[1];
- if (name) return name;
-
// Fall back to kind label from EXTRA_KINDS
const kindDef = EXTRA_KINDS.find((def) =>
def.subKinds?.some((sub) => sub.kind === event.kind) || def.kind === event.kind,
@@ -181,10 +181,13 @@ function ProfileCommentContext({ pubkey, className }: { pubkey: string; classNam
function GenericAddrCommentContext({ root, className }: { root: CommentRoot; className?: string }) {
const { data: event, isLoading } = useAddrEvent(root.addr);
+ const isCommunity = root.rootKind === '34550' || root.addr?.kind === 34550;
+ const prefix = isCommunity ? 'Posted in' : 'Commenting on';
+
if (isLoading) {
return (
-
Commenting on
+
{prefix}
{link ? (
n === 'name')?.[1]
+ || event?.tags.find(([n]) => n === 'd')?.[1]
+ || 'Community';
+ const communityImage = event?.tags.find(([n]) => n === 'image')?.[1];
+ const communityDescription = event?.tags.find(([n]) => n === 'description')?.[1];
+ const moderatorCount = event?.tags.filter(([n, , , role]) => n === 'p' && role === 'moderator').length ?? 0;
+
+ const link = useMemo(() => {
+ return `/${nip19.naddrEncode({ kind: addr.kind, pubkey: addr.pubkey, identifier: addr.identifier })}`;
+ }, [addr]);
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {communityImage ? (
+

+ ) : (
+
+
+
+ )}
+
+
+
+
+ Community
+ {moderatorCount > 0 && (
+ · {moderatorCount} mod{moderatorCount !== 1 ? 's' : ''}
+ )}
+
+
+ {communityName}
+
+ {communityDescription && (
+
+ {communityDescription}
+
+ )}
+
+
+ );
+}
+
export function ProfilePreview({ pubkey }: { pubkey: string }) {
const author = useAuthor(pubkey);
const metadata = author.data?.metadata;
diff --git a/src/pages/PostDetailPage.tsx b/src/pages/PostDetailPage.tsx
index a5b920dc..6267ab0b 100644
--- a/src/pages/PostDetailPage.tsx
+++ b/src/pages/PostDetailPage.tsx
@@ -71,7 +71,7 @@ import { ProfileHoverCard } from '@/components/ProfileHoverCard';
import { useProfileUrl } from '@/hooks/useProfileUrl';
import { ContentWarningGuard } from '@/components/ContentWarningGuard';
import { MutedContentGuard } from '@/components/MutedContentGuard';
-import { ExternalContentPreview, ProfilePreview } from '@/components/ExternalContentHeader';
+import { ExternalContentPreview, ProfilePreview, CommunityPreview } from '@/components/ExternalContentHeader';
import { getParentEventId, isReplyEvent } from '@/lib/nostrEvents';
import { EmojiPackContent } from '@/components/EmojiPackContent';
import { CommunityContent } from '@/components/CommunityContent';
@@ -851,6 +851,21 @@ function PostDetailContent({ event }: { event: NostrEvent }) {
return parts[1] || undefined;
}, [event, isComment]);
+ // For kind 1111 comments on a community (kind 34550), extract the addr for the community preview
+ const communityRootAddr = useMemo(() => {
+ if (!isComment) return undefined;
+ const kTag = event.tags.find(([n]) => n === 'K')?.[1];
+ if (kTag !== '34550') return undefined;
+ const aTag = event.tags.find(([n]) => n === 'A')?.[1];
+ if (!aTag) return undefined;
+ const parts = aTag.split(':');
+ const kind = parseInt(parts[0], 10);
+ const pubkey = parts[1];
+ const identifier = parts.slice(2).join(':');
+ if (!pubkey || isNaN(kind)) return undefined;
+ return { kind, pubkey, identifier };
+ }, [event, isComment]);
+
// Keep the focused post pinned to top while ancestor content loads above it.
// A ResizeObserver on the ancestor container re-scrolls on every layout shift
// (image loads, skeleton→content swaps) for the first few seconds.
@@ -900,13 +915,16 @@ function PostDetailContent({ event }: { event: NostrEvent }) {
return (
- {/* Content preview for kind 1111 comments: external content or profile */}
+ {/* Content preview for kind 1111 comments: external content, profile, or community */}
{externalIdentifier && (
)}
{profileRootPubkey && (
)}
+ {communityRootAddr && (
+
+ )}
{/* Ancestor thread chain if this is a reply */}
{parentEventId && (