From b559b8250f90b5e1864aea59a0825e2bcdad4d8f Mon Sep 17 00:00:00 2001 From: Citali Date: Sun, 1 Feb 2026 23:28:09 +0100 Subject: [PATCH] Fix responsive layout with max items per row for each breakpoint --- src/components/gallery/JustifiedGallery.tsx | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/gallery/JustifiedGallery.tsx b/src/components/gallery/JustifiedGallery.tsx index 2364d10..c7956d7 100644 --- a/src/components/gallery/JustifiedGallery.tsx +++ b/src/components/gallery/JustifiedGallery.tsx @@ -125,7 +125,13 @@ export default function JustifiedGallery({ const isMobile = containerWidth < 640; const targetH = isMobile ? targetRowHeightMobile : targetRowHeight; - const maxItems = isMobile ? maxRowItemsMobile : maxRowItems; + const minRowHeight = Math.round(targetH * 0.8); + const maxItems = (() => { + if (containerWidth < 480) return Math.min(2, maxRowItemsMobile); + if (containerWidth < 720) return Math.min(3, maxRowItems); + if (containerWidth < 1024) return Math.min(4, maxRowItems); + return maxRowItems; + })(); const rowTiles: RowTile[][] = []; let current: Array<{ item: JustifiedGalleryItem; aspect: number }> = []; @@ -164,6 +170,23 @@ export default function JustifiedGallery({ // Estimate the row width if we were to keep targetH const estimatedWidth = aspectSum * targetH + gap * (current.length - 1); + // If the computed height would be too small, split the row earlier. + if (current.length > 1) { + const gaps = gap * (current.length - 1); + const widthWithoutGaps = Math.max(0, available - gaps); + const computedH = widthWithoutGaps / aspectSum; + if (computedH < minRowHeight) { + const last = current.pop(); + if (last) { + aspectSum -= last.aspect; + flush(); + current = [last]; + aspectSum = last.aspect; + } + continue; + } + } + // If we've filled the row (or reached max items) and have at least 2 tiles, flush. if ( (estimatedWidth >= available || current.length >= maxItems) &&