From c9621bdf9f6cb06855b2476bac258ca6eccd5342 Mon Sep 17 00:00:00 2001 From: Gianni Ferullo Date: Tue, 21 Jan 2025 17:33:14 -0500 Subject: [PATCH] aspect ratio on grid --- .../react-components/src/components/gif.tsx | 7 +--- .../react-components/src/components/grid.tsx | 39 ++++++++++++------- .../src/components/masonry-grid.tsx | 28 ++++++------- .../react-components/stories/grid.stories.tsx | 31 ++++++++------- 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/packages/react-components/src/components/gif.tsx b/packages/react-components/src/components/gif.tsx index c8d8ce89..13d0a233 100644 --- a/packages/react-components/src/components/gif.tsx +++ b/packages/react-components/src/components/gif.tsx @@ -55,6 +55,7 @@ type GifProps = { gif: IGif width: number percentWidth?: string + percentHeight?: string height?: number backgroundColor?: string className?: string @@ -92,6 +93,7 @@ const Gif = ({ gif: { bottle_data: bottleData = {} }, width, percentWidth, + percentHeight, height: forcedHeight, onGifRightClick = noop, className = '', @@ -233,11 +235,6 @@ const Gif = ({ } }, []) const height = forcedHeight || getGifHeight(gif, width) - let percentHeight: string | undefined - if (!forcedHeight && percentWidth) { - const ratio = Math.round((height / width) * 100) - percentHeight = `${ratio}%` - } const bestRendition = getBestRendition(gif.images, width, height) if (!bestRendition) { if (gif.images) { diff --git a/packages/react-components/src/components/grid.tsx b/packages/react-components/src/components/grid.tsx index ed62d4f0..72a621c6 100644 --- a/packages/react-components/src/components/grid.tsx +++ b/packages/react-components/src/components/grid.tsx @@ -8,8 +8,7 @@ import { debounce } from 'throttle-debounce' import Observer from '../util/observer' import FetchError from './fetch-error' import Gif, { EventProps } from './gif' -import DotsLoader from './loader' -import MasonryGrid from './masonry-grid' +import MasonryGrid, { fillArray } from './masonry-grid' import PingbackContextManager from './pingback-context-manager' import type { GifOverlayProps } from './types' @@ -163,19 +162,30 @@ class Grid extends PureComponent { loaderConfig, tabIndex = 0, layoutType = 'GRID', - loader: LoaderVisual = DotsLoader, fetchPriority, } = this.props const { gifWidth, gifs, isError, isDoneFetching } = this.state const showLoader = !isDoneFetching const isFirstLoad = gifs.length === 0 // get the height of each grid item - const itemHeights = gifs.map((gif) => getGifHeight(gif, gifWidth)) const gifPercentWidth = percentWidth ? `${(gifWidth / width) * 100}%` : undefined + const totalHeights: number[] = fillArray(columns, columnOffsets) + const itemHeights = gifs.map((gif) => getGifHeight(gif, gifWidth)) + gifs.forEach((_, index: number) => { + const columnTarget = totalHeights.indexOf(Math.min(...totalHeights)) + const height = itemHeights[index] + if (height) { + totalHeights[columnTarget] += height + gutter + } + }) + const totalHeight = Math.round(Math.max(...totalHeights) - gutter) + const percentHeights = itemHeights.map((h) => `${(h / totalHeight) * 100}%`) return (
{ width={gifWidth} height={percentWidth ? itemHeights[index] : undefined} percentWidth={gifPercentWidth} + percentHeight={percentHeights[index]} onGifClick={onGifClick} onGifKeyPress={onGifKeyPress} onGifSeen={onGifSeen} @@ -208,18 +219,16 @@ class Grid extends PureComponent { ))} {!showLoader && gifs.length === 0 && noResultsMessage} - {isError ? ( - - ) : ( - showLoader && ( - - - - - - ) - )}
+ {isError ? ( + + ) : ( + showLoader && ( + + + + ) + )}
) } diff --git a/packages/react-components/src/components/masonry-grid.tsx b/packages/react-components/src/components/masonry-grid.tsx index bf0385ff..e285115f 100644 --- a/packages/react-components/src/components/masonry-grid.tsx +++ b/packages/react-components/src/components/masonry-grid.tsx @@ -1,10 +1,12 @@ import React, { CSSProperties, memo, ReactNode } from 'react' -function fillArray(length: number, columnOffsets: number[] = []) { +export function fillArray(length: number, columnOffsets: number[] = []) { return Array.apply(null, Array(length)).map((_, index) => columnOffsets[index] || 0) } type Props = { + totalHeight: number + totalWidth: number columns: number gutter: number percentWidth?: string @@ -15,6 +17,8 @@ type Props = { columnOffsets?: number[] } const MasonryGrid = ({ + totalHeight, + totalWidth, columns, gutter, itemWidth, @@ -23,22 +27,15 @@ const MasonryGrid = ({ columnOffsets = [], percentWidth, }: Props) => { - const containerStyle: CSSProperties = {} + const containerStyle: CSSProperties = { + position: 'relative', + } function getChildren() { - const totalHeights: number[] = fillArray(columns, columnOffsets) - const totalWidth = columns * itemWidth + (columns - 1) * gutter - React.Children.forEach(children, (_, index: number) => { - const columnTarget = totalHeights.indexOf(Math.min(...totalHeights)) - const height = itemHeights[index] - if (height) { - totalHeights[columnTarget] += height + gutter - } - }) - const totalHeight = Math.max(...totalHeights) - gutter const columnHeights: number[] = fillArray(columns, columnOffsets) const result = React.Children.map(children, (child: React.ReactNode, index: number) => { - const columnTarget = columnHeights.indexOf(Math.min.apply(Math, columnHeights)) - const top = `${(columnHeights[columnTarget] / totalHeight) * 100}%` + const columnTarget = columnHeights.indexOf(Math.min(...columnHeights)) + const topPerc = (columnHeights[columnTarget] / totalHeight) * 100 + const top = `${topPerc}%` const leftPixelTarget = (itemWidth + gutter) * columnTarget const left = `${(leftPixelTarget / totalWidth) * 100}%` const height = itemHeights[index] @@ -53,9 +50,8 @@ const MasonryGrid = ({ }, }) }) - containerStyle.position = 'relative' containerStyle.width = percentWidth - containerStyle.height = `${Math.max(...columnHeights) - gutter}px` + containerStyle.aspectRatio = `${totalWidth} / ${totalHeight}` return result } diff --git a/packages/react-components/stories/grid.stories.tsx b/packages/react-components/stories/grid.stories.tsx index ee653785..32cffab2 100644 --- a/packages/react-components/stories/grid.stories.tsx +++ b/packages/react-components/stories/grid.stories.tsx @@ -30,9 +30,9 @@ const NoResultsContainer = styled.div` const Overlay = ({ gif, isHovered }: GifOverlayProps) => {isHovered ? gif.id : ''} -type GridProps = Partial> +type GridProps = Partial> & { containerSize: number } -const Grid = ({ loader, ...other }: GridProps) => { +const Grid = ({ loader, containerSize, ...other }: GridProps) => { const [term, setTerm] = useState('always sunny') const [width, setWidth] = useState(innerWidth) const onResize = throttle(500, () => setWidth(innerWidth)) @@ -63,17 +63,19 @@ const Grid = ({ loader, ...other }: GridProps) => { value={term} /> {term && ( - +
+ +
)} ) @@ -107,6 +109,9 @@ export const GridStory: Story = {} export const GridResponsive: Story = { args: { percentWidth: '100%', + width: 375, + columns: 2, + containerSize: 500, }, }