Add 3-photo split layout to og images

This commit is contained in:
Sam Becker 2025-09-27 22:02:19 -05:00
parent 1d0973bfd1
commit 64c4b21f75
2 changed files with 64 additions and 36 deletions

View File

@ -66,7 +66,7 @@ export default function EntityHover({
} }
}, [photosCount]); }, [photosCount]);
const splitLayout = photosCount === 3; const hasSplitLayout = photosCount === 3;
const content = useMemo(() => const content = useMemo(() =>
<div className="relative w-full h-full"> <div className="relative w-full h-full">
@ -77,7 +77,7 @@ export default function EntityHover({
<PhotoMedium <PhotoMedium
key={photos[index].id} key={photos[index].id}
photo={photos[index]} photo={photos[index]}
className={clsx(splitLayout && index === 0 && 'row-span-2')} className={clsx(hasSplitLayout && index === 0 && 'row-span-2')}
/>)} />)}
</div> </div>
{/* Placeholder grid */} {/* Placeholder grid */}
@ -93,7 +93,7 @@ export default function EntityHover({
key={index} key={index}
className={clsx( className={clsx(
'border-[0.5px] border-main', 'border-[0.5px] border-main',
splitLayout && index === 0 && 'row-span-2', hasSplitLayout && index === 0 && 'row-span-2',
)} )}
/>)} />)}
</div> </div>
@ -137,7 +137,7 @@ export default function EntityHover({
</div> </div>
, [ , [
gridClass, gridClass,
splitLayout, hasSplitLayout,
photosToShow, photosToShow,
photos, photos,
header, header,

View File

@ -26,11 +26,12 @@ export default async function ImagePhotoGrid({
{ width: NextImageSize, widthArbitrary?: undefined } | { width: NextImageSize, widthArbitrary?: undefined } |
{ width?: undefined, widthArbitrary: number } { width?: undefined, widthArbitrary: number }
))) { ))) {
let count = 1; let count = photos.length;
if (photos.length >= 12) { count = 12; } if (photos.length >= 12) { count = 12; }
else if (photos.length >= 6) { count = 6; } else if (photos.length >= 6) { count = 6; }
else if (photos.length >= 4) { count = 4; } else if (photos.length >= 4) { count = 4; }
else if (photos.length >= 2) { count = 2; }
const hasSplitLayout = count === 3;
const nextImageWidth: NextImageSize = count <= 2 const nextImageWidth: NextImageSize = count <= 2
? width ?? 1080 ? width ?? 1080
@ -39,17 +40,48 @@ export default async function ImagePhotoGrid({
let rows = 1; let rows = 1;
if (count > 12) { rows = 4; } if (count > 12) { rows = 4; }
else if (count > 6) { rows = 3; } else if (count > 6) { rows = 3; }
else if (count > 3) { rows = 2; } else if (count >= 3) { rows = 2; }
const imagesPerRow = count / rows; const imagesPerRow = Math.round(count / rows);
const cellWidth = (width ?? widthArbitrary) / imagesPerRow - const cellWidth = (
(imagesPerRow - 1) * gap / (imagesPerRow); (width ?? widthArbitrary) / imagesPerRow -
(imagesPerRow - 1) * gap / (imagesPerRow)
);
const cellHeight= height / rows - const cellHeight= height / rows -
(rows - 1) * gap / rows; (rows - 1) * gap / rows;
const doOptimizedFilesExist = await doAllPhotosHaveOptimizedFiles(photos); const doOptimizedFilesExist = await doAllPhotosHaveOptimizedFiles(photos);
const renderPhoto = ({ id, url }: Photo, width: number, height: number) =>
<div
key={id}
style={{
display: 'flex',
width,
height,
overflow: 'hidden',
filter: 'saturate(1.1)',
}}
>
<img {...{
src: getOptimizedPhotoUrl({
imageUrl: url,
size: nextImageWidth,
addBypassSecret: IS_PREVIEW,
compatibilityMode: !doOptimizedFilesExist,
}),
style: {
...imageStyle,
width: '100%',
...imagePosition === 'center' && {
height: '100%',
},
objectFit: 'cover',
},
}} />
</div>;
return ( return (
<div <div
style={{ style={{
@ -60,35 +92,31 @@ export default async function ImagePhotoGrid({
gap, gap,
}} }}
> >
{photos.slice(0, count).map(({ id, url }) => {hasSplitLayout
<div ? <>
key={id} {/* Large image (L) */}
style={{ <div style={{
display: 'flex', display: 'flex',
width: cellWidth, width: cellWidth,
height: cellHeight * 2,
}}>
{renderPhoto(photos[0], cellWidth, cellHeight * 2)}
</div>
{/* Small images (R) */}
<div style={{
display: 'flex',
flexDirection: 'column',
width: cellWidth,
height: cellHeight, height: cellHeight,
overflow: 'hidden', }}>
filter: 'saturate(1.1)', {photos.slice(1).map(photo =>
}} renderPhoto(photo, cellWidth, cellHeight),
> )}
<img {...{ </div>
src: getOptimizedPhotoUrl({ </>
imageUrl: url, : photos.slice(0, count).map(photo =>
size: nextImageWidth, renderPhoto(photo, cellWidth, cellHeight),
addBypassSecret: IS_PREVIEW, )}
compatibilityMode: !doOptimizedFilesExist,
}),
style: {
...imageStyle,
width: '100%',
...imagePosition === 'center' && {
height: '100%',
},
objectFit: 'cover',
},
}} />
</div>,
)}
</div> </div>
); );
} }