implement item list grid card row customization

This commit is contained in:
jeffvli
2025-11-14 15:18:25 -08:00
parent 56d0669510
commit b6c3200419
17 changed files with 559 additions and 149 deletions
+2
View File
@@ -128,6 +128,7 @@
"yes": "yes", "yes": "yes",
"explicit": "explicit", "explicit": "explicit",
"clean": "clean", "clean": "clean",
"gridRows": "grid rows",
"tableColumns": "table columns" "tableColumns": "table columns"
}, },
"entity": { "entity": {
@@ -858,6 +859,7 @@
"label": { "label": {
"actions": "$t(common.action_other)", "actions": "$t(common.action_other)",
"album": "$t(entity.album_one)", "album": "$t(entity.album_one)",
"albumCount": "$t(entity.album_other)",
"albumArtist": "$t(entity.albumArtist_one)", "albumArtist": "$t(entity.albumArtist_one)",
"artist": "$t(entity.artist_one)", "artist": "$t(entity.artist_one)",
"biography": "$t(common.biography)", "biography": "$t(common.biography)",
@@ -96,6 +96,18 @@
color: var(--theme-colors-foreground-muted); color: var(--theme-colors-foreground-muted);
} }
.row.align-start {
text-align: left;
}
.row.align-center {
text-align: center;
}
.row.align-end {
text-align: right;
}
.container.poster { .container.poster {
padding: 0; padding: 0;
background-color: inherit; background-color: inherit;
+333 -93
View File
@@ -1,4 +1,5 @@
import clsx from 'clsx'; import clsx from 'clsx';
import formatDuration from 'format-duration';
import { AnimatePresence } from 'motion/react'; import { AnimatePresence } from 'motion/react';
import { Fragment, memo, ReactNode, useState } from 'react'; import { Fragment, memo, ReactNode, useState } from 'react';
import { generatePath, Link } from 'react-router'; import { generatePath, Link } from 'react-router';
@@ -11,6 +12,7 @@ import { ItemListStateActions } from '/@/renderer/components/item-list/helpers/i
import { ItemControls } from '/@/renderer/components/item-list/types'; import { ItemControls } from '/@/renderer/components/item-list/types';
import { useDragDrop } from '/@/renderer/hooks/use-drag-drop'; import { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
import { AppRoute } from '/@/renderer/router/routes'; import { AppRoute } from '/@/renderer/router/routes';
import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
import { Image } from '/@/shared/components/image/image'; import { Image } from '/@/shared/components/image/image';
import { Separator } from '/@/shared/components/separator/separator'; import { Separator } from '/@/shared/components/separator/separator';
import { Skeleton } from '/@/shared/components/skeleton/skeleton'; import { Skeleton } from '/@/shared/components/skeleton/skeleton';
@@ -26,6 +28,13 @@ import {
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { DragOperation, DragTarget } from '/@/shared/types/drag-and-drop'; import { DragOperation, DragTarget } from '/@/shared/types/drag-and-drop';
export type DataRow = {
align?: 'center' | 'end' | 'start';
format: (data: Album | AlbumArtist | Artist | Playlist | Song) => null | ReactNode | string;
id: string;
isMuted?: boolean;
};
export interface ItemCardProps { export interface ItemCardProps {
controls?: ItemControls; controls?: ItemControls;
data: Album | AlbumArtist | Artist | Playlist | Song | undefined; data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
@@ -33,16 +42,11 @@ export interface ItemCardProps {
internalState?: ItemListStateActions; internalState?: ItemListStateActions;
isRound?: boolean; isRound?: boolean;
itemType: LibraryItem; itemType: LibraryItem;
rows?: DataRow[];
type?: 'compact' | 'default' | 'poster'; type?: 'compact' | 'default' | 'poster';
withControls?: boolean; withControls?: boolean;
} }
type DataRow = {
format: (data: Album | AlbumArtist | Artist | Playlist | Song) => ReactNode | string;
id: string;
isMuted?: boolean;
};
export const ItemCard = ({ export const ItemCard = ({
controls, controls,
data, data,
@@ -50,11 +54,13 @@ export const ItemCard = ({
internalState, internalState,
isRound, isRound,
itemType, itemType,
rows: providedRows,
type = 'poster', type = 'poster',
withControls, withControls,
}: ItemCardProps) => { }: ItemCardProps) => {
const imageUrl = getImageUrl(data); const imageUrl = getImageUrl(data);
const rows = getDataRows(itemType); const defaultRows = getDataRows();
const rows = providedRows && providedRows.length > 0 ? providedRows : defaultRows;
switch (type) { switch (type) {
case 'compact': case 'compact':
@@ -218,9 +224,20 @@ const CompactItemCard = ({
)} )}
</AnimatePresence> </AnimatePresence>
<div className={clsx(styles.detailContainer, styles.compact)}> <div className={clsx(styles.detailContainer, styles.compact)}>
{rows.map((row) => ( {rows
<ItemCardRow data={data!} key={row.id} row={row} type="compact" /> .filter(
))} (row): row is NonNullable<typeof row> =>
row !== null && row !== undefined,
)
.map((row, index) => (
<ItemCardRow
data={data!}
index={index}
key={row.id}
row={row}
type="compact"
/>
))}
</div> </div>
</div> </div>
</div> </div>
@@ -232,11 +249,21 @@ const CompactItemCard = ({
<div className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}> <div className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}>
<Skeleton className={styles.image} /> <Skeleton className={styles.image} />
<div className={clsx(styles.detailContainer, styles.compact)}> <div className={clsx(styles.detailContainer, styles.compact)}>
{rows.map((row) => ( {rows
<div className={styles.row} key={row.id}> .filter(
&nbsp; (row): row is NonNullable<typeof row> =>
</div> row !== null && row !== undefined,
))} )
.map((row, index) => (
<div
className={clsx(styles.row, {
[styles.muted]: index > 0,
})}
key={row.id}
>
&nbsp;
</div>
))}
</div> </div>
</div> </div>
</div> </div>
@@ -352,9 +379,20 @@ const DefaultItemCard = ({
</AnimatePresence> </AnimatePresence>
</div> </div>
<div className={styles.detailContainer}> <div className={styles.detailContainer}>
{rows.map((row) => ( {rows
<ItemCardRow data={data!} key={row.id} row={row} type="default" /> .filter(
))} (row): row is NonNullable<typeof row> =>
row !== null && row !== undefined,
)
.map((row, index) => (
<ItemCardRow
data={data!}
index={index}
key={row.id}
row={row}
type="default"
/>
))}
</div> </div>
</div> </div>
); );
@@ -366,11 +404,20 @@ const DefaultItemCard = ({
<Skeleton className={styles.image} /> <Skeleton className={styles.image} />
</div> </div>
<div className={styles.detailContainer}> <div className={styles.detailContainer}>
{rows.map((row) => ( {rows
<div className={styles.row} key={row.id}> .filter(
&nbsp; (row): row is NonNullable<typeof row> => row !== null && row !== undefined,
</div> )
))} .map((row, index) => (
<div
className={clsx(styles.row, {
[styles.muted]: index > 0,
})}
key={row.id}
>
&nbsp;
</div>
))}
</div> </div>
</div> </div>
); );
@@ -531,9 +578,20 @@ const PosterItemCard = ({
</div> </div>
{data && ( {data && (
<div className={styles.detailContainer}> <div className={styles.detailContainer}>
{rows.map((row) => ( {rows
<ItemCardRow data={data} key={row.id} row={row} type="poster" /> .filter(
))} (row): row is NonNullable<typeof row> =>
row !== null && row !== undefined,
)
.map((row, index) => (
<ItemCardRow
data={data}
index={index}
key={row.id}
row={row}
type="poster"
/>
))}
</div> </div>
)} )}
</div> </div>
@@ -546,83 +604,253 @@ const PosterItemCard = ({
<Skeleton className={clsx(styles.image, { [styles.isRound]: isRound })} /> <Skeleton className={clsx(styles.image, { [styles.isRound]: isRound })} />
</div> </div>
<div className={styles.detailContainer}> <div className={styles.detailContainer}>
{rows.map((row) => ( {rows
<div className={styles.row} key={row.id}> .filter(
&nbsp; (row): row is NonNullable<typeof row> => row !== null && row !== undefined,
</div> )
))} .map((row, index) => (
<div
className={clsx(styles.row, {
[styles.muted]: index > 0,
})}
key={row.id}
>
&nbsp;
</div>
))}
</div> </div>
</div> </div>
); );
}; };
const getDataRows = (itemType: LibraryItem): DataRow[] => { export const getDataRows = (): DataRow[] => {
switch (itemType) { return [
case LibraryItem.ALBUM: {
return [ format: (data) => {
{ if ('name' in data && data.name) {
format: (data) => { if ('id' in data && data.id) {
const album = data as Album; if ('_itemType' in data) {
switch (data._itemType) {
case LibraryItem.ALBUM:
return (
<Link
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
albumId: data.id,
})}
>
{data.name}
</Link>
);
case LibraryItem.ALBUM_ARTIST:
return (
<Link
to={generatePath(
AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
{
albumArtistId: data.id,
},
)}
>
{data.name}
</Link>
);
case LibraryItem.PLAYLIST:
return (
<Link
to={generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, {
playlistId: data.id,
})}
>
{data.name}
</Link>
);
default:
return data.name;
}
}
}
return data.name;
}
return '';
},
id: 'name',
},
{
format: (data) => {
if ('albumArtists' in data && Array.isArray(data.albumArtists)) {
return (data as Album | Song).albumArtists.map((artist, index) => (
<Fragment key={artist.id}>
<Link
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id,
})}
>
{artist.name}
</Link>
{index < (data as Album | Song).albumArtists.length - 1 && (
<Separator />
)}
</Fragment>
));
}
return '';
},
id: 'albumArtists',
isMuted: true,
},
{
format: (data) => {
if ('artists' in data && Array.isArray(data.artists)) {
return (data as Album | Song).artists.map((artist, index) => (
<Fragment key={artist.id}>
<Link
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id,
})}
>
{artist.name}
</Link>
{index < (data as Album | Song).artists.length - 1 && <Separator />}
</Fragment>
));
}
return '';
},
id: 'artists',
isMuted: true,
},
{
format: (data) => {
if ('duration' in data && data.duration !== null) {
return formatDuration(data.duration * 1000);
}
return '';
},
id: 'duration',
},
{
format: (data) => {
if ('releaseYear' in data && data.releaseYear !== null) {
return String(data.releaseYear);
}
return '';
},
id: 'releaseYear',
},
{
format: (data) => {
if ('releaseDate' in data && data.releaseDate) {
return data.releaseDate;
}
return '';
},
id: 'releaseDate',
},
{
format: (data) => {
if ('createdAt' in data && data.createdAt) {
return formatDateAbsolute(data.createdAt);
}
return '';
},
id: 'createdAt',
},
{
format: (data) => {
if ('lastPlayedAt' in data && data.lastPlayedAt) {
return formatDateRelative(data.lastPlayedAt);
}
return '';
},
id: 'lastPlayedAt',
},
{
format: (data) => {
if ('playCount' in data && data.playCount !== null) {
return String(data.playCount);
}
return '';
},
id: 'playCount',
},
{
format: (data) => {
if ('genres' in data && Array.isArray(data.genres)) {
return (data as Album | AlbumArtist | Song).genres
.map((genre) => genre.name)
.join(', ');
}
return '';
},
id: 'genres',
isMuted: true,
},
{
format: (data) => {
if ('album' in data && data.album) {
const song = data as Song;
if ('albumId' in song && song.albumId) {
return ( return (
<Link <Link
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, { to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
albumId: album.id, albumId: song.albumId,
})} })}
> >
{album.name} {song.album}
</Link> </Link>
); );
}, }
id: 'name', return song.album;
}, }
{ return '';
format: (data) => { },
const album = data as Album; id: 'album',
return album.albumArtists.map((artist, index) => ( isMuted: true,
<Fragment key={artist.id}> },
<Link {
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, { format: (data) => {
albumArtistId: artist.id, if ('songCount' in data && data.songCount !== null) {
})} return String(data.songCount);
> }
{artist.name} return '';
</Link> },
{index < album.albumArtists.length - 1 && <Separator />} id: 'songCount',
</Fragment> },
)); {
}, format: (data) => {
id: 'albumArtists', if ('albumCount' in data && data.albumCount !== null) {
isMuted: true, return String(data.albumCount);
}, }
]; return '';
case LibraryItem.ALBUM_ARTIST: },
return [{ format: (data) => (data as AlbumArtist).name, id: 'name' }]; id: 'albumCount',
case LibraryItem.ARTIST: },
return [{ format: (data) => (data as Artist).name, id: 'name' }]; {
case LibraryItem.PLAYLIST: format: (data) => {
return [{ format: (data) => (data as Playlist).name, id: 'name' }]; if (
case LibraryItem.SONG: 'userRating' in data &&
return [{ format: (data) => (data as Song).name, id: 'name' }]; (data as Album | AlbumArtist | Song).userRating !== null
default: ) {
return []; return formatRating(data as Album | AlbumArtist | Song);
} }
return null;
},
id: 'rating',
},
{
format: (data) => {
if ('userFavorite' in data) {
return (data as Album | AlbumArtist | Song).userFavorite ? '★' : '';
}
return '';
},
id: 'userFavorite',
},
];
}; };
export const getDataRowsCount = (itemType: LibraryItem) => { export const getDataRowsCount = () => {
switch (itemType) { return getDataRows().length;
case LibraryItem.ALBUM:
return 2;
case LibraryItem.ALBUM_ARTIST:
return 1;
case LibraryItem.ARTIST:
return 1;
case LibraryItem.PLAYLIST:
return 2;
case LibraryItem.SONG:
return 2;
default:
return 1;
}
}; };
const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | undefined) => { const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | undefined) => {
@@ -635,20 +863,32 @@ const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | unde
const ItemCardRow = ({ const ItemCardRow = ({
data, data,
index,
row, row,
type, type,
}: { }: {
data: Album | AlbumArtist | Artist | Playlist | Song | undefined; data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
index: number;
row: DataRow; row: DataRow;
type?: 'compact' | 'default' | 'poster'; type?: 'compact' | 'default' | 'poster';
}) => { }) => {
const alignmentClass =
row.align === 'center'
? styles['align-center']
: row.align === 'end'
? styles['align-end']
: styles['align-start'];
// All rows except the first one (index 0) should be muted
const isMuted = index > 0 || row.isMuted;
if (!data) { if (!data) {
return ( return (
<div <div
className={clsx(styles.row, { className={clsx(styles.row, alignmentClass, {
[styles.compact]: type === 'compact', [styles.compact]: type === 'compact',
[styles.default]: type === 'default', [styles.default]: type === 'default',
[styles.muted]: row.isMuted, [styles.muted]: isMuted,
[styles.poster]: type === 'poster', [styles.poster]: type === 'poster',
})} })}
> >
@@ -659,10 +899,10 @@ const ItemCardRow = ({
return ( return (
<Text <Text
className={clsx(styles.row, { className={clsx(styles.row, alignmentClass, {
[styles.compact]: type === 'compact', [styles.compact]: type === 'compact',
[styles.default]: type === 'default', [styles.default]: type === 'default',
[styles.muted]: row.isMuted, [styles.muted]: isMuted,
[styles.poster]: type === 'poster', [styles.poster]: type === 'poster',
})} })}
> >
@@ -0,0 +1,111 @@
import { useMemo } from 'react';
import { type DataRow, getDataRows } from '/@/renderer/components/item-card/item-card';
import { useSettingsStore } from '/@/renderer/store';
import { LibraryItem } from '/@/shared/types/domain-types';
import { TableColumn } from '/@/shared/types/types';
import { ItemListKey } from '/@/shared/types/types';
const getDefaultRowsForItemType = (itemType: LibraryItem): DataRow[] => {
const allRows = getDataRows();
const rowMap = new Map(allRows.map((row) => [row.id, row]));
switch (itemType) {
case LibraryItem.ALBUM:
return [rowMap.get('name'), rowMap.get('albumArtists')].filter(
(row): row is NonNullable<typeof row> => row !== undefined,
);
case LibraryItem.ALBUM_ARTIST:
return [rowMap.get('name')].filter(
(row): row is NonNullable<typeof row> => row !== undefined,
);
case LibraryItem.ARTIST:
return [rowMap.get('name')].filter(
(row): row is NonNullable<typeof row> => row !== undefined,
);
case LibraryItem.PLAYLIST:
return [rowMap.get('name')].filter(
(row): row is NonNullable<typeof row> => row !== undefined,
);
case LibraryItem.SONG:
return [rowMap.get('name')].filter(
(row): row is NonNullable<typeof row> => row !== undefined,
);
default:
return [];
}
};
// Map TableColumn enum values to row IDs used in getDataRows
const getRowIdFromTableColumn = (tableColumn: TableColumn): null | string => {
// Map TableColumn enum values to the row IDs used in getDataRows
const columnToRowIdMap: Record<TableColumn, null | string> = {
[TableColumn.ACTIONS]: null,
[TableColumn.ALBUM]: 'album',
[TableColumn.ALBUM_ARTIST]: 'albumArtists',
[TableColumn.ALBUM_COUNT]: 'albumCount',
[TableColumn.ARTIST]: 'artists',
[TableColumn.BIOGRAPHY]: null,
[TableColumn.BIT_RATE]: null,
[TableColumn.BPM]: null,
[TableColumn.CHANNELS]: null,
[TableColumn.CODEC]: null,
[TableColumn.COMMENT]: null,
[TableColumn.DATE_ADDED]: 'createdAt',
[TableColumn.DISC_NUMBER]: null,
[TableColumn.DURATION]: 'duration',
[TableColumn.GENRE]: 'genres',
[TableColumn.GENRE_BADGE]: null,
[TableColumn.ID]: null,
[TableColumn.IMAGE]: null,
[TableColumn.LAST_PLAYED]: 'lastPlayedAt',
[TableColumn.OWNER]: null,
[TableColumn.PATH]: null,
[TableColumn.PLAY_COUNT]: 'playCount',
[TableColumn.RELEASE_DATE]: 'releaseDate',
[TableColumn.ROW_INDEX]: null,
[TableColumn.SIZE]: null,
[TableColumn.SKIP]: null,
[TableColumn.SONG_COUNT]: 'songCount',
[TableColumn.TITLE]: 'name',
[TableColumn.TITLE_COMBINED]: null,
[TableColumn.TRACK_NUMBER]: null,
[TableColumn.USER_FAVORITE]: 'userFavorite',
[TableColumn.USER_RATING]: 'rating',
[TableColumn.YEAR]: 'releaseYear',
};
return columnToRowIdMap[tableColumn] || null;
};
export const useGridRows = (itemType: LibraryItem, listKey?: ItemListKey) => {
const gridRowsConfig = useSettingsStore((state) =>
listKey ? state.lists[listKey]?.grid?.rows : undefined,
);
return useMemo(() => {
const allRows = getDataRows();
if (!listKey || !gridRowsConfig || gridRowsConfig.length === 0) {
const defaultRows = getDefaultRowsForItemType(itemType);
return defaultRows.length > 0 ? defaultRows : allRows;
}
const rowMap = new Map(allRows.map((row) => [row.id, row]));
const configuredRows = gridRowsConfig
.filter((config) => config.isEnabled)
.map((config) => {
const rowId = getRowIdFromTableColumn(config.id);
const baseRow = rowId ? rowMap.get(rowId) : null;
if (!baseRow) return null;
return {
...baseRow,
align: config.align,
};
})
.filter((row): row is NonNullable<typeof row> => row !== null && row !== undefined);
return configuredRows.length > 0 ? configuredRows : allRows;
}, [itemType, listKey, gridRowsConfig]);
};
@@ -60,6 +60,7 @@ interface VirtualizedGridListProps {
onScrollEnd?: ItemGridListProps['onScrollEnd']; onScrollEnd?: ItemGridListProps['onScrollEnd'];
outerRef: RefObject<any>; outerRef: RefObject<any>;
ref: RefObject<FixedSizeList<GridItemProps>>; ref: RefObject<FixedSizeList<GridItemProps>>;
rows?: ItemCardProps['rows'];
tableMeta: null | { tableMeta: null | {
columnCount: number; columnCount: number;
itemHeight: number; itemHeight: number;
@@ -85,6 +86,7 @@ const VirtualizedGridList = React.memo(
onScrollEnd, onScrollEnd,
outerRef, outerRef,
ref, ref,
rows,
tableMeta, tableMeta,
width, width,
}: VirtualizedGridListProps) => { }: VirtualizedGridListProps) => {
@@ -99,11 +101,13 @@ const VirtualizedGridList = React.memo(
gap, gap,
internalState, internalState,
itemType, itemType,
rows,
tableMeta, tableMeta,
}; };
}, [ }, [
tableMeta, tableMeta,
controls, controls,
rows,
data, data,
enableDrag, enableDrag,
enableExpansion, enableExpansion,
@@ -167,59 +171,51 @@ const VirtualizedGridList = React.memo(
VirtualizedGridList.displayName = 'VirtualizedGridList'; VirtualizedGridList.displayName = 'VirtualizedGridList';
const createThrottledSetTableMeta = (itemsPerRow?: number) => { const createThrottledSetTableMeta = (itemsPerRow?: number, rowsCount?: number) => {
return throttle( return throttle((width: number, dataLength: number, setTableMeta: (meta: any) => void) => {
( const isSm = width >= 600;
width: number, const isMd = width >= 768;
dataLength: number, const isLg = width >= 960;
type: LibraryItem, const isXl = width >= 1200;
setTableMeta: (meta: any) => void, const is2xl = width >= 1440;
) => { const is3xl = width >= 1920;
const isSm = width >= 600; const is4xl = width >= 2560;
const isMd = width >= 768;
const isLg = width >= 960;
const isXl = width >= 1200;
const is2xl = width >= 1440;
const is3xl = width >= 1920;
const is4xl = width >= 2560;
let dynamicItemsPerRow = 2; let dynamicItemsPerRow = 2;
if (is4xl) { if (is4xl) {
dynamicItemsPerRow = 12; dynamicItemsPerRow = 12;
} else if (is3xl) { } else if (is3xl) {
dynamicItemsPerRow = 10; dynamicItemsPerRow = 10;
} else if (is2xl) { } else if (is2xl) {
dynamicItemsPerRow = 8; dynamicItemsPerRow = 8;
} else if (isXl) { } else if (isXl) {
dynamicItemsPerRow = 6; dynamicItemsPerRow = 6;
} else if (isLg) { } else if (isLg) {
dynamicItemsPerRow = 5; dynamicItemsPerRow = 5;
} else if (isMd) { } else if (isMd) {
dynamicItemsPerRow = 4; dynamicItemsPerRow = 4;
} else if (isSm) { } else if (isSm) {
dynamicItemsPerRow = 3; dynamicItemsPerRow = 3;
} else { } else {
dynamicItemsPerRow = 2; dynamicItemsPerRow = 2;
} }
const setItemsPerRow = itemsPerRow || dynamicItemsPerRow; const setItemsPerRow = itemsPerRow || dynamicItemsPerRow;
const widthPerItem = Number(width) / setItemsPerRow; const widthPerItem = Number(width) / setItemsPerRow;
const itemHeight = widthPerItem + getDataRowsCount(type) * 26; const itemHeight = widthPerItem + (rowsCount || getDataRowsCount()) * 26;
if (widthPerItem === 0) { if (widthPerItem === 0) {
return; return;
} }
setTableMeta({ setTableMeta({
columnCount: setItemsPerRow, columnCount: setItemsPerRow,
itemHeight, itemHeight,
rowCount: Math.ceil(dataLength / setItemsPerRow), rowCount: Math.ceil(dataLength / setItemsPerRow),
}); });
}, }, 200);
200,
);
}; };
export interface GridItemProps { export interface GridItemProps {
@@ -232,6 +228,7 @@ export interface GridItemProps {
gap: 'lg' | 'md' | 'sm' | 'xl' | 'xs'; gap: 'lg' | 'md' | 'sm' | 'xl' | 'xs';
internalState: ItemListStateActions; internalState: ItemListStateActions;
itemType: LibraryItem; itemType: LibraryItem;
rows?: ItemCardProps['rows'];
tableMeta: null | { tableMeta: null | {
columnCount: number; columnCount: number;
itemHeight: number; itemHeight: number;
@@ -257,6 +254,7 @@ export interface ItemGridListProps {
onScroll?: (offset: number, direction: 'down' | 'up') => void; onScroll?: (offset: number, direction: 'down' | 'up') => void;
onScrollEnd?: (offset: number, direction: 'down' | 'up') => void; onScrollEnd?: (offset: number, direction: 'down' | 'up') => void;
ref?: Ref<ItemListHandle>; ref?: Ref<ItemListHandle>;
rows?: ItemCardProps['rows'];
} }
export const ItemGridList = ({ export const ItemGridList = ({
@@ -273,6 +271,7 @@ export const ItemGridList = ({
onScroll, onScroll,
onScrollEnd, onScrollEnd,
ref, ref,
rows,
}: ItemGridListProps) => { }: ItemGridListProps) => {
const rootRef = useRef(null); const rootRef = useRef(null);
const outerRef = useRef(null); const outerRef = useRef(null);
@@ -334,12 +333,12 @@ export const ItemGridList = ({
}, [initialize, tableMeta]); }, [initialize, tableMeta]);
const throttledSetTableMeta = useMemo(() => { const throttledSetTableMeta = useMemo(() => {
return createThrottledSetTableMeta(itemsPerRow); return createThrottledSetTableMeta(itemsPerRow, rows?.length);
}, [itemsPerRow]); }, [itemsPerRow, rows?.length]);
useLayoutEffect(() => { useLayoutEffect(() => {
throttledSetTableMeta(containerWidth, data.length, itemType, setTableMeta); throttledSetTableMeta(containerWidth, data.length, setTableMeta);
}, [containerWidth, data.length, itemType, throttledSetTableMeta]); }, [containerWidth, data.length, throttledSetTableMeta]);
const controls = useDefaultItemListControls(); const controls = useDefaultItemListControls();
@@ -620,6 +619,7 @@ export const ItemGridList = ({
onScrollEnd={onScrollEnd ?? (() => {})} onScrollEnd={onScrollEnd ?? (() => {})}
outerRef={outerRef} outerRef={outerRef}
ref={listRef} ref={listRef}
rows={rows}
tableMeta={tableMeta} tableMeta={tableMeta}
width={width} width={width}
/> />
@@ -638,7 +638,7 @@ export const ItemGridList = ({
const ListComponent = memo((props: ListChildComponentProps<GridItemProps>) => { const ListComponent = memo((props: ListChildComponentProps<GridItemProps>) => {
const { index, style } = props; const { index, style } = props;
const { columns, controls, data, enableDrag, gap, itemType } = props.data; const { columns, controls, data, enableDrag, gap, itemType, rows } = props.data;
const items: ReactNode[] = []; const items: ReactNode[] = [];
const itemCount = data.length; const itemCount = data.length;
@@ -667,6 +667,7 @@ const ListComponent = memo((props: ListChildComponentProps<GridItemProps>) => {
enableDrag={enableDrag} enableDrag={enableDrag}
internalState={props.data.internalState} internalState={props.data.internalState}
itemType={itemType} itemType={itemType}
rows={rows}
withControls withControls
/> />
</div>, </div>,
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -52,6 +53,8 @@ export const AlbumListInfiniteGrid = forwardRef<any, AlbumListInfiniteGridProps>
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ALBUM, ItemListKey.ALBUM);
return ( return (
<ItemGridList <ItemGridList
data={data} data={data}
@@ -64,6 +67,7 @@ export const AlbumListInfiniteGrid = forwardRef<any, AlbumListInfiniteGridProps>
itemType={LibraryItem.ALBUM} itemType={LibraryItem.ALBUM}
onRangeChanged={onRangeChanged} onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
rows={rows}
/> />
); );
}, },
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader'; import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination'; import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
@@ -15,6 +16,7 @@ import {
LibraryItem, LibraryItem,
SortOrder, SortOrder,
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
interface AlbumListPaginatedGridProps extends ItemListGridComponentProps<AlbumListQuery> {} interface AlbumListPaginatedGridProps extends ItemListGridComponentProps<AlbumListQuery> {}
@@ -55,6 +57,8 @@ export const AlbumListPaginatedGrid = forwardRef<any, AlbumListPaginatedGridProp
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ALBUM, ItemListKey.ALBUM);
return ( return (
<ItemListWithPagination <ItemListWithPagination
currentPage={currentPage} currentPage={currentPage}
@@ -74,6 +78,7 @@ export const AlbumListPaginatedGrid = forwardRef<any, AlbumListPaginatedGridProp
itemType={LibraryItem.ALBUM} itemType={LibraryItem.ALBUM}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
ref={ref} ref={ref}
rows={rows}
/> />
</ItemListWithPagination> </ItemListWithPagination>
); );
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -15,7 +16,8 @@ import {
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types'; import { ItemListKey } from '/@/shared/types/types';
interface AlbumArtistListInfiniteGridProps extends ItemListGridComponentProps<AlbumArtistListQuery> {} interface AlbumArtistListInfiniteGridProps
extends ItemListGridComponentProps<AlbumArtistListQuery> {}
export const AlbumArtistListInfiniteGrid = forwardRef<any, AlbumArtistListInfiniteGridProps>( export const AlbumArtistListInfiniteGrid = forwardRef<any, AlbumArtistListInfiniteGridProps>(
( (
@@ -53,6 +55,8 @@ export const AlbumArtistListInfiniteGrid = forwardRef<any, AlbumArtistListInfini
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ALBUM_ARTIST, ItemListKey.ALBUM_ARTIST);
return ( return (
<ItemGridList <ItemGridList
data={data} data={data}
@@ -65,6 +69,7 @@ export const AlbumArtistListInfiniteGrid = forwardRef<any, AlbumArtistListInfini
itemType={LibraryItem.ALBUM_ARTIST} itemType={LibraryItem.ALBUM_ARTIST}
onRangeChanged={onRangeChanged} onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
rows={rows}
/> />
); );
}, },
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader'; import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination'; import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
@@ -15,6 +16,7 @@ import {
LibraryItem, LibraryItem,
SortOrder, SortOrder,
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
interface AlbumArtistListPaginatedGridProps interface AlbumArtistListPaginatedGridProps
extends ItemListGridComponentProps<AlbumArtistListQuery> {} extends ItemListGridComponentProps<AlbumArtistListQuery> {}
@@ -57,6 +59,8 @@ export const AlbumArtistListPaginatedGrid = forwardRef<any, AlbumArtistListPagin
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ALBUM_ARTIST, ItemListKey.ALBUM_ARTIST);
return ( return (
<ItemListWithPagination <ItemListWithPagination
currentPage={currentPage} currentPage={currentPage}
@@ -77,6 +81,7 @@ export const AlbumArtistListPaginatedGrid = forwardRef<any, AlbumArtistListPagin
itemType={LibraryItem.ALBUM_ARTIST} itemType={LibraryItem.ALBUM_ARTIST}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
ref={ref} ref={ref}
rows={rows}
/> />
</ItemListWithPagination> </ItemListWithPagination>
); );
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -53,6 +54,8 @@ export const ArtistListInfiniteGrid = forwardRef<any, ArtistListInfiniteGridProp
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ARTIST, ItemListKey.ARTIST);
return ( return (
<ItemGridList <ItemGridList
data={data} data={data}
@@ -65,6 +68,7 @@ export const ArtistListInfiniteGrid = forwardRef<any, ArtistListInfiniteGridProp
itemType={LibraryItem.ARTIST} itemType={LibraryItem.ARTIST}
onRangeChanged={onRangeChanged} onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
rows={rows}
/> />
); );
}, },
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader'; import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination'; import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
@@ -15,6 +16,7 @@ import {
LibraryItem, LibraryItem,
SortOrder, SortOrder,
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
interface ArtistListPaginatedGridProps extends ItemListGridComponentProps<ArtistListQuery> {} interface ArtistListPaginatedGridProps extends ItemListGridComponentProps<ArtistListQuery> {}
@@ -56,6 +58,8 @@ export const ArtistListPaginatedGrid = forwardRef<any, ArtistListPaginatedGridPr
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.ARTIST, ItemListKey.ARTIST);
return ( return (
<ItemListWithPagination <ItemListWithPagination
currentPage={currentPage} currentPage={currentPage}
@@ -76,6 +80,7 @@ export const ArtistListPaginatedGrid = forwardRef<any, ArtistListPaginatedGridPr
itemType={LibraryItem.ARTIST} itemType={LibraryItem.ARTIST}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
ref={ref} ref={ref}
rows={rows}
/> />
</ItemListWithPagination> </ItemListWithPagination>
); );
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -53,6 +54,8 @@ export const GenreListInfiniteGrid = forwardRef<any, GenreListInfiniteGridProps>
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.GENRE, ItemListKey.GENRE);
return ( return (
<ItemGridList <ItemGridList
data={data} data={data}
@@ -65,6 +68,7 @@ export const GenreListInfiniteGrid = forwardRef<any, GenreListInfiniteGridProps>
itemType={LibraryItem.GENRE} itemType={LibraryItem.GENRE}
onRangeChanged={onRangeChanged} onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
rows={rows}
/> />
); );
}, },
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader'; import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination'; import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
@@ -15,6 +16,7 @@ import {
LibraryItem, LibraryItem,
SortOrder, SortOrder,
} from '/@/shared/types/domain-types'; } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
interface GenreListPaginatedGridProps extends ItemListGridComponentProps<GenreListQuery> {} interface GenreListPaginatedGridProps extends ItemListGridComponentProps<GenreListQuery> {}
@@ -56,6 +58,8 @@ export const GenreListPaginatedGrid = forwardRef<any, GenreListPaginatedGridProp
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.GENRE, ItemListKey.GENRE);
return ( return (
<ItemListWithPagination <ItemListWithPagination
currentPage={currentPage} currentPage={currentPage}
@@ -76,6 +80,7 @@ export const GenreListPaginatedGrid = forwardRef<any, GenreListPaginatedGridProp
itemType={LibraryItem.GENRE} itemType={LibraryItem.GENRE}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
ref={ref} ref={ref}
rows={rows}
/> />
</ItemListWithPagination> </ItemListWithPagination>
); );
@@ -253,9 +253,6 @@ const GridRowConfig = ({
); );
}, [data]); }, [data]);
console.log('data', data);
console.log(labelMap);
const handleChangeEnabled = useCallback( const handleChangeEnabled = useCallback(
(item: ItemGridListRowConfig, checked: boolean) => { (item: ItemGridListRowConfig, checked: boolean) => {
const value = useSettingsStore.getState().lists[listKey]?.grid.rows; const value = useSettingsStore.getState().lists[listKey]?.grid.rows;
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader'; import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist'; import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -48,6 +49,8 @@ export const SongListInfiniteGrid = forwardRef<any, SongListInfiniteGridProps>(
enabled: saveScrollOffset, enabled: saveScrollOffset,
}); });
const rows = useGridRows(LibraryItem.SONG, ItemListKey.SONG);
return ( return (
<ItemGridList <ItemGridList
data={data} data={data}
@@ -60,6 +63,7 @@ export const SongListInfiniteGrid = forwardRef<any, SongListInfiniteGridProps>(
itemType={LibraryItem.SONG} itemType={LibraryItem.SONG}
onRangeChanged={onRangeChanged} onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd} onScrollEnd={handleOnScrollEnd}
rows={rows}
/> />
); );
}, },
@@ -3,12 +3,14 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader'; import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list'; import { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination'; import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination'; import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types'; import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
import { songsQueries } from '/@/renderer/features/songs/api/songs-api'; import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
import { LibraryItem, SongListQuery, SongListSort, SortOrder } from '/@/shared/types/domain-types'; import { LibraryItem, SongListQuery, SongListSort, SortOrder } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
interface SongListPaginatedGridProps extends ItemListGridComponentProps<SongListQuery> {} interface SongListPaginatedGridProps extends ItemListGridComponentProps<SongListQuery> {}
@@ -44,6 +46,8 @@ export const SongListPaginatedGrid = forwardRef<any, SongListPaginatedGridProps>
serverId, serverId,
}); });
const rows = useGridRows(LibraryItem.SONG, ItemListKey.SONG);
return ( return (
<ItemListWithPagination <ItemListWithPagination
currentPage={currentPage} currentPage={currentPage}
@@ -58,6 +62,7 @@ export const SongListPaginatedGrid = forwardRef<any, SongListPaginatedGridProps>
gap={gap} gap={gap}
itemType={LibraryItem.SONG} itemType={LibraryItem.SONG}
ref={ref} ref={ref}
rows={rows}
/> />
</ItemListWithPagination> </ItemListWithPagination>
); );
+1
View File
@@ -8,6 +8,7 @@ export enum DragTarget {
ARTIST = LibraryItem.ARTIST, ARTIST = LibraryItem.ARTIST,
GENERIC = 'generic', GENERIC = 'generic',
GENRE = LibraryItem.GENRE, GENRE = LibraryItem.GENRE,
GRID_ROW = 'gridRow',
PLAYLIST = LibraryItem.PLAYLIST, PLAYLIST = LibraryItem.PLAYLIST,
QUEUE_SONG = LibraryItem.QUEUE_SONG, QUEUE_SONG = LibraryItem.QUEUE_SONG,
SONG = LibraryItem.SONG, SONG = LibraryItem.SONG,