diff --git a/src/components/Note/Highlight/index.tsx b/src/components/Note/Highlight/index.tsx index 7885f93..c089882 100644 --- a/src/components/Note/Highlight/index.tsx +++ b/src/components/Note/Highlight/index.tsx @@ -4,6 +4,42 @@ import { nip19 } from 'nostr-tools' import logger from '@/lib/logger' import HighlightSourcePreview from '@/components/UniversalContent/HighlightSourcePreview' +/** + * Check if a string is a URL or Nostr address + */ +function isUrlOrNostrAddress(value: string | undefined): boolean { + if (!value || typeof value !== 'string') { + return false + } + + // Check if it's a URL (http://, https://, or starts with common URL patterns) + try { + if (value.startsWith('http://') || value.startsWith('https://') || value.startsWith('ws://') || value.startsWith('wss://')) { + new URL(value) // Validate it's a proper URL + return true + } + } catch { + // Not a valid URL + } + + // Check if it's a Nostr address (nostr: prefix or bech32 encoded) + if (value.startsWith('nostr:')) { + return true + } + + // Check if it's a bech32 encoded Nostr address + try { + const decoded = nip19.decode(value) + if (['npub', 'nprofile', 'nevent', 'naddr', 'note', 'nrelay'].includes(decoded.type)) { + return true + } + } catch { + // Not a valid Nostr address + } + + return false +} + export default function Highlight({ event, className @@ -15,6 +51,7 @@ export default function Highlight({ // Extract the source (e-tag, a-tag, or r-tag) with improved priority handling let source = null + let quoteSource: string | null = null // For plain text r-tags that aren't URLs/Nostr addresses let sourceTag: string[] | undefined // Check for 'source' marker first (highest priority) @@ -50,13 +87,13 @@ export default function Highlight({ // Process the selected source tag if (sourceTag) { - if (sourceTag[0] === 'e') { + if (sourceTag[0] === 'e' && sourceTag[1]) { source = { type: 'event' as const, value: sourceTag[1], bech32: nip19.noteEncode(sourceTag[1]) } - } else if (sourceTag[0] === 'a') { + } else if (sourceTag[0] === 'a' && sourceTag[1]) { const [kind, pubkey, identifier] = sourceTag[1].split(':') const relay = sourceTag[2] source = { @@ -70,10 +107,16 @@ export default function Highlight({ }) } } else if (sourceTag[0] === 'r') { - source = { - type: 'url' as const, - value: sourceTag[1], - bech32: sourceTag[1] + // Check if the r-tag value is a URL or Nostr address + if (sourceTag[1] && isUrlOrNostrAddress(sourceTag[1])) { + source = { + type: 'url' as const, + value: sourceTag[1], + bech32: sourceTag[1] + } + } else if (sourceTag[1]) { + // It's plain text, store it as a quote source + quoteSource = sourceTag[1] } } } @@ -90,30 +133,56 @@ export default function Highlight({
- "{context}" -+
{t('The main editor above should contain only the text you want to highlight. This field should contain the full quote or paragraph for context.')}
diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx
index ef48703..39c35d7 100644
--- a/src/components/PostEditor/PostContent.tsx
+++ b/src/components/PostEditor/PostContent.tsx
@@ -38,12 +38,14 @@ export default function PostContent({
defaultContent = '',
parentEvent,
close,
- openFrom
+ openFrom,
+ initialHighlightData
}: {
defaultContent?: string
parentEvent?: Event
close: () => void
openFrom?: string[]
+ initialHighlightData?: HighlightData
}) {
const { t } = useTranslation()
const { pubkey, publish, checkLogin } = useNostr()
@@ -64,11 +66,13 @@ export default function PostContent({
const [extractedMentions, setExtractedMentions] = useState