From d6aa39b8181ba9879b29d9ebec5dc70968834448 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Jan 2026 15:02:06 +0000 Subject: [PATCH] feat: integrate compose/reply dialog into UI Add compose and reply actions to the user interface: ## User Menu Integration - Add "Compose Note" menu item to user menu (when logged in) - Opens ComposeDialog for creating new kind 1 notes - Positioned prominently after user profile section ## Event Menu Integration - Add "Reply" menu item to EventMenu dropdown (when logged in) - Opens ComposeDialog with replyTo context - Automatically handles NIP-10/NIP-22 threading - Available on all event renderers via BaseEventRenderer ## Changes - src/components/nostr/user-menu.tsx: - Import ComposeDialog and PenSquare icon - Add showCompose state - Add "Compose Note" menu item - src/components/nostr/kinds/BaseEventRenderer.tsx: - Import ComposeDialog, Reply icon, and account manager - Add showReply state to EventMenu - Add conditional "Reply" menu item (only when account exists) - Render ComposeDialog with replyTo event Users can now compose notes and reply to events directly from the UI! --- .../nostr/kinds/BaseEventRenderer.tsx | 19 ++++++++++++++++++- src/components/nostr/user-menu.tsx | 18 +++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/components/nostr/kinds/BaseEventRenderer.tsx b/src/components/nostr/kinds/BaseEventRenderer.tsx index 5f2a420..05fb9e8 100644 --- a/src/components/nostr/kinds/BaseEventRenderer.tsx +++ b/src/components/nostr/kinds/BaseEventRenderer.tsx @@ -10,7 +10,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { Menu, Copy, Check, FileJson, ExternalLink } from "lucide-react"; +import { Menu, Copy, Check, FileJson, ExternalLink, Reply } from "lucide-react"; import { useGrimoire } from "@/core/state"; import { useCopy } from "@/hooks/useCopy"; import { JsonViewer } from "@/components/JsonViewer"; @@ -21,6 +21,9 @@ import { getSeenRelays } from "applesauce-core/helpers/relays"; import { EventFooter } from "@/components/EventFooter"; import { cn } from "@/lib/utils"; import { isAddressableKind } from "@/lib/nostr-kinds"; +import { ComposeDialog } from "@/components/compose"; +import { use$ } from "applesauce-react/hooks"; +import accountManager from "@/services/accounts"; /** * Universal event properties and utilities shared across all kind renderers @@ -101,9 +104,11 @@ function ReplyPreview({ * Event menu - universal actions for any event */ export function EventMenu({ event }: { event: NostrEvent }) { + const account = use$(accountManager.active$); const { addWindow } = useGrimoire(); const { copy, copied } = useCopy(); const [jsonDialogOpen, setJsonDialogOpen] = useState(false); + const [showReply, setShowReply] = useState(false); const openEventDetail = () => { let pointer; @@ -181,6 +186,12 @@ export function EventMenu({ event }: { event: NostrEvent }) { Open + {account && ( + setShowReply(true)}> + + Reply + + )} {copied ? ( @@ -201,6 +212,12 @@ export function EventMenu({ event }: { event: NostrEvent }) { onOpenChange={setJsonDialogOpen} title={`Event ${event.id.slice(0, 8)}... - Raw JSON`} /> + ); } diff --git a/src/components/nostr/user-menu.tsx b/src/components/nostr/user-menu.tsx index f6dd4ed..2e4fc89 100644 --- a/src/components/nostr/user-menu.tsx +++ b/src/components/nostr/user-menu.tsx @@ -1,4 +1,4 @@ -import { User } from "lucide-react"; +import { User, PenSquare } from "lucide-react"; import accounts from "@/services/accounts"; import { useProfile } from "@/hooks/useProfile"; import { use$ } from "applesauce-react/hooks"; @@ -19,6 +19,7 @@ import Nip05 from "./nip05"; import { RelayLink } from "./RelayLink"; import SettingsDialog from "@/components/SettingsDialog"; import LoginDialog from "./LoginDialog"; +import { ComposeDialog } from "@/components/compose"; import { useState } from "react"; function UserAvatar({ pubkey }: { pubkey: string }) { @@ -56,6 +57,7 @@ export default function UserMenu() { const relays = state.activeAccount?.relays; const [showSettings, setShowSettings] = useState(false); const [showLogin, setShowLogin] = useState(false); + const [showCompose, setShowCompose] = useState(false); function openProfile() { if (!account?.pubkey) return; @@ -75,6 +77,11 @@ export default function UserMenu() { <> +