diff --git a/src/lib/modules/feed/Kind1FeedPage.svelte b/src/lib/modules/feed/Kind1FeedPage.svelte index 1bcabc6..09877ae 100644 --- a/src/lib/modules/feed/Kind1FeedPage.svelte +++ b/src/lib/modules/feed/Kind1FeedPage.svelte @@ -9,21 +9,42 @@ let loading = $state(true); let replyingTo = $state(null); let showNewPostForm = $state(false); + let hasMore = $state(true); + let loadingMore = $state(false); onMount(async () => { await nostrClient.initialize(); loadFeed(); + + // Set up infinite scroll + window.addEventListener('scroll', handleScroll); + + return () => { + window.removeEventListener('scroll', handleScroll); + }; }); - async function loadFeed() { - loading = true; + async function loadFeed(reset = true) { + if (reset) { + loading = true; + posts = []; + hasMore = true; + } else { + loadingMore = true; + } + try { const config = nostrClient.getConfig(); + const oldestTimestamp = posts.length > 0 + ? Math.min(...posts.map(p => p.created_at)) + : undefined; + const filters = [ { kinds: [1], - limit: 50 + limit: 50, + ...(oldestTimestamp ? { until: oldestTimestamp } : {}) } ]; @@ -31,15 +52,45 @@ filters, [...config.defaultRelays], { useCache: true, cacheResults: true, onUpdate: (updated) => { - posts = sortPosts(updated); + if (reset) { + posts = sortPosts(updated); + } else { + // Merge new posts + const existingIds = new Set(posts.map(p => p.id)); + const newPosts = updated.filter(e => !existingIds.has(e.id)); + posts = sortPosts([...posts, ...newPosts]); + } }} ); - posts = sortPosts(events); + if (reset) { + posts = sortPosts(events); + } else { + // Merge new posts + const existingIds = new Set(posts.map(p => p.id)); + const newPosts = events.filter(e => !existingIds.has(e.id)); + posts = sortPosts([...posts, ...newPosts]); + } + + hasMore = events.length >= 50; } catch (error) { console.error('Error loading feed:', error); } finally { loading = false; + loadingMore = false; + } + } + + function handleScroll() { + if (loadingMore || !hasMore) return; + + const scrollTop = window.scrollY || document.documentElement.scrollTop; + const windowHeight = window.innerHeight; + const documentHeight = document.documentElement.scrollHeight; + + // Load more when within 200px of bottom + if (scrollTop + windowHeight >= documentHeight - 200) { + loadFeed(false); } } @@ -94,6 +145,12 @@ {/each} + {#if loadingMore} +

Loading more...

+ {/if} + {#if !hasMore && posts.length > 0} +

No more posts

+ {/if} {/if} diff --git a/src/lib/modules/threads/CreateThreadForm.svelte b/src/lib/modules/threads/CreateThreadForm.svelte index f6ab25f..a66b334 100644 --- a/src/lib/modules/threads/CreateThreadForm.svelte +++ b/src/lib/modules/threads/CreateThreadForm.svelte @@ -1,6 +1,7 @@