Restore smart back-button label on artist detail page
PR #644 removed the back-button label logic as collateral when removing the full originStack. The label is independent of the stack — restore it without restoring the old click-handler navigation (browser history handles that now). - _artistDetailLabelStack: module-level stack of {type:'page',pageId} or {type:'artist',name} entries, pushed on forward navigation, popped on back - _artistDetailGoingBack flag: set by the back button click handler so navigateToArtistDetail knows to pop instead of push when called by the React route on browser-history navigation - Backfill currentArtistName from the API response so URL-driven entries (which pass '' for name) have real names on state before the next similar- artist navigation pushes them onto the stack - No-history fallback navigates to the recorded origin page
This commit is contained in:
parent
4bfa43bece
commit
e7ba5408aa
2 changed files with 70 additions and 2 deletions
|
|
@ -3417,6 +3417,7 @@ const WHATS_NEW = {
|
||||||
{ date: 'May 18, 2026 — 2.5.6 release' },
|
{ date: 'May 18, 2026 — 2.5.6 release' },
|
||||||
{ title: 'MusicBrainz as Primary Metadata Source', desc: 'MusicBrainz is now a full primary metadata source on equal footing with Deezer, iTunes, Spotify, and Discogs. switch to it in Settings → Metadata Source — always available, no account or API key needed, rate-limited to 1 req/sec. covers all primary source flows: search, album/track/artist lookup, watchlist scans, discover hero, similar artist backfill, artist map.', page: 'settings' },
|
{ title: 'MusicBrainz as Primary Metadata Source', desc: 'MusicBrainz is now a full primary metadata source on equal footing with Deezer, iTunes, Spotify, and Discogs. switch to it in Settings → Metadata Source — always available, no account or API key needed, rate-limited to 1 req/sec. covers all primary source flows: search, album/track/artist lookup, watchlist scans, discover hero, similar artist backfill, artist map.', page: 'settings' },
|
||||||
{ title: 'Fix: MusicBrainz artist detail showing MBID as name', desc: 'clicking a MusicBrainz artist from search results was showing the raw MBID as the artist name on the detail page. URL-driven routing (PR #644) no longer passes the display name to the backend, so the source detail endpoint now looks it up directly from MusicBrainz by MBID.' },
|
{ title: 'Fix: MusicBrainz artist detail showing MBID as name', desc: 'clicking a MusicBrainz artist from search results was showing the raw MBID as the artist name on the detail page. URL-driven routing (PR #644) no longer passes the display name to the backend, so the source detail endpoint now looks it up directly from MusicBrainz by MBID.' },
|
||||||
|
{ title: 'Fix: artist detail back button always showing "← Back"', desc: 'PR #644 removed the back-button label logic along with the origin stack. restored: a label stack (separate from browser history, which handles actual navigation) tracks where you came from across the full similar-artist chain — "← Back to Search", "← Back to Artist A", "← Back to Artist B", etc. API response backfills the current artist name so the stack has real names when clicking similar artists.' },
|
||||||
],
|
],
|
||||||
'2.5.5': [
|
'2.5.5': [
|
||||||
{ date: 'May 17, 2026 — 2.5.5 release' },
|
{ date: 'May 17, 2026 — 2.5.5 release' },
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,26 @@ async function toggleLibraryCardWatchlist(btn, artist) {
|
||||||
// ===============================================
|
// ===============================================
|
||||||
|
|
||||||
// Artist detail page state
|
// Artist detail page state
|
||||||
|
const _ARTIST_DETAIL_BACK_LABELS = {
|
||||||
|
library: 'Back to Library',
|
||||||
|
search: 'Back to Search',
|
||||||
|
discover: 'Back to Discover',
|
||||||
|
watchlist: 'Back to Watchlist',
|
||||||
|
wishlist: 'Back to Wishlist',
|
||||||
|
stats: 'Back to Stats',
|
||||||
|
'playlist-explorer': 'Back to Explorer',
|
||||||
|
automations: 'Back to Automations',
|
||||||
|
dashboard: 'Back to Dashboard',
|
||||||
|
sync: 'Back to Sync',
|
||||||
|
'active-downloads': 'Back to Downloads',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stack of origins for the back-button label. Each entry: {type:'page', pageId}
|
||||||
|
// or {type:'artist', name}. Pushed on forward navigation, popped on back.
|
||||||
|
// Separate from browser history — only used for the label display.
|
||||||
|
let _artistDetailLabelStack = [];
|
||||||
|
let _artistDetailGoingBack = false;
|
||||||
|
|
||||||
let artistDetailPageState = {
|
let artistDetailPageState = {
|
||||||
isInitialized: false,
|
isInitialized: false,
|
||||||
currentArtistId: null,
|
currentArtistId: null,
|
||||||
|
|
@ -797,6 +817,23 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt
|
||||||
}
|
}
|
||||||
console.log(`🎵 Navigating to artist detail: ${artistName} (ID: ${artistId}${sourceOverride ? `, source: ${sourceOverride}` : ''})`);
|
console.log(`🎵 Navigating to artist detail: ${artistName} (ID: ${artistId}${sourceOverride ? `, source: ${sourceOverride}` : ''})`);
|
||||||
|
|
||||||
|
// Maintain the label stack. Back navigations pop; forward navigations push.
|
||||||
|
if (_artistDetailGoingBack) {
|
||||||
|
_artistDetailLabelStack.pop();
|
||||||
|
_artistDetailGoingBack = false;
|
||||||
|
} else {
|
||||||
|
if (currentPage !== 'artist-detail') {
|
||||||
|
_artistDetailLabelStack = []; // fresh chain from a non-artist page
|
||||||
|
}
|
||||||
|
if (currentPage === 'artist-detail' && artistDetailPageState.currentArtistName) {
|
||||||
|
_artistDetailLabelStack.push({ type: 'artist', name: artistDetailPageState.currentArtistName });
|
||||||
|
} else {
|
||||||
|
const pageId = (typeof currentPage === 'string' && currentPage && currentPage !== 'artist-detail')
|
||||||
|
? currentPage : 'library';
|
||||||
|
_artistDetailLabelStack.push({ type: 'page', pageId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Abort any in-progress completion stream
|
// Abort any in-progress completion stream
|
||||||
if (artistDetailPageState.completionController) {
|
if (artistDetailPageState.completionController) {
|
||||||
artistDetailPageState.completionController.abort();
|
artistDetailPageState.completionController.abort();
|
||||||
|
|
@ -851,10 +888,28 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt
|
||||||
initializeArtistDetailPage();
|
initializeArtistDetailPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateArtistDetailBackButtonLabel();
|
||||||
|
|
||||||
// Load artist data
|
// Load artist data
|
||||||
loadArtistDetailData(artistId, artistName);
|
loadArtistDetailData(artistId, artistName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _updateArtistDetailBackButtonLabel() {
|
||||||
|
const backBtnLabel = document.querySelector('#artist-detail-back-btn span');
|
||||||
|
if (!backBtnLabel) return;
|
||||||
|
const top = _artistDetailLabelStack[_artistDetailLabelStack.length - 1];
|
||||||
|
if (!top) {
|
||||||
|
backBtnLabel.textContent = '← Back';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (top.type === 'artist') {
|
||||||
|
backBtnLabel.textContent = `← Back to ${top.name}`;
|
||||||
|
} else {
|
||||||
|
const friendly = _ARTIST_DETAIL_BACK_LABELS[top.pageId] || _ARTIST_DETAIL_BACK_LABELS.library;
|
||||||
|
backBtnLabel.textContent = `← ${friendly}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initializeArtistDetailPage() {
|
function initializeArtistDetailPage() {
|
||||||
console.log("🔧 Initializing Artist Detail page...");
|
console.log("🔧 Initializing Artist Detail page...");
|
||||||
|
|
||||||
|
|
@ -870,12 +925,15 @@ function initializeArtistDetailPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.history.length > 1) {
|
if (window.history.length > 1) {
|
||||||
|
_artistDetailGoingBack = true;
|
||||||
window.history.back();
|
window.history.back();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No history — default to library
|
// No history — fall back to recorded origin page or library
|
||||||
navigateToPage('library');
|
const top = _artistDetailLabelStack.pop();
|
||||||
|
_updateArtistDetailBackButtonLabel();
|
||||||
|
navigateToPage(top?.type === 'page' ? (top.pageId || 'library') : 'library');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -981,6 +1039,15 @@ async function loadArtistDetailData(artistId, artistName) {
|
||||||
artistDetailPageState.currentArtistId = data.artist.id;
|
artistDetailPageState.currentArtistId = data.artist.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backfill name from API response — URL-driven navigation passes '' for the
|
||||||
|
// name so the label stack has real names when the user clicks a similar artist.
|
||||||
|
if (data.artist?.name && !artistDetailPageState.currentArtistName) {
|
||||||
|
artistDetailPageState.currentArtistName = data.artist.name;
|
||||||
|
if (typeof _updateSidebarLibraryBreadcrumb === 'function') {
|
||||||
|
_updateSidebarLibraryBreadcrumb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keep the resolved metadata source for album-track lookups.
|
// Keep the resolved metadata source for album-track lookups.
|
||||||
artistDetailPageState.currentArtistSource = data.discography?.source || data.artist?.source || null;
|
artistDetailPageState.currentArtistSource = data.discography?.source || data.artist?.source || null;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue