From a0d275490be01e918adab183de16363954c1e72e Mon Sep 17 00:00:00 2001 From: Claudio Date: Mon, 11 May 2026 10:32:14 +0200 Subject: [PATCH] =?UTF-8?q?ui(preview):=20preload=20thumbs=20for=20=C2=B15?= =?UTF-8?q?=20neighbors,=20not=20just=20adjacent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/preview/PreviewView.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/preview/PreviewView.tsx b/frontend/src/components/preview/PreviewView.tsx index 1a09dbe..dcf5937 100644 --- a/frontend/src/components/preview/PreviewView.tsx +++ b/frontend/src/components/preview/PreviewView.tsx @@ -138,13 +138,17 @@ export function PreviewView() { useHotkeys('right', goNext, { preventDefault: true }) useHotkeys('i', () => setInfoPanelOpen((v) => !v), { preventDefault: true }) - // Preload the immediate neighbors so arrow nav feels instant. Skip videos - // (browsers can't preload them via Image()) and skip when at the edges. + // Preload the ±5 neighbor thumbnails so arrow nav feels instant. Cheap + // because getPreviewImageSrc returns the 1280px thumb; the current photo's + // full-res /proxy upgrade is handled separately inside PreviewImage. Skip + // videos (browsers can't preload them via Image()) and clamp to bounds. useEffect(() => { - const neighbors: Photo[] = [] - if (safeIndex > 0) neighbors.push(photos[safeIndex - 1]) - if (safeIndex < photos.length - 1) neighbors.push(photos[safeIndex + 1]) - for (const p of neighbors) { + const PRELOAD_RADIUS = 5 + const start = Math.max(0, safeIndex - PRELOAD_RADIUS) + const end = Math.min(photos.length - 1, safeIndex + PRELOAD_RADIUS) + for (let i = start; i <= end; i++) { + if (i === safeIndex) continue + const p = photos[i] if (isVideo(p)) continue const img = new Image() img.src = getPreviewImageSrc(p)