From cb23c7954f359a769698000338f2490cc02daf22 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Sat, 11 Oct 2025 09:44:38 +0200 Subject: [PATCH] render markup in discussions and bugfix relay selection and updating --- .../Note/DiscussionContent/index.tsx | 47 ++++++++++ src/components/Note/index.tsx | 3 +- .../DiscussionsPage/CreateThreadDialog.tsx | 5 +- src/pages/primary/DiscussionsPage/index.tsx | 85 ++++++++++++++++--- src/services/client.service.ts | 5 +- 5 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 src/components/Note/DiscussionContent/index.tsx diff --git a/src/components/Note/DiscussionContent/index.tsx b/src/components/Note/DiscussionContent/index.tsx new file mode 100644 index 0000000..c052c9f --- /dev/null +++ b/src/components/Note/DiscussionContent/index.tsx @@ -0,0 +1,47 @@ +import Markdown from 'react-markdown' +import remarkGfm from 'remark-gfm' +import { Event } from 'nostr-tools' +import { useMemo } from 'react' +import NostrNode from '../LongFormArticle/NostrNode' +import { remarkNostr } from '../LongFormArticle/remarkNostr' +import { Components } from '../LongFormArticle/types' + +export default function DiscussionContent({ + event, + className +}: { + event: Event + className?: string +}) { + const components = useMemo( + () => + ({ + nostr: (props) => ( + + ), + }) as Components, + [] + ) + + return ( +
+ { + if (url.startsWith('nostr:')) { + return url.slice(6) // Remove 'nostr:' prefix for rendering + } + return url + }} + components={components} + > + {event.content} + +
+ ) +} diff --git a/src/components/Note/index.tsx b/src/components/Note/index.tsx index 30148ea..126d414 100644 --- a/src/components/Note/index.tsx +++ b/src/components/Note/index.tsx @@ -19,6 +19,7 @@ import UserAvatar from '../UserAvatar' import Username from '../Username' import { MessageSquare } from 'lucide-react' import CommunityDefinition from './CommunityDefinition' +import DiscussionContent from './DiscussionContent' import GroupMetadata from './GroupMetadata' import Highlight from './Highlight' import IValue from './IValue' @@ -97,7 +98,7 @@ export default function Note({ content = ( <>

{title}

- + ) } else if (event.kind === ExtendedKind.POLL) { diff --git a/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx b/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx index a22baff..ef2ceb5 100644 --- a/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx +++ b/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx @@ -12,6 +12,7 @@ import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useNostr } from '@/providers/NostrProvider' import { TDraftEvent } from '@/types' +import { NostrEvent } from 'nostr-tools' import { prefixNostrAddresses } from '@/lib/nostr-address' import { showPublishingError } from '@/lib/publishing-feedback' import dayjs from 'dayjs' @@ -41,7 +42,7 @@ interface CreateThreadDialogProps { availableRelays: string[] selectedRelay?: string | null onClose: () => void - onThreadCreated: () => void + onThreadCreated: (publishedEvent?: NostrEvent) => void } export const DISCUSSION_TOPICS = [ @@ -206,7 +207,7 @@ export default function CreateThreadDialog({ if (publishedEvent) { - onThreadCreated() + onThreadCreated(publishedEvent) onClose() } else { throw new Error(t('Failed to publish thread')) diff --git a/src/pages/primary/DiscussionsPage/index.tsx b/src/pages/primary/DiscussionsPage/index.tsx index bb5a943..9901aab 100644 --- a/src/pages/primary/DiscussionsPage/index.tsx +++ b/src/pages/primary/DiscussionsPage/index.tsx @@ -18,6 +18,7 @@ import TopicSubscribeButton from '@/components/TopicSubscribeButton' import { NostrEvent } from 'nostr-tools' import client from '@/services/client.service' import noteStatsService from '@/services/note-stats.service' +import storage from '@/services/local-storage.service' import { useSecondaryPage } from '@/PageManager' import { toNote } from '@/lib/link' import { kinds } from 'nostr-tools' @@ -60,20 +61,56 @@ const DiscussionsPage = forwardRef((_, ref) => { [pubkey, favoriteRelays] ) - // Memoize relay URLs with deduplication - const relayUrls = useMemo(() => { - if (selectedRelay) { - // Check if it's a relay set - const relaySet = relaySets.find(set => set.id === selectedRelay) - if (relaySet) { - return relaySet.relayUrls + // State for relay URLs + const [relayUrls, setRelayUrls] = useState([]) + + // Update relay URLs when dependencies change + useEffect(() => { + const updateRelayUrls = async () => { + if (selectedRelay) { + // Check if it's a relay set + const relaySet = relaySets.find(set => set.id === selectedRelay) + if (relaySet) { + setRelayUrls(relaySet.relayUrls) + return + } + // It's an individual relay + setRelayUrls([selectedRelay]) + return } - // It's an individual relay - return [selectedRelay] + + // For "All Relays", include user's write relays and stored relay sets too + let userWriteRelays: string[] = [] + let storedRelaySetRelays: string[] = [] + + if (pubkey) { + try { + // Get user's write relays + const relayList = await client.fetchRelayList(pubkey) + userWriteRelays = relayList?.write || [] + + // Get relays from stored relay sets (additional safety check) + // Note: favoriteRelays should already include these, but let's be thorough + const storedRelaySets = storage.getRelaySets() + storedRelaySetRelays = storedRelaySets.flatMap(set => set.relayUrls) + } catch (error) { + console.warn('Failed to fetch user relay list:', error) + } + } + + // Deduplicate and combine all relays: favorite relays, user write relays, stored relay sets, and fast read relays + const allRelays = Array.from(new Set([ + ...availableRelays, + ...userWriteRelays, + ...storedRelaySetRelays, + ...FAST_READ_RELAY_URLS + ])) + + setRelayUrls(allRelays) } - // Deduplicate and combine relays - return Array.from(new Set([...availableRelays, ...FAST_READ_RELAY_URLS])) - }, [selectedRelay, availableRelays, relaySets]) + + updateRelayUrls() + }, [selectedRelay, availableRelays, relaySets, pubkey, favoriteRelays]) // Available topic IDs for matching const availableTopicIds = useMemo(() => @@ -451,9 +488,29 @@ const DiscussionsPage = forwardRef((_, ref) => { setShowCreateThread(true) } - const handleThreadCreated = () => { + const handleThreadCreated = (publishedEvent?: NostrEvent) => { setShowCreateThread(false) - fetchAllThreads() // Refresh all threads + + if (publishedEvent) { + // Optimistically add the new thread to the local state + setAllThreads(prev => { + // Check if the thread is already in the list (avoid duplicates) + if (prev.some(thread => thread.id === publishedEvent.id)) { + return prev + } + + // Add relay source info + const eventHints = client.getEventHints(publishedEvent.id) + const relaySource = eventHints.length > 0 ? eventHints[0] : 'unknown' + const newThread = { ...publishedEvent, _relaySource: relaySource } + + // Add the new thread at the beginning (newest first) + return [newThread, ...prev] + }) + } else { + // Fallback: refresh all threads if no published event provided + fetchAllThreads() + } } return ( diff --git a/src/services/client.service.ts b/src/services/client.service.ts index ced50ad..da3cf06 100644 --- a/src/services/client.service.ts +++ b/src/services/client.service.ts @@ -1768,8 +1768,9 @@ class ClientService extends EventTarget { } }) - // Limit to 3 relays to prevent "too many concurrent REQs" errors - return validRelays.slice(0, 3) + // Limit to 8 relays to prevent "too many concurrent REQs" errors + // Increased from 3 to 8 for discussions to include more relay sources + return validRelays.slice(0, 8) } // ================= Utils =================