Change gap calculation on gallery for better breakpoint on mobile and tablet
This commit is contained in:
@ -44,6 +44,9 @@ type Props = {
|
||||
maxRowItems?: number; // desktop
|
||||
maxRowItemsMobile?: number; // <640px
|
||||
gap?: number; // px
|
||||
gapNarrow?: number; // px for narrower containers
|
||||
gapNarrowMaxWidth?: number; // px breakpoint for gapNarrow
|
||||
gapBreakpoints?: Array<{ maxWidth: number; gap: number }>;
|
||||
debug?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
@ -85,12 +88,33 @@ export default function JustifiedGallery({
|
||||
maxRowItems = 5,
|
||||
maxRowItemsMobile = 3,
|
||||
gap = 12,
|
||||
gapNarrow,
|
||||
gapNarrowMaxWidth = 720,
|
||||
gapBreakpoints,
|
||||
debug = false,
|
||||
className,
|
||||
}: Props) {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const sentinelRef = useRef<HTMLDivElement | null>(null);
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
const effectiveGap = (() => {
|
||||
if (gapBreakpoints && containerWidth > 0) {
|
||||
const sorted = [...gapBreakpoints].sort((a, b) => a.maxWidth - b.maxWidth);
|
||||
for (const bp of sorted) {
|
||||
if (containerWidth <= bp.maxWidth) return bp.gap;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
gapNarrow != null &&
|
||||
containerWidth > 0 &&
|
||||
containerWidth <= gapNarrowMaxWidth
|
||||
) {
|
||||
return gapNarrow;
|
||||
}
|
||||
|
||||
return gap;
|
||||
})();
|
||||
|
||||
// Measure container width (responsive)
|
||||
useEffect(() => {
|
||||
@ -143,7 +167,7 @@ export default function JustifiedGallery({
|
||||
const flush = () => {
|
||||
if (current.length === 0) return;
|
||||
|
||||
const gaps = gap * (current.length - 1);
|
||||
const gaps = effectiveGap * (current.length - 1);
|
||||
const widthWithoutGaps = Math.max(0, available - gaps);
|
||||
|
||||
// Compute row height so it exactly fills the row width.
|
||||
@ -172,14 +196,15 @@ export default function JustifiedGallery({
|
||||
aspectSum += a;
|
||||
|
||||
// Estimate the row width if we were to keep targetH
|
||||
const estimatedWidth = aspectSum * targetH + gap * (current.length - 1);
|
||||
const estimatedWidth =
|
||||
aspectSum * targetH + effectiveGap * (current.length - 1);
|
||||
|
||||
// If we've filled the row (or reached max items) and have at least 2 tiles, flush.
|
||||
if (
|
||||
(estimatedWidth >= available || current.length >= maxItems) &&
|
||||
current.length > 1
|
||||
) {
|
||||
const gaps = gap * (current.length - 1);
|
||||
const gaps = effectiveGap * (current.length - 1);
|
||||
const widthWithoutGaps = Math.max(0, available - gaps);
|
||||
const computedH = widthWithoutGaps / aspectSum;
|
||||
|
||||
@ -227,7 +252,7 @@ export default function JustifiedGallery({
|
||||
}, [
|
||||
items,
|
||||
containerWidth,
|
||||
gap,
|
||||
effectiveGap,
|
||||
targetRowHeight,
|
||||
targetRowHeightMobile,
|
||||
maxRowHeight,
|
||||
@ -260,7 +285,7 @@ export default function JustifiedGallery({
|
||||
? "justify-start"
|
||||
: "justify-between",
|
||||
)}
|
||||
style={{ columnGap: gap }}
|
||||
style={{ columnGap: effectiveGap }}
|
||||
>
|
||||
{row.map((t) => (
|
||||
<GalleryTile
|
||||
@ -275,7 +300,8 @@ export default function JustifiedGallery({
|
||||
{debug ? (
|
||||
<div className="text-xs text-muted-foreground font-mono">
|
||||
{`row ${idx + 1} | h=${Math.round(row[0]?.h ?? 0)} | w=${Math.round(
|
||||
row.reduce((sum, t) => sum + t.w, 0) + gap * (row.length - 1),
|
||||
row.reduce((sum, t) => sum + t.w, 0) +
|
||||
effectiveGap * (row.length - 1),
|
||||
)} | items=${row.length} | `}
|
||||
{row
|
||||
.map(
|
||||
|
||||
@ -151,6 +151,11 @@ export default function PortfolioGallery({
|
||||
maxRowItems={5}
|
||||
maxRowItemsMobile={1}
|
||||
gap={12}
|
||||
gapBreakpoints={[
|
||||
{ maxWidth: 685, gap: 6 },
|
||||
{ maxWidth: 910, gap: 8 },
|
||||
{ maxWidth: 1130, gap: 10 },
|
||||
]}
|
||||
onLoadMore={done ? undefined : () => void loadMore()}
|
||||
hasMore={!done}
|
||||
isLoadingMore={loading}
|
||||
|
||||
Reference in New Issue
Block a user