mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-06-16 17:48:34 +02:00
feat(chat): add chat menu option to all events with NIP-22 support
- Remove restriction that limited "Chat" menu option to kind 1 events only - Add support for opening chat on any event using NIP-22 adapter - Special handling for kind 1111 comments: extracts root event and opens chat with root - For all other events: encodes as nevent/naddr and lets adapter priority system auto-detect protocol - Properly converts CommentPointer types (from getCommentReplyPointer) to standard nip19 pointer formats - Updates both EventMenu (dropdown) and EventContextMenu (right-click) with same functionality - Allows users to view threaded discussions for any Nostr event type
This commit is contained in:
@@ -36,6 +36,8 @@ import { nip19 } from "nostr-tools";
|
||||
import { getTagValue } from "applesauce-core/helpers";
|
||||
import { parseAddressPointer } from "@/lib/nip89-helpers";
|
||||
import { getSeenRelays } from "applesauce-core/helpers/relays";
|
||||
import { getCommentReplyPointer } from "applesauce-common/helpers";
|
||||
import { parseChatCommand } from "@/lib/chat-parser";
|
||||
import { EventFooter } from "@/components/EventFooter";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { isAddressableKind } from "@/lib/nostr-kinds";
|
||||
@@ -214,25 +216,86 @@ export function EventMenu({
|
||||
};
|
||||
|
||||
const openChatWindow = () => {
|
||||
// Only kind 1 notes support NIP-10 thread chat
|
||||
if (event.kind === 1) {
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
// Special handling for kind 1111 comments - open chat with root event
|
||||
if (event.kind === 1111) {
|
||||
const rootPointer = getCommentReplyPointer(event);
|
||||
if (rootPointer) {
|
||||
// Encode root as nevent/naddr and parse
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
// Open chat with NIP-10 thread protocol
|
||||
addWindow("chat", {
|
||||
protocol: "nip-10",
|
||||
identifier: {
|
||||
type: "thread",
|
||||
value: {
|
||||
id: event.id,
|
||||
relays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
let encoded: string;
|
||||
// Convert CommentPointer to standard nip19 pointer types
|
||||
if (
|
||||
rootPointer.type === "address" &&
|
||||
rootPointer.pubkey &&
|
||||
rootPointer.identifier !== undefined
|
||||
) {
|
||||
// CommentAddressPointer -> AddressPointer
|
||||
encoded = nip19.naddrEncode({
|
||||
kind: rootPointer.kind,
|
||||
pubkey: rootPointer.pubkey,
|
||||
identifier: rootPointer.identifier,
|
||||
relays: rootPointer.relay ? [rootPointer.relay, ...relays] : relays,
|
||||
});
|
||||
} else if (rootPointer.type === "event" && rootPointer.id) {
|
||||
// CommentEventPointer -> EventPointer
|
||||
encoded = nip19.neventEncode({
|
||||
id: rootPointer.id,
|
||||
relays: rootPointer.relay ? [rootPointer.relay, ...relays] : relays,
|
||||
author: rootPointer.pubkey,
|
||||
kind: rootPointer.kind,
|
||||
});
|
||||
} else {
|
||||
console.error("Unsupported comment root pointer type:", rootPointer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and open
|
||||
try {
|
||||
const result = parseChatCommand([encoded]);
|
||||
addWindow("chat", {
|
||||
protocol: result.protocol,
|
||||
identifier: result.identifier,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to open chat for comment root:", err);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For all other events, encode as nevent/naddr and let parser detect protocol
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
let encoded: string;
|
||||
if (isAddressableKind(event.kind)) {
|
||||
const dTag = getTagValue(event, "d") || "";
|
||||
encoded = nip19.naddrEncode({
|
||||
kind: event.kind,
|
||||
pubkey: event.pubkey,
|
||||
identifier: dTag,
|
||||
relays: relays,
|
||||
});
|
||||
} else {
|
||||
encoded = nip19.neventEncode({
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
relays: relays,
|
||||
});
|
||||
}
|
||||
|
||||
// Parse and open
|
||||
try {
|
||||
const result = parseChatCommand([encoded]);
|
||||
addWindow("chat", {
|
||||
protocol: result.protocol,
|
||||
identifier: result.identifier,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to open chat for event:", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -252,12 +315,10 @@ export function EventMenu({
|
||||
<Zap className="size-4 mr-2 text-yellow-500" />
|
||||
Zap
|
||||
</DropdownMenuItem>
|
||||
{event.kind === 1 && (
|
||||
<DropdownMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</DropdownMenuItem>
|
||||
{canSign && onReactClick && (
|
||||
<DropdownMenuItem onClick={onReactClick}>
|
||||
<SmilePlus className="size-4 mr-2" />
|
||||
@@ -384,25 +445,86 @@ export function EventContextMenu({
|
||||
};
|
||||
|
||||
const openChatWindow = () => {
|
||||
// Only kind 1 notes support NIP-10 thread chat
|
||||
if (event.kind === 1) {
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
// Special handling for kind 1111 comments - open chat with root event
|
||||
if (event.kind === 1111) {
|
||||
const rootPointer = getCommentReplyPointer(event);
|
||||
if (rootPointer) {
|
||||
// Encode root as nevent/naddr and parse
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
// Open chat with NIP-10 thread protocol
|
||||
addWindow("chat", {
|
||||
protocol: "nip-10",
|
||||
identifier: {
|
||||
type: "thread",
|
||||
value: {
|
||||
id: event.id,
|
||||
relays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
let encoded: string;
|
||||
// Convert CommentPointer to standard nip19 pointer types
|
||||
if (
|
||||
rootPointer.type === "address" &&
|
||||
rootPointer.pubkey &&
|
||||
rootPointer.identifier !== undefined
|
||||
) {
|
||||
// CommentAddressPointer -> AddressPointer
|
||||
encoded = nip19.naddrEncode({
|
||||
kind: rootPointer.kind,
|
||||
pubkey: rootPointer.pubkey,
|
||||
identifier: rootPointer.identifier,
|
||||
relays: rootPointer.relay ? [rootPointer.relay, ...relays] : relays,
|
||||
});
|
||||
} else if (rootPointer.type === "event" && rootPointer.id) {
|
||||
// CommentEventPointer -> EventPointer
|
||||
encoded = nip19.neventEncode({
|
||||
id: rootPointer.id,
|
||||
relays: rootPointer.relay ? [rootPointer.relay, ...relays] : relays,
|
||||
author: rootPointer.pubkey,
|
||||
kind: rootPointer.kind,
|
||||
});
|
||||
} else {
|
||||
console.error("Unsupported comment root pointer type:", rootPointer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and open
|
||||
try {
|
||||
const result = parseChatCommand([encoded]);
|
||||
addWindow("chat", {
|
||||
protocol: result.protocol,
|
||||
identifier: result.identifier,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to open chat for comment root:", err);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For all other events, encode as nevent/naddr and let parser detect protocol
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
let encoded: string;
|
||||
if (isAddressableKind(event.kind)) {
|
||||
const dTag = getTagValue(event, "d") || "";
|
||||
encoded = nip19.naddrEncode({
|
||||
kind: event.kind,
|
||||
pubkey: event.pubkey,
|
||||
identifier: dTag,
|
||||
relays: relays,
|
||||
});
|
||||
} else {
|
||||
encoded = nip19.neventEncode({
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
relays: relays,
|
||||
});
|
||||
}
|
||||
|
||||
// Parse and open
|
||||
try {
|
||||
const result = parseChatCommand([encoded]);
|
||||
addWindow("chat", {
|
||||
protocol: result.protocol,
|
||||
identifier: result.identifier,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to open chat for event:", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -418,12 +540,10 @@ export function EventContextMenu({
|
||||
<Zap className="size-4 mr-2 text-yellow-500" />
|
||||
Zap
|
||||
</ContextMenuItem>
|
||||
{event.kind === 1 && (
|
||||
<ContextMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
<ContextMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</ContextMenuItem>
|
||||
{canSign && onReactClick && (
|
||||
<ContextMenuItem onClick={onReactClick}>
|
||||
<SmilePlus className="size-4 mr-2" />
|
||||
|
||||
Reference in New Issue
Block a user