diff --git a/src/lib/components/views/SearchView.svelte b/src/lib/components/views/SearchView.svelte index 3a5bea121..f2b892fd8 100644 --- a/src/lib/components/views/SearchView.svelte +++ b/src/lib/components/views/SearchView.svelte @@ -220,6 +220,56 @@ let hasMoreTracks = $derived(trackResults ? trackResults.offset + trackResults.items.length < trackResults.total : false); let hasMoreArtists = $derived(artistResults ? artistResults.offset + artistResults.items.length < artistResults.total : false); + // Determine the "Most Popular" result based on query matching + // Priority: exact match > starts with > contains > default to first artist + type MostPopularType = 'artist' | 'album' | 'track'; + interface MostPopularResult { + type: MostPopularType; + artist?: Artist; + album?: Album; + track?: Track; + } + + let mostPopularResult = $derived.by((): MostPopularResult | null => { + if (!allResults) return null; + + const q = query.toLowerCase().trim(); + if (!q) return null; + + const firstArtist = allResults.artists.items[0]; + const firstAlbum = allResults.albums.items[0]; + const firstTrack = allResults.tracks.items[0]; + + // Check for exact matches first + if (firstArtist && firstArtist.name.toLowerCase() === q) { + return { type: 'artist', artist: firstArtist }; + } + if (firstAlbum && firstAlbum.title.toLowerCase() === q) { + return { type: 'album', album: firstAlbum }; + } + if (firstTrack && firstTrack.title.toLowerCase() === q) { + return { type: 'track', track: firstTrack }; + } + + // Check for "starts with" matches + if (firstArtist && firstArtist.name.toLowerCase().startsWith(q)) { + return { type: 'artist', artist: firstArtist }; + } + if (firstAlbum && firstAlbum.title.toLowerCase().startsWith(q)) { + return { type: 'album', album: firstAlbum }; + } + if (firstTrack && firstTrack.title.toLowerCase().startsWith(q)) { + return { type: 'track', track: firstTrack }; + } + + // Default: return artist if available, then album, then track + if (firstArtist) return { type: 'artist', artist: firstArtist }; + if (firstAlbum) return { type: 'album', album: firstAlbum }; + if (firstTrack) return { type: 'track', track: firstTrack }; + + return null; + }); + function debounceSearch() { if (searchTimeout) clearTimeout(searchTimeout); // Reset filter when user types a new search @@ -733,54 +783,78 @@

Most Popular

-
{allResults.artists.items[0].name}
- {#if allResults.artists.items[0].albums_count} -
{$t('library.albumCount', { values: { count: allResults.artists.items[0].albums_count } })}
- {/if} - - {:else if allResults.albums.items.length > 0} - onAlbumPlay(allResults.albums.items[0].id) : undefined} - onPlayNext={onAlbumPlayNext ? () => onAlbumPlayNext(allResults.albums.items[0].id) : undefined} - onPlayLater={onAlbumPlayLater ? () => onAlbumPlayLater(allResults.albums.items[0].id) : undefined} - onAddAlbumToPlaylist={onAddAlbumToPlaylist ? () => onAddAlbumToPlaylist(album.id) : undefined} - onShareQobuz={onAlbumShareQobuz ? () => onAlbumShareQobuz(allResults.albums.items[0].id) : undefined} - onShareSonglink={onAlbumShareSonglink ? () => onAlbumShareSonglink(allResults.albums.items[0].id) : undefined} - onDownload={onAlbumDownload ? () => onAlbumDownload(allResults.albums.items[0].id) : undefined} - isAlbumFullyDownloaded={isAlbumDownloaded(allResults.albums.items[0].id)} - onOpenContainingFolder={onOpenAlbumFolder ? () => onOpenAlbumFolder(allResults.albums.items[0].id) : undefined} - onReDownloadAlbum={onReDownloadAlbum ? () => onReDownloadAlbum(allResults.albums.items[0].id) : undefined} - {downloadStateVersion} - onclick={() => { onAlbumClick?.(allResults.albums.items[0].id); loadAlbumDownloadStatus(allResults.albums.items[0].id); }} - /> - {/if} + + {:else if mostPopularResult?.type === 'album' && mostPopularResult.album} + {@const album = mostPopularResult.album} + onAlbumPlay(album.id) : undefined} + onPlayNext={onAlbumPlayNext ? () => onAlbumPlayNext(album.id) : undefined} + onPlayLater={onAlbumPlayLater ? () => onAlbumPlayLater(album.id) : undefined} + onAddAlbumToPlaylist={onAddAlbumToPlaylist ? () => onAddAlbumToPlaylist(album.id) : undefined} + onShareQobuz={onAlbumShareQobuz ? () => onAlbumShareQobuz(album.id) : undefined} + onShareSonglink={onAlbumShareSonglink ? () => onAlbumShareSonglink(album.id) : undefined} + onDownload={onAlbumDownload ? () => onAlbumDownload(album.id) : undefined} + isAlbumFullyDownloaded={isAlbumDownloaded(album.id)} + onOpenContainingFolder={onOpenAlbumFolder ? () => onOpenAlbumFolder(album.id) : undefined} + onReDownloadAlbum={onReDownloadAlbum ? () => onReDownloadAlbum(album.id) : undefined} + {downloadStateVersion} + onclick={() => { onAlbumClick?.(album.id); loadAlbumDownloadStatus(album.id); }} + /> + {:else if mostPopularResult?.type === 'track' && mostPopularResult.track} + {@const track = mostPopularResult.track} + + {/if} @@ -1792,6 +1866,88 @@ min-height: 120px; } + /* Track card for Most Popular */ + .track-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 12px; + background: var(--bg-secondary); + border: none; + border-radius: 8px; + cursor: pointer; + transition: background 150ms ease; + text-align: center; + } + + .track-card:hover { + background: var(--bg-tertiary); + } + + .track-card.most-popular-card { + width: 160px; + height: 220px; + justify-content: flex-start; + } + + .track-card-artwork { + width: 120px; + height: 120px; + border-radius: 8px; + overflow: hidden; + flex-shrink: 0; + } + + .track-card-artwork img { + width: 100%; + height: 100%; + object-fit: cover; + } + + .track-card-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: var(--bg-tertiary); + color: var(--text-muted); + } + + .track-card-info { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; + width: 100%; + } + + .track-card-title { + font-size: 13px; + font-weight: 500; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .track-card-artist { + font-size: 12px; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .track-card-album { + font-size: 11px; + color: var(--text-muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .artists-section h3, .section-header h3 { font-size: 16px; font-weight: 600;