From 30c2cef9ee9259e293ebcfc47f8e2fe493be03ad Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 3 Feb 2026 18:13:31 +0100 Subject: [PATCH] comments to threads fixed --- .../modals/PublicationStatusModal.svelte | 72 +++++++++++++++++- src/lib/modules/comments/CommentForm.svelte | 39 ++++++++-- src/lib/modules/comments/CommentThread.svelte | 76 ++++++++++++++++++- 3 files changed, 178 insertions(+), 9 deletions(-) diff --git a/src/lib/components/modals/PublicationStatusModal.svelte b/src/lib/components/modals/PublicationStatusModal.svelte index d8af1b2..d3b7873 100644 --- a/src/lib/components/modals/PublicationStatusModal.svelte +++ b/src/lib/components/modals/PublicationStatusModal.svelte @@ -12,16 +12,24 @@ let autoCloseTimeout: ReturnType | null = null; $effect(() => { + // Clear any existing timeout when modal state changes + if (autoCloseTimeout) { + clearTimeout(autoCloseTimeout); + autoCloseTimeout = null; + } + if (open && results) { // Auto-close after 30 seconds autoCloseTimeout = setTimeout(() => { open = false; + autoCloseTimeout = null; }, 30000); } return () => { if (autoCloseTimeout) { clearTimeout(autoCloseTimeout); + autoCloseTimeout = null; } }; }); @@ -33,6 +41,37 @@ autoCloseTimeout = null; } } + + /** + * Convert URLs in text to clickable links + */ + function linkify(text: string): Array { + const urlRegex = /(https?:\/\/[^\s]+)/g; + const parts: Array = []; + let lastIndex = 0; + let match; + + while ((match = urlRegex.exec(text)) !== null) { + // Add text before the URL + if (match.index > lastIndex) { + parts.push(text.substring(lastIndex, match.index)); + } + // Add the URL as a link object + parts.push({ + type: 'link', + url: match[0], + text: match[0] + }); + lastIndex = match.index + match[0].length; + } + + // Add remaining text + if (lastIndex < text.length) { + parts.push(text.substring(lastIndex)); + } + + return parts.length > 0 ? parts : [text]; + } {#if open && results} @@ -68,7 +107,16 @@
    {#each results.failed as { relay, error }}
  • - {relay}: {error} + {relay}: + + {#each linkify(error) as part} + {#if typeof part === 'object' && part.type === 'link'} + {part.text} + {:else} + {part} + {/if} + {/each} +
  • {/each}
@@ -164,6 +212,28 @@ padding: 0.25rem 0; } + .error-message { + word-break: break-word; + } + + .error-link { + color: #3b82f6; + text-decoration: underline; + cursor: pointer; + } + + .error-link:hover { + color: #2563eb; + } + + :global(.dark) .error-link { + color: #60a5fa; + } + + :global(.dark) .error-link:hover { + color: #93c5fd; + } + .modal-footer { padding: 1rem; border-top: 1px solid #cbd5e1; diff --git a/src/lib/modules/comments/CommentForm.svelte b/src/lib/modules/comments/CommentForm.svelte index 3361df3..aa5df56 100644 --- a/src/lib/modules/comments/CommentForm.svelte +++ b/src/lib/modules/comments/CommentForm.svelte @@ -2,6 +2,9 @@ import { sessionManager } from '../../services/auth/session-manager.js'; import { signAndPublish } from '../../services/nostr/auth-handler.js'; import { nostrClient } from '../../services/nostr/nostr-client.js'; + import { relayManager } from '../../services/nostr/relay-manager.js'; + import { fetchRelayLists } from '../../services/user-data.js'; + import PublicationStatusModal from '../../components/modals/PublicationStatusModal.svelte'; import type { NostrEvent } from '../../types/nostr.js'; interface Props { @@ -17,6 +20,8 @@ let content = $state(''); let publishing = $state(false); let includeClientTag = $state(true); + let showStatusModal = $state(false); + let publicationResults: { success: string[]; failed: Array<{ relay: string; error: string }> } | null = $state(null); /** * Determine what kind of reply to create @@ -106,18 +111,40 @@ content: content.trim() }; - const config = nostrClient.getConfig(); - const result = await signAndPublish(event, [...config.defaultRelays]); + // Get target's inbox if replying to someone + let targetInbox: string[] | undefined; + const targetPubkey = parentEvent?.pubkey || rootEvent?.pubkey; + if (targetPubkey && targetPubkey !== sessionManager.getCurrentPubkey()) { + try { + const { inbox } = await fetchRelayLists(targetPubkey); + targetInbox = inbox; + } catch (error) { + console.warn('Failed to fetch target inbox relays:', error); + // Continue without target inbox + } + } + + // Use proper relay selection for comments + const publishRelays = relayManager.getCommentPublishRelays(targetInbox); + const result = await signAndPublish(event, publishRelays); + + // Show publication status modal + publicationResults = result; + showStatusModal = true; if (result.success.length > 0) { content = ''; onPublished?.(); - } else { - alert('Failed to publish comment'); } } catch (error) { console.error('Error publishing comment:', error); - alert('Error publishing comment'); + // Show error in modal if possible, otherwise alert + const errorMessage = error instanceof Error ? error.message : String(error); + publicationResults = { + success: [], + failed: [{ relay: 'Unknown', error: errorMessage }] + }; + showStatusModal = true; } finally { publishing = false; } @@ -162,6 +189,8 @@ + +