diff --git a/src/components/GifPicker/index.tsx b/src/components/GifPicker/index.tsx
index 699e8b70..87aaabbf 100644
--- a/src/components/GifPicker/index.tsx
+++ b/src/components/GifPicker/index.tsx
@@ -280,19 +280,6 @@ export default function GifPicker({
- {isLoggedIn && (
-
-
- setPublishDescription(e.target.value)}
- className="min-w-0"
- />
-
- )}
+ {isLoggedIn && (
+
+
+ setPublishDescription(e.target.value)}
+ className="min-w-0"
+ />
+
+ )}
{isLoggedIn && (
<>
(undefined)
const [highlightDefaultContent, setHighlightDefaultContent] = useState('')
const [postEditorOpen, setPostEditorOpen] = useState(false)
+ const [publicMessageTo, setPublicMessageTo] = useState(null)
const openHighlight = useCallback((data: HighlightData, eventContent?: string) => {
setHighlightData(data)
setHighlightDefaultContent(eventContent ?? '')
+ setPublicMessageTo(null)
+ setPostEditorOpen(true)
+ }, [])
+
+ const openPublicMessage = useCallback((pubkey: string) => {
+ setPublicMessageTo(pubkey)
setPostEditorOpen(true)
}, [])
@@ -276,7 +283,10 @@ export default function Note({
setPostEditorOpen(false)
setHighlightData(undefined)
setHighlightDefaultContent('')
+ setPublicMessageTo(null)
}}
+ onOpenPublicMessage={openPublicMessage}
+ initialPublicMessageTo={publicMessageTo}
/>
)}
diff --git a/src/components/NoteOptions/index.tsx b/src/components/NoteOptions/index.tsx
index 42a3ef9e..160946a2 100644
--- a/src/components/NoteOptions/index.tsx
+++ b/src/components/NoteOptions/index.tsx
@@ -16,7 +16,9 @@ export default function NoteOptions({
initialHighlightData,
highlightDefaultContent,
isPostEditorOpen,
- onPostEditorClose
+ onPostEditorClose,
+ onOpenPublicMessage,
+ initialPublicMessageTo
}: {
event: Event
className?: string
@@ -24,6 +26,10 @@ export default function NoteOptions({
highlightDefaultContent?: string
isPostEditorOpen?: boolean
onPostEditorClose?: () => void
+ /** Opens the post editor in public message mode with the given pubkey in the mention list. */
+ onOpenPublicMessage?: (pubkey: string) => void
+ /** When set, the post editor is opened in public message mode with this pubkey pre-filled. */
+ initialPublicMessageTo?: string | null
}) {
const { isSmallScreen } = useScreenSize()
const [isRawEventDialogOpen, setIsRawEventDialogOpen] = useState(false)
@@ -54,7 +60,8 @@ export default function NoteOptions({
showSubMenuActions,
setIsRawEventDialogOpen,
setIsReportDialogOpen,
- isSmallScreen
+ isSmallScreen,
+ onOpenPublicMessage
})
const trigger = useMemo(
@@ -105,6 +112,7 @@ export default function NoteOptions({
}}
defaultContent={highlightDefaultContent ?? ''}
initialHighlightData={initialHighlightData}
+ initialPublicMessageTo={initialPublicMessageTo ?? undefined}
/>
)}
diff --git a/src/components/NoteOptions/useMenuActions.tsx b/src/components/NoteOptions/useMenuActions.tsx
index 27d4282c..c01960ae 100644
--- a/src/components/NoteOptions/useMenuActions.tsx
+++ b/src/components/NoteOptions/useMenuActions.tsx
@@ -13,7 +13,7 @@ import { useNostr } from '@/providers/NostrProvider'
import { BIG_RELAY_URLS, FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants'
import client from '@/services/client.service'
import { nip66Service } from '@/services/nip66.service'
-import { Bell, BellOff, Code, Copy, Link, SatelliteDish, Trash2, TriangleAlert, Pin, FileDown, Globe, BookOpen } from 'lucide-react'
+import { Bell, BellOff, Code, Copy, Link, SatelliteDish, Trash2, TriangleAlert, Pin, FileDown, Globe, BookOpen, MessageCircle } from 'lucide-react'
import { Event, kinds } from 'nostr-tools'
import { nip19 } from 'nostr-tools'
import { useMemo, useState, useEffect, useContext } from 'react'
@@ -46,6 +46,8 @@ interface UseMenuActionsProps {
setIsRawEventDialogOpen: (open: boolean) => void
setIsReportDialogOpen: (open: boolean) => void
isSmallScreen: boolean
+ /** When provided, adds "Send public message" to open composer with this pubkey in the mention list. */
+ onOpenPublicMessage?: (pubkey: string) => void
}
export function useMenuActions({
@@ -55,6 +57,7 @@ export function useMenuActions({
setIsRawEventDialogOpen,
setIsReportDialogOpen,
isSmallScreen,
+ onOpenPublicMessage,
}: UseMenuActionsProps) {
const { t } = useTranslation()
// Use useContext directly to avoid error if provider is not available
@@ -588,6 +591,18 @@ export function useMenuActions({
closeDrawer()
}
},
+ ...(pubkey && event.pubkey !== pubkey && onOpenPublicMessage
+ ? [
+ {
+ icon: MessageCircle,
+ label: t('Send public message'),
+ onClick: () => {
+ closeDrawer()
+ onOpenPublicMessage(event.pubkey)
+ }
+ } as MenuAction
+ ]
+ : []),
{
icon: Link,
label: t('Share with Jumble'),
diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx
index 7111a440..bde3c5d1 100644
--- a/src/components/PostEditor/PostContent.tsx
+++ b/src/components/PostEditor/PostContent.tsx
@@ -67,13 +67,16 @@ export default function PostContent({
parentEvent,
close,
openFrom,
- initialHighlightData
+ initialHighlightData,
+ initialPublicMessageTo
}: {
defaultContent?: string
parentEvent?: Event
close: () => void
openFrom?: string[]
initialHighlightData?: HighlightData
+ /** When set, opens in public message mode with this pubkey in the mention list. */
+ initialPublicMessageTo?: string
}) {
const { t } = useTranslation()
const { pubkey, publish, checkLogin } = useNostr()
@@ -90,8 +93,10 @@ export default function PostContent({
const [mentions, setMentions] = useState([])
const [isNsfw, setIsNsfw] = useState(false)
const [isPoll, setIsPoll] = useState(false)
- const [isPublicMessage, setIsPublicMessage] = useState(false)
- const [extractedMentions, setExtractedMentions] = useState([])
+ const [isPublicMessage, setIsPublicMessage] = useState(!!initialPublicMessageTo)
+ const [extractedMentions, setExtractedMentions] = useState(
+ initialPublicMessageTo ? [initialPublicMessageTo] : []
+ )
const [isProtectedEvent, setIsProtectedEvent] = useState(false)
const [additionalRelayUrls, setAdditionalRelayUrls] = useState([])
const [isHighlight, setIsHighlight] = useState(!!initialHighlightData)
@@ -283,7 +288,7 @@ export default function PostContent({
useEffect(() => {
if (!text) {
- setExtractedMentions([])
+ if (!initialPublicMessageTo) setExtractedMentions([])
return
}
@@ -295,7 +300,7 @@ export default function PostContent({
return () => {
clearTimeout(timeoutId)
}
- }, [text, extractMentionsFromContent])
+ }, [text, extractMentionsFromContent, initialPublicMessageTo])
// Check for private relays availability
useEffect(() => {
@@ -1533,7 +1538,7 @@ export default function PostContent({
}
return (
-
+
{/* Dynamic Title based on mode */}
{(() => {
@@ -2237,8 +2242,8 @@ export default function PostContent({
mentions={extractedMentions}
/>
)}
-
-
+
+
{/* Audio button for replies and new PMs - placed before image button */}
{(parentEvent || isPublicMessage) && (
-
+
openFrom?: string[]
initialHighlightData?: import('./HighlightEditor').HighlightData
+ /** When set, opens in public message mode with this pubkey in the mention list. */
+ initialPublicMessageTo?: string
}) {
const { isSmallScreen } = useScreenSize()
- // If initialHighlightData is provided and we're creating a highlight from an event,
- // we need to pass the event content as defaultContent for the main editor
- // Note: This is handled separately - we'll pass the event content when opening from menu
- const effectiveDefaultContent = defaultContent
+ const effectiveDefaultContent = useMemo(() => {
+ if (initialPublicMessageTo) {
+ const npub = pubkeyToNpub(initialPublicMessageTo)
+ return npub ? `nostr:${npub} ` : defaultContent
+ }
+ return defaultContent
+ }, [initialPublicMessageTo, defaultContent])
const content = useMemo(() => {
return (
@@ -49,15 +56,16 @@ export default function PostEditor({
close={() => setOpen(false)}
openFrom={openFrom}
initialHighlightData={initialHighlightData}
+ initialPublicMessageTo={initialPublicMessageTo}
/>
)
- }, [effectiveDefaultContent, parentEvent, openFrom, setOpen, initialHighlightData])
+ }, [effectiveDefaultContent, parentEvent, openFrom, setOpen, initialHighlightData, initialPublicMessageTo])
if (isSmallScreen) {
return (
{
@@ -67,8 +75,8 @@ export default function PostEditor({
}
}}
>
-
-
+
+
Post Editor
Create a new post or reply
@@ -84,7 +92,7 @@ export default function PostEditor({
return (