From 176e710dff435df3b56b42e97878ce44a307e7d5 Mon Sep 17 00:00:00 2001 From: silberengel Date: Sun, 10 Aug 2025 15:49:56 +0200 Subject: [PATCH] simplified quote structure and corrected msg jump --- src/lib/components/Notifications.svelte | 139 ++++++++++++++++-------- src/lib/utils/kind24_utils.ts | 14 +-- 2 files changed, 98 insertions(+), 55 deletions(-) diff --git a/src/lib/components/Notifications.svelte b/src/lib/components/Notifications.svelte index f46607a..e915315 100644 --- a/src/lib/components/Notifications.svelte +++ b/src/lib/components/Notifications.svelte @@ -19,6 +19,7 @@ import { searchProfiles } from "$lib/utils/search_utility"; import type { NostrProfile } from "$lib/utils/search_types"; import { PlusOutline, ReplyOutline } from "flowbite-svelte-icons"; + import { parseBasicmarkup } from "$lib/utils/markup/basicMarkupParser"; const { event } = $props<{ event: NDKEvent }>(); @@ -182,31 +183,46 @@ } } - function renderContentWithLinks(content: string): string { - // Parse markdown links [text](url) and convert to HTML - let rendered = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + async function parseContent(content: string): Promise { + if (!content) return ""; - // Handle quote format and convert to small gray bars like Jumble - const patterns = [ - /> QUOTED: ([^•]*?) • LINK:\s*\n((?:nostr:)?nevent[^\s]*)/g, - /> QUOTED: ([^\n]*?)\n> LINK: ((?:nostr:)?nevent[^\s]*)/g, - /> QUOTED: ([^•]*?) • LINK:\s*((?:nostr:)?nevent[^\s]*)/g, - /> QUOTED: ([^•]*?) • LINK: ((?:nostr:)?nevent[^\s]*)/g, // Without optional whitespace - ]; + let parsedContent = await parseBasicmarkup(content); - for (const pattern of patterns) { - const beforeReplace = rendered; - rendered = rendered.replace(pattern, (match, quotedText, neventUrl) => { - const encodedUrl = neventUrl.replace(/'/g, '''); - const cleanQuotedText = quotedText.trim(); - return `
${cleanQuotedText}
`; - }); - if (beforeReplace !== rendered) { - break; + return parsedContent; + } + + function renderQuotedContent(message: NDKEvent): string { + const qTags = message.getMatchingTags("q"); + if (qTags.length === 0) return ""; + + const qTag = qTags[0]; + const nevent = qTag[1]; + + // Extract event ID from nevent + let eventId = ''; + try { + const decoded = nip19.decode(nevent); + if (decoded.type === 'nevent' && decoded.data.id) { + eventId = decoded.data.id; + } + } catch (error) { + // If decode fails, try to extract hex ID directly + const hexMatch = nevent.match(/[a-f0-9]{64}/i); + if (hexMatch) { + eventId = hexMatch[0]; + } + } + + if (eventId) { + // Find the quoted message in our public messages + const quotedMessage = publicMessages.find(msg => msg.id === eventId); + if (quotedMessage) { + const quotedContent = quotedMessage.content ? quotedMessage.content.slice(0, 200) : "No content"; + return `
${quotedContent}
`; } } - return rendered; + return ""; } function getNotificationType(event: NDKEvent): string { @@ -226,35 +242,59 @@ goto(`/events?id=${nevent}`); } - function jumpToMessageInFeed(nevent: string) { + function jumpToMessageInFeed(eventIdOrNevent: string) { // Switch to public messages tab and scroll to the specific message notificationMode = "public-messages"; // Try to find and scroll to the specific message setTimeout(() => { - try { - // Decode the nevent to get the event ID - const decoded = nip19.decode(nevent); - if (decoded.type === 'nevent' && decoded.data.id) { - const eventId = decoded.data.id; + let eventId = eventIdOrNevent; + + // If it's a nevent URL, try to extract the event ID + if (eventIdOrNevent.startsWith('nostr:nevent') || eventIdOrNevent.startsWith('nevent')) { + try { + const decoded = nip19.decode(eventIdOrNevent); + if (decoded.type === 'nevent' && decoded.data.id) { + eventId = decoded.data.id; + } + } catch (error) { + // If decode fails, try to extract hex ID directly + const hexMatch = eventIdOrNevent.match(/[a-f0-9]{64}/i); + if (hexMatch) { + eventId = hexMatch[0]; + } else { + console.warn('Failed to extract event ID from nevent:', eventIdOrNevent); + return; + } + } + } + + // Find the message in our public messages + const targetMessage = publicMessages.find(msg => msg.id === eventId); + if (targetMessage) { + // Try to find the element in the DOM + const element = document.querySelector(`[data-event-id="${eventId}"]`); + if (element) { + // Check if element is in viewport + const rect = element.getBoundingClientRect(); + const isInView = ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); - // Find the message in our public messages - const targetMessage = publicMessages.find(msg => msg.id === eventId); - if (targetMessage) { - // Try to scroll to the element if it exists in the DOM - const element = document.querySelector(`[data-event-id="${eventId}"]`); - if (element) { - element.scrollIntoView({ behavior: 'smooth', block: 'center' }); - // Briefly highlight the message - element.classList.add('ring-2', 'ring-blue-500'); - setTimeout(() => { - element.classList.remove('ring-2', 'ring-blue-500'); - }, 2000); - } + // Only scroll if not in view + if (!isInView) { + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } + + // ALWAYS highlight the message in blue + element.classList.add('ring-2', 'ring-blue-500'); + setTimeout(() => { + element.classList.remove('ring-2', 'ring-blue-500'); + }, 2000); } - } catch (error) { - console.warn('Failed to jump to message:', error); } }, 100); } @@ -1020,9 +1060,18 @@ {/if} + {#if message.getMatchingTags("q").length > 0} +
+ {@html renderQuotedContent(message)} +
+ {/if} {#if message.content}
- {@html truncateRenderedContent(renderContentWithLinks(message.content), 300)} + {#await parseContent(message.content) then parsedContent} + {@html parsedContent} + {:catch} + {@html message.content} + {/await}
{/if} @@ -1136,7 +1185,11 @@
Replying to:
- {@html renderContentWithLinks(quotedContent)} + {#await parseContent(quotedContent) then parsedContent} + {@html parsedContent} + {:catch} + {@html quotedContent} + {/await}
{/if} diff --git a/src/lib/utils/kind24_utils.ts b/src/lib/utils/kind24_utils.ts index 9d1271e..cb43e57 100644 --- a/src/lib/utils/kind24_utils.ts +++ b/src/lib/utils/kind24_utils.ts @@ -151,18 +151,8 @@ export async function createKind24Reply( return { success: false, error: "No relays available for publishing" }; } - // Build content with quoted message if replying - let finalContent = content; - if (originalEvent) { - // Use multiple relays for better discoverability - const nevent = nip19.neventEncode({ - id: originalEvent.id, - relays: prioritizedRelays.slice(0, 3) // Use first 3 relays - }); - const quotedContent = originalEvent.content ? originalEvent.content.slice(0, 200) : "No content"; - // Use a more visible quote format with a clickable link - finalContent = `> QUOTED: ${quotedContent}\n> LINK: ${nevent}\n\n${content}`; - } + // Use the content as-is, quoted content is handled via q tag + const finalContent = content; // Build tags for the kind 24 event const tags: string[][] = [