diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index c9ba70183..d7e5ac17e 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -128,6 +128,7 @@
"yes": "yes",
"explicit": "explicit",
"clean": "clean",
+ "gridRows": "grid rows",
"tableColumns": "table columns"
},
"entity": {
@@ -858,6 +859,7 @@
"label": {
"actions": "$t(common.action_other)",
"album": "$t(entity.album_one)",
+ "albumCount": "$t(entity.album_other)",
"albumArtist": "$t(entity.albumArtist_one)",
"artist": "$t(entity.artist_one)",
"biography": "$t(common.biography)",
diff --git a/src/renderer/components/item-card/item-card.module.css b/src/renderer/components/item-card/item-card.module.css
index a956771b8..42949a30c 100644
--- a/src/renderer/components/item-card/item-card.module.css
+++ b/src/renderer/components/item-card/item-card.module.css
@@ -96,6 +96,18 @@
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 {
padding: 0;
background-color: inherit;
diff --git a/src/renderer/components/item-card/item-card.tsx b/src/renderer/components/item-card/item-card.tsx
index f1509a53c..8e1099268 100644
--- a/src/renderer/components/item-card/item-card.tsx
+++ b/src/renderer/components/item-card/item-card.tsx
@@ -1,4 +1,5 @@
import clsx from 'clsx';
+import formatDuration from 'format-duration';
import { AnimatePresence } from 'motion/react';
import { Fragment, memo, ReactNode, useState } from 'react';
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 { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
import { AppRoute } from '/@/renderer/router/routes';
+import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
import { Image } from '/@/shared/components/image/image';
import { Separator } from '/@/shared/components/separator/separator';
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
@@ -26,6 +28,13 @@ import {
} from '/@/shared/types/domain-types';
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 {
controls?: ItemControls;
data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
@@ -33,16 +42,11 @@ export interface ItemCardProps {
internalState?: ItemListStateActions;
isRound?: boolean;
itemType: LibraryItem;
+ rows?: DataRow[];
type?: 'compact' | 'default' | 'poster';
withControls?: boolean;
}
-type DataRow = {
- format: (data: Album | AlbumArtist | Artist | Playlist | Song) => ReactNode | string;
- id: string;
- isMuted?: boolean;
-};
-
export const ItemCard = ({
controls,
data,
@@ -50,11 +54,13 @@ export const ItemCard = ({
internalState,
isRound,
itemType,
+ rows: providedRows,
type = 'poster',
withControls,
}: ItemCardProps) => {
const imageUrl = getImageUrl(data);
- const rows = getDataRows(itemType);
+ const defaultRows = getDataRows();
+ const rows = providedRows && providedRows.length > 0 ? providedRows : defaultRows;
switch (type) {
case 'compact':
@@ -218,9 +224,20 @@ const CompactItemCard = ({
)}
- {rows.map((row) => (
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable =>
+ row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+
+ ))}
@@ -232,11 +249,21 @@ const CompactItemCard = ({
- {rows.map((row) => (
-
-
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable
=>
+ row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+ 0,
+ })}
+ key={row.id}
+ >
+
+
+ ))}
@@ -352,9 +379,20 @@ const DefaultItemCard = ({
- {rows.map((row) => (
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable =>
+ row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+
+ ))}
);
@@ -366,11 +404,20 @@ const DefaultItemCard = ({
- {rows.map((row) => (
-
-
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable
=> row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+ 0,
+ })}
+ key={row.id}
+ >
+
+
+ ))}
);
@@ -531,9 +578,20 @@ const PosterItemCard = ({
{data && (
- {rows.map((row) => (
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable =>
+ row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+
+ ))}
)}
@@ -546,83 +604,253 @@ const PosterItemCard = ({
- {rows.map((row) => (
-
-
-
- ))}
+ {rows
+ .filter(
+ (row): row is NonNullable
=> row !== null && row !== undefined,
+ )
+ .map((row, index) => (
+ 0,
+ })}
+ key={row.id}
+ >
+
+
+ ))}
);
};
-const getDataRows = (itemType: LibraryItem): DataRow[] => {
- switch (itemType) {
- case LibraryItem.ALBUM:
- return [
- {
- format: (data) => {
- const album = data as Album;
+export const getDataRows = (): DataRow[] => {
+ return [
+ {
+ format: (data) => {
+ if ('name' in data && data.name) {
+ if ('id' in data && data.id) {
+ if ('_itemType' in data) {
+ switch (data._itemType) {
+ case LibraryItem.ALBUM:
+ return (
+
+ {data.name}
+
+ );
+ case LibraryItem.ALBUM_ARTIST:
+ return (
+
+ {data.name}
+
+ );
+ case LibraryItem.PLAYLIST:
+ return (
+
+ {data.name}
+
+ );
+ 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) => (
+
+
+ {artist.name}
+
+ {index < (data as Album | Song).albumArtists.length - 1 && (
+
+ )}
+
+ ));
+ }
+ return '';
+ },
+ id: 'albumArtists',
+ isMuted: true,
+ },
+ {
+ format: (data) => {
+ if ('artists' in data && Array.isArray(data.artists)) {
+ return (data as Album | Song).artists.map((artist, index) => (
+
+
+ {artist.name}
+
+ {index < (data as Album | Song).artists.length - 1 && }
+
+ ));
+ }
+ 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 (
- {album.name}
+ {song.album}
);
- },
- id: 'name',
- },
- {
- format: (data) => {
- const album = data as Album;
- return album.albumArtists.map((artist, index) => (
-
-
- {artist.name}
-
- {index < album.albumArtists.length - 1 && }
-
- ));
- },
- id: 'albumArtists',
- isMuted: true,
- },
- ];
- case LibraryItem.ALBUM_ARTIST:
- return [{ format: (data) => (data as AlbumArtist).name, id: 'name' }];
- case LibraryItem.ARTIST:
- return [{ format: (data) => (data as Artist).name, id: 'name' }];
- case LibraryItem.PLAYLIST:
- return [{ format: (data) => (data as Playlist).name, id: 'name' }];
- case LibraryItem.SONG:
- return [{ format: (data) => (data as Song).name, id: 'name' }];
- default:
- return [];
- }
+ }
+ return song.album;
+ }
+ return '';
+ },
+ id: 'album',
+ isMuted: true,
+ },
+ {
+ format: (data) => {
+ if ('songCount' in data && data.songCount !== null) {
+ return String(data.songCount);
+ }
+ return '';
+ },
+ id: 'songCount',
+ },
+ {
+ format: (data) => {
+ if ('albumCount' in data && data.albumCount !== null) {
+ return String(data.albumCount);
+ }
+ return '';
+ },
+ id: 'albumCount',
+ },
+ {
+ format: (data) => {
+ if (
+ 'userRating' in data &&
+ (data as Album | AlbumArtist | Song).userRating !== null
+ ) {
+ 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) => {
- switch (itemType) {
- 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;
- }
+export const getDataRowsCount = () => {
+ return getDataRows().length;
};
const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | undefined) => {
@@ -635,20 +863,32 @@ const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | unde
const ItemCardRow = ({
data,
+ index,
row,
type,
}: {
data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
+ index: number;
row: DataRow;
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) {
return (
@@ -659,10 +899,10 @@ const ItemCardRow = ({
return (
diff --git a/src/renderer/components/item-list/helpers/use-grid-rows.ts b/src/renderer/components/item-list/helpers/use-grid-rows.ts
new file mode 100644
index 000000000..19af7a3d8
--- /dev/null
+++ b/src/renderer/components/item-list/helpers/use-grid-rows.ts
@@ -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 => row !== undefined,
+ );
+ case LibraryItem.ALBUM_ARTIST:
+ return [rowMap.get('name')].filter(
+ (row): row is NonNullable => row !== undefined,
+ );
+ case LibraryItem.ARTIST:
+ return [rowMap.get('name')].filter(
+ (row): row is NonNullable => row !== undefined,
+ );
+ case LibraryItem.PLAYLIST:
+ return [rowMap.get('name')].filter(
+ (row): row is NonNullable => row !== undefined,
+ );
+ case LibraryItem.SONG:
+ return [rowMap.get('name')].filter(
+ (row): row is NonNullable => 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.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 => row !== null && row !== undefined);
+
+ return configuredRows.length > 0 ? configuredRows : allRows;
+ }, [itemType, listKey, gridRowsConfig]);
+};
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 b76b5411c..63fbebfcb 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
@@ -60,6 +60,7 @@ interface VirtualizedGridListProps {
onScrollEnd?: ItemGridListProps['onScrollEnd'];
outerRef: RefObject;
ref: RefObject>;
+ rows?: ItemCardProps['rows'];
tableMeta: null | {
columnCount: number;
itemHeight: number;
@@ -85,6 +86,7 @@ const VirtualizedGridList = React.memo(
onScrollEnd,
outerRef,
ref,
+ rows,
tableMeta,
width,
}: VirtualizedGridListProps) => {
@@ -99,11 +101,13 @@ const VirtualizedGridList = React.memo(
gap,
internalState,
itemType,
+ rows,
tableMeta,
};
}, [
tableMeta,
controls,
+ rows,
data,
enableDrag,
enableExpansion,
@@ -167,59 +171,51 @@ const VirtualizedGridList = React.memo(
VirtualizedGridList.displayName = 'VirtualizedGridList';
-const createThrottledSetTableMeta = (itemsPerRow?: number) => {
- return throttle(
- (
- width: number,
- dataLength: number,
- type: LibraryItem,
- setTableMeta: (meta: any) => void,
- ) => {
- const isSm = width >= 600;
- const isMd = width >= 768;
- const isLg = width >= 960;
- const isXl = width >= 1200;
- const is2xl = width >= 1440;
- const is3xl = width >= 1920;
- const is4xl = width >= 2560;
+const createThrottledSetTableMeta = (itemsPerRow?: number, rowsCount?: number) => {
+ return throttle((width: number, dataLength: number, setTableMeta: (meta: any) => void) => {
+ const isSm = width >= 600;
+ 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) {
- dynamicItemsPerRow = 12;
- } else if (is3xl) {
- dynamicItemsPerRow = 10;
- } else if (is2xl) {
- dynamicItemsPerRow = 8;
- } else if (isXl) {
- dynamicItemsPerRow = 6;
- } else if (isLg) {
- dynamicItemsPerRow = 5;
- } else if (isMd) {
- dynamicItemsPerRow = 4;
- } else if (isSm) {
- dynamicItemsPerRow = 3;
- } else {
- dynamicItemsPerRow = 2;
- }
+ if (is4xl) {
+ dynamicItemsPerRow = 12;
+ } else if (is3xl) {
+ dynamicItemsPerRow = 10;
+ } else if (is2xl) {
+ dynamicItemsPerRow = 8;
+ } else if (isXl) {
+ dynamicItemsPerRow = 6;
+ } else if (isLg) {
+ dynamicItemsPerRow = 5;
+ } else if (isMd) {
+ dynamicItemsPerRow = 4;
+ } else if (isSm) {
+ dynamicItemsPerRow = 3;
+ } else {
+ dynamicItemsPerRow = 2;
+ }
- const setItemsPerRow = itemsPerRow || dynamicItemsPerRow;
+ const setItemsPerRow = itemsPerRow || dynamicItemsPerRow;
- const widthPerItem = Number(width) / setItemsPerRow;
- const itemHeight = widthPerItem + getDataRowsCount(type) * 26;
+ const widthPerItem = Number(width) / setItemsPerRow;
+ const itemHeight = widthPerItem + (rowsCount || getDataRowsCount()) * 26;
- if (widthPerItem === 0) {
- return;
- }
+ if (widthPerItem === 0) {
+ return;
+ }
- setTableMeta({
- columnCount: setItemsPerRow,
- itemHeight,
- rowCount: Math.ceil(dataLength / setItemsPerRow),
- });
- },
- 200,
- );
+ setTableMeta({
+ columnCount: setItemsPerRow,
+ itemHeight,
+ rowCount: Math.ceil(dataLength / setItemsPerRow),
+ });
+ }, 200);
};
export interface GridItemProps {
@@ -232,6 +228,7 @@ export interface GridItemProps {
gap: 'lg' | 'md' | 'sm' | 'xl' | 'xs';
internalState: ItemListStateActions;
itemType: LibraryItem;
+ rows?: ItemCardProps['rows'];
tableMeta: null | {
columnCount: number;
itemHeight: number;
@@ -257,6 +254,7 @@ export interface ItemGridListProps {
onScroll?: (offset: number, direction: 'down' | 'up') => void;
onScrollEnd?: (offset: number, direction: 'down' | 'up') => void;
ref?: Ref;
+ rows?: ItemCardProps['rows'];
}
export const ItemGridList = ({
@@ -273,6 +271,7 @@ export const ItemGridList = ({
onScroll,
onScrollEnd,
ref,
+ rows,
}: ItemGridListProps) => {
const rootRef = useRef(null);
const outerRef = useRef(null);
@@ -334,12 +333,12 @@ export const ItemGridList = ({
}, [initialize, tableMeta]);
const throttledSetTableMeta = useMemo(() => {
- return createThrottledSetTableMeta(itemsPerRow);
- }, [itemsPerRow]);
+ return createThrottledSetTableMeta(itemsPerRow, rows?.length);
+ }, [itemsPerRow, rows?.length]);
useLayoutEffect(() => {
- throttledSetTableMeta(containerWidth, data.length, itemType, setTableMeta);
- }, [containerWidth, data.length, itemType, throttledSetTableMeta]);
+ throttledSetTableMeta(containerWidth, data.length, setTableMeta);
+ }, [containerWidth, data.length, throttledSetTableMeta]);
const controls = useDefaultItemListControls();
@@ -620,6 +619,7 @@ export const ItemGridList = ({
onScrollEnd={onScrollEnd ?? (() => {})}
outerRef={outerRef}
ref={listRef}
+ rows={rows}
tableMeta={tableMeta}
width={width}
/>
@@ -638,7 +638,7 @@ export const ItemGridList = ({
const ListComponent = memo((props: ListChildComponentProps) => {
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 itemCount = data.length;
@@ -667,6 +667,7 @@ const ListComponent = memo((props: ListChildComponentProps) => {
enableDrag={enableDrag}
internalState={props.data.internalState}
itemType={itemType}
+ rows={rows}
withControls
/>
,
diff --git a/src/renderer/features/albums/components/album-list-infinite-grid.tsx b/src/renderer/features/albums/components/album-list-infinite-grid.tsx
index 4a63fc015..9bed75515 100644
--- a/src/renderer/features/albums/components/album-list-infinite-grid.tsx
+++ b/src/renderer/features/albums/components/album-list-infinite-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -52,6 +53,8 @@ export const AlbumListInfiniteGrid = forwardRef
enabled: saveScrollOffset,
});
+ const rows = useGridRows(LibraryItem.ALBUM, ItemListKey.ALBUM);
+
return (
itemType={LibraryItem.ALBUM}
onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd}
+ rows={rows}
/>
);
},
diff --git a/src/renderer/features/albums/components/album-list-paginated-grid.tsx b/src/renderer/features/albums/components/album-list-paginated-grid.tsx
index 48af9cf34..6cb7b2e55 100644
--- a/src/renderer/features/albums/components/album-list-paginated-grid.tsx
+++ b/src/renderer/features/albums/components/album-list-paginated-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { 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';
@@ -15,6 +16,7 @@ import {
LibraryItem,
SortOrder,
} from '/@/shared/types/domain-types';
+import { ItemListKey } from '/@/shared/types/types';
interface AlbumListPaginatedGridProps extends ItemListGridComponentProps {}
@@ -55,6 +57,8 @@ export const AlbumListPaginatedGrid = forwardRef
);
diff --git a/src/renderer/features/artists/components/album-artist-list-infinite-grid.tsx b/src/renderer/features/artists/components/album-artist-list-infinite-grid.tsx
index 6cde6e78f..47710b3f3 100644
--- a/src/renderer/features/artists/components/album-artist-list-infinite-grid.tsx
+++ b/src/renderer/features/artists/components/album-artist-list-infinite-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -15,7 +16,8 @@ import {
} from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
-interface AlbumArtistListInfiniteGridProps extends ItemListGridComponentProps {}
+interface AlbumArtistListInfiniteGridProps
+ extends ItemListGridComponentProps {}
export const AlbumArtistListInfiniteGrid = forwardRef(
(
@@ -53,6 +55,8 @@ export const AlbumArtistListInfiniteGrid = forwardRef
);
},
diff --git a/src/renderer/features/artists/components/album-artist-list-paginated-grid.tsx b/src/renderer/features/artists/components/album-artist-list-paginated-grid.tsx
index 504c2630c..6cb00e0ff 100644
--- a/src/renderer/features/artists/components/album-artist-list-paginated-grid.tsx
+++ b/src/renderer/features/artists/components/album-artist-list-paginated-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { 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';
@@ -15,6 +16,7 @@ import {
LibraryItem,
SortOrder,
} from '/@/shared/types/domain-types';
+import { ItemListKey } from '/@/shared/types/types';
interface AlbumArtistListPaginatedGridProps
extends ItemListGridComponentProps {}
@@ -57,6 +59,8 @@ export const AlbumArtistListPaginatedGrid = forwardRef
);
diff --git a/src/renderer/features/artists/components/artist-list-infinite-grid.tsx b/src/renderer/features/artists/components/artist-list-infinite-grid.tsx
index 817c68c6f..99bcab1e1 100644
--- a/src/renderer/features/artists/components/artist-list-infinite-grid.tsx
+++ b/src/renderer/features/artists/components/artist-list-infinite-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -53,6 +54,8 @@ export const ArtistListInfiniteGrid = forwardRef
);
},
diff --git a/src/renderer/features/artists/components/artist-list-paginated-grid.tsx b/src/renderer/features/artists/components/artist-list-paginated-grid.tsx
index 4471051dc..04957e19c 100644
--- a/src/renderer/features/artists/components/artist-list-paginated-grid.tsx
+++ b/src/renderer/features/artists/components/artist-list-paginated-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { 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';
@@ -15,6 +16,7 @@ import {
LibraryItem,
SortOrder,
} from '/@/shared/types/domain-types';
+import { ItemListKey } from '/@/shared/types/types';
interface ArtistListPaginatedGridProps extends ItemListGridComponentProps {}
@@ -56,6 +58,8 @@ export const ArtistListPaginatedGrid = forwardRef
);
diff --git a/src/renderer/features/genres/components/genre-list-infinite-grid.tsx b/src/renderer/features/genres/components/genre-list-infinite-grid.tsx
index 667e9a82c..8924f2cf1 100644
--- a/src/renderer/features/genres/components/genre-list-infinite-grid.tsx
+++ b/src/renderer/features/genres/components/genre-list-infinite-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -53,6 +54,8 @@ export const GenreListInfiniteGrid = forwardRef
enabled: saveScrollOffset,
});
+ const rows = useGridRows(LibraryItem.GENRE, ItemListKey.GENRE);
+
return (
itemType={LibraryItem.GENRE}
onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd}
+ rows={rows}
/>
);
},
diff --git a/src/renderer/features/genres/components/genre-list-paginated-grid.tsx b/src/renderer/features/genres/components/genre-list-paginated-grid.tsx
index b334c4edc..cbf646723 100644
--- a/src/renderer/features/genres/components/genre-list-paginated-grid.tsx
+++ b/src/renderer/features/genres/components/genre-list-paginated-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { 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';
@@ -15,6 +16,7 @@ import {
LibraryItem,
SortOrder,
} from '/@/shared/types/domain-types';
+import { ItemListKey } from '/@/shared/types/types';
interface GenreListPaginatedGridProps extends ItemListGridComponentProps {}
@@ -56,6 +58,8 @@ export const GenreListPaginatedGrid = forwardRef
);
diff --git a/src/renderer/features/shared/components/grid-config.tsx b/src/renderer/features/shared/components/grid-config.tsx
index 004367022..c668907a5 100644
--- a/src/renderer/features/shared/components/grid-config.tsx
+++ b/src/renderer/features/shared/components/grid-config.tsx
@@ -253,9 +253,6 @@ const GridRowConfig = ({
);
}, [data]);
- console.log('data', data);
- console.log(labelMap);
-
const handleChangeEnabled = useCallback(
(item: ItemGridListRowConfig, checked: boolean) => {
const value = useSettingsStore.getState().lists[listKey]?.grid.rows;
diff --git a/src/renderer/features/songs/components/song-list-infinite-grid.tsx b/src/renderer/features/songs/components/song-list-infinite-grid.tsx
index 88f4d016f..4d6eb045f 100644
--- a/src/renderer/features/songs/components/song-list-infinite-grid.tsx
+++ b/src/renderer/features/songs/components/song-list-infinite-grid.tsx
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { ItemGridList } from '/@/renderer/components/item-list/item-grid-list/item-grid-list';
import { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
@@ -48,6 +49,8 @@ export const SongListInfiniteGrid = forwardRef(
enabled: saveScrollOffset,
});
+ const rows = useGridRows(LibraryItem.SONG, ItemListKey.SONG);
+
return (
(
itemType={LibraryItem.SONG}
onRangeChanged={onRangeChanged}
onScrollEnd={handleOnScrollEnd}
+ rows={rows}
/>
);
},
diff --git a/src/renderer/features/songs/components/song-list-paginated-grid.tsx b/src/renderer/features/songs/components/song-list-paginated-grid.tsx
index 986d9932e..7397c16da 100644
--- a/src/renderer/features/songs/components/song-list-paginated-grid.tsx
+++ b/src/renderer/features/songs/components/song-list-paginated-grid.tsx
@@ -3,12 +3,14 @@ import { forwardRef } from 'react';
import { api } from '/@/renderer/api';
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 { 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 { ItemListGridComponentProps } from '/@/renderer/components/item-list/types';
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
import { LibraryItem, SongListQuery, SongListSort, SortOrder } from '/@/shared/types/domain-types';
+import { ItemListKey } from '/@/shared/types/types';
interface SongListPaginatedGridProps extends ItemListGridComponentProps {}
@@ -44,6 +46,8 @@ export const SongListPaginatedGrid = forwardRef
serverId,
});
+ const rows = useGridRows(LibraryItem.SONG, ItemListKey.SONG);
+
return (
gap={gap}
itemType={LibraryItem.SONG}
ref={ref}
+ rows={rows}
/>
);
diff --git a/src/shared/types/drag-and-drop.ts b/src/shared/types/drag-and-drop.ts
index d2e71b548..66a4ab521 100644
--- a/src/shared/types/drag-and-drop.ts
+++ b/src/shared/types/drag-and-drop.ts
@@ -8,6 +8,7 @@ export enum DragTarget {
ARTIST = LibraryItem.ARTIST,
GENERIC = 'generic',
GENRE = LibraryItem.GENRE,
+ GRID_ROW = 'gridRow',
PLAYLIST = LibraryItem.PLAYLIST,
QUEUE_SONG = LibraryItem.QUEUE_SONG,
SONG = LibraryItem.SONG,