From 62127df4f43b94339c5d1b0706e27b0e5e8647c2 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 24 Oct 2025 00:05:10 -0700 Subject: [PATCH] more grid list optimizations --- .../components/item-card/item-card.tsx | 46 ++-- .../item-grid-list/item-grid-list.tsx | 210 +++++++++--------- 2 files changed, 117 insertions(+), 139 deletions(-) diff --git a/src/renderer/components/item-card/item-card.tsx b/src/renderer/components/item-card/item-card.tsx index c75db1c5c..af0ab3ff2 100644 --- a/src/renderer/components/item-card/item-card.tsx +++ b/src/renderer/components/item-card/item-card.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; import { AnimatePresence } from 'motion/react'; -import { Dispatch, Fragment, memo, ReactNode, SetStateAction, useState } from 'react'; +import { Fragment, memo, ReactNode, useState } from 'react'; import { generatePath, Link } from 'react-router'; import styles from './item-card.module.css'; @@ -44,8 +44,6 @@ export const ItemCard = ({ type = 'poster', withControls, }: ItemCardProps) => { - const [showControls, setShowControls] = useState(false); - const imageUrl = getImageUrl(data); const rows = getDataRows(itemType); @@ -59,8 +57,6 @@ export const ItemCard = ({ isRound={isRound} itemType={itemType} rows={rows} - setShowControls={setShowControls} - showControls={showControls} withControls={withControls} /> ); @@ -73,8 +69,6 @@ export const ItemCard = ({ isRound={isRound} itemType={itemType} rows={rows} - setShowControls={setShowControls} - showControls={showControls} withControls={withControls} /> ); @@ -88,8 +82,6 @@ export const ItemCard = ({ isRound={isRound} itemType={itemType} rows={rows} - setShowControls={setShowControls} - showControls={showControls} withControls={withControls} /> ); @@ -100,8 +92,6 @@ export interface ItemCardDerivativeProps extends Omit { controls: ItemControls; imageUrl: string | undefined; rows: DataRow[]; - setShowControls: Dispatch>; - showControls: boolean; } const CompactItemCard = ({ @@ -111,10 +101,10 @@ const CompactItemCard = ({ isRound, itemType, rows, - setShowControls, - showControls, withControls, }: ItemCardDerivativeProps) => { + const [showControls, setShowControls] = useState(false); + if (data) { return (
@@ -170,10 +160,10 @@ const DefaultItemCard = ({ isRound, itemType, rows, - setShowControls, - showControls, withControls, }: ItemCardDerivativeProps) => { + const [showControls, setShowControls] = useState(false); + if (data) { return (
@@ -229,10 +219,10 @@ const PosterItemCard = ({ isRound, itemType, rows, - setShowControls, - showControls, withControls, }: ItemCardDerivativeProps) => { + const [showControls, setShowControls] = useState(false); + if (data) { return (
@@ -246,16 +236,14 @@ const PosterItemCard = ({ className={clsx(styles.image, { [styles.isRound]: isRound })} src={imageUrl} /> - - {withControls && showControls && ( - - )} - + {withControls && showControls && ( + + )}
{rows.map((row) => ( @@ -273,7 +261,9 @@ const PosterItemCard = ({
{rows.map((row) => ( - +
+   +
))}
diff --git a/src/renderer/components/item-list/item-grid-list/item-grid-list.tsx b/src/renderer/components/item-list/item-grid-list/item-grid-list.tsx index b4f78547a..a2ee936e6 100644 --- a/src/renderer/components/item-list/item-grid-list/item-grid-list.tsx +++ b/src/renderer/components/item-list/item-grid-list/item-grid-list.tsx @@ -6,6 +6,8 @@ import { AnimatePresence } from 'motion/react'; import { useOverlayScrollbars } from 'overlayscrollbars-react'; import React, { CSSProperties, + memo, + ReactNode, Ref, UIEvent, useCallback, @@ -28,7 +30,7 @@ import { ItemListStateActions, useItemListState, } from '/@/renderer/components/item-list/helpers/item-list-state'; -import { ItemListHandle } from '/@/renderer/components/item-list/types'; +import { ItemControls, ItemListHandle } from '/@/renderer/components/item-list/types'; import { LibraryItem } from '/@/shared/types/domain-types'; interface VirtualizedGridListProps { @@ -61,40 +63,69 @@ const VirtualizedGridList = React.memo( onScroll, tableMeta, }: VirtualizedGridListProps) => { - const elements = useMemo(() => { - if (!tableMeta) { - return []; - } - - return data - .map((d, i) => { - return { - data: d, - index: i, - }; - }) - .reduce( - (acc, d) => { - if (d.index % (tableMeta?.columnCount || 0) === 0) { - acc.push([]); - } - const prev = acc[acc.length - 1]; - prev.push(d); - return acc; + const itemProps: GridItemProps = useMemo(() => { + return { + columns: tableMeta?.columnCount || 0, + controls: { + onClick: enableSelection + ? (item, itemType) => { + return itemListControls.handleItemClick( + item, + itemType, + internalState, + ); + } + : undefined, + onDoubleClick: (item, itemType) => { + return itemListControls.handleItemDoubleClick( + item, + itemType, + internalState, + ); }, - [] as { data: any; index: number }[][], - ); - }, [tableMeta, data]); - - const itemProps: GridItemProps = { - columns: tableMeta?.columnCount || 0, - data: elements, + onFavorite: (item, itemType) => { + return itemListControls.handleItemFavorite(item, itemType, internalState); + }, + onItemExpand: enableExpansion + ? (item, itemType) => { + return itemListControls.handleItemExpand( + item, + itemType, + internalState, + ); + } + : undefined, + onMore: (item, itemType) => { + return itemListControls.handleItemMore(item, itemType, internalState); + }, + onPlay: (item, itemType, playType) => { + return itemListControls.handleItemPlay( + item, + itemType, + playType, + internalState, + ); + }, + onRating: (item, itemType) => { + return itemListControls.handleItemRating(item, itemType, internalState); + }, + }, + data, + enableExpansion, + enableSelection, + gap, + internalState, + itemType, + }; + }, [ + data, + tableMeta?.columnCount, enableExpansion, enableSelection, gap, internalState, itemType, - }; + ]); return ( { return throttle( ( @@ -170,6 +200,7 @@ const createThrottledSetTableMeta = (itemsPerRow?: number) => { export interface GridItemProps { columns: number; + controls: ItemControls; data: any[]; enableExpansion?: boolean; enableSelection?: boolean; @@ -427,88 +458,45 @@ export const ItemGridList = ({ ); }; -const ListComponent = ({ - columns, - data, - enableExpansion, - enableSelection, - gap, - index, - internalState, - itemType, - style, -}: RowComponentProps) => { - return ( -
- {data[index].map((d) => ( +const ListComponent = memo( + ({ + columns, + controls, + data, + gap, + index, + itemType, + style, + }: RowComponentProps) => { + const items: ReactNode[] = []; + const itemCount = data.length; + const startIndex = index * columns; + const stopIndex = Math.min(itemCount - 1, startIndex + columns - 1); + + const columnCountInRow = stopIndex - startIndex + 1; + + let columnCountToAdd = 0; + + if (columnCountInRow !== columns) { + columnCountToAdd = columns - columnCountInRow; + } + + for (let i = startIndex; i <= stopIndex + columnCountToAdd; i += 1) { + items.push(
- { - return itemListControls.handleItemClick( - item, - itemType, - internalState, - ); - } - : undefined, - onDoubleClick: (item, itemType) => { - return itemListControls.handleItemDoubleClick( - item, - itemType, - internalState, - ); - }, - onFavorite: (item, itemType) => { - return itemListControls.handleItemFavorite( - item, - itemType, - internalState, - ); - }, - onItemExpand: enableExpansion - ? (item, itemType) => { - return itemListControls.handleItemExpand( - item, - itemType, - internalState, - ); - } - : undefined, - onMore: (item, itemType) => { - return itemListControls.handleItemMore( - item, - itemType, - internalState, - ); - }, - onPlay: (item, itemType, playType) => { - return itemListControls.handleItemPlay( - item, - itemType, - playType, - internalState, - ); - }, - onRating: (item, itemType) => { - return itemListControls.handleItemRating( - item, - itemType, - internalState, - ); - }, - }} - data={d.data} - itemType={itemType} - withControls - /> -
- ))} -
- ); -}; + +
, + ); + } + + return ( +
+ {items} +
+ ); + }, +);