diff --git a/web/apps/photos/package.json b/web/apps/photos/package.json index d251673d67..60ec4e439c 100644 --- a/web/apps/photos/package.json +++ b/web/apps/photos/package.json @@ -19,7 +19,7 @@ "react-dom": "^19.0.0", "react-select": "^5.10.1", "react-top-loading-bar": "^3.0.2", - "react-virtualized-auto-sizer": "^1.0.25", + "react-virtualized-auto-sizer": "^1.0.26", "react-window": "^1.8.11", "sanitize-filename": "^1.6.3", "similarity-transformation": "^0.0.1", diff --git a/web/apps/photos/src/components/Collections/AllAlbums.tsx b/web/apps/photos/src/components/Collections/AllAlbums.tsx index bdba10219d..c9bcf6993f 100644 --- a/web/apps/photos/src/components/Collections/AllAlbums.tsx +++ b/web/apps/photos/src/components/Collections/AllAlbums.tsx @@ -21,15 +21,11 @@ import { import type { CollectionSummary } from "ente-new/photos/services/collection/ui"; import { CollectionsSortBy } from "ente-new/photos/services/collection/ui"; import { FlexWrapper, FluidContainer } from "ente-shared/components/Container"; -import useWindowSize from "ente-shared/hooks/useWindowSize"; import { t } from "i18next"; import memoize from "memoize-one"; import React, { useEffect, useRef, useState } from "react"; -import { - areEqual, - FixedSizeList as List, - ListChildComponentProps, -} from "react-window"; +import AutoSizer from "react-virtualized-auto-sizer"; +import { areEqual, FixedSizeList, ListChildComponentProps } from "react-window"; interface AllAlbums { open: boolean; @@ -84,7 +80,7 @@ export const AllAlbums: React.FC = ({ ); }; -export const AllCollectionMobileBreakpoint = 559; +const Column3To2Breakpoint = 559; const AllAlbumsDialog = styled(Dialog)(({ theme }) => ({ "& .MuiDialog-container": { justifyContent: "flex-end" }, @@ -94,7 +90,7 @@ const AllAlbumsDialog = styled(Dialog)(({ theme }) => ({ paddingRight: theme.spacing(1), }, "& .MuiDialogContent-root": { padding: theme.spacing(2) }, - [theme.breakpoints.down(AllCollectionMobileBreakpoint)]: { + [theme.breakpoints.down(Column3To2Breakpoint)]: { "& .MuiPaper-root": { width: "324px" }, "& .MuiDialogContent-root": { padding: 6 }, }, @@ -142,20 +138,8 @@ const Title = ({ ); -const MobileColumns = 2; -const DesktopColumns = 3; - const CollectionRowItemSize = 154; -const getCollectionRowListHeight = ( - collectionRowList: CollectionSummary[][], - windowSize: { height: number; width: number }, -) => - Math.min( - collectionRowList.length * CollectionRowItemSize + 32, - windowSize?.height - 177, - ) || 0; - interface ItemData { collectionRowList: CollectionSummary[][]; onCollectionClick: (id?: number) => void; @@ -211,15 +195,21 @@ const AllAlbumsContent: React.FC = ({ collectionSummaries, onCollectionClick, }) => { + const isTwoColumn = useMediaQuery(`(width < ${Column3To2Breakpoint}px)`); + const refreshInProgress = useRef(false); const shouldRefresh = useRef(false); const [collectionRowList, setCollectionRowList] = useState([]); - const windowSize = useWindowSize(); + const columns = isTwoColumn ? 2 : 3; + const maxListContentHeight = + Math.ceil(collectionSummaries.length / columns) * + CollectionRowItemSize + + 32; /* padding above first and below last row */ useEffect(() => { - if (!windowSize.width || !collectionSummaries) { + if (!collectionSummaries) { return; } const main = async () => { @@ -231,10 +221,6 @@ const AllAlbumsContent: React.FC = ({ const collectionRowList: CollectionSummary[][] = []; let index = 0; - const columns = - windowSize.width > AllCollectionMobileBreakpoint - ? DesktopColumns - : MobileColumns; while (index < collectionSummaries.length) { const collectionRow: CollectionSummary[] = []; for ( @@ -254,7 +240,7 @@ const AllAlbumsContent: React.FC = ({ } }; main(); - }, [collectionSummaries, windowSize]); + }, [collectionSummaries, columns]); // Bundle additional data to list items using the "itemData" prop. // It will be accessible to item renderers as props.data. @@ -262,19 +248,29 @@ const AllAlbumsContent: React.FC = ({ const itemData = createItemData(collectionRowList, onCollectionClick); return ( - - + + {({ width, height }) => ( + + {AlbumsRow} + )} - width={"100%"} - itemCount={collectionRowList.length} - itemSize={CollectionRowItemSize} - itemData={itemData} - > - {AlbumsRow} - + ); }; diff --git a/web/packages/shared/hooks/useWindowSize.tsx b/web/packages/shared/hooks/useWindowSize.tsx deleted file mode 100644 index 2b0cad3468..0000000000 --- a/web/packages/shared/hooks/useWindowSize.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// https://usehooks.com/useWindowSize/ -import { useEffect, useState } from "react"; - -// Hook -export default function useWindowSize() { - // Initialize state with undefined width/height so server and client renders match - // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/ - const [windowSize, setWindowSize] = useState<{ - width: number; - height: number; - }>({ width: undefined, height: undefined }); - - useEffect(() => { - // Handler to call on window resize - function handleResize() { - // Set window width/height to state - setWindowSize({ - width: window.innerWidth, - height: window.innerHeight, - }); - } - - // Add event listener - window.addEventListener("resize", handleResize); - - // Call handler right away so state gets updated with initial window size - handleResize(); - - // Remove event listener on cleanup - return () => window.removeEventListener("resize", handleResize); - }, []); // Empty array ensures that effect is only run on mount - - return windowSize; -} diff --git a/web/yarn.lock b/web/yarn.lock index 50abd1b02e..6d728a8c00 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -3381,10 +3381,10 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react-virtualized-auto-sizer@^1.0.25: - version "1.0.25" - resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.25.tgz#b13cbc528ac200be2bd1ffa40c8bb19bcc60ac3f" - integrity sha512-YHsksEGDfsHbHuaBVDYwJmcktblcHGafz4ZVuYPQYuSHMUGjpwmUCrAOcvMSGMwwk1eFWj1M/1GwYpNPuyhaBg== +react-virtualized-auto-sizer@^1.0.26: + version "1.0.26" + resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz#e9470ef6a778dc4f1d5fd76305fa2d8b610c357a" + integrity sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A== react-window@^1.8.11: version "1.8.11"