From 64a87f0d37ce0846947b0c37c5d49ae9407f36f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Balogh=20Barnab=C3=A1s?= Date: Wed, 24 Dec 2025 00:07:10 +0100 Subject: [PATCH 1/2] Trim devlogs list and adjust scroll on load more --- src/routes/dashboard/explore/+page.svelte | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/routes/dashboard/explore/+page.svelte b/src/routes/dashboard/explore/+page.svelte index 2ac2c3f..a5c7ebd 100644 --- a/src/routes/dashboard/explore/+page.svelte +++ b/src/routes/dashboard/explore/+page.svelte @@ -1,10 +1,13 @@ @@ -52,7 +53,7 @@ /> - {#if devlog.model} + {#if devlog.model && show3DPreview}
diff --git a/src/routes/dashboard/explore/+page.svelte b/src/routes/dashboard/explore/+page.svelte index a5c7ebd..40f3fba 100644 --- a/src/routes/dashboard/explore/+page.svelte +++ b/src/routes/dashboard/explore/+page.svelte @@ -5,9 +5,6 @@ let { data } = $props(); - const MAX_DEVLOGS = 60; - const TRIMMED_DEVLOGS = 45; - let devlogs = $state([...data.devlogs]); let hasMore = $state(data.hasMore); let nextOffset = $state(data.nextOffset); @@ -17,6 +14,10 @@ let observer: IntersectionObserver | null = null; const rootMargin = '320px 0px'; + let devlogRefs = $state<(HTMLDivElement | null)[]>([]); + let previewVisibility = $state(new Array(data.devlogs.length).fill(true)); + const PREVIEW_UNMOUNT_MARGIN = 1200; + function hydrateDevlogs(rawDevlogs: typeof data.devlogs) { return rawDevlogs.map((entry) => ({ ...entry, @@ -27,45 +28,35 @@ })); } - async function trimDevlogsIfNeeded() { - await tick(); - if (devlogs.length <= MAX_DEVLOGS) return; - - const previousScroll = window.scrollY; - const previousHeight = document.body.scrollHeight; - const excess = devlogs.length - TRIMMED_DEVLOGS; - - devlogs = devlogs.slice(excess); - await tick(); - - const heightDelta = previousHeight - document.body.scrollHeight; - - if (heightDelta > 0) { - window.scrollTo({ top: Math.max(0, previousScroll - heightDelta) }); - } + function updatePreviewVisibility() { + previewVisibility = devlogRefs.map((ref) => { + if (!ref) return false; + const rect = ref.getBoundingClientRect(); + return ( + rect.bottom > -PREVIEW_UNMOUNT_MARGIN && + rect.top < window.innerHeight + PREVIEW_UNMOUNT_MARGIN + ); + }); } async function loadMoreDevlogs() { if (loadingMore || !hasMore) return; - loadingMore = true; loadError = ''; - try { const params = new URLSearchParams({ offset: `${nextOffset}` }); const response = await fetch(`/dashboard/explore?${params.toString()}`); - if (!response.ok) { throw new Error('Failed to load more devlogs'); } - const payload = await response.json(); const incoming = hydrateDevlogs(payload.devlogs ?? []); - devlogs = [...devlogs, ...incoming]; + previewVisibility = [...previewVisibility, ...new Array(incoming.length).fill(false)]; nextOffset = payload.nextOffset ?? nextOffset + incoming.length; hasMore = Boolean(payload.hasMore); - await trimDevlogsIfNeeded(); + await tick(); + updatePreviewVisibility(); } catch (error) { console.error(error); loadError = 'Could not load more right now.'; @@ -75,6 +66,11 @@ } onMount(() => { + const onScroll = () => updatePreviewVisibility(); + window.addEventListener('scroll', onScroll, { passive: true }); + window.addEventListener('resize', onScroll); + tick().then(updatePreviewVisibility); + if (!hasMore || !sentinel) return; observer = new IntersectionObserver( @@ -90,7 +86,11 @@ observer.observe(sentinel); - return () => observer?.disconnect(); + return () => { + window.removeEventListener('scroll', onScroll); + window.removeEventListener('resize', onScroll); + observer?.disconnect(); + }; }); @@ -109,23 +109,23 @@ />
{:else} - {#each devlogs as devlog (devlog.devlog.id)} - + {#each devlogs as devlog, i (devlog.devlog.id)} +
+ +
{/each} -
- {#if loadingMore}

Loading more...

{/if} - {#if loadError}
{loadError} @@ -134,7 +134,6 @@
{/if} - {#if !hasMore && !loadingMore}

You're caught up.

{/if}