mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
add search input to album detail table
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user