diff --git a/desktop/src/features/home/lib/inbox.ts b/desktop/src/features/home/lib/inbox.ts index 99d4fe31ba..575507fc2a 100644 --- a/desktop/src/features/home/lib/inbox.ts +++ b/desktop/src/features/home/lib/inbox.ts @@ -47,6 +47,7 @@ export type InboxReply = { parentId?: string | null; reactions?: TimelineReaction[]; rootId?: string | null; + tags?: string[][]; }; export type InboxContextMessage = InboxReply & { diff --git a/desktop/src/features/home/ui/HomeView.tsx b/desktop/src/features/home/ui/HomeView.tsx index fd5085bb31..a25d775027 100644 --- a/desktop/src/features/home/ui/HomeView.tsx +++ b/desktop/src/features/home/ui/HomeView.tsx @@ -245,6 +245,7 @@ export function HomeView({ mentionNames: resolveMentionNames(message.tags ?? [], feedProfiles) ?? [], reactions: message.reactions, + tags: message.tags, }; }); }, [ @@ -544,6 +545,7 @@ export function HomeView({ id: result.eventId, parentId: result.parentEventId, rootId: result.rootEventId, + tags: emojiTags, }; setLocalRepliesByItemId((current) => ({ ...current, diff --git a/desktop/src/features/home/ui/InboxMessageRow.tsx b/desktop/src/features/home/ui/InboxMessageRow.tsx index 81062f109f..1dc82b3790 100644 --- a/desktop/src/features/home/ui/InboxMessageRow.tsx +++ b/desktop/src/features/home/ui/InboxMessageRow.tsx @@ -5,6 +5,7 @@ import type { TimelineMessage } from "@/features/messages/types"; import { MessageActionBar } from "@/features/messages/ui/MessageActionBar"; import { MessageReactions } from "@/features/messages/ui/MessageReactions"; import { useReactionHandler } from "@/features/messages/ui/useReactionHandler"; +import { useMessageEmoji } from "@/features/messages/lib/useMessageEmoji"; import { cn } from "@/shared/lib/cn"; import { Markdown } from "@/shared/ui/markdown"; import { UserAvatar } from "@/shared/ui/UserAvatar"; @@ -22,6 +23,7 @@ function toTimelineMessage(message: InboxDisplayMessage): TimelineMessage { createdAt: 0, depth: message.depth, reactions: message.reactions ?? [], + tags: message.tags, time: message.fullTimestampLabel, }; } @@ -52,6 +54,10 @@ export function InboxMessageRow({ () => toTimelineMessage(message), [message], ); + const { customEmoji, emojiOnly } = useMessageEmoji( + message.content, + message.tags, + ); const [badgeBurstEmoji, setBadgeBurstEmoji] = React.useState( null, ); @@ -128,8 +134,13 @@ export function InboxMessageRow({
{ + const customEmoji = customEmojiFromTags(EMOJI_TAGS); + assert.deepEqual(customEmoji, [ + { shortcode: "buzz", url: "https://relay/buzz.png" }, + ]); + assert.equal(isEmojiOnlyMessage(":buzz:", customEmoji), true); + assert.equal(isEmojiOnlyMessage("hi :buzz:", customEmoji), false); +}); + +test("messages without tags get no custom emoji and are never emoji-only", () => { + const customEmoji = undefined; + assert.equal(isEmojiOnlyMessage(":buzz:", customEmoji), false); +}); diff --git a/desktop/src/features/messages/lib/useMessageEmoji.ts b/desktop/src/features/messages/lib/useMessageEmoji.ts new file mode 100644 index 0000000000..3b6dc8e239 --- /dev/null +++ b/desktop/src/features/messages/lib/useMessageEmoji.ts @@ -0,0 +1,26 @@ +import * as React from "react"; + +import { customEmojiFromTags } from "@/shared/api/customEmoji"; +import { isEmojiOnlyMessage } from "@/shared/lib/emojiOnly"; +import type { CustomEmoji } from "@/shared/lib/remarkCustomEmoji"; + +/** + * Derive custom-emoji rendering info for a message body from its raw event + * tags. Shared by channel and inbox message rows so NIP-30 `:shortcode:` + * emoji (and the emoji-only large-render treatment) behave identically + * everywhere a message body is shown. + */ +export function useMessageEmoji( + body: string, + tags: ReadonlyArray> | undefined, +): { customEmoji: CustomEmoji[] | undefined; emojiOnly: boolean } { + const customEmoji = React.useMemo( + () => (tags ? customEmojiFromTags(tags) : undefined), + [tags], + ); + const emojiOnly = React.useMemo( + () => isEmojiOnlyMessage(body, customEmoji), + [body, customEmoji], + ); + return { customEmoji, emojiOnly }; +} diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx index 869ef0cb4b..88ed7196cb 100644 --- a/desktop/src/features/messages/ui/MessageRow.tsx +++ b/desktop/src/features/messages/ui/MessageRow.tsx @@ -12,8 +12,7 @@ import { normalizePubkey } from "@/shared/lib/pubkey"; import { UserAvatar } from "@/shared/ui/UserAvatar"; import { useChannelNavigation } from "@/shared/context/ChannelNavigationContext"; import { parseImetaTags } from "@/features/messages/lib/parseImeta"; -import { customEmojiFromTags } from "@/shared/api/customEmoji"; -import { isEmojiOnlyMessage } from "@/shared/lib/emojiOnly"; +import { useMessageEmoji } from "@/features/messages/lib/useMessageEmoji"; import { resolveMentionNames, resolveMentionPubkeysByName, @@ -131,13 +130,9 @@ export const MessageRow = React.memo( [message.tags], ); - const customEmoji = React.useMemo( - () => (message.tags ? customEmojiFromTags(message.tags) : undefined), - [message.tags], - ); - const emojiOnly = React.useMemo( - () => isEmojiOnlyMessage(message.body, customEmoji), - [message.body, customEmoji], + const { customEmoji, emojiOnly } = useMessageEmoji( + message.body, + message.tags, ); const bodyOffsetClass = emojiOnly ? "mt-1" : "-mt-0.5";