fix: visible-order range selection + preview-after-Space sequence

Two related bugs around visible vs API order.

1. Multi-select range selection (Shift+Click, Shift+Arrow):
- The previous selectRange walked the API photos array and only
  ADDED to the existing selection, never replacing or shrinking. So
  Shift+clicking to the left often "did nothing" (already-selected
  ids skipped) and the selection never matched the user's intended
  range.
- Replace with a store action that walks visiblePhotoIds (the visual
  row-major sequence Timeline already publishes), de-dupes ids
  (tag-grouped views can repeat photos), and REPLACES the selection.
- Track the range anchor as rangeStartId (a photo id) instead of an
  index so it survives filter changes and works correctly when API
  index != visual position.
- Drop the now-redundant lastSelectedIndex / globalIndex plumbing
  from selectPhoto / togglePhotoSelection — call sites simplify to
  pass just the photo id.

2. Preview navigation after pressing Space:
- The Space hotkey path called openPreview(id) without a sequence
  and relied on the store's fallback to whatever Timeline most
  recently published. Make it explicit: read visiblePhotoIds from
  the store snapshot at fire time and pass it through. Same effect
  in the happy case but eliminates any subtle publisher timing
  question.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-08 22:04:18 +02:00
parent e2ee9b691c
commit 123c60ed2c
3 changed files with 90 additions and 59 deletions

View File

@@ -300,8 +300,13 @@ export function useKeyboardShortcuts(props: KeyboardShortcutsProps) {
// Space toggles the preview view (open from grid, close from preview).
// Double-click on a thumbnail does the same.
const openPreviewFromGrid = () => {
const id = usePhotoStore.getState().activePhotoId ?? getFirstPhotoId?.() ?? null
if (id) openPreview(id)
const state = usePhotoStore.getState()
const id = state.activePhotoId ?? getFirstPhotoId?.() ?? null
if (!id) return
// Pass the current visible sequence explicitly so preview navigation
// walks the order the user actually sees, even if the active photo
// was selected before the publisher caught up.
openPreview(id, state.visiblePhotoIds)
}
const togglePreview = () => {