diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx index 1a72b454..5911d139 100644 --- a/src/renderer/features/albums/components/album-detail-content.tsx +++ b/src/renderer/features/albums/components/album-detail-content.tsx @@ -1,5 +1,5 @@ import { MutableRefObject, useCallback, useMemo } from 'react'; -import { Button, GridCarousel, Text, TextTitle } from '/@/renderer/components'; +import { Button, Text } from '/@/renderer/components'; import { ColDef, RowDoubleClickedEvent, RowHeightParams, RowNode } from '@ag-grid-community/core'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import { Box, Group, Stack } from '@mantine/core'; @@ -31,6 +31,7 @@ import { useFixedTableHeader, VirtualTable, } from '/@/renderer/components/virtual-table'; +import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel'; const isFullWidthRow = (node: RowNode) => { return node.id?.includes('disc-'); @@ -174,13 +175,14 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { query: { _custom: { jellyfin: { - albumArtistIds: detailQuery?.data?.albumArtists[0]?.id, + AlbumArtistIds: detailQuery?.data?.albumArtists[0]?.id, + ExcludeItemIds: detailQuery?.data?.id, }, navidrome: { artist_id: detailQuery?.data?.albumArtists[0]?.id, }, }, - limit: itemsPerPage, + limit: 10, sortBy: AlbumListSort.YEAR, sortOrder: SortOrder.DESC, startIndex: pagination.artist * itemsPerPage, @@ -198,14 +200,7 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { hasPreviousPage: pagination.artist > 0, itemsPerPage, }, - title: ( - - More from this artist - - ), + title: 'More from this artist', uniqueId: 'mostPlayed', }, ]; @@ -325,7 +320,10 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { )} - + { ref={cq.ref} mt="5rem" > - {carousels.map((carousel, index) => ( - - {carousel.title} - - ))} + <> + {cq.height || cq.width ? ( + <> + {carousels.map((carousel, index) => ( + + ))} + + ) : null} + ); 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 1b78023c..ad782174 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { Button, GridCarousel, Text, TextTitle } from '/@/renderer/components'; +import { Button, Text, TextTitle } from '/@/renderer/components'; import { ColDef, RowDoubleClickedEvent } from '@ag-grid-community/core'; import { Box, Group, Stack } from '@mantine/core'; import { RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri'; @@ -14,7 +14,7 @@ import { useHandleGeneralContextMenu, useHandleTableContextMenu, } from '/@/renderer/features/context-menu'; -import { Play, TableColumn } from '/@/renderer/types'; +import { CardRow, Play, TableColumn } from '/@/renderer/types'; import { ARTIST_CONTEXT_MENU_ITEMS, SONG_CONTEXT_MENU_ITEMS, @@ -22,6 +22,8 @@ import { import { PlayButton, useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared'; import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query'; import { + Album, + AlbumArtist, AlbumListSort, LibraryItem, QueueSong, @@ -32,6 +34,7 @@ import { usePlayQueueAdd } from '/@/renderer/features/player'; import { useAlbumArtistDetail } from '/@/renderer/features/artists/queries/album-artist-detail-query'; import { useTopSongsList } from '/@/renderer/features/artists/queries/top-songs-list-query'; import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-table'; +import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel'; const ContentContainer = styled.div` position: relative; @@ -55,7 +58,6 @@ export const AlbumArtistDetailContent = () => { const cq = useContainerQuery(); const handlePlayQueueAdd = usePlayQueueAdd(); const server = useCurrentServer(); - const itemsPerPage = cq.isXl ? 9 : cq.isLg ? 7 : cq.isMd ? 5 : cq.isSm ? 4 : 3; const detailQuery = useAlbumArtistDetail({ query: { id: albumArtistId }, serverId: server?.id }); @@ -77,7 +79,7 @@ export const AlbumArtistDetailContent = () => { query: { _custom: { jellyfin: { - ...(server?.type === ServerType.JELLYFIN ? { artistIds: albumArtistId } : undefined), + ...(server?.type === ServerType.JELLYFIN ? { ArtistIds: albumArtistId } : undefined), }, navidrome: { ...(server?.type === ServerType.NAVIDROME @@ -85,7 +87,7 @@ export const AlbumArtistDetailContent = () => { : undefined), }, }, - limit: itemsPerPage, + // limit: 10, sortBy: AlbumListSort.RELEASE_DATE, sortOrder: SortOrder.DESC, startIndex: 0, @@ -98,7 +100,7 @@ export const AlbumArtistDetailContent = () => { _custom: { jellyfin: { ...(server?.type === ServerType.JELLYFIN - ? { contributingArtistIds: albumArtistId } + ? { ContributingArtistIds: albumArtistId } : undefined), }, navidrome: { @@ -107,7 +109,7 @@ export const AlbumArtistDetailContent = () => { : undefined), }, }, - limit: itemsPerPage, + // limit: 10, sortBy: AlbumListSort.RELEASE_DATE, sortOrder: SortOrder.DESC, startIndex: 0, @@ -140,7 +142,7 @@ export const AlbumArtistDetailContent = () => { [], ); - const cardRows = { + const cardRows: Record[] | CardRow[]> = { album: [ { property: 'name', @@ -169,17 +171,25 @@ export const AlbumArtistDetailContent = () => { ], }; + const cardRoutes = { + album: { + route: AppRoute.LIBRARY_ALBUMS_DETAIL, + slugs: [{ idProperty: 'id', slugProperty: 'albumId' }], + }, + albumArtist: { + route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, + slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }], + }, + }; + const carousels = [ { data: recentAlbumsQuery?.data?.items, isHidden: !recentAlbumsQuery?.data?.items?.length, itemType: LibraryItem.ALBUM, loading: recentAlbumsQuery?.isLoading || recentAlbumsQuery.isFetching, - pagination: { - itemsPerPage, - }, title: ( - <> + { > View discography - + ), uniqueId: 'recentReleases', }, @@ -204,9 +214,6 @@ export const AlbumArtistDetailContent = () => { isHidden: !compilationAlbumsQuery?.data?.items?.length, itemType: LibraryItem.ALBUM, loading: compilationAlbumsQuery?.isLoading || compilationAlbumsQuery.isFetching, - pagination: { - itemsPerPage, - }, title: ( { uniqueId: 'compilationAlbums', }, { - data: detailQuery?.data?.similarArtists?.slice(0, itemsPerPage), + data: detailQuery?.data?.similarArtists || [], isHidden: !detailQuery?.data?.similarArtists, itemType: LibraryItem.ALBUM_ARTIST, loading: detailQuery?.isLoading || detailQuery.isFetching, - pagination: { - itemsPerPage, - }, title: ( { {carousels .filter((c) => !c.isHidden) .map((carousel) => ( - - {carousel.title} - + /> ))} diff --git a/src/renderer/features/home/routes/home-route.tsx b/src/renderer/features/home/routes/home-route.tsx index e7805c20..4e0a9ed3 100644 --- a/src/renderer/features/home/routes/home-route.tsx +++ b/src/renderer/features/home/routes/home-route.tsx @@ -1,27 +1,22 @@ -import { useCallback, useMemo, useRef } from 'react'; +import { useMemo, useRef } from 'react'; import { Box, Stack } from '@mantine/core'; -import { useSetState } from '@mantine/hooks'; import { AlbumListSort, LibraryItem, ServerType, SortOrder } from '/@/renderer/api/types'; -import { TextTitle, FeatureCarousel, GridCarousel, NativeScrollArea } from '/@/renderer/components'; +import { FeatureCarousel, NativeScrollArea } from '/@/renderer/components'; import { useAlbumList } from '/@/renderer/features/albums'; import { useRecentlyPlayed } from '/@/renderer/features/home/queries/recently-played-query'; import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared'; import { useContainerQuery } from '/@/renderer/hooks'; import { AppRoute } from '/@/renderer/router/routes'; -import { useCurrentServer } from '/@/renderer/store'; +import { useCurrentServer, useWindowSettings } from '/@/renderer/store'; +import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel'; +import { Platform } from '/@/renderer/types'; const HomeRoute = () => { const scrollAreaRef = useRef(null); const server = useCurrentServer(); const cq = useContainerQuery(); - const itemsPerPage = cq.isXl ? 9 : cq.isLg ? 7 : cq.isMd ? 5 : cq.isSm ? 4 : 3; - - const [pagination, setPagination] = useSetState({ - mostPlayed: 0, - random: 0, - recentlyAdded: 0, - recentlyPlayed: 0, - }); + const itemsPerPage = 25; + const { windowBarStyle } = useWindowSettings(); const feature = useAlbumList({ options: { @@ -43,154 +38,85 @@ const HomeRoute = () => { const random = useAlbumList({ options: { - cacheTime: 1000 * 60, - keepPreviousData: true, - staleTime: 1000 * 60, + staleTime: 1000 * 60 * 5, }, query: { limit: itemsPerPage, sortBy: AlbumListSort.RANDOM, sortOrder: SortOrder.ASC, - startIndex: pagination.random * itemsPerPage, + startIndex: 0, }, serverId: server?.id, }); const recentlyPlayed = useRecentlyPlayed({ options: { - keepPreviousData: true, staleTime: 0, }, query: { limit: itemsPerPage, sortBy: AlbumListSort.RECENTLY_PLAYED, sortOrder: SortOrder.DESC, - startIndex: pagination.recentlyPlayed * itemsPerPage, + startIndex: 0, }, serverId: server?.id, }); const recentlyAdded = useAlbumList({ - options: { - keepPreviousData: true, - staleTime: 1000 * 60, - }, query: { limit: itemsPerPage, sortBy: AlbumListSort.RECENTLY_ADDED, sortOrder: SortOrder.DESC, - startIndex: pagination.recentlyAdded * itemsPerPage, + startIndex: 0, }, serverId: server?.id, }); const mostPlayed = useAlbumList({ options: { - keepPreviousData: true, - staleTime: 1000 * 60 * 60, + staleTime: 1000 * 60 * 5, }, query: { limit: itemsPerPage, sortBy: AlbumListSort.PLAY_COUNT, sortOrder: SortOrder.DESC, - startIndex: pagination.mostPlayed * itemsPerPage, + startIndex: 0, }, serverId: server?.id, }); - const handleNextPage = useCallback( - (key: 'mostPlayed' | 'random' | 'recentlyAdded' | 'recentlyPlayed') => { - setPagination({ - [key]: pagination[key as keyof typeof pagination] + 1, - }); - }, - [pagination, setPagination], - ); - - const handlePreviousPage = useCallback( - (key: 'mostPlayed' | 'random' | 'recentlyAdded' | 'recentlyPlayed') => { - setPagination({ - [key]: pagination[key as keyof typeof pagination] - 1, - }); - }, - [pagination, setPagination], - ); - const carousels = [ { data: random?.data?.items, - loading: random?.isLoading || random.isFetching, - pagination: { - handleNextPage: () => handleNextPage('random'), - handlePreviousPage: () => handlePreviousPage('random'), - hasPreviousPage: pagination.random > 0, - itemsPerPage, - }, - title: ( - - Explore from your library - - ), + loading: random?.isLoading, + title: 'Explore from your library', uniqueId: 'random', }, { data: recentlyPlayed?.data?.items, - loading: recentlyPlayed?.isLoading || recentlyPlayed.isFetching, + loading: recentlyPlayed?.isLoading, pagination: { - handleNextPage: () => handleNextPage('recentlyPlayed'), - handlePreviousPage: () => handlePreviousPage('recentlyPlayed'), - hasPreviousPage: pagination.recentlyPlayed > 0, itemsPerPage, }, - title: ( - - Recently played - - ), + title: 'Recently played', uniqueId: 'recentlyPlayed', }, { data: recentlyAdded?.data?.items, - loading: recentlyAdded?.isLoading || recentlyAdded.isFetching, + loading: recentlyAdded?.isLoading, pagination: { - handleNextPage: () => handleNextPage('recentlyAdded'), - handlePreviousPage: () => handlePreviousPage('recentlyAdded'), - hasPreviousPage: pagination.recentlyAdded > 0, itemsPerPage, }, - title: ( - - Newly added releases - - ), + title: 'Newly added releases', uniqueId: 'recentlyAdded', }, { data: mostPlayed?.data?.items, - loading: mostPlayed?.isLoading || mostPlayed.isFetching, + loading: mostPlayed?.isLoading, pagination: { - handleNextPage: () => handleNextPage('mostPlayed'), - handlePreviousPage: () => handlePreviousPage('mostPlayed'), - hasPreviousPage: pagination.mostPlayed > 0, itemsPerPage, }, - title: ( - - Most played - - ), + title: 'Most played', uniqueId: 'mostPlayed', }, ]; @@ -211,12 +137,8 @@ const HomeRoute = () => { > @@ -231,9 +153,9 @@ const HomeRoute = () => { return carousel; }) - .map((carousel, index) => ( - ( + { }, }, ]} - containerWidth={cq.width} data={carousel.data} + isLoading={carousel.loading} itemType={LibraryItem.ALBUM} - loading={carousel.loading} - pagination={carousel.pagination} + route={{ + route: AppRoute.LIBRARY_ALBUMS_DETAIL, + slugs: [{ idProperty: 'id', slugProperty: 'albumId' }], + }} + title={{ label: carousel.title }} uniqueId={carousel.uniqueId} - > - {carousel.title} - + /> ))}