mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-11 16:07:15 +02:00
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!
This commit is contained in:
@@ -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 }) {
|
||||
<ExternalLink className="size-4 mr-2" />
|
||||
Open
|
||||
</DropdownMenuItem>
|
||||
{account && (
|
||||
<DropdownMenuItem onClick={() => setShowReply(true)}>
|
||||
<Reply className="size-4 mr-2" />
|
||||
Reply
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={copyEventId}>
|
||||
{copied ? (
|
||||
@@ -201,6 +212,12 @@ export function EventMenu({ event }: { event: NostrEvent }) {
|
||||
onOpenChange={setJsonDialogOpen}
|
||||
title={`Event ${event.id.slice(0, 8)}... - Raw JSON`}
|
||||
/>
|
||||
<ComposeDialog
|
||||
open={showReply}
|
||||
onOpenChange={setShowReply}
|
||||
replyTo={event}
|
||||
kind={1}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
<>
|
||||
<SettingsDialog open={showSettings} onOpenChange={setShowSettings} />
|
||||
<LoginDialog open={showLogin} onOpenChange={setShowLogin} />
|
||||
<ComposeDialog
|
||||
open={showCompose}
|
||||
onOpenChange={setShowCompose}
|
||||
kind={1}
|
||||
/>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
@@ -101,6 +108,15 @@ export default function UserMenu() {
|
||||
</DropdownMenuLabel>
|
||||
</DropdownMenuGroup>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() => setShowCompose(true)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<PenSquare className="mr-2 size-4" />
|
||||
Compose Note
|
||||
</DropdownMenuItem>
|
||||
|
||||
{relays && relays.length > 0 && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
Reference in New Issue
Block a user