mirror of
https://github.com/dergigi/boris.git
synced 2025-12-19 07:34:28 +01:00
perf(ui): stream results to UI; show cached/local immediately (articles, highlights, explore)
This commit is contained in:
@@ -46,7 +46,21 @@ const Explore: React.FC<ExploreProps> = ({ relayPool }) => {
|
||||
const posts = await fetchBlogPostsFromAuthors(
|
||||
relayPool,
|
||||
Array.from(contacts),
|
||||
relayUrls
|
||||
relayUrls,
|
||||
(post) => {
|
||||
// Stream posts as we get them
|
||||
setBlogPosts((prev) => {
|
||||
const exists = prev.some(p => p.event.id === post.event.id)
|
||||
if (exists) return prev
|
||||
const next = [...prev, post]
|
||||
// Keep sorted by published or created_at
|
||||
return next.sort((a, b) => {
|
||||
const timeA = a.published || a.event.created_at
|
||||
const timeB = b.published || b.event.created_at
|
||||
return timeB - timeA
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (posts.length === 0) {
|
||||
|
||||
@@ -57,7 +57,21 @@ export function useExternalUrlLoader({
|
||||
|
||||
// Check if fetchHighlightsForUrl exists, otherwise skip
|
||||
if (typeof fetchHighlightsForUrl === 'function') {
|
||||
const highlightsList = await fetchHighlightsForUrl(relayPool, url)
|
||||
const seen = new Set<string>()
|
||||
const highlightsList = await fetchHighlightsForUrl(
|
||||
relayPool,
|
||||
url,
|
||||
(highlight) => {
|
||||
if (seen.has(highlight.id)) return
|
||||
seen.add(highlight.id)
|
||||
setHighlights((prev) => {
|
||||
if (prev.some(h => h.id === highlight.id)) return prev
|
||||
const next = [...prev, highlight]
|
||||
return next.sort((a, b) => b.created_at - a.created_at)
|
||||
})
|
||||
}
|
||||
)
|
||||
// Ensure final list is sorted and contains all items
|
||||
setHighlights(highlightsList.sort((a, b) => b.created_at - a.created_at))
|
||||
console.log(`📌 Found ${highlightsList.length} highlights for URL`)
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RelayPool, completeOnEose } from 'applesauce-relay'
|
||||
import { lastValueFrom, race, takeUntil, timer, toArray } from 'rxjs'
|
||||
import { RelayPool, completeOnEose, onlyEvents } from 'applesauce-relay'
|
||||
import { lastValueFrom, take, takeUntil, timer, toArray } from 'rxjs'
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { AddressPointer } from 'nostr-tools/nip19'
|
||||
import { NostrEvent } from 'nostr-tools'
|
||||
@@ -119,7 +119,12 @@ export async function fetchArticleByNaddr(
|
||||
events = await lastValueFrom(
|
||||
relayPool
|
||||
.req(localRelays, filter)
|
||||
.pipe(completeOnEose(), takeUntil(timer(1200)), toArray())
|
||||
.pipe(
|
||||
onlyEvents(),
|
||||
take(1),
|
||||
takeUntil(timer(1200)),
|
||||
toArray()
|
||||
)
|
||||
)
|
||||
} catch {
|
||||
events = []
|
||||
@@ -131,7 +136,12 @@ export async function fetchArticleByNaddr(
|
||||
events = await lastValueFrom(
|
||||
relayPool
|
||||
.req(orderedRelays, filter)
|
||||
.pipe(completeOnEose(), takeUntil(timer(6000)), toArray())
|
||||
.pipe(
|
||||
onlyEvents(),
|
||||
take(1),
|
||||
takeUntil(timer(6000)),
|
||||
toArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ export interface BlogPostPreview {
|
||||
export const fetchBlogPostsFromAuthors = async (
|
||||
relayPool: RelayPool,
|
||||
pubkeys: string[],
|
||||
relayUrls: string[]
|
||||
relayUrls: string[],
|
||||
onPost?: (post: BlogPostPreview) => void
|
||||
): Promise<BlogPostPreview[]> => {
|
||||
try {
|
||||
if (pubkeys.length === 0) {
|
||||
@@ -48,7 +49,11 @@ export const fetchBlogPostsFromAuthors = async (
|
||||
authors: pubkeys,
|
||||
limit: 100
|
||||
})
|
||||
.pipe(completeOnEose(), takeUntil(timer(1200)), toArray())
|
||||
.pipe(
|
||||
completeOnEose(),
|
||||
takeUntil(timer(1200)),
|
||||
toArray()
|
||||
)
|
||||
)
|
||||
} catch {
|
||||
events = []
|
||||
@@ -84,14 +89,18 @@ export const fetchBlogPostsFromAuthors = async (
|
||||
|
||||
// Convert to blog post previews and sort by published date (most recent first)
|
||||
const blogPosts: BlogPostPreview[] = Array.from(uniqueEvents.values())
|
||||
.map(event => ({
|
||||
event,
|
||||
title: getArticleTitle(event) || 'Untitled',
|
||||
summary: getArticleSummary(event),
|
||||
image: getArticleImage(event),
|
||||
published: getArticlePublished(event),
|
||||
author: event.pubkey
|
||||
}))
|
||||
.map(event => {
|
||||
const post: BlogPostPreview = {
|
||||
event,
|
||||
title: getArticleTitle(event) || 'Untitled',
|
||||
summary: getArticleSummary(event),
|
||||
image: getArticleImage(event),
|
||||
published: getArticlePublished(event),
|
||||
author: event.pubkey
|
||||
}
|
||||
if (onPost) onPost(post)
|
||||
return post
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const timeA = a.published || a.event.created_at
|
||||
const timeB = b.published || b.event.created_at
|
||||
|
||||
@@ -169,6 +169,7 @@ export const fetchHighlightsForArticle = async (
|
||||
export const fetchHighlightsForUrl = async (
|
||||
relayPool: RelayPool,
|
||||
url: string,
|
||||
onHighlight?: (highlight: Highlight) => void,
|
||||
settings?: UserSettings
|
||||
): Promise<Highlight[]> => {
|
||||
try {
|
||||
@@ -187,6 +188,10 @@ export const fetchHighlightsForUrl = async (
|
||||
onlyEvents(),
|
||||
tap((event: NostrEvent) => {
|
||||
seenIds.add(event.id)
|
||||
if (onHighlight) {
|
||||
const h = eventToHighlight(event)
|
||||
onHighlight(h)
|
||||
}
|
||||
}),
|
||||
completeOnEose(),
|
||||
takeUntil(timer(1200)),
|
||||
@@ -205,6 +210,10 @@ export const fetchHighlightsForUrl = async (
|
||||
onlyEvents(),
|
||||
tap((event: NostrEvent) => {
|
||||
seenIds.add(event.id)
|
||||
if (onHighlight) {
|
||||
const h = eventToHighlight(event)
|
||||
onHighlight(h)
|
||||
}
|
||||
}),
|
||||
completeOnEose(),
|
||||
takeUntil(timer(6000)),
|
||||
|
||||
Reference in New Issue
Block a user