refactor: rename loupe to preview, bind to E and Space, fix empty viewer
The loupe view is now called "preview" everywhere — file paths, type
names, store actions, and the contextual hint pill. There's a single
preview action bound to E and Space (Enter is gone); double-click on a
thumbnail still works. Both shortcuts toggle: open from grid, close
from preview.
This commit also folds in the fix for the "preview shows nothing" bug
the user just hit:
- Extract usePhotosQuery into frontend/src/hooks/usePhotosQuery.ts so
Timeline, PreviewView, and App.tsx all share one query — and one
cache entry. Previously PreviewView and App.tsx looked the cache up
by ['photos'], but the Timeline query key gained the filter params
(['photos', filterParams]) when the filter bar shipped, so the
lookup returned undefined and the preview rendered "No photo to
display". App.tsx's getFirstPhotoId callback had the same bug.
- Harden PreviewImage: render the <img> immediately and overlay the
spinner with absolute positioning, instead of toggling opacity-0 →
opacity-100 on load. The previous opacity-toggle could leave the
image stuck invisible if the load event raced with a key change.
- Add { preventDefault: true } to every useHotkeys call so single
letter shortcuts (1-5, P, X, U) no longer leak into Firefox quick-
find, and Cmd/Ctrl+F no longer triggers the browser find toolbar.
Files renamed:
components/loupe/LoupeView.tsx -> components/preview/PreviewView.tsx
components/loupe/LoupeImage.tsx -> components/preview/PreviewImage.tsx
components/loupe/LoupeFilmstrip.tsx -> components/preview/PreviewFilmstrip.tsx
components/loupe/loupeSrc.ts -> components/preview/previewSrc.ts
Symbol renames: openLoupe→openPreview, closeLoupe→closePreview, the
viewMode 'loupe' tag → 'preview', and all the LoupeXxx component and
helper exports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,23 +4,23 @@ export function KeyboardHints() {
|
||||
const selectedCount = usePhotoStore((state) => state.selectedPhotos.length)
|
||||
const viewMode = usePhotoStore((state) => state.viewMode)
|
||||
|
||||
// In loupe mode the photo viewer has its own context, so the grid hints
|
||||
// In preview mode the viewer has its own context, so the grid hints
|
||||
// would just be confusing. Hide them.
|
||||
if (viewMode === 'loupe') return null
|
||||
if (viewMode === 'preview') return null
|
||||
|
||||
const hints = selectedCount > 0
|
||||
? [
|
||||
{ key: '1-5', action: 'Rate' },
|
||||
{ key: 'P', action: 'Pick' },
|
||||
{ key: 'X', action: 'Trash' },
|
||||
{ key: 'E', action: 'Loupe' },
|
||||
{ key: 'E / Space', action: 'Preview' },
|
||||
{ key: 'Esc', action: 'Deselect' },
|
||||
]
|
||||
: [
|
||||
{ key: '↑↓←→', action: 'Navigate' },
|
||||
{ key: 'Click', action: 'Select' },
|
||||
{ key: 'Shift+Click', action: 'Range' },
|
||||
{ key: 'Space', action: 'Preview' },
|
||||
{ key: 'E / Space', action: 'Preview' },
|
||||
{ key: '\\', action: 'Filters' },
|
||||
{ key: '/', action: 'Search' },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user