import { useMemo, useState } from 'react'; import { X } from 'lucide-react'; import { Link } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import type { NostrEvent } from '@nostrify/nostrify'; import { Dialog, DialogContent, DialogTitle, } from '@/components/ui/dialog'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { NoteContent } from '@/components/NoteContent'; import { ComposeBox } from '@/components/ComposeBox'; import { useAuthor } from '@/hooks/useAuthor'; import { genUserName } from '@/lib/genUserName'; import { VerifiedNip05Text } from '@/components/Nip05Badge'; import { timeAgo } from '@/lib/timeAgo'; import { cn } from '@/lib/utils'; interface ReplyComposeModalProps { /** The event being replied to. When `null`, the modal acts as a "New post" composer. */ event?: NostrEvent | null; /** The event being quoted (for quote posts). */ quotedEvent?: NostrEvent | null; open: boolean; onOpenChange: (open: boolean) => void; } /** Extracts image URLs from note content. */ function extractImages(content: string): string[] { const urlRegex = /https?:\/\/[^\s]+\.(jpg|jpeg|png|gif|webp|svg)(\?[^\s]*)?/gi; return content.match(urlRegex) || []; } export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange }: ReplyComposeModalProps) { const isReply = !!event; const isQuote = !!quotedEvent; const [previewMode, setPreviewMode] = useState(false); const [hasPreviewableContent, setHasPreviewableContent] = useState(false); return ( {/* Header */}
{isReply ? 'Reply to post' : isQuote ? 'Quote post' : 'New post'}
{/* Preview toggle */} {hasPreviewableContent && (
)}
{/* Embedded original post (reply only - quote embeds are shown in ComposeBox) */} {event && !isQuote && } {/* Compose area */} onOpenChange(false)} placeholder={isReply ? "What's on your mind?" : isQuote ? "Add a comment..." : "What's happening?"} forceExpanded hideAvatar previewMode={previewMode} onHasPreviewableContentChange={setHasPreviewableContent} />
); } /** Compact embedded preview of the post being replied to. */ function EmbeddedPost({ event }: { event: NostrEvent }) { const author = useAuthor(event.pubkey); const metadata = author.data?.metadata; const displayName = metadata?.name || genUserName(event.pubkey); const nip05 = metadata?.nip05; const npub = useMemo(() => nip19.npubEncode(event.pubkey), [event.pubkey]); const images = useMemo(() => extractImages(event.content), [event.content]); return (
{/* Author row */}
{displayName[0].toUpperCase()}
{displayName} {nip05 && ( )} {metadata?.bot && ( 🤖 )} · {timeAgo(event.created_at)}
{/* Content preview – clamp to a few lines */}
{/* Show first image thumbnail if any */} {images.length > 0 && (
)}
); }