add search input to album detail table

This commit is contained in:
jeffvli
2025-11-19 02:10:31 -08:00
parent 883406ef11
commit d590ac33a1
@@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Suspense, useMemo } from 'react'; import { Suspense, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { generatePath, Link, useParams } from 'react-router'; import { generatePath, Link, useParams } from 'react-router';
@@ -17,6 +17,7 @@ import { usePlayer } from '/@/renderer/features/player/context/player-context';
import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay'; import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay';
import { ListConfigMenu } from '/@/renderer/features/shared/components/list-config-menu'; import { ListConfigMenu } from '/@/renderer/features/shared/components/list-config-menu';
import { PlayButton } from '/@/renderer/features/shared/components/play-button'; import { PlayButton } from '/@/renderer/features/shared/components/play-button';
import { searchLibraryItems } from '/@/renderer/features/shared/utils';
import { useContainerQuery } from '/@/renderer/hooks'; import { useContainerQuery } from '/@/renderer/hooks';
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route'; import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
import { useCurrentServer } from '/@/renderer/store'; import { useCurrentServer } from '/@/renderer/store';
@@ -30,9 +31,11 @@ import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Button } from '/@/shared/components/button/button'; import { Button } from '/@/shared/components/button/button';
import { Checkbox } from '/@/shared/components/checkbox/checkbox'; import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Group } from '/@/shared/components/group/group'; import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon';
import { Spinner } from '/@/shared/components/spinner/spinner'; import { Spinner } from '/@/shared/components/spinner/spinner';
import { Spoiler } from '/@/shared/components/spoiler/spoiler'; import { Spoiler } from '/@/shared/components/spoiler/spoiler';
import { Stack } from '/@/shared/components/stack/stack'; import { Stack } from '/@/shared/components/stack/stack';
import { TextInput } from '/@/shared/components/text-input/text-input';
import { Text } from '/@/shared/components/text/text'; import { Text } from '/@/shared/components/text/text';
import { AlbumListSort, LibraryItem, Song, SortOrder } from '/@/shared/types/domain-types'; import { AlbumListSort, LibraryItem, Song, SortOrder } from '/@/shared/types/domain-types';
import { ItemListKey, ListDisplayType } from '/@/shared/types/types'; import { ItemListKey, ListDisplayType } from '/@/shared/types/types';
@@ -149,17 +152,6 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
/> />
</Group> </Group>
</Group> </Group>
<ListConfigMenu
displayTypes={[{ hidden: true, value: ListDisplayType.GRID }]}
listKey={ItemListKey.ALBUM_DETAIL}
optionsConfig={{
table: {
itemsPerPage: { hidden: true },
pagination: { hidden: true },
},
}}
tableColumnsData={SONG_TABLE_COLUMNS}
/>
</Group> </Group>
</section> </section>
{showGenres && ( {showGenres && (
@@ -273,12 +265,17 @@ interface AlbumDetailSongsTableProps {
const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => { const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [searchTerm, setSearchTerm] = useState('');
const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.ALBUM_DETAIL]?.table); const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.ALBUM_DETAIL]?.table);
const columns = useMemo(() => { const columns = useMemo(() => {
return tableConfig?.columns || []; return tableConfig?.columns || [];
}, [tableConfig?.columns]); }, [tableConfig?.columns]);
const filteredSongs = useMemo(() => {
return searchLibraryItems(songs, searchTerm, LibraryItem.SONG);
}, [songs, searchTerm]);
const { handleColumnReordered } = useItemListColumnReorder({ const { handleColumnReordered } = useItemListColumnReorder({
itemListKey: ItemListKey.ALBUM_DETAIL, itemListKey: ItemListKey.ALBUM_DETAIL,
}); });
@@ -288,7 +285,7 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
}); });
const discGroups = useMemo(() => { const discGroups = useMemo(() => {
if (songs.length === 0) return []; if (filteredSongs.length === 0) return [];
const groups: Array<{ const groups: Array<{
discNumber: number; discNumber: number;
@@ -298,7 +295,7 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
let lastDiscNumber = -1; let lastDiscNumber = -1;
let currentGroupStartIndex = 0; let currentGroupStartIndex = 0;
songs.forEach((song, index) => { filteredSongs.forEach((song, index) => {
if (song.discNumber !== lastDiscNumber) { if (song.discNumber !== lastDiscNumber) {
// If we have a previous group, calculate its item count // If we have a previous group, calculate its item count
if (groups.length > 0) { if (groups.length > 0) {
@@ -317,44 +314,18 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
// Set item count for the last group // Set item count for the last group
if (groups.length > 0) { if (groups.length > 0) {
groups[groups.length - 1].itemCount = songs.length - currentGroupStartIndex; groups[groups.length - 1].itemCount = filteredSongs.length - currentGroupStartIndex;
} }
return groups; return groups;
}, [songs]); }, [filteredSongs]);
// const maxHeight = useMemo(() => {
// if (!tableConfig) return undefined;
// const headerHeight = 40;
// const rowHeights = {
// compact: 40,
// default: 64,
// large: 88,
// };
// const rowHeight = rowHeights[tableConfig.size || 'default'];
// const maxRows = 20;
// return headerHeight + maxRows * rowHeight;
// }, [tableConfig]);
// Uncomment to enable static table height
// const containerHeight = useMemo(() => {
// if (!tableConfig || !maxHeight) return undefined;
// const headerHeight = 40;
// const rowHeights = {
// compact: 40,
// default: 64,
// large: 88,
// };
// const rowHeight = rowHeights[tableConfig.size || 'default'];
// const actualRows = Math.min(songs.length, 20);
// return Math.min(headerHeight + actualRows * rowHeight, maxHeight);
// }, [tableConfig, maxHeight, songs.length]);
const groups = useMemo(() => { const groups = useMemo(() => {
// Remove groups when filtering
if (searchTerm.trim()) {
return undefined;
}
if (discGroups.length <= 1) { if (discGroups.length <= 1) {
return undefined; return undefined;
} }
@@ -439,33 +410,66 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
}, },
rowHeight: 40, rowHeight: 40,
})); }));
}, [discGroups, t]); }, [discGroups, t, searchTerm]);
if (!tableConfig || columns.length === 0) { if (!tableConfig || columns.length === 0) {
return null; return null;
} }
return ( return (
<ItemTableList <Stack gap="md">
autoFitColumns={tableConfig.autoFitColumns} <Group gap="sm" w="100%">
CellComponent={ItemTableListColumn} <TextInput
columns={columns} flex={1}
data={songs} leftSection={<Icon icon="search" />}
enableAlternateRowColors={tableConfig.enableAlternateRowColors} onChange={(e) => setSearchTerm(e.target.value)}
enableDrag placeholder={t('common.search', { postProcess: 'sentenceCase' })}
enableExpansion={false} radius="xl"
enableHeader rightSection={
enableHorizontalBorders={tableConfig.enableHorizontalBorders} searchTerm ? (
enableRowHoverHighlight={tableConfig.enableRowHoverHighlight} <ActionIcon
enableSelection icon="x"
enableStickyGroupRows onClick={() => setSearchTerm('')}
enableStickyHeader size="sm"
enableVerticalBorders={tableConfig.enableVerticalBorders} variant="transparent"
groups={groups} />
itemType={LibraryItem.SONG} ) : null
onColumnReordered={handleColumnReordered} }
onColumnResized={handleColumnResized} value={searchTerm}
size={tableConfig.size} />
/> <ListConfigMenu
displayTypes={[{ hidden: true, value: ListDisplayType.GRID }]}
listKey={ItemListKey.ALBUM_DETAIL}
optionsConfig={{
table: {
itemsPerPage: { hidden: true },
pagination: { hidden: true },
},
}}
tableColumnsData={SONG_TABLE_COLUMNS}
/>
</Group>
<ItemTableList
autoFitColumns={tableConfig.autoFitColumns}
CellComponent={ItemTableListColumn}
columns={columns}
data={filteredSongs}
enableAlternateRowColors={tableConfig.enableAlternateRowColors}
enableDrag
enableExpansion={false}
enableHeader
enableHorizontalBorders={tableConfig.enableHorizontalBorders}
enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
enableSelection
enableStickyGroupRows
enableStickyHeader
enableVerticalBorders={tableConfig.enableVerticalBorders}
groups={groups}
itemType={LibraryItem.SONG}
onColumnReordered={handleColumnReordered}
onColumnResized={handleColumnResized}
size={tableConfig.size}
/>
</Stack>
); );
}; };