From c64ce9507ed9931a25d4be793eb36a0f27d20e87 Mon Sep 17 00:00:00 2001 From: nick-funk <code@nickfunk.com> Date: Sat, 27 Jul 2024 01:40:52 -0600 Subject: [PATCH 1/3] stack tenor gif results tightly in a cascade grid --- .../tabs/Comments/TenorInput/TenorGrid.css | 34 ++++ .../tabs/Comments/TenorInput/TenorGrid.tsx | 158 ++++++++++++++++++ .../tabs/Comments/TenorInput/TenorInput.css | 29 ---- .../tabs/Comments/TenorInput/TenorInput.tsx | 37 +--- 4 files changed, 201 insertions(+), 57 deletions(-) create mode 100644 client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css create mode 100644 client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css new file mode 100644 index 0000000000..5c2772950b --- /dev/null +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css @@ -0,0 +1,34 @@ +.grid { + max-height: 300px; + overflow: auto; +} + +.gridColumns { + display: flex; + flex-direction: row; + justify-content: center; +} + +.gridColumn { + display: flex; + flex-direction: column; +} + +.gridControls { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.gridItem { + width: 85px; + background: var(--palette-background-body); + border-style: none; + padding: 0px; +} + +.gridImage { + width: 100%; + height: auto; +} diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx new file mode 100644 index 0000000000..a12bc4642a --- /dev/null +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx @@ -0,0 +1,158 @@ +import { Localized } from "@fluent/react/compat"; +import React, { + FunctionComponent, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { useCoralContext } from "coral-framework/lib/bootstrap"; +import { Button } from "coral-ui/components/v2"; + +import { GifResult } from "./TenorInput"; + +import styles from "./TenorGrid.css"; + +interface GridItemProps { + gif: GifResult; + onSelect: (gif: GifResult) => void; +} + +const TenorGridItem: FunctionComponent<GridItemProps> = ({ gif, onSelect }) => { + const onClick = useCallback(() => { + onSelect(gif); + }, [gif, onSelect]); + + return ( + <button className={styles.gridItem} onClick={onClick}> + <img className={styles.gridImage} alt={gif.title} src={gif.preview}></img> + </button> + ); +}; + +interface GridColumnsProps { + gifs: GifResult[]; + onSelectGif: (gif: GifResult) => void; + numColumns: number; +} + +const TenorGridColumns: FunctionComponent<GridColumnsProps> = ({ + gifs, + onSelectGif, + numColumns, +}) => { + const columns = useMemo(() => { + const resultColumns: GifResult[][] = []; + for (let i = 0; i < numColumns; i++) { + resultColumns.push(new Array<GifResult>()); + } + + let columnIndex = 0; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let j = 0; j < gifs.length; j++) { + const column = resultColumns[columnIndex]; + const gif = gifs[j]; + + column.push(gif); + + columnIndex++; + if (columnIndex >= numColumns) { + columnIndex = 0; + } + } + + return resultColumns; + }, [gifs, numColumns]); + + return ( + <div className={styles.gridColumns}> + {columns.map((colGifs, colIndex) => { + return ( + <div + key={`tenor-gif-result-column-${colIndex}`} + className={styles.gridColumn} + > + {colGifs && + colGifs.map((gif, index) => { + return ( + <TenorGridItem + key={`${gif.id}-${index}`} + gif={gif} + onSelect={onSelectGif} + /> + ); + })} + </div> + ); + })} + </div> + ); +}; + +interface Props { + gifs: GifResult[]; + showLoadMore?: boolean; + + onSelectGif: (gif: GifResult) => void; + onLoadMore: () => void; +} + +const TenorGrid: FunctionComponent<Props> = ({ + gifs, + showLoadMore, + onSelectGif, + onLoadMore, +}) => { + const { window } = useCoralContext(); + + const gridRef = useRef<HTMLDivElement>(null); + const [cols, setCols] = useState<number>(0); + + const resizeGrid = useCallback(() => { + if (!gridRef || !gridRef.current) { + setCols(0); + return; + } + + const rect = gridRef.current.getBoundingClientRect(); + const numCols = rect.width / 90; + + setCols(numCols); + }, [gridRef, setCols]); + + useEffect(() => { + window.requestAnimationFrame(resizeGrid); + window.addEventListener("resize", resizeGrid); + + return () => { + window.removeEventListener("resize", resizeGrid); + }; + // include gifs so we re-calc grid col's on gif change + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [gifs]); + + return ( + <div className={styles.grid}> + {gifs && cols > 0 && ( + <TenorGridColumns + gifs={gifs} + onSelectGif={onSelectGif} + numColumns={cols} + /> + )} + {showLoadMore && ( + <div className={styles.gridControls} ref={gridRef}> + <Localized id="comments-postComment-gifSearch-search-loadMore"> + <Button color="stream" onClick={onLoadMore}> + Load More + </Button> + </Localized> + </div> + )} + </div> + ); +}; + +export default TenorGrid; diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.css b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.css index 201a68c1a7..1446ef3e8c 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.css +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.css @@ -29,35 +29,6 @@ max-width: 100%; } -.grid { - max-height: 300px; - overflow: auto; - - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 8px; -} - -.gridControls { - width: 100%; - display: flex; - justify-content: center; - align-items: center; -} - -.gridItem { - width: 85px; - background: var(--palette-background-body); - border-style: none; - padding: 0px; -} - -.gridImage { - width: 100%; - height: auto; -} - .input { border-top-right-radius: 0; border-bottom-right-radius: 0; diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx index ae9e8e90de..5d0f62e6fd 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx @@ -18,6 +18,7 @@ import { ButtonSvgIcon, SearchIcon } from "coral-ui/components/icons"; import { Button, HorizontalGutter, TextField } from "coral-ui/components/v2"; import TenorAttribution from "./TenorAttribution"; +import TenorGrid from "./TenorGrid"; import styles from "./TenorInput.css"; @@ -181,34 +182,14 @@ const TenorInput: FunctionComponent<Props> = ({ onSelect }) => { } ref={inputRef} /> - <div className={styles.grid}> - {query && - gifs && - gifs.map((gif, index) => { - return ( - <button - className={styles.gridItem} - key={`${gif.id}-${index}`} - onClick={() => onGifClick(gif)} - > - <img - className={styles.gridImage} - alt={gif.title} - src={gif.preview} - ></img> - </button> - ); - })} - {next && gifs && gifs.length > 0 && query?.length > 0 && ( - <div className={styles.gridControls}> - <Localized id="comments-postComment-gifSearch-search-loadMore"> - <Button color="stream" onClick={onLoadMore}> - Load More - </Button> - </Localized> - </div> - )} - </div> + <TenorGrid + gifs={query ? gifs : []} + showLoadMore={ + !!(next && gifs && gifs.length > 0 && query?.length > 0) + } + onSelectGif={onGifClick} + onLoadMore={onLoadMore} + /> <TenorAttribution /> </HorizontalGutter> </div> From 921a71b318be5e17ab8107daf60fa97f96d9f692 Mon Sep 17 00:00:00 2001 From: nick-funk <code@nickfunk.com> Date: Sat, 27 Jul 2024 01:47:34 -0600 Subject: [PATCH 2/3] flex center tenor gif search result images --- .../core/client/stream/tabs/Comments/TenorInput/TenorGrid.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css index 5c2772950b..e3b40ccca6 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css @@ -26,6 +26,9 @@ background: var(--palette-background-body); border-style: none; padding: 0px; + + display: flex; + justify-content: center; } .gridImage { From 426039d0da9eadb40d04b0d3d26de698927625ba Mon Sep 17 00:00:00 2001 From: nick-funk <code@nickfunk.com> Date: Wed, 31 Jul 2024 09:20:42 -0600 Subject: [PATCH 3/3] set padding on grid items --- .../core/client/stream/tabs/Comments/TenorInput/TenorGrid.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css index e3b40ccca6..458806cd34 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css @@ -25,7 +25,7 @@ width: 85px; background: var(--palette-background-body); border-style: none; - padding: 0px; + padding: 2px; display: flex; justify-content: center;