ui: uniform 160px thumbnail cells across all grid views

Timeline, Memories, and Duplicates now share a single fixed cell size
(THUMBNAIL_SIZE=160) with no 1fr stretching — cells stay exactly 160px
regardless of sidebar state, at the cost of a small right-edge strip
when the container width isn't a multiple of (160+gap). Width is
measured on the scroll container itself with padding subtracted so
sidebar expand/collapse reliably reflows the grid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-15 15:41:40 +02:00
parent 66b3bc5e1f
commit 45f1649979
3 changed files with 66 additions and 95 deletions

View File

@@ -87,7 +87,7 @@ export function DuplicatesView() {
// Track the rendered column count of the duplicates grid so ↑/↓ can
// skip a row instead of jumping a single cell. The grid uses
// `repeat(auto-fill, minmax(180px, 1fr))` so columns = floor(width/180).
// `repeat(auto-fill, minmax(160px, 1fr))` so columns = floor(width/160).
// We measure the FIRST section's grid container — every section uses
// the same auto-fill rule so any one is representative.
const [columns, setColumns] = useState(4)
@@ -100,7 +100,7 @@ export function DuplicatesView() {
sampleObserverRef.current = null
if (!el) return
const measure = () => {
const cols = Math.max(1, Math.floor(el.clientWidth / 180))
const cols = Math.max(1, Math.floor(el.clientWidth / 160))
setColumns(cols)
}
measure()
@@ -386,7 +386,7 @@ const DuplicateGroupSection = memo(function DuplicateGroupSection({
className="grid gap-1 p-2"
style={{
gridTemplateColumns:
'repeat(auto-fill, minmax(180px, 1fr))',
'repeat(auto-fill, 160px)',
}}
>
{group.members.map((member) => {
@@ -399,7 +399,7 @@ const DuplicateGroupSection = memo(function DuplicateGroupSection({
>
<PhotoThumbnail
photo={photoByMemberId.get(member.id)!}
size={180}
size={160}
fill
isSelected={selectedSet.has(member.id)}
onClick={handleClick}