mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-06 20:10:12 +02:00
adjust top songs / favorite songs sections
- use table row height configuration for container calculation - add wrapper component and use for both Top Songs and Favorite Songs - remove the view more button, show all items by default
This commit is contained in:
@@ -225,6 +225,39 @@ const AlbumArtistMetadataBiography = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TABLE_ROW_HEIGHT = {
|
||||||
|
compact: 40,
|
||||||
|
default: 64,
|
||||||
|
large: 88,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const TABLE_HEADER_HEIGHT = 40;
|
||||||
|
|
||||||
|
interface SongTableListContainerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
enableHeader?: boolean;
|
||||||
|
itemCount: number;
|
||||||
|
maxRows?: number;
|
||||||
|
tableSize?: 'compact' | 'default' | 'large';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableRowHeight(size: 'compact' | 'default' | 'large' | undefined): number {
|
||||||
|
return size ? TABLE_ROW_HEIGHT[size] : TABLE_ROW_HEIGHT.default;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SongTableListContainer = ({
|
||||||
|
children,
|
||||||
|
enableHeader = true,
|
||||||
|
itemCount,
|
||||||
|
maxRows = 5,
|
||||||
|
tableSize = 'default',
|
||||||
|
}: SongTableListContainerProps) => {
|
||||||
|
const rowHeight = getTableRowHeight(tableSize);
|
||||||
|
const headerOffset = enableHeader ? TABLE_HEADER_HEIGHT : 0;
|
||||||
|
const height = headerOffset + rowHeight * Math.min(itemCount, maxRows);
|
||||||
|
return <div style={{ height }}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
interface AlbumArtistMetadataTopSongsProps {
|
interface AlbumArtistMetadataTopSongsProps {
|
||||||
detailQuery: ReturnType<typeof useSuspenseQuery<AlbumArtistDetailResponse>>;
|
detailQuery: ReturnType<typeof useSuspenseQuery<AlbumArtistDetailResponse>>;
|
||||||
routeId: string;
|
routeId: string;
|
||||||
@@ -237,7 +270,6 @@ const AlbumArtistMetadataTopSongsContent = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
|
const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
|
||||||
const [showAll, setShowAll] = useState(false);
|
|
||||||
const [topSongsQueryType, setTopSongsQueryType] = useLocalStorage<'community' | 'personal'>({
|
const [topSongsQueryType, setTopSongsQueryType] = useLocalStorage<'community' | 'personal'>({
|
||||||
defaultValue: 'community',
|
defaultValue: 'community',
|
||||||
key: 'album-artist-top-songs-query-type',
|
key: 'album-artist-top-songs-query-type',
|
||||||
@@ -269,13 +301,8 @@ const AlbumArtistMetadataTopSongsContent = ({
|
|||||||
}, [tableConfig?.columns]);
|
}, [tableConfig?.columns]);
|
||||||
|
|
||||||
const filteredSongs = useMemo(() => {
|
const filteredSongs = useMemo(() => {
|
||||||
const filtered = searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG);
|
return searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG);
|
||||||
// When searching, show all results. Otherwise, limit to 5 if not showing all
|
}, [songs, debouncedSearchTerm]);
|
||||||
if (debouncedSearchTerm?.trim() || showAll) {
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
return filtered.slice(0, 5);
|
|
||||||
}, [songs, debouncedSearchTerm, showAll]);
|
|
||||||
|
|
||||||
const { handleColumnReordered } = useItemListColumnReorder({
|
const { handleColumnReordered } = useItemListColumnReorder({
|
||||||
itemListKey: ItemListKey.SONG,
|
itemListKey: ItemListKey.SONG,
|
||||||
@@ -459,35 +486,35 @@ const AlbumArtistMetadataTopSongsContent = ({
|
|||||||
tableColumnsData={SONG_TABLE_COLUMNS}
|
tableColumnsData={SONG_TABLE_COLUMNS}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<ItemTableList
|
<SongTableListContainer
|
||||||
activeRowId={currentSongId}
|
|
||||||
autoFitColumns={tableConfig.autoFitColumns}
|
|
||||||
CellComponent={ItemTableListColumn}
|
|
||||||
columns={columns}
|
|
||||||
data={filteredSongs}
|
|
||||||
enableAlternateRowColors={tableConfig.enableAlternateRowColors}
|
|
||||||
enableDrag
|
|
||||||
enableDragScroll={false}
|
|
||||||
enableExpansion={false}
|
|
||||||
enableHeader={tableConfig.enableHeader}
|
enableHeader={tableConfig.enableHeader}
|
||||||
enableHorizontalBorders={tableConfig.enableHorizontalBorders}
|
itemCount={filteredSongs.length}
|
||||||
enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
|
maxRows={5}
|
||||||
enableSelection
|
tableSize={tableConfig.size}
|
||||||
enableSelectionDialog={false}
|
>
|
||||||
enableVerticalBorders={tableConfig.enableVerticalBorders}
|
<ItemTableList
|
||||||
itemType={LibraryItem.SONG}
|
activeRowId={currentSongId}
|
||||||
onColumnReordered={handleColumnReordered}
|
autoFitColumns={tableConfig.autoFitColumns}
|
||||||
onColumnResized={handleColumnResized}
|
CellComponent={ItemTableListColumn}
|
||||||
overrideControls={overrideControls}
|
columns={columns}
|
||||||
size={tableConfig.size}
|
data={filteredSongs}
|
||||||
/>
|
enableAlternateRowColors={tableConfig.enableAlternateRowColors}
|
||||||
{!searchTerm.trim() && songs.length > 5 && !showAll && (
|
enableDrag
|
||||||
<Group justify="center" w="100%">
|
enableDragScroll={false}
|
||||||
<Button onClick={() => setShowAll(true)} variant="subtle">
|
enableExpansion={false}
|
||||||
{t('action.viewMore', { postProcess: 'sentenceCase' })}
|
enableHeader={tableConfig.enableHeader}
|
||||||
</Button>
|
enableHorizontalBorders={tableConfig.enableHorizontalBorders}
|
||||||
</Group>
|
enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
|
||||||
)}
|
enableSelection
|
||||||
|
enableSelectionDialog={false}
|
||||||
|
enableVerticalBorders={tableConfig.enableVerticalBorders}
|
||||||
|
itemType={LibraryItem.SONG}
|
||||||
|
onColumnReordered={handleColumnReordered}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
|
overrideControls={overrideControls}
|
||||||
|
size={tableConfig.size}
|
||||||
|
/>
|
||||||
|
</SongTableListContainer>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -523,7 +550,6 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
|
const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
|
||||||
const [showAll, setShowAll] = useState(false);
|
|
||||||
const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.SONG]?.table);
|
const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.SONG]?.table);
|
||||||
const currentSong = usePlayerSong();
|
const currentSong = usePlayerSong();
|
||||||
const player = usePlayer();
|
const player = usePlayer();
|
||||||
@@ -548,13 +574,8 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori
|
|||||||
}, [tableConfig?.columns]);
|
}, [tableConfig?.columns]);
|
||||||
|
|
||||||
const filteredSongs = useMemo(() => {
|
const filteredSongs = useMemo(() => {
|
||||||
const filtered = searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG);
|
return searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG);
|
||||||
// When searching, show all results. Otherwise, limit to 5 if not showing all
|
}, [songs, debouncedSearchTerm]);
|
||||||
if (debouncedSearchTerm?.trim() || showAll) {
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
return filtered.slice(0, 5);
|
|
||||||
}, [songs, debouncedSearchTerm, showAll]);
|
|
||||||
|
|
||||||
const { handleColumnReordered } = useItemListColumnReorder({
|
const { handleColumnReordered } = useItemListColumnReorder({
|
||||||
itemListKey: ItemListKey.SONG,
|
itemListKey: ItemListKey.SONG,
|
||||||
@@ -717,8 +738,12 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori
|
|||||||
tableColumnsData={SONG_TABLE_COLUMNS}
|
tableColumnsData={SONG_TABLE_COLUMNS}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
{/* Restrict the height. Rendering all items in the DOM makes for a long delay */}
|
<SongTableListContainer
|
||||||
<div style={{ height: 50 + 64 * Math.min(songs.length, 5) }}>
|
enableHeader={tableConfig.enableHeader}
|
||||||
|
itemCount={filteredSongs.length}
|
||||||
|
maxRows={5}
|
||||||
|
tableSize={tableConfig.size}
|
||||||
|
>
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
activeRowId={currentSongId}
|
activeRowId={currentSongId}
|
||||||
autoFitColumns={tableConfig.autoFitColumns}
|
autoFitColumns={tableConfig.autoFitColumns}
|
||||||
@@ -741,15 +766,7 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori
|
|||||||
overrideControls={overrideControls}
|
overrideControls={overrideControls}
|
||||||
size={tableConfig.size}
|
size={tableConfig.size}
|
||||||
/>
|
/>
|
||||||
</div>
|
</SongTableListContainer>
|
||||||
|
|
||||||
{!searchTerm.trim() && songs.length > 5 && !showAll && (
|
|
||||||
<Group justify="center" w="100%">
|
|
||||||
<Button onClick={() => setShowAll(true)} variant="subtle">
|
|
||||||
{t('action.viewMore', { postProcess: 'sentenceCase' })}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
Reference in New Issue
Block a user