diff --git a/js/app.js b/js/app.js index 796542d..e9d37b3 100644 --- a/js/app.js +++ b/js/app.js @@ -2302,15 +2302,6 @@ document.addEventListener('DOMContentLoaded', async () => { albumItem.textContent = `Go to ${label}`; albumItem.style.display = track.album ? 'block' : 'none'; } - if (artistItem) { - const artists = track.artists || (track.artist ? [track.artist] : []); - if (artists.length === 1) { - artistItem.style.display = 'block'; - artistItem.textContent = `Go to ${artists[0].name || 'artist'}`; - } else { - artistItem.style.display = 'none'; - } - } } } } diff --git a/js/events.js b/js/events.js index 5223b6f..6d1c4bc 100644 --- a/js/events.js +++ b/js/events.js @@ -1508,9 +1508,6 @@ async function updateContextMenuLikeState(contextMenu, contextTrack) { // Handle multiple artists for "Go to artist" const artistItem = contextMenu.querySelector('li[data-action="go-to-artist"]'); if (artistItem) { - // Remove any previously added multiple artist items - contextMenu.querySelectorAll('.dynamic-artist-item').forEach((i) => i.remove()); - const artists = Array.isArray(contextTrack.artists) ? contextTrack.artists : contextTrack.artist @@ -1519,35 +1516,14 @@ async function updateContextMenuLikeState(contextMenu, contextTrack) { const canShowArtist = type === 'track' || type === 'album'; if (artists.length > 1 && canShowArtist) { - artistItem.style.display = 'none'; - // Sort artists by name to be consistent - [...artists] - .sort((a, b) => (a.name || '').localeCompare(b.name || '')) - .forEach((artist) => { - const li = document.createElement('li'); - li.classList.add('dynamic-artist-item'); - li.dataset.action = 'go-to-artist'; - li.dataset.artistId = artist.id || ''; - - // Handle tracker/unreleased tracks - const isTracker = - contextTrack.isTracker || (contextTrack.id && String(contextTrack.id).startsWith('tracker-')); - if (isTracker && contextTrack.trackerInfo?.sheetId) { - li.dataset.trackerSheetId = contextTrack.trackerInfo.sheetId; - } - - li.textContent = `Go to ${artist.name || 'Unknown Artist'}`; - artistItem.parentNode.insertBefore(li, artistItem.nextSibling); - }); + artistItem.style.display = 'block'; + artistItem.textContent = 'Go to artists'; + artistItem.dataset.hasMultipleArtists = 'true'; } else { - // Restore default behavior for single artist const hasArtist = artists.length > 0; artistItem.style.display = hasArtist && canShowArtist ? 'block' : 'none'; - if (hasArtist) { - artistItem.textContent = `Go to ${artists[0].name || 'artist'}`; - } else { - artistItem.textContent = 'Go to artist'; - } + artistItem.dataset.hasMultipleArtists = 'false'; + artistItem.textContent = artists.length > 1 ? 'Go to artists' : 'Go to artist'; delete artistItem.dataset.artistId; delete artistItem.dataset.trackerSheetId; } @@ -1614,6 +1590,11 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen item = { id, uuid: id, title: card.querySelector('.card-title')?.textContent || 'Item' }; } + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + contextMenu._originalHTML = null; + } + contextTrack = item; contextMenu._contextTrack = item; contextMenu._contextType = type; @@ -1639,12 +1620,21 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen clickedTrack && contextTrack.id === clickedTrack.id ) { + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + } contextMenu.style.display = 'none'; + contextMenu._contextType = null; + contextMenu._originalHTML = null; return; } contextTrack = clickedTrack; if (contextTrack) { + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + contextMenu._originalHTML = null; + } contextMenu._contextTrack = contextTrack; contextMenu._contextType = 'track'; await updateContextMenuLikeState(contextMenu, contextTrack); @@ -1659,7 +1649,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen if (trackItem && (trackItem.classList.contains('unavailable') || trackItem.classList.contains('blocked'))) { return; } - if (trackItem && !trackItem.dataset.queueIndex && !e.target.closest('.remove-from-playlist-btn')) { + if (trackItem && !trackItem.dataset.queueIndex && !e.target.closest('.remove-from-playlist-btn') && !e.target.closest('.artist-link')) { const parentList = trackItem.closest('.track-list'); const allTrackElements = Array.from(parentList.querySelectorAll('.track-item')); const trackList = allTrackElements.map((el) => trackDataStore.get(el)).filter(Boolean); @@ -1674,6 +1664,20 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen } } + // Handle artist link clicks in track lists + const artistLink = e.target.closest('.artist-link'); + if (artistLink) { + e.stopPropagation(); + const artistId = artistLink.dataset.artistId; + const trackerSheetId = artistLink.dataset.trackerSheetId; + if (trackerSheetId) { + navigate(`/unreleased/${trackerSheetId}`); + } else if (artistId) { + navigate(`/artist/${artistId}`); + } + return; + } + const card = e.target.closest('.card'); if (card) { // Don't navigate if card is blocked (unless clicking menu button) @@ -1714,6 +1718,11 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen if (contextTrack) { if (contextTrack.isLocal) return; + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + contextMenu._originalHTML = null; + } + // Hide actions for unavailable tracks const unavailableActions = ['play-next', 'add-to-queue', 'download', 'track-mix']; contextMenu.querySelectorAll('[data-action]').forEach((btn) => { @@ -1745,6 +1754,12 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen uuid: id, title: card.querySelector('.card-title')?.textContent, }; + + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + contextMenu._originalHTML = null; + } + contextTrack = item; contextMenu._contextTrack = item; contextMenu._contextType = type.replace('userplaylist', 'user-playlist'); @@ -1756,7 +1771,14 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen }); document.addEventListener('click', () => { - contextMenu.style.display = 'none'; + if (contextMenu.style.display === 'block') { + if (contextMenu._originalHTML) { + contextMenu.innerHTML = contextMenu._originalHTML; + } + contextMenu.style.display = 'none'; + contextMenu._contextType = null; + contextMenu._originalHTML = null; + } }); contextMenu.addEventListener('click', async (e) => { @@ -1767,11 +1789,48 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen const action = target.dataset.action; const track = contextMenu._contextTrack || contextTrack; const type = contextMenu._contextType || 'track'; + + if (action === 'go-to-artists' || (action === 'go-to-artist' && target.dataset.hasMultipleArtists === 'true')) { + const artists = Array.isArray(track.artists) ? track.artists : track.artist ? [track.artist] : []; + if (artists.length > 1) { + // Save original HTML if not already saved + if (!contextMenu._originalHTML) { + contextMenu._originalHTML = contextMenu.innerHTML; + } + + // Render sub-menu + let subMenuHTML = '