grid tiles get their gap back, and the picture fills the tile
TWO REPORTS, ONE MEASUREMENT WRONG AND ONE SHAPE WRONG. the rows looked vertically stacked because the card OVERFLOWED its row. GRID_ROW_HEIGHT was 130 while the card was `p-4` around a 64px thumbnail plus two lines of text — about 148 — so each card ate the 12px gap and the next row touched it. the horizontal gap was fine, which is exactly what made it read as a styling oddity rather than a number being wrong. the height is now derived from the card instead of guessed: a 96px image band, `py-2` around a 20px name and a 16px meta line, inside a 2px border. 152. guessing is how it came to be 130. THE PICTURE NOW FILLS THE TILE. it was a fixed `h-16 w-20` box, so a landscape photo sat in the middle with air either side and a portrait one shrank to nothing. `w-full` with the card clipping means every tile reads as the same shape whatever the photograph is — which is the whole reason a grid of pictures is easier to scan than a grid of names. so the card lost its padding and gained `overflow-hidden`: the image reaches the edges and the card does the clipping. the padding moved to the text block, the only part that ever wanted it. the image itself is not rounded — the card clips, and rounding both would show a sliver of card colour inside each corner. a folder icon sits in the same 96px band, so a folder and a photograph are the same shape and the rows line up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
+13
-1
@@ -15,7 +15,19 @@ type FileGridProps = {
|
||||
};
|
||||
|
||||
const LIST_ROW_HEIGHT = 42;
|
||||
const GRID_ROW_HEIGHT = 130;
|
||||
/*
|
||||
What one grid row actually occupies, and why the number changed.
|
||||
|
||||
It was 130 while the card was `p-4` around a 64px thumbnail plus two lines of text — about 148. The
|
||||
card overflowed its own row by roughly the size of the gap, so consecutive rows touched and the grid
|
||||
looked vertically stacked. The horizontal gap was fine, which is what made it read as a styling
|
||||
oddity rather than a measurement being wrong.
|
||||
|
||||
Now: a 96px image band, then `py-2` (16) around a 20px name and a 16px meta line, inside a 2px
|
||||
border. 96 + 16 + 20 + 16 + 4 = 152. Measured against the card rather than guessed, because guessing
|
||||
is how it came to be 130.
|
||||
*/
|
||||
const GRID_ROW_HEIGHT = 152;
|
||||
const GRID_GAP = 12;
|
||||
const HEADER_HEIGHT = 36;
|
||||
// Type-ahead: keys pressed within this window accumulate into one burst. 1–2 chars jump to the first
|
||||
|
||||
+21
-4
@@ -641,7 +641,20 @@ export const FileItem = ({
|
||||
sharp enough for a retina screen at both. One key, one render, and the views cannot diverge.
|
||||
*/
|
||||
const listVisual = entry.thumb ? withThumb(entry.thumb, icon, 'size-7 rounded', 256) : icon;
|
||||
const gridVisual = entry.thumb ? withThumb(entry.thumb, iconLarge, 'h-16 w-20 rounded-md', 256) : iconLarge;
|
||||
|
||||
/*
|
||||
The grid picture fills the card's WIDTH and is cropped by height.
|
||||
|
||||
It used to be a fixed `h-16 w-20` box centred with `object-contain`, so a landscape photo sat in the
|
||||
middle of the card with air either side and a portrait one shrank to nothing. `w-full` with the
|
||||
card's own `overflow-hidden` doing the clipping means every tile reads as the same shape whatever
|
||||
the photograph is — which is the whole reason a grid of pictures is easier to scan than a grid of
|
||||
names.
|
||||
|
||||
No rounding here: the card clips, so rounding the image too would show a sliver of card colour
|
||||
inside the corner.
|
||||
*/
|
||||
const gridVisual = entry.thumb ? withThumb(entry.thumb, iconLarge, 'h-24 w-full', 256) : iconLarge;
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -784,7 +797,7 @@ export const FileItem = ({
|
||||
<ContextMenuTrigger asChild onContextMenu={handleContextMenu}>
|
||||
<div
|
||||
data-file-item
|
||||
className={`group relative rounded-lg border-2 p-4 flex flex-col items-center gap-2 hover:border-duck-teal/50 data-[state=open]:border-duck-teal/50 transition-colors cursor-pointer ${
|
||||
className={`group relative flex cursor-pointer flex-col overflow-hidden rounded-lg border-2 hover:border-duck-teal/50 data-[state=open]:border-duck-teal/50 transition-colors ${
|
||||
selected ? 'border-duck-teal/50 bg-duck-teal/10' : 'border-duck-dark/20'
|
||||
} ${cutOpacity} select-none`}
|
||||
style={selected ? undefined : cardStyle()}
|
||||
@@ -800,8 +813,11 @@ export const FileItem = ({
|
||||
<EllipsisMenu {...menuProps} onEnsureSelected={ensureSelected} />
|
||||
</div>
|
||||
|
||||
{gridVisual}
|
||||
{/* One fixed-height band whether it holds a photograph or a folder icon, so every tile is
|
||||
the same shape and the rows line up. The card clips; this does not round. */}
|
||||
<div className="flex h-24 w-full shrink-0 items-center justify-center overflow-hidden">{gridVisual}</div>
|
||||
|
||||
<div className="flex min-w-0 flex-col items-center gap-0.5 px-2 py-2">
|
||||
{renaming ? (
|
||||
<InlineRenameInput
|
||||
initialName={entry.name}
|
||||
@@ -809,7 +825,7 @@ export const FileItem = ({
|
||||
onCancel={() => setRenaming(false)}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-sm font-medium text-duck-dark text-center truncate w-full">{entry.name}</span>
|
||||
<span className="w-full truncate text-center text-sm font-medium text-duck-dark">{entry.name}</span>
|
||||
)}
|
||||
|
||||
<span className="text-xs text-duck-dark/50">
|
||||
@@ -818,6 +834,7 @@ export const FileItem = ({
|
||||
{date(entry.modifiedAt, { month: 'short', day: 'numeric', year: 'numeric' })}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent className="z-[600]">
|
||||
<ContextMenuItems {...menuProps} />
|
||||
|
||||
Reference in New Issue
Block a user