discover: fold the remaining mixes into the "Your Mixes" shelf
Fresh Tape (release_radar), The Archives (discovery_weekly), and the Seasonal/Summer Mix (seasonal_playlist) move out of their old full-width compact-track-table sections into the unified shelf as mix cards (set the global in the controller renderItems, then _upsertMixCard + collapse the old section after load). Daily Mixes loader is converted the same way (each mix → a card) for if/when that HIDDEN feature is re-enabled. So every active mix now lives in one consistent shelf. 64 script-integrity tests green.
This commit is contained in:
parent
9d5e58c4b8
commit
9c832ab3c3
1 changed files with 41 additions and 58 deletions
|
|
@ -1788,11 +1788,7 @@ async function loadDiscoverReleaseRadar() {
|
||||||
contentEl: '#release-radar-playlist',
|
contentEl: '#release-radar-playlist',
|
||||||
fetchUrl: '/api/discover/release-radar',
|
fetchUrl: '/api/discover/release-radar',
|
||||||
extractItems: (data) => data.tracks || [],
|
extractItems: (data) => data.tracks || [],
|
||||||
renderItems: (items) => {
|
renderItems: (items) => { discoverReleaseRadarTracks = items; return ''; },
|
||||||
discoverReleaseRadarTracks = items;
|
|
||||||
const rows = items.map((t, i) => _renderCompactTrackRow(t, i)).join('');
|
|
||||||
return `<div class="discover-playlist-tracks-compact">${rows}</div>`;
|
|
||||||
},
|
|
||||||
loadingMessage: 'Loading release radar...',
|
loadingMessage: 'Loading release radar...',
|
||||||
emptyMessage: 'No new releases available',
|
emptyMessage: 'No new releases available',
|
||||||
errorMessage: 'Failed to load release radar',
|
errorMessage: 'Failed to load release radar',
|
||||||
|
|
@ -1800,7 +1796,16 @@ async function loadDiscoverReleaseRadar() {
|
||||||
showErrorToast: true,
|
showErrorToast: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return _releaseRadarCtrl.load();
|
await _releaseRadarCtrl.load();
|
||||||
|
const c = document.querySelector('#release-radar-playlist');
|
||||||
|
if (c) _collapseOldMixSection(c);
|
||||||
|
if (discoverReleaseRadarTracks && discoverReleaseRadarTracks.length) {
|
||||||
|
_upsertMixCard({
|
||||||
|
key: 'release_radar', title: 'Fresh Tape',
|
||||||
|
subtitle: 'New releases from artists you follow',
|
||||||
|
tracks: discoverReleaseRadarTracks, syncKey: 'release_radar',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _weeklyCtrl = null;
|
let _weeklyCtrl = null;
|
||||||
|
|
@ -1812,11 +1817,7 @@ async function loadDiscoverWeekly() {
|
||||||
contentEl: '#discovery-weekly-playlist',
|
contentEl: '#discovery-weekly-playlist',
|
||||||
fetchUrl: '/api/discover/weekly',
|
fetchUrl: '/api/discover/weekly',
|
||||||
extractItems: (data) => data.tracks || [],
|
extractItems: (data) => data.tracks || [],
|
||||||
renderItems: (items) => {
|
renderItems: (items) => { discoverWeeklyTracks = items; return ''; },
|
||||||
discoverWeeklyTracks = items;
|
|
||||||
const rows = items.map((t, i) => _renderCompactTrackRow(t, i)).join('');
|
|
||||||
return `<div class="discover-playlist-tracks-compact">${rows}</div>`;
|
|
||||||
},
|
|
||||||
loadingMessage: 'Curating your discovery playlist...',
|
loadingMessage: 'Curating your discovery playlist...',
|
||||||
emptyMessage: 'No tracks available yet',
|
emptyMessage: 'No tracks available yet',
|
||||||
errorMessage: 'Failed to load discovery weekly',
|
errorMessage: 'Failed to load discovery weekly',
|
||||||
|
|
@ -1824,7 +1825,16 @@ async function loadDiscoverWeekly() {
|
||||||
showErrorToast: true,
|
showErrorToast: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return _weeklyCtrl.load();
|
await _weeklyCtrl.load();
|
||||||
|
const c = document.querySelector('#discovery-weekly-playlist');
|
||||||
|
if (c) _collapseOldMixSection(c);
|
||||||
|
if (discoverWeeklyTracks && discoverWeeklyTracks.length) {
|
||||||
|
_upsertMixCard({
|
||||||
|
key: 'discovery_weekly', title: 'The Archives',
|
||||||
|
subtitle: 'A weekly dig through artists across your library',
|
||||||
|
tracks: discoverWeeklyTracks, syncKey: 'discovery_weekly',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===============================
|
// ===============================
|
||||||
|
|
@ -4050,23 +4060,6 @@ async function loadSeasonalPlaylist(seasonData) {
|
||||||
const playlistContainer = document.getElementById('seasonal-playlist');
|
const playlistContainer = document.getElementById('seasonal-playlist');
|
||||||
if (!playlistContainer) return;
|
if (!playlistContainer) return;
|
||||||
|
|
||||||
// Show seasonal playlist section
|
|
||||||
const seasonalPlaylistSection = document.getElementById('seasonal-playlist-section');
|
|
||||||
if (seasonalPlaylistSection) {
|
|
||||||
seasonalPlaylistSection.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update header
|
|
||||||
const playlistTitle = document.getElementById('seasonal-playlist-title');
|
|
||||||
const playlistSubtitle = document.getElementById('seasonal-playlist-subtitle');
|
|
||||||
|
|
||||||
if (playlistTitle) {
|
|
||||||
playlistTitle.textContent = `${seasonData.icon} ${seasonData.name} Mix`;
|
|
||||||
}
|
|
||||||
if (playlistSubtitle) {
|
|
||||||
playlistSubtitle.textContent = `Curated playlist for ${seasonData.name.toLowerCase()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-create the controller when the season key changes so the
|
// Re-create the controller when the season key changes so the
|
||||||
// fetchUrl always points at the active season's endpoint.
|
// fetchUrl always points at the active season's endpoint.
|
||||||
if (!_seasonalPlaylistCtrl || _seasonalPlaylistCtrlKey !== currentSeasonKey) {
|
if (!_seasonalPlaylistCtrl || _seasonalPlaylistCtrlKey !== currentSeasonKey) {
|
||||||
|
|
@ -4075,11 +4068,7 @@ async function loadSeasonalPlaylist(seasonData) {
|
||||||
contentEl: '#seasonal-playlist',
|
contentEl: '#seasonal-playlist',
|
||||||
fetchUrl: `/api/discover/seasonal/${currentSeasonKey}/playlist`,
|
fetchUrl: `/api/discover/seasonal/${currentSeasonKey}/playlist`,
|
||||||
extractItems: (data) => data.tracks || [],
|
extractItems: (data) => data.tracks || [],
|
||||||
renderItems: (items) => {
|
renderItems: (items) => { discoverSeasonalTracks = items; return ''; },
|
||||||
discoverSeasonalTracks = items;
|
|
||||||
const rows = items.map((t, i) => _renderCompactTrackRow(t, i)).join('');
|
|
||||||
return `<div class="discover-playlist-tracks-compact">${rows}</div>`;
|
|
||||||
},
|
|
||||||
loadingMessage: 'Loading playlist...',
|
loadingMessage: 'Loading playlist...',
|
||||||
emptyMessage: 'No tracks available yet',
|
emptyMessage: 'No tracks available yet',
|
||||||
errorMessage: 'Failed to load playlist',
|
errorMessage: 'Failed to load playlist',
|
||||||
|
|
@ -4088,7 +4077,16 @@ async function loadSeasonalPlaylist(seasonData) {
|
||||||
});
|
});
|
||||||
_seasonalPlaylistCtrlKey = currentSeasonKey;
|
_seasonalPlaylistCtrlKey = currentSeasonKey;
|
||||||
}
|
}
|
||||||
return _seasonalPlaylistCtrl.load();
|
await _seasonalPlaylistCtrl.load();
|
||||||
|
_collapseOldMixSection(playlistContainer);
|
||||||
|
if (discoverSeasonalTracks && discoverSeasonalTracks.length) {
|
||||||
|
_upsertMixCard({
|
||||||
|
key: 'seasonal_playlist',
|
||||||
|
title: `${seasonData.icon} ${seasonData.name} Mix`,
|
||||||
|
subtitle: `Curated playlist for ${seasonData.name.toLowerCase()}`,
|
||||||
|
tracks: discoverSeasonalTracks, syncKey: 'seasonal_playlist',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideSeasonalSections() {
|
function hideSeasonalSections() {
|
||||||
|
|
@ -4364,31 +4362,16 @@ async function loadPersonalizedDailyMixes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
personalizedDailyMixes = data.mixes;
|
personalizedDailyMixes = data.mixes;
|
||||||
|
// Fold each daily mix into the unified "Your Mixes" shelf (#discover redesign).
|
||||||
// Render Daily Mix cards
|
// (Their old open action was a no-op stub; opening to the track list is an upgrade.)
|
||||||
let html = '';
|
|
||||||
data.mixes.forEach((mix, index) => {
|
data.mixes.forEach((mix, index) => {
|
||||||
const coverUrl = mix.tracks && mix.tracks.length > 0 ?
|
_upsertMixCard({
|
||||||
(mix.tracks[0].album_cover_url || '/static/placeholder-album.png') :
|
key: `daily_mix_${index}`, title: mix.name,
|
||||||
'/static/placeholder-album.png';
|
subtitle: mix.description || 'Daily Mix',
|
||||||
|
tracks: mix.tracks || [],
|
||||||
html += `
|
});
|
||||||
<div class="discover-playlist-card" onclick="openDailyMix(${index})">
|
|
||||||
<div class="discover-playlist-cover">
|
|
||||||
<img src="${coverUrl}" alt="${mix.name}" loading="lazy">
|
|
||||||
<div class="playlist-play-overlay">▶</div>
|
|
||||||
</div>
|
|
||||||
<div class="discover-playlist-info">
|
|
||||||
<h4 class="discover-playlist-name">${mix.name}</h4>
|
|
||||||
<p class="discover-playlist-description">${mix.description}</p>
|
|
||||||
<p class="discover-playlist-count">${mix.track_count} tracks</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
});
|
});
|
||||||
|
_collapseOldMixSection(container);
|
||||||
container.innerHTML = html;
|
|
||||||
container.closest('.discover-section').style.display = 'block';
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading daily mixes:', error);
|
console.error('Error loading daily mixes:', error);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue