diff --git a/src/renderer/features/artists/components/album-artist-detail-content.tsx b/src/renderer/features/artists/components/album-artist-detail-content.tsx index 524df676b..a36fdf747 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -228,6 +228,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
{children}
; +}; + interface AlbumArtistMetadataTopSongsProps { detailQuery: ReturnType>; routeId: string; @@ -240,7 +273,6 @@ const AlbumArtistMetadataTopSongsContent = ({ const { t } = useTranslation(); const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300); - const [showAll, setShowAll] = useState(false); const [topSongsQueryType, setTopSongsQueryType] = useLocalStorage<'community' | 'personal'>({ defaultValue: 'community', key: 'album-artist-top-songs-query-type', @@ -272,13 +304,8 @@ const AlbumArtistMetadataTopSongsContent = ({ }, [tableConfig?.columns]); const filteredSongs = useMemo(() => { - const filtered = searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG); - // When searching, show all results. Otherwise, limit to 5 if not showing all - if (debouncedSearchTerm?.trim() || showAll) { - return filtered; - } - return filtered.slice(0, 5); - }, [songs, debouncedSearchTerm, showAll]); + return searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG); + }, [songs, debouncedSearchTerm]); const { handleColumnReordered } = useItemListColumnReorder({ itemListKey: ItemListKey.SONG, @@ -465,35 +492,35 @@ const AlbumArtistMetadataTopSongsContent = ({ tableColumnsData={SONG_TABLE_COLUMNS} /> - - {!searchTerm.trim() && songs.length > 5 && !showAll && ( - - - - )} + itemCount={filteredSongs.length} + maxRows={5} + tableSize={tableConfig.size} + > + + ) : null} @@ -529,7 +556,6 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori const { t } = useTranslation(); const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300); - const [showAll, setShowAll] = useState(false); const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.SONG]?.table); const currentSong = usePlayerSong(); const player = usePlayer(); @@ -554,13 +580,8 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori }, [tableConfig?.columns]); const filteredSongs = useMemo(() => { - const filtered = searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG); - // When searching, show all results. Otherwise, limit to 5 if not showing all - if (debouncedSearchTerm?.trim() || showAll) { - return filtered; - } - return filtered.slice(0, 5); - }, [songs, debouncedSearchTerm, showAll]); + return searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG); + }, [songs, debouncedSearchTerm]); const { handleColumnReordered } = useItemListColumnReorder({ itemListKey: ItemListKey.SONG, @@ -726,35 +747,35 @@ const AlbumArtistMetadataFavoriteSongs = ({ routeId }: AlbumArtistMetadataFavori tableColumnsData={SONG_TABLE_COLUMNS} /> - - {!searchTerm.trim() && songs.length > 5 && !showAll && ( - - - - )} + itemCount={filteredSongs.length} + maxRows={5} + tableSize={tableConfig.size} + > + + ) : null} diff --git a/src/renderer/features/shared/utils.ts b/src/renderer/features/shared/utils.ts index c35088a0e..49b07cb63 100644 --- a/src/renderer/features/shared/utils.ts +++ b/src/renderer/features/shared/utils.ts @@ -128,23 +128,12 @@ export const createFuseForLibraryItem = ( }); } - const sampleItem = items[0]; - - const stringKeys = Object.keys(sampleItem).filter( - (key) => - typeof sampleItem[key as keyof T] === 'string' && - !key.startsWith('_') && - key !== 'id' && - key !== 'albumId' && - key !== 'streamUrl' && - key !== 'serverId' && - key !== 'ownerId', - ) as string[]; - + const stringKeys: string[] = []; const nestedKeys: Array<{ getFn: (item: T) => string; name: string }> = []; switch (itemType) { case LibraryItem.ALBUM: { + stringKeys.push('name', 'releaseType'); nestedKeys.push( { getFn: (item) => { @@ -172,6 +161,7 @@ export const createFuseForLibraryItem = ( } case LibraryItem.ALBUM_ARTIST: { + stringKeys.push('name'); nestedKeys.push({ getFn: (item) => { const aa = item as AlbumArtist; @@ -185,9 +175,10 @@ export const createFuseForLibraryItem = ( case LibraryItem.ARTIST: case LibraryItem.GENRE: case LibraryItem.RADIO_STATION: + stringKeys.push('name'); break; - case LibraryItem.PLAYLIST: { + stringKeys.push('name'); nestedKeys.push({ getFn: (item) => { const p = item as Playlist; @@ -200,7 +191,8 @@ export const createFuseForLibraryItem = ( case LibraryItem.PLAYLIST_SONG: case LibraryItem.QUEUE_SONG: - case LibraryItem.SONG: { + case LibraryItem.SONG: + stringKeys.push('album', 'name'); nestedKeys.push( { getFn: (item) => { @@ -218,7 +210,6 @@ export const createFuseForLibraryItem = ( }, ); break; - } } return new Fuse(items, {