Browse Source

render markup in discussions and bugfix relay selection and updating

imwald
Silberengel 5 months ago
parent
commit
cb23c7954f
  1. 47
      src/components/Note/DiscussionContent/index.tsx
  2. 3
      src/components/Note/index.tsx
  3. 5
      src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx
  4. 85
      src/pages/primary/DiscussionsPage/index.tsx
  5. 5
      src/services/client.service.ts

47
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) => (
<NostrNode
rawText={props.rawText}
bech32Id={props.bech32Id}
/>
),
}) as Components,
[]
)
return (
<div
className={`prose prose-zinc max-w-none dark:prose-invert break-words overflow-wrap-anywhere ${className || ''}`}
>
<Markdown
remarkPlugins={[remarkGfm, remarkNostr]}
urlTransform={(url) => {
if (url.startsWith('nostr:')) {
return url.slice(6) // Remove 'nostr:' prefix for rendering
}
return url
}}
components={components}
>
{event.content}
</Markdown>
</div>
)
}

3
src/components/Note/index.tsx

@ -19,6 +19,7 @@ import UserAvatar from '../UserAvatar'
import Username from '../Username' import Username from '../Username'
import { MessageSquare } from 'lucide-react' import { MessageSquare } from 'lucide-react'
import CommunityDefinition from './CommunityDefinition' import CommunityDefinition from './CommunityDefinition'
import DiscussionContent from './DiscussionContent'
import GroupMetadata from './GroupMetadata' import GroupMetadata from './GroupMetadata'
import Highlight from './Highlight' import Highlight from './Highlight'
import IValue from './IValue' import IValue from './IValue'
@ -97,7 +98,7 @@ export default function Note({
content = ( content = (
<> <>
<h3 className="mt-2 text-lg font-semibold leading-tight break-words">{title}</h3> <h3 className="mt-2 text-lg font-semibold leading-tight break-words">{title}</h3>
<Content className="mt-2" event={event} /> <DiscussionContent className="mt-2" event={event} />
</> </>
) )
} else if (event.kind === ExtendedKind.POLL) { } else if (event.kind === ExtendedKind.POLL) {

5
src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx

@ -12,6 +12,7 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { TDraftEvent } from '@/types' import { TDraftEvent } from '@/types'
import { NostrEvent } from 'nostr-tools'
import { prefixNostrAddresses } from '@/lib/nostr-address' import { prefixNostrAddresses } from '@/lib/nostr-address'
import { showPublishingError } from '@/lib/publishing-feedback' import { showPublishingError } from '@/lib/publishing-feedback'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -41,7 +42,7 @@ interface CreateThreadDialogProps {
availableRelays: string[] availableRelays: string[]
selectedRelay?: string | null selectedRelay?: string | null
onClose: () => void onClose: () => void
onThreadCreated: () => void onThreadCreated: (publishedEvent?: NostrEvent) => void
} }
export const DISCUSSION_TOPICS = [ export const DISCUSSION_TOPICS = [
@ -206,7 +207,7 @@ export default function CreateThreadDialog({
if (publishedEvent) { if (publishedEvent) {
onThreadCreated() onThreadCreated(publishedEvent)
onClose() onClose()
} else { } else {
throw new Error(t('Failed to publish thread')) throw new Error(t('Failed to publish thread'))

85
src/pages/primary/DiscussionsPage/index.tsx

@ -18,6 +18,7 @@ import TopicSubscribeButton from '@/components/TopicSubscribeButton'
import { NostrEvent } from 'nostr-tools' import { NostrEvent } from 'nostr-tools'
import client from '@/services/client.service' import client from '@/services/client.service'
import noteStatsService from '@/services/note-stats.service' import noteStatsService from '@/services/note-stats.service'
import storage from '@/services/local-storage.service'
import { useSecondaryPage } from '@/PageManager' import { useSecondaryPage } from '@/PageManager'
import { toNote } from '@/lib/link' import { toNote } from '@/lib/link'
import { kinds } from 'nostr-tools' import { kinds } from 'nostr-tools'
@ -60,20 +61,56 @@ const DiscussionsPage = forwardRef((_, ref) => {
[pubkey, favoriteRelays] [pubkey, favoriteRelays]
) )
// Memoize relay URLs with deduplication // State for relay URLs
const relayUrls = useMemo(() => { const [relayUrls, setRelayUrls] = useState<string[]>([])
if (selectedRelay) {
// Check if it's a relay set // Update relay URLs when dependencies change
const relaySet = relaySets.find(set => set.id === selectedRelay) useEffect(() => {
if (relaySet) { const updateRelayUrls = async () => {
return relaySet.relayUrls 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])) updateRelayUrls()
}, [selectedRelay, availableRelays, relaySets]) }, [selectedRelay, availableRelays, relaySets, pubkey, favoriteRelays])
// Available topic IDs for matching // Available topic IDs for matching
const availableTopicIds = useMemo(() => const availableTopicIds = useMemo(() =>
@ -451,9 +488,29 @@ const DiscussionsPage = forwardRef((_, ref) => {
setShowCreateThread(true) setShowCreateThread(true)
} }
const handleThreadCreated = () => { const handleThreadCreated = (publishedEvent?: NostrEvent) => {
setShowCreateThread(false) 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 ( return (

5
src/services/client.service.ts

@ -1768,8 +1768,9 @@ class ClientService extends EventTarget {
} }
}) })
// Limit to 3 relays to prevent "too many concurrent REQs" errors // Limit to 8 relays to prevent "too many concurrent REQs" errors
return validRelays.slice(0, 3) // Increased from 3 to 8 for discussions to include more relay sources
return validRelays.slice(0, 8)
} }
// ================= Utils ================= // ================= Utils =================

Loading…
Cancel
Save