From 81a48bd0f6591a612b4a30851f7ffa28ebcfc5ef Mon Sep 17 00:00:00 2001 From: Gigi Date: Fri, 3 Oct 2025 00:46:11 +0200 Subject: [PATCH] feat(ui): resolve nprofile/npub mentions to names in content - Add ResolvedMention component using applesauce ProfileModel - Update parsed content renderer to use ResolvedMention for mentions - Mentions now show @name and link to search page --- src/components/ResolvedMention.tsx | 42 ++++++++++++++++++++++++++++++ src/utils/bookmarkUtils.tsx | 17 +++--------- 2 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 src/components/ResolvedMention.tsx diff --git a/src/components/ResolvedMention.tsx b/src/components/ResolvedMention.tsx new file mode 100644 index 00000000..42bbfe1e --- /dev/null +++ b/src/components/ResolvedMention.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import { useEventModel } from 'applesauce-react/hooks' +import { Models } from 'applesauce-core' +import { decode, npubEncode } from 'nostr-tools/nip19' +import { getPubkeyFromDecodeResult } from 'applesauce-core/helpers' + +interface ResolvedMentionProps { + encoded?: string +} + +const ResolvedMention: React.FC = ({ encoded }) => { + if (!encoded) return null + let pubkey: string | undefined + try { + pubkey = getPubkeyFromDecodeResult(decode(encoded)) + } catch { + // ignore; will fallback to showing the encoded value + } + + const profile = pubkey ? useEventModel(Models.ProfileModel, [pubkey]) : undefined + const display = profile?.name || profile?.display_name || profile?.nip05 || (pubkey ? `${pubkey.slice(0, 8)}...` : encoded) + const npub = pubkey ? npubEncode(pubkey) : undefined + + if (npub) { + return ( + + @{display} + + ) + } + + return {encoded} +} + +export default ResolvedMention + + diff --git a/src/utils/bookmarkUtils.tsx b/src/utils/bookmarkUtils.tsx index b41a9613..ad03ef6b 100644 --- a/src/utils/bookmarkUtils.tsx +++ b/src/utils/bookmarkUtils.tsx @@ -1,13 +1,14 @@ import React from 'react' import { ParsedContent, ParsedNode } from '../types/bookmarks' -import { ContentWithResolvedProfiles } from '../components/ContentWithResolvedProfiles' +import ResolvedMention from '../components/ResolvedMention' +// Note: ContentWithResolvedProfiles is imported by components directly to keep this file component-only for fast refresh export const formatDate = (timestamp: number) => { return new Date(timestamp * 1000).toLocaleDateString() } // Component to render content with resolved nprofile names -export { default as ContentWithResolvedProfiles } from '../components/ContentWithResolvedProfiles' +// Intentionally no exports except components and render helpers // Component to render parsed content using applesauce-content export const renderParsedContent = (parsedContent: ParsedContent) => { @@ -21,17 +22,7 @@ export const renderParsedContent = (parsedContent: ParsedContent) => { } if (node.type === 'mention') { - return ( - - {node.encoded} - - ) + return } if (node.type === 'link') {