diff --git a/src/lib/components/FavoritePlaylistCard.svelte b/src/lib/components/FavoritePlaylistCard.svelte new file mode 100644 index 000000000..e8dad458c --- /dev/null +++ b/src/lib/components/FavoritePlaylistCard.svelte @@ -0,0 +1,351 @@ + + +
e.key === 'Enter' && onclick?.()} +> +
+ + +
+
+ + + +
+
+
+ +
+
0} + style="--ticker-offset: {titleOffset}; --ticker-duration: {titleDuration};" + bind:this={titleRef} + > + {playlist.name} +
+
+ {playlist.owner.name} + - + {playlist.tracks_count} tracks +
+
+
+ +{#if menuOpen} +
+ + + + + + +
+{/if} + + diff --git a/src/lib/components/views/FavoritesView.svelte b/src/lib/components/views/FavoritesView.svelte index 04b7bf45e..e1fe1386b 100644 --- a/src/lib/components/views/FavoritesView.svelte +++ b/src/lib/components/views/FavoritesView.svelte @@ -6,7 +6,7 @@ import TrackRow from '../TrackRow.svelte'; import QualityBadge from '../QualityBadge.svelte'; import VirtualizedTrackList from '../VirtualizedTrackList.svelte'; - import PlaylistCollage from '../PlaylistCollage.svelte'; + import FavoritePlaylistCard from '../FavoritePlaylistCard.svelte'; import FavoritesEditModal from '../FavoritesEditModal.svelte'; import ViewTransition from '../ViewTransition.svelte'; import { type OfflineCacheStatus } from '$lib/stores/offlineCacheState'; @@ -95,6 +95,11 @@ onTrackReDownload?: (track: DisplayTrack) => void; getTrackOfflineCacheStatus?: (trackId: number) => { status: OfflineCacheStatus; progress: number }; onPlaylistSelect?: (playlistId: number) => void; + onPlaylistPlay?: (playlistId: number) => void; + onPlaylistPlayNext?: (playlistId: number) => void; + onPlaylistPlayLater?: (playlistId: number) => void; + onPlaylistRemoveFavorite?: (playlistId: number) => void; + onPlaylistShareQobuz?: (playlistId: number) => void; selectedTab?: TabType; onTabNavigate?: (tab: TabType) => void; activeTrackId?: number | null; @@ -146,6 +151,11 @@ onTrackReDownload, getTrackOfflineCacheStatus, onPlaylistSelect, + onPlaylistPlay, + onPlaylistPlayNext, + onPlaylistPlayLater, + onPlaylistRemoveFavorite, + onPlaylistShareQobuz, selectedTab, onTabNavigate, activeTrackId = null, @@ -2083,13 +2093,15 @@ {:else}
{#each filteredPlaylists as playlist (playlist.id)} - + onPlaylistSelect?.(playlist.id)} + onPlay={() => onPlaylistPlay?.(playlist.id)} + onPlayNext={() => onPlaylistPlayNext?.(playlist.id)} + onPlayLater={() => onPlaylistPlayLater?.(playlist.id)} + onRemoveFavorite={() => onPlaylistRemoveFavorite?.(playlist.id)} + onShareQobuz={() => onPlaylistShareQobuz?.(playlist.id)} + /> {/each}
{/if} @@ -2937,49 +2949,9 @@ /* Playlist grid styles */ .playlist-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + grid-template-columns: repeat(auto-fill, 140px); gap: 24px; - } - - .playlist-card { - display: flex; - flex-direction: column; - align-items: center; - padding: 16px; - background-color: var(--bg-secondary); - border: none; - border-radius: 12px; - cursor: pointer; - transition: background-color 150ms ease; - } - - .playlist-card:hover { - background-color: var(--bg-tertiary); - } - - .playlist-artwork { - width: 140px; - height: 140px; - border-radius: 8px; - overflow: hidden; - margin-bottom: 12px; - } - - .playlist-name { - font-size: 14px; - font-weight: 600; - color: var(--text-primary); - text-align: center; - max-width: 140px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .playlist-meta { - font-size: 12px; - color: var(--text-muted); - margin-top: 4px; + justify-content: start; } /* Artist Two-Column Sidepanel Layout */ diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a68a6a3af..1abc78043 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1184,6 +1184,18 @@ showToast('Playlist link copied to clipboard', 'success'); } + async function removePlaylistFavoriteById(playlistId: number) { + try { + await invoke('playlist_set_favorite', { playlistId, favorite: false }); + showToast('Playlist removed from favorites', 'success'); + sidebarRef?.refreshPlaylists(); + sidebarRef?.refreshPlaylistSettings(); + } catch (err) { + console.error('Failed to remove playlist favorite:', err); + showToast(`Failed to remove from favorites: ${err}`, 'error'); + } + } + // Playback Functions - QobuzTrack from search results async function handleTrackPlay(track: QobuzTrack) { console.log('Playing track:', track); @@ -3132,6 +3144,11 @@ onTrackReDownload={handleDisplayTrackDownload} getTrackOfflineCacheStatus={getTrackOfflineCacheStatus} onPlaylistSelect={selectPlaylist} + onPlaylistPlay={playPlaylistById} + onPlaylistPlayNext={queuePlaylistNextById} + onPlaylistPlayLater={queuePlaylistLaterById} + onPlaylistRemoveFavorite={removePlaylistFavoriteById} + onPlaylistShareQobuz={sharePlaylistQobuzLinkById} selectedTab={getFavoritesTabFromView(activeView) ?? favoritesDefaultTab} onTabNavigate={(tab) => navigateToFavorites(tab)} activeTrackId={currentTrack?.id ?? null}