fix: preview navigation walks the timeline's visible order
Previously the preview view walked the raw API photos array for arrow navigation and the filmstrip. In tag-grouped mode (and any future layout where the visible grid order diverges from the API sort) that diverged from the order the user actually saw — they'd hit ← / → and land on a photo that wasn't adjacent in the grid. Fix: Timeline publishes its flat visible-order id sequence into the photo store as visiblePhotoIds whenever its layout items change (including duplicates from tag buckets, which is what the user wants in tag mode — landing on a photo's second appearance in the next bucket is the right behavior). PreviewView resolves that sequence back to Photo objects via the rawPhotos map and uses the result for both arrow nav and the filmstrip. Falls back to the raw photos list when the sequence isn't populated yet. Also clean up the lingering hardcoded http://localhost:8001 in usePhotosQuery — switched to the shared axios instance with the relative /api/v1 baseURL so the hook works cross-machine through the nginx / vite proxy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import { X, Info } from 'lucide-react'
|
||||
import { usePhotoStore } from '../../store/photoStore'
|
||||
@@ -13,6 +13,7 @@ export function PreviewView() {
|
||||
const activePhotoId = usePhotoStore((s) => s.activePhotoId)
|
||||
const setActivePhoto = usePhotoStore((s) => s.setActivePhoto)
|
||||
const closePreview = usePhotoStore((s) => s.closePreview)
|
||||
const visiblePhotoIds = usePhotoStore((s) => s.visiblePhotoIds)
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const previouslyFocusedRef = useRef<HTMLElement | null>(null)
|
||||
@@ -20,7 +21,23 @@ export function PreviewView() {
|
||||
|
||||
// Same hook Timeline uses, so we share one cache entry rather than looking
|
||||
// it up by key (which broke when the key gained the filter params).
|
||||
const { data: photos = [] } = usePhotosQuery()
|
||||
const { data: rawPhotos = [] } = usePhotosQuery()
|
||||
|
||||
// Walk the timeline's visible-order sequence (published by Timeline
|
||||
// into the photo store), which respects tag-grouping and any other
|
||||
// grid-layout rearrangement. Falls back to the raw photos list when
|
||||
// the sequence isn't populated yet — relevant on a fresh page load
|
||||
// where the user opened preview before the timeline mounted.
|
||||
const photos: Photo[] = useMemo(() => {
|
||||
if (visiblePhotoIds.length === 0) return rawPhotos
|
||||
const byId = new Map(rawPhotos.map((p) => [p.id, p]))
|
||||
const out: Photo[] = []
|
||||
for (const id of visiblePhotoIds) {
|
||||
const p = byId.get(id)
|
||||
if (p) out.push(p)
|
||||
}
|
||||
return out
|
||||
}, [visiblePhotoIds, rawPhotos])
|
||||
|
||||
const currentIndex = activePhotoId
|
||||
? photos.findIndex((p) => p.id === activePhotoId)
|
||||
|
||||
Reference in New Issue
Block a user