From f7ea6c45f5f28d8508ccef1f74a3e609dbed1d06 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 8 Nov 2022 01:35:21 -0800 Subject: [PATCH] Add lazy image component --- package-lock.json | 16 ++ package.json | 1 + .../virtual-grid/grid-card/default-card.tsx | 181 +++--------------- .../virtual-grid/grid-card/poster-card.tsx | 76 +++----- 4 files changed, 70 insertions(+), 204 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f574a64b..f572edf0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "react-player": "^2.10.0", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", + "react-simple-img": "^3.0.0", "react-slider": "^2.0.0", "react-virtualized-auto-sizer": "^1.0.6", "react-window": "^1.8.7", @@ -17399,6 +17400,15 @@ "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-simple-img": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-simple-img/-/react-simple-img-3.0.0.tgz", + "integrity": "sha512-I0sG/GgY9c+04BgWf1YRlipWBQxR3oG2s/bagU8EO7zals3/Vkfk1PJMeYh/wHfjxJtUmal+y7HWEBm4MzXVsQ==", + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/react-slider": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-slider/-/react-slider-2.0.0.tgz", @@ -36732,6 +36742,12 @@ "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" } }, + "react-simple-img": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-simple-img/-/react-simple-img-3.0.0.tgz", + "integrity": "sha512-I0sG/GgY9c+04BgWf1YRlipWBQxR3oG2s/bagU8EO7zals3/Vkfk1PJMeYh/wHfjxJtUmal+y7HWEBm4MzXVsQ==", + "requires": {} + }, "react-slider": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-slider/-/react-slider-2.0.0.tgz", diff --git a/package.json b/package.json index f9f9dcaf8..e7e73450d 100644 --- a/package.json +++ b/package.json @@ -285,6 +285,7 @@ "react-player": "^2.10.0", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", + "react-simple-img": "^3.0.0", "react-slider": "^2.0.0", "react-virtualized-auto-sizer": "^1.0.6", "react-window": "^1.8.7", diff --git a/src/renderer/components/virtual-grid/grid-card/default-card.tsx b/src/renderer/components/virtual-grid/grid-card/default-card.tsx index 3f4d716c7..7f429ff60 100644 --- a/src/renderer/components/virtual-grid/grid-card/default-card.tsx +++ b/src/renderer/components/virtual-grid/grid-card/default-card.tsx @@ -3,6 +3,7 @@ import { Center, Skeleton } from '@mantine/core'; import { RiAlbumFill } from 'react-icons/ri'; import { generatePath, useNavigate } from 'react-router'; import { Link } from 'react-router-dom'; +import { SimpleImg, initSimpleImg } from 'react-simple-img'; import { ListChildComponentProps } from 'react-window'; import styled from 'styled-components'; import { Text } from '@/renderer/components/text'; @@ -15,6 +16,8 @@ import { CardRoute, } from '@/renderer/types'; +initSimpleImg({ threshold: 0.5 }, true); + const CardWrapper = styled.div<{ itemGap: number; itemHeight: number; @@ -87,14 +90,7 @@ const ImageSection = styled.div<{ size?: number }>` } `; -interface ImageProps { - height: number; - isLoading?: boolean; -} - -const Image = styled.img` - width: ${({ height }) => `${height - 24}px`}; - height: ${({ height }) => `${height - 24}px`}; +const Image = styled(SimpleImg)` object-fit: cover; border: 0; border-radius: var(--card-default-radius); @@ -127,6 +123,7 @@ const Row = styled.div<{ $secondary?: boolean }>` $secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)'}; white-space: nowrap; text-overflow: ellipsis; + user-select: none; `; interface BaseGridCardProps { @@ -136,7 +133,7 @@ interface BaseGridCardProps { cardRows: CardRow[]; handlePlayQueueAdd: (options: PlayQueueAddOptions) => void; itemType: LibraryItem; - route?: CardRoute; + route: CardRoute; }; data: any; listChildProps: Omit; @@ -161,161 +158,37 @@ export const DefaultCard = ({ controls; if (data) { - if (route) { - return ( - - navigate( - generatePath( - route.route, - route.slugs?.reduce((acc, slug) => { - return { - ...acc, - [slug.slugProperty]: data[slug.idProperty], - }; - }, {}) - ) - ) - } - > - - - {data?.imageUrl ? ( - - ) : ( -
- -
- )} - - {!isScrolling && ( - - )} - -
- - {cardRows.map((row: CardRow, index: number) => { - if (row.arrayProperty && row.route) { - return ( - 0} - > - {data[row.property].map( - (item: any, itemIndex: number) => ( - - {itemIndex > 0 && ( - - , - - )}{' '} - 0} - component={Link} - overflow="hidden" - to={generatePath( - row.route!.route, - row.route!.slugs?.reduce((acc, slug) => { - return { - ...acc, - [slug.slugProperty]: data[slug.idProperty], - }; - }, {}) - )} - onClick={(e) => e.stopPropagation()} - > - {row.arrayProperty && item[row.arrayProperty]} - - - ) - )} - - ); - } - - if (row.arrayProperty) { - return ( - - {data[row.property].map((item: any) => ( - 0} - overflow="hidden" - > - {row.arrayProperty && item[row.arrayProperty]} - - ))} - - ); - } - - return ( - - {row.route ? ( - { - return { - ...acc, - [slug.slugProperty]: data[slug.idProperty], - }; - }, {}) - )} - onClick={(e) => e.stopPropagation()} - > - {data && data[row.property]} - - ) : ( - 0} overflow="hidden"> - {data && data[row.property]} - - )} - - ); - })} - -
-
- ); - } return ( + navigate( + generatePath( + route.route, + route.slugs?.reduce((acc, slug) => { + return { + ...acc, + [slug.slugProperty]: data[slug.idProperty], + }; + }, {}) + ) + ) + } > {data?.imageUrl ? ( - + ) : (
` - width: ${({ height }) => `${height}px`}; - height: ${({ height }) => `${height}px`}; +const Image = styled(SimpleImg)` object-fit: cover; border: 0; border-radius: var(--card-poster-radius); - - ${fadeIn} - animation: fadein 0.3s ease-in-out; `; const ControlsContainer = styled.div` @@ -122,6 +119,7 @@ const Row = styled.div<{ $secondary?: boolean }>` $secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)'}; white-space: nowrap; text-overflow: ellipsis; + user-select: none; `; interface BaseGridCardProps { @@ -131,7 +129,7 @@ interface BaseGridCardProps { cardRows: CardRow[]; handlePlayQueueAdd: (options: PlayQueueAddOptions) => void; itemType: LibraryItem; - route?: CardRoute; + route: CardRoute; }; data: any; listChildProps: Omit; @@ -163,49 +161,27 @@ export const PosterCard = ({ itemWidth={itemWidth} > - {route ? ( - { - return { - ...acc, - [slug.slugProperty]: data[slug.idProperty], - }; - }, {}) - )} - > - - {data?.imageUrl ? ( - - ) : ( -
- -
- )} - - {!isScrolling && ( - - )} - -
- - ) : ( + { + return { + ...acc, + [slug.slugProperty]: data[slug.idProperty], + }; + }, {}) + )} + > {data?.imageUrl ? ( - + ) : (
- )} + {cardRows.map((row: CardRow, index: number) => { if (row.arrayProperty && row.route) {