diff --git a/frontend/src/components/timeline/PhotoThumbnail.tsx b/frontend/src/components/timeline/PhotoThumbnail.tsx index 908c7f4..21ac608 100644 --- a/frontend/src/components/timeline/PhotoThumbnail.tsx +++ b/frontend/src/components/timeline/PhotoThumbnail.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useRef } from 'react' -import { Star, Check, X, RefreshCw } from 'lucide-react' +import { Star, Check, Trash2, RefreshCw } from 'lucide-react' import clsx from 'clsx' import { photos as photosApi } from '../../services/api' import type { Photo } from '../../types/photo' @@ -28,9 +28,11 @@ export function PhotoThumbnail({ photo, size, isSelected, onClick, onDoubleClick const baseUrl = photosApi.getThumbnailUrl(photo.id, 'medium') const thumbnailUrl = retryCount > 0 ? `${baseUrl}?retry=${retryCount}` : baseUrl - // Calculate aspect ratio for proper sizing (default to 1:1 if dimensions unknown) - const aspectRatio = (photo.height && photo.width) ? photo.height / photo.width : 1 - const displayHeight = size * Math.min(aspectRatio, 1.5) // Cap height at 1.5x width + // Square cells (Lightroom-style grid). Variable-aspect cells previously + // overflowed their row because TanStack Virtual estimates row height as a + // single fixed value — portraits in a landscape row would overlap the row + // below. With object-cover the image still fills the cell, just cropped. + const displayHeight = size const clearRetryTimer = () => { if (retryTimerRef.current !== null) { @@ -169,8 +171,8 @@ export function PhotoThumbnail({ photo, size, isSelected, onClick, onDoubleClick {photo.is_picked && ( )} - {photo.is_rejected && ( - + {photo.is_trashed && ( + )}