diff --git a/src/components/MarkdownContent.tsx b/src/components/MarkdownContent.tsx index 77c9e28..f63afb2 100644 --- a/src/components/MarkdownContent.tsx +++ b/src/components/MarkdownContent.tsx @@ -1,8 +1,11 @@ +import { useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { Link } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { cn } from '@/lib/utils'; +import { useAuthor } from '@/hooks/useAuthor'; +import { genUserName } from '@/lib/genUserName'; interface MarkdownContentProps { content: string; @@ -14,6 +17,36 @@ interface MarkdownContentProps { * Used for rendering NIP-23 long-form blog posts */ export function MarkdownContent({ content, className }: MarkdownContentProps) { + // Preprocess content to convert plain nostr: URIs into markdown links + const processedContent = useMemo(() => { + // Regex to find nostr: URIs that are NOT already in markdown link format + // This matches nostr:npub1..., nostr:note1..., etc. that aren't part of [text](nostr:...) + const nostrUriRegex = /(? { + const nostrId = `${prefix}${data}`; + + try { + // Validate it's a proper NIP-19 identifier + const decoded = nip19.decode(nostrId); + + // For npub/nprofile, we'll show @username in the link text + // For other types, show the nostr: URI + if (decoded.type === 'npub' || decoded.type === 'nprofile') { + const pubkey = decoded.type === 'npub' ? decoded.data : decoded.data.pubkey; + // We'll use a special format that we can detect in the link component + return `[nostr-mention:${pubkey}](/${nostrId})`; + } else { + // For note, nevent, naddr - show the nostr: URI as link text + return `[${match}](/${nostrId})`; + } + } catch { + // If decoding fails, leave it as-is + return match; + } + }); + }, [content]); + return (
{ - // Handle nostr: URIs + // Handle nostr-mention links (generated by preprocessor) + if (typeof children === 'string' && children.startsWith('nostr-mention:')) { + const pubkey = children.substring(14); // Remove "nostr-mention:" prefix + return ; + } + + // Handle nostr: URIs in markdown links [text](nostr:npub1...) if (href?.startsWith('nostr:')) { const nostrId = href.substring(6); // Remove "nostr:" prefix @@ -74,7 +113,19 @@ export function MarkdownContent({ content, className }: MarkdownContentProps) { } } - // Regular links open in new tab + // Handle internal links (starting with /) + if (href?.startsWith('/')) { + return ( + + {children} + + ); + } + + // Regular external links open in new tab return ( - {content} + {processedContent}
); } + +// Helper component to display user mentions +function NostrMention({ pubkey, href }: { pubkey: string; href?: string }) { + const author = useAuthor(pubkey); + const hasRealName = !!author.data?.metadata?.name; + const displayName = author.data?.metadata?.name ?? genUserName(pubkey); + + return ( + + @{displayName} + + ); +}