diff --git a/packages/app/src/Element/Event/NoteCreator.tsx b/packages/app/src/Element/Event/NoteCreator.tsx index 4b2612b9..f1880bb3 100644 --- a/packages/app/src/Element/Event/NoteCreator.tsx +++ b/packages/app/src/Element/Event/NoteCreator.tsx @@ -95,6 +95,22 @@ export function NoteCreator() { extraTags ??= []; extraTags.push(...note.pollOptions.map((a, i) => ["poll_option", i.toString(), a])); } + // add quote repost + if (note.quote) { + if (!note.note.endsWith("\n")) { + note.note += "\n"; + } + const link = NostrLink.fromEvent(note.quote); + note.note += `nostr:${link.encode()}`; + const quoteTag = link.toEventTag(); + if (quoteTag) { + extraTags ??= []; + if (quoteTag[0] === "e") { + quoteTag[0] = "q"; // how to 'q' tag replacable events? + } + extraTags.push(quoteTag); + } + } const hk = (eb: EventBuilder) => { extraTags?.forEach(t => eb.tag(t)); eb.kind(kind); @@ -464,18 +480,42 @@ export function NoteCreator() { return ( <> {note.replyTo && ( - + <> +

+ +

+ + + )} + {note.quote && ( + <> +

+ +

+ + )} {note.preview && getPreviewNote()} {!note.preview && ( diff --git a/packages/app/src/Element/Event/NoteFooter.tsx b/packages/app/src/Element/Event/NoteFooter.tsx index cd108b06..1ee72bd6 100644 --- a/packages/app/src/Element/Event/NoteFooter.tsx +++ b/packages/app/src/Element/Event/NoteFooter.tsx @@ -1,8 +1,9 @@ import React, { HTMLProps, useContext, useEffect, useState } from "react"; -import { useIntl } from "react-intl"; +import { FormattedMessage, useIntl } from "react-intl"; import { useLongPress } from "use-long-press"; import { TaggedNostrEvent, ParsedZap, countLeadingZeros, NostrLink } from "@snort/system"; import { SnortContext, useUserProfile } from "@snort/system-react"; +import { Menu, MenuItem } from "@szhsin/react-menu"; import { formatShort } from "Number"; import useEventPublisher from "Hooks/useEventPublisher"; @@ -20,6 +21,7 @@ import { System } from "index"; import { Zapper, ZapTarget } from "Zapper"; import { getDisplayName } from "Element/User/DisplayName"; import { useNoteCreator } from "State/NoteCreator"; +import Icon from "Icons/Icon"; import messages from "../messages"; @@ -56,8 +58,8 @@ export default function NoteFooter(props: NoteFooterProps) { const author = useUserProfile(ev.pubkey); const interactionCache = useInteractionCache(publicKey, ev.id); const publisher = useEventPublisher(); - const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update })); - const willRenderNoteCreator = note.show && note.replyTo?.id === ev.id; + const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update, quote: n.quote })); + const willRenderNoteCreator = note.show && (note.replyTo?.id === ev.id || note.quote); const [tip, setTip] = useState(false); const [zapping, setZapping] = useState(false); const walletState = useWallet(); @@ -211,16 +213,40 @@ export default function NoteFooter(props: NoteFooterProps) { function repostIcon() { if (readonly) return; return ( - { - if (readonly) return; - await repost(); - }} - /> + + } + menuClassName="ctx-menu" + align="start"> +
+ {/* This menu item serves as a "close menu" button; + it allows the user to click anywhere nearby the menu to close it. */} + +
+ +
+ repost()} disabled={hasReposted()}> + + + + + note.update(n => { + n.reset(); + n.quote = ev; + n.show = true; + }) + }> + + + +
); } diff --git a/packages/app/src/State/NoteCreator.tsx b/packages/app/src/State/NoteCreator.tsx index a12d508b..f5d08278 100644 --- a/packages/app/src/State/NoteCreator.tsx +++ b/packages/app/src/State/NoteCreator.tsx @@ -12,6 +12,7 @@ interface NoteCreatorDataSnapshot { advanced: boolean; preview?: NostrEvent; replyTo?: TaggedNostrEvent; + quote?: TaggedNostrEvent; selectedCustomRelays?: Array; zapSplits?: Array; sensitive?: string; @@ -55,6 +56,7 @@ class NoteCreatorStore extends ExternalStore { d.sendStarted = false; d.preview = undefined; d.replyTo = undefined; + d.quote = undefined; d.selectedCustomRelays = undefined; d.zapSplits = undefined; d.sensitive = undefined; diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json index 93cae8ac..679be1f7 100644 --- a/packages/app/src/lang.json +++ b/packages/app/src/lang.json @@ -241,6 +241,9 @@ "89q5wc": { "defaultMessage": "Confirm Reposts" }, + "8ED/4u": { + "defaultMessage": "Reply To" + }, "8Kboo2": { "defaultMessage": "Scan this QR code with your signer app to get started" }, @@ -344,6 +347,9 @@ "C5xzTC": { "defaultMessage": "Premium" }, + "C7642/": { + "defaultMessage": "Quote Repost" + }, "C81/uG": { "defaultMessage": "Logout" }, diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json index 72d0a8ee..275e08f8 100644 --- a/packages/app/src/translations/en.json +++ b/packages/app/src/translations/en.json @@ -79,6 +79,7 @@ "7hp70g": "NIP-05", "8/vBbP": "Reposts ({n})", "89q5wc": "Confirm Reposts", + "8ED/4u": "Reply To", "8Kboo2": "Scan this QR code with your signer app to get started", "8QDesP": "Zap {n} sats", "8Rkoyb": "Recipient", @@ -112,6 +113,7 @@ "BjNwZW": "Nostr address (nip05)", "C1LjMx": "Lightning Donation", "C5xzTC": "Premium", + "C7642/": "Quote Repost", "C81/uG": "Logout", "C8HhVE": "Suggested Follows", "CHTbO3": "Failed to load invoice",