/| / | .
+ // Standalone image paragraphs are handled separately in renderParagraph().
+ const label = String(token.text ?? src)
if (isVideo(cleaned) || isAudio(cleaned)) {
- // Inline context: do NOT mount block media players inside paragraph flow.
out.push(
- {src}
+ {label}
)
break
}
if (!isImage(cleaned) || !isSafeMediaUrl(cleaned)) {
- // Non-HTTP image tokens (e.g. npub...) must not be passed to image/media components.
- out.push(
-
- {src}
-
- )
+ out.push({label})
break
}
- const identifier = getImageIdentifier?.(cleaned)
- const thumbnail =
- imageThumbnailMap?.get(cleaned) ??
- (identifier ? imageThumbnailMap?.get(`__img_id:${identifier}`) : undefined)
- const imageUrl = thumbnail || src
- const imageIdx = imageIndexMap.get(cleaned)
out.push(
- {
- e.stopPropagation()
- if (typeof imageIdx === 'number') openLightbox(imageIdx)
- }}
- />
+
+ {label}
+
)
break
}
diff --git a/src/components/Note/PublicationIndex/PublicationIndex.tsx b/src/components/Note/PublicationIndex/PublicationIndex.tsx
index 02d07d4f..a8d47c9d 100644
--- a/src/components/Note/PublicationIndex/PublicationIndex.tsx
+++ b/src/components/Note/PublicationIndex/PublicationIndex.tsx
@@ -626,7 +626,7 @@ export default function PublicationIndex({
)
}
- const eventKind = ref.kind || ref.event.kind
+ const eventKind = ref.event?.kind ?? ref.kind ?? 0
const effectiveParentImageUrl = !isNested ? metadata.image : parentImageUrl
if (eventKind === ExtendedKind.PUBLICATION) {
diff --git a/src/hooks/usePublicationSectionLoader.ts b/src/hooks/usePublicationSectionLoader.ts
index 5e88e923..45630e4b 100644
--- a/src/hooks/usePublicationSectionLoader.ts
+++ b/src/hooks/usePublicationSectionLoader.ts
@@ -15,6 +15,7 @@ import type { Event } from 'nostr-tools'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
const PUB_SEC_LOG = '[PublicationSection]'
+const SINGLE_REF_FALLBACK_TIMEOUT_MS = 7000
function pubLog(message: string, data?: Record) {
if (!import.meta.env.DEV) return
if (data) logger.info(`${PUB_SEC_LOG} ${message}`, data)
@@ -60,13 +61,18 @@ async function hydrateRefsFromIndexedDb(refs: PublicationSectionRef[]): Promise<
}
async function fetchSingleRefFallback(ref: PublicationSectionRef): Promise {
+ const withTimeout = (p: Promise, ms: number): Promise =>
+ new Promise((resolve) => {
+ const t = setTimeout(() => resolve(undefined), ms)
+ p.then((v) => resolve(v)).catch(() => resolve(undefined)).finally(() => clearTimeout(t))
+ })
try {
if (ref.type === 'a' && ref.coordinate) {
const bech32 = generateBech32IdFromATag(['a', ref.coordinate, ref.relay || '', ''])
- if (bech32) return await eventService.fetchEvent(bech32)
+ if (bech32) return await withTimeout(eventService.fetchEvent(bech32), SINGLE_REF_FALLBACK_TIMEOUT_MS)
}
if (ref.type === 'e' && ref.eventId) {
- return await eventService.fetchEvent(ref.eventId)
+ return await withTimeout(eventService.fetchEvent(ref.eventId), SINGLE_REF_FALLBACK_TIMEOUT_MS)
}
} catch {
/* ignore */
@@ -87,36 +93,51 @@ export function usePublicationSectionLoader(indexEvent: Event, referencesData: P
}
return keys
}, [referencesData])
+ const orderedKeysSignature = useMemo(() => orderedKeys.join('|'), [orderedKeys])
const [rows, setRows] = useState |