Fix heart button interactions on cards and reorder library tabs
- Fix: Card heart buttons didn't work because of button nested in anchor. Changed cards to div with data-href.\n- Fix: Home page and Artist page cards didn't have data bound or like state initialized.\n- Feature: Move Playlists to the last position in Library tabs.
This commit is contained in:
parent
f4f6a1941c
commit
cdffe88eba
6 changed files with 209 additions and 73 deletions
15
index.html
15
index.html
|
|
@ -22,6 +22,7 @@
|
|||
<audio id="audio-player"></audio>
|
||||
<div id="context-menu">
|
||||
<ul>
|
||||
<li data-action="toggle-like">Like</li>
|
||||
<li data-action="play-next">Play Next</li>
|
||||
<li data-action="add-to-queue">Add to Queue</li>
|
||||
<li data-action="download">Download</li>
|
||||
|
|
@ -168,15 +169,12 @@
|
|||
<div id="page-library" class="page">
|
||||
<h2 class="section-title">Your Library</h2>
|
||||
<div class="search-tabs">
|
||||
<button class="search-tab active" data-tab="playlists">Playlists</button>
|
||||
<button class="search-tab" data-tab="tracks">Liked Songs</button>
|
||||
<button class="search-tab active" data-tab="tracks">Liked Songs</button>
|
||||
<button class="search-tab" data-tab="albums">Albums</button>
|
||||
<button class="search-tab" data-tab="artists">Artists</button>
|
||||
<button class="search-tab" data-tab="playlists">Playlists</button>
|
||||
</div>
|
||||
<div class="search-tab-content active" id="library-tab-playlists">
|
||||
<div class="card-grid" id="library-playlists-container"></div>
|
||||
</div>
|
||||
<div class="search-tab-content" id="library-tab-tracks">
|
||||
<div class="search-tab-content active" id="library-tab-tracks">
|
||||
<div class="track-list" id="library-tracks-container"></div>
|
||||
</div>
|
||||
<div class="search-tab-content" id="library-tab-albums">
|
||||
|
|
@ -185,6 +183,9 @@
|
|||
<div class="search-tab-content" id="library-tab-artists">
|
||||
<div class="card-grid" id="library-artists-container"></div>
|
||||
</div>
|
||||
<div class="search-tab-content" id="library-tab-playlists">
|
||||
<div class="card-grid" id="library-playlists-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="page-album" class="page">
|
||||
|
|
@ -515,6 +516,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="volume-controls">
|
||||
<button id="now-playing-like-btn" class="like-btn" data-action="toggle-like" title="Save to Library" style="display: none;">
|
||||
</button>
|
||||
<button id="download-current-btn" title="Download current track" class="desktop-only">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
|
|
|
|||
|
|
@ -200,13 +200,18 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
|
||||
initializeSettings(scrobbler, player, api, ui);
|
||||
initializePlayerEvents(player, audioPlayer, scrobbler);
|
||||
initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'), lyricsManager);
|
||||
initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'), lyricsManager, ui);
|
||||
initializeUIInteractions(player, api);
|
||||
initializeKeyboardShortcuts(player, audioPlayer, lyricsPanel);
|
||||
|
||||
const castBtn = document.getElementById('cast-btn');
|
||||
initializeCasting(audioPlayer, castBtn);
|
||||
|
||||
// Restore UI state for the current track (like button, theme)
|
||||
if (player.currentTrack) {
|
||||
ui.setCurrentTrack(player.currentTrack);
|
||||
}
|
||||
|
||||
document.querySelector('.now-playing-bar .cover').addEventListener('click', async () => {
|
||||
if (!player.currentTrack) {
|
||||
alert('No track is currently playing');
|
||||
|
|
@ -284,7 +289,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
|
||||
document.getElementById('download-current-btn')?.addEventListener('click', () => {
|
||||
if (player.currentTrack) {
|
||||
handleTrackAction('download', player.currentTrack, player, api, lyricsManager);
|
||||
handleTrackAction('download', player.currentTrack, player, api, lyricsManager, 'track', ui);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
156
js/events.js
156
js/events.js
|
|
@ -291,23 +291,95 @@ function initializeSmoothSliders(audioPlayer, player) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function handleTrackAction(action, track, player, api, lyricsManager) {
|
||||
if (!track) return;
|
||||
export async function handleTrackAction(action, item, player, api, lyricsManager, type = 'track', ui = null) {
|
||||
if (!item) return;
|
||||
|
||||
if (action === 'add-to-queue') {
|
||||
player.addToQueue(track);
|
||||
player.addToQueue(item);
|
||||
renderQueue(player);
|
||||
showNotification(`Added to queue: ${track.title}`);
|
||||
showNotification(`Added to queue: ${item.title}`);
|
||||
} else if (action === 'play-next') {
|
||||
player.addNextToQueue(track);
|
||||
player.addNextToQueue(item);
|
||||
renderQueue(player);
|
||||
showNotification(`Playing next: ${track.title}`);
|
||||
showNotification(`Playing next: ${item.title}`);
|
||||
} else if (action === 'download') {
|
||||
await downloadTrackWithMetadata(track, player.quality, api, lyricsManager);
|
||||
await downloadTrackWithMetadata(item, player.quality, api, lyricsManager);
|
||||
} else if (action === 'toggle-like') {
|
||||
const added = await db.toggleFavorite(type, item);
|
||||
|
||||
// Update all instances of this item's like button on the page
|
||||
const id = type === 'playlist' ? item.uuid : item.id;
|
||||
const selector = type === 'track'
|
||||
? `.track-item[data-track-id="${id}"] .like-btn`
|
||||
: `.card[data-${type}-id="${id}"] .like-btn, .card[data-playlist-id="${id}"] .like-btn`;
|
||||
|
||||
// Also check header buttons
|
||||
const headerBtn = document.getElementById(`like-${type}-btn`);
|
||||
|
||||
const elementsToUpdate = [...document.querySelectorAll(selector)];
|
||||
if (headerBtn) elementsToUpdate.push(headerBtn);
|
||||
|
||||
const nowPlayingLikeBtn = document.getElementById('now-playing-like-btn');
|
||||
if (nowPlayingLikeBtn && type === 'track' && player?.currentTrack?.id === item.id) {
|
||||
elementsToUpdate.push(nowPlayingLikeBtn);
|
||||
}
|
||||
|
||||
elementsToUpdate.forEach(btn => {
|
||||
const heartIcon = btn.querySelector('svg');
|
||||
if (heartIcon) {
|
||||
heartIcon.classList.toggle('filled', added);
|
||||
if (heartIcon.hasAttribute('fill')) {
|
||||
heartIcon.setAttribute('fill', added ? 'currentColor' : 'none');
|
||||
}
|
||||
}
|
||||
btn.classList.toggle('active', added);
|
||||
btn.title = added ? 'Remove from Library' : 'Add to Library';
|
||||
});
|
||||
|
||||
// Handle Library Page Update
|
||||
if (window.location.hash === '#library') {
|
||||
const itemSelector = type === 'track'
|
||||
? `.track-item[data-track-id="${id}"]`
|
||||
: `.card[data-${type}-id="${id}"], .card[data-playlist-id="${id}"]`;
|
||||
|
||||
const itemEl = document.querySelector(itemSelector);
|
||||
|
||||
if (!added && itemEl) {
|
||||
// Remove item
|
||||
const container = itemEl.parentElement;
|
||||
itemEl.remove();
|
||||
if (container && container.children.length === 0) {
|
||||
const msg = type === 'track' ? 'No liked songs yet.' : `No liked ${type}s yet.`;
|
||||
container.innerHTML = `<div class="placeholder-text">${msg}</div>`;
|
||||
}
|
||||
} else if (added && !itemEl && ui && type === 'track') {
|
||||
// Add item (specifically for tracks currently)
|
||||
const tracksContainer = document.getElementById('library-tracks-container');
|
||||
if (tracksContainer) {
|
||||
// Remove placeholder if it exists
|
||||
const placeholder = tracksContainer.querySelector('.placeholder-text');
|
||||
if (placeholder) placeholder.remove();
|
||||
|
||||
// Create track element
|
||||
const index = tracksContainer.children.length;
|
||||
const trackHTML = ui.createTrackItemHTML(item, index, true, false);
|
||||
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = trackHTML;
|
||||
const newEl = tempDiv.firstElementChild;
|
||||
|
||||
if (newEl) {
|
||||
tracksContainer.appendChild(newEl);
|
||||
trackDataStore.set(newEl, item);
|
||||
ui.updateLikeState(newEl, 'track', item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeTrackInteractions(player, api, mainContent, contextMenu, lyricsManager) {
|
||||
export function initializeTrackInteractions(player, api, mainContent, contextMenu, lyricsManager, ui) {
|
||||
let contextTrack = null;
|
||||
|
||||
mainContent.addEventListener('click', async e => {
|
||||
|
|
@ -340,37 +412,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
|||
}
|
||||
|
||||
if (item) {
|
||||
if (action === 'add-to-queue' && type === 'track') {
|
||||
player.addToQueue(item);
|
||||
renderQueue(player);
|
||||
showNotification(`Added to queue: ${item.title}`);
|
||||
} else if (action === 'toggle-like') {
|
||||
db.toggleFavorite(type, item).then(added => {
|
||||
const heartIcon = actionBtn.querySelector('svg');
|
||||
if (heartIcon) {
|
||||
heartIcon.setAttribute('fill', added ? 'currentColor' : 'none');
|
||||
heartIcon.classList.toggle('filled', added);
|
||||
}
|
||||
actionBtn.classList.toggle('active', added);
|
||||
actionBtn.title = added ? 'Remove from Library' : 'Add to Library';
|
||||
|
||||
if (!added && window.location.hash === '#library' && itemElement) {
|
||||
itemElement.remove();
|
||||
const containerId = `library-${type}s-container`;
|
||||
const container = document.getElementById(containerId);
|
||||
if (container && container.children.length === 0) {
|
||||
const msg = type === 'track' ? 'No liked songs yet.' : `No liked ${type}s yet.`;
|
||||
container.innerHTML = `<div class="placeholder-text">${msg}</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (action === 'play-next' && type === 'track') {
|
||||
player.addNextToQueue(item);
|
||||
renderQueue(player);
|
||||
showNotification(`Playing next: ${item.title}`);
|
||||
} else if (action === 'download' && type === 'track') {
|
||||
handleDownload(item, player, api);
|
||||
}
|
||||
await handleTrackAction(action, item, player, api, lyricsManager, type, ui);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -382,6 +424,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
|||
if (trackItem && !trackItem.dataset.queueIndex) {
|
||||
contextTrack = trackDataStore.get(trackItem);
|
||||
if (contextTrack) {
|
||||
await updateContextMenuLikeState(contextMenu, contextTrack);
|
||||
const rect = menuBtn.getBoundingClientRect();
|
||||
positionMenu(contextMenu, rect.left, rect.bottom + 5, rect);
|
||||
}
|
||||
|
|
@ -404,15 +447,28 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
|||
player.playTrackFromQueue();
|
||||
}
|
||||
}
|
||||
|
||||
const card = e.target.closest('.card');
|
||||
if (card) {
|
||||
const href = card.dataset.href;
|
||||
if (href) {
|
||||
// Allow native links inside card to work if any exist
|
||||
if (e.target.closest('a')) return;
|
||||
|
||||
e.preventDefault();
|
||||
window.location.hash = href;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mainContent.addEventListener('contextmenu', e => {
|
||||
mainContent.addEventListener('contextmenu', async e => {
|
||||
const trackItem = e.target.closest('.track-item');
|
||||
if (trackItem && !trackItem.dataset.queueIndex) {
|
||||
e.preventDefault();
|
||||
contextTrack = trackDataStore.get(trackItem);
|
||||
|
||||
if (contextTrack) {
|
||||
await updateContextMenuLikeState(contextMenu, contextTrack);
|
||||
positionMenu(contextMenu, e.pageX, e.pageY);
|
||||
}
|
||||
}
|
||||
|
|
@ -426,7 +482,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
|||
e.stopPropagation();
|
||||
const action = e.target.dataset.action;
|
||||
if (action && contextTrack) {
|
||||
await handleTrackAction(action, contextTrack, player, api, lyricsManager);
|
||||
await handleTrackAction(action, contextTrack, player, api, lyricsManager, 'track', ui);
|
||||
}
|
||||
contextMenu.style.display = 'none';
|
||||
});
|
||||
|
|
@ -445,6 +501,16 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
|||
window.location.hash = `#artist/${track.artist.id}`;
|
||||
}
|
||||
});
|
||||
|
||||
const nowPlayingLikeBtn = document.getElementById('now-playing-like-btn');
|
||||
if (nowPlayingLikeBtn) {
|
||||
nowPlayingLikeBtn.addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
if (player.currentTrack) {
|
||||
await handleTrackAction('toggle-like', player.currentTrack, player, api, lyricsManager, 'track', ui);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderQueue(player) {
|
||||
|
|
@ -461,6 +527,14 @@ function formatTime(seconds) {
|
|||
return `${m}:${String(s).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
async function updateContextMenuLikeState(menu, track) {
|
||||
const likeItem = menu.querySelector('[data-action="toggle-like"]');
|
||||
if (likeItem) {
|
||||
const isLiked = await db.isFavorite('track', track.id);
|
||||
likeItem.textContent = isLiked ? 'Remove from Library' : 'Add to Library';
|
||||
}
|
||||
}
|
||||
|
||||
function positionMenu(menu, x, y, anchorRect = null) {
|
||||
// Temporarily show to measure dimensions
|
||||
menu.style.visibility = 'hidden';
|
||||
|
|
|
|||
95
js/ui.js
95
js/ui.js
|
|
@ -1,5 +1,5 @@
|
|||
//js/ui.js
|
||||
import { SVG_PLAY, SVG_DOWNLOAD, SVG_MENU, formatTime, createPlaceholder, trackDataStore, hasExplicitContent, getTrackArtists, getTrackTitle, calculateTotalDuration, formatDuration } from './utils.js';
|
||||
import { SVG_PLAY, SVG_DOWNLOAD, SVG_MENU, SVG_HEART, formatTime, createPlaceholder, trackDataStore, hasExplicitContent, getTrackArtists, getTrackTitle, calculateTotalDuration, formatDuration } from './utils.js';
|
||||
import { recentActivityManager, backgroundSettings, trackListSettings } from './storage.js';
|
||||
import { db } from './db.js';
|
||||
|
||||
|
|
@ -13,11 +13,10 @@ export class UIRenderer {
|
|||
|
||||
// Helper for Heart Icon
|
||||
createHeartIcon(filled = false) {
|
||||
return `
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="${filled ? 'currentColor' : 'none'}" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="heart-icon ${filled ? 'filled' : ''}">
|
||||
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
|
||||
</svg>
|
||||
`;
|
||||
if (filled) {
|
||||
return SVG_HEART.replace('class="heart-icon"', 'class="heart-icon filled"');
|
||||
}
|
||||
return SVG_HEART;
|
||||
}
|
||||
|
||||
async updateLikeState(element, type, id) {
|
||||
|
|
@ -33,6 +32,17 @@ export class UIRenderer {
|
|||
setCurrentTrack(track) {
|
||||
this.currentTrack = track;
|
||||
this.updateGlobalTheme();
|
||||
|
||||
const likeBtn = document.getElementById('now-playing-like-btn');
|
||||
if (likeBtn) {
|
||||
if (track) {
|
||||
likeBtn.style.display = 'flex';
|
||||
// Use the centralized update logic if possible, or manual here
|
||||
this.updateLikeState(likeBtn.parentElement, 'track', track.id);
|
||||
} else {
|
||||
likeBtn.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateGlobalTheme() {
|
||||
|
|
@ -177,7 +187,7 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
return `
|
||||
<a href="#album/${album.id}" class="card" data-album-id="${album.id}">
|
||||
<div class="card" data-album-id="${album.id}" data-href="#album/${album.id}" style="cursor: pointer;">
|
||||
<div class="card-image-wrapper">
|
||||
<img src="${this.api.getCoverUrl(album.cover, '320')}" alt="${album.title}" class="card-image" loading="lazy">
|
||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Library">
|
||||
|
|
@ -187,14 +197,14 @@ export class UIRenderer {
|
|||
<h3 class="card-title">${album.title} ${explicitBadge}</h3>
|
||||
<p class="card-subtitle">${album.artist?.name ?? ''}</p>
|
||||
<p class="card-subtitle">${yearDisplay}${typeLabel}</p>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
createPlaylistCardHTML(playlist) {
|
||||
const imageId = playlist.squareImage || playlist.image || playlist.uuid; // Fallback or use a specific cover getter if needed
|
||||
return `
|
||||
<a href="#playlist/${playlist.uuid}" class="card" data-playlist-id="${playlist.uuid}">
|
||||
<div class="card" data-playlist-id="${playlist.uuid}" data-href="#playlist/${playlist.uuid}" style="cursor: pointer;">
|
||||
<div class="card-image-wrapper">
|
||||
<img src="${this.api.getCoverUrl(imageId, '320')}" alt="${playlist.title}" class="card-image" loading="lazy">
|
||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="playlist" title="Add to Library">
|
||||
|
|
@ -203,13 +213,13 @@ export class UIRenderer {
|
|||
</div>
|
||||
<h3 class="card-title">${playlist.title}</h3>
|
||||
<p class="card-subtitle">${playlist.numberOfTracks || 0} tracks</p>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
createArtistCardHTML(artist) {
|
||||
return `
|
||||
<a href="#artist/${artist.id}" class="card artist" data-artist-id="${artist.id}">
|
||||
<div class="card artist" data-artist-id="${artist.id}" data-href="#artist/${artist.id}" style="cursor: pointer;">
|
||||
<div class="card-image-wrapper">
|
||||
<img src="${this.api.getArtistPictureUrl(artist.picture, '320')}" alt="${artist.name}" class="card-image" loading="lazy">
|
||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="artist" title="Add to Library">
|
||||
|
|
@ -217,7 +227,7 @@ export class UIRenderer {
|
|||
</button>
|
||||
</div>
|
||||
<h3 class="card-title">${artist.name}</h3>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
@ -508,18 +518,45 @@ export class UIRenderer {
|
|||
const artistsContainer = document.getElementById('home-recent-artists');
|
||||
const playlistsContainer = document.getElementById('home-recent-playlists');
|
||||
|
||||
albumsContainer.innerHTML = recents.albums.length
|
||||
? recents.albums.map(album => this.createAlbumCardHTML(album)).join('')
|
||||
: createPlaceholder("You haven't viewed any albums yet. Search for music to get started!");
|
||||
if (recents.albums.length) {
|
||||
albumsContainer.innerHTML = recents.albums.map(album => this.createAlbumCardHTML(album)).join('');
|
||||
recents.albums.forEach(album => {
|
||||
const el = albumsContainer.querySelector(`[data-album-id="${album.id}"]`);
|
||||
if (el) {
|
||||
trackDataStore.set(el, album);
|
||||
this.updateLikeState(el, 'album', album.id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
albumsContainer.innerHTML = createPlaceholder("You haven't viewed any albums yet. Search for music to get started!");
|
||||
}
|
||||
|
||||
artistsContainer.innerHTML = recents.artists.length
|
||||
? recents.artists.map(artist => this.createArtistCardHTML(artist)).join('')
|
||||
: createPlaceholder("You haven't viewed any artists yet. Search for music to get started!");
|
||||
if (recents.artists.length) {
|
||||
artistsContainer.innerHTML = recents.artists.map(artist => this.createArtistCardHTML(artist)).join('');
|
||||
recents.artists.forEach(artist => {
|
||||
const el = artistsContainer.querySelector(`[data-artist-id="${artist.id}"]`);
|
||||
if (el) {
|
||||
trackDataStore.set(el, artist);
|
||||
this.updateLikeState(el, 'artist', artist.id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
artistsContainer.innerHTML = createPlaceholder("You haven't viewed any artists yet. Search for music to get started!");
|
||||
}
|
||||
|
||||
if (playlistsContainer) {
|
||||
playlistsContainer.innerHTML = recents.playlists && recents.playlists.length
|
||||
? recents.playlists.map(playlist => this.createPlaylistCardHTML(playlist)).join('')
|
||||
: createPlaceholder("You haven't viewed any playlists yet. Search for music to get started!");
|
||||
if (recents.playlists && recents.playlists.length) {
|
||||
playlistsContainer.innerHTML = recents.playlists.map(playlist => this.createPlaylistCardHTML(playlist)).join('');
|
||||
recents.playlists.forEach(playlist => {
|
||||
const el = playlistsContainer.querySelector(`[data-playlist-id="${playlist.uuid}"]`);
|
||||
if (el) {
|
||||
trackDataStore.set(el, playlist);
|
||||
this.updateLikeState(el, 'playlist', playlist.uuid);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
playlistsContainer.innerHTML = createPlaceholder("You haven't viewed any playlists yet. Search for music to get started!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -776,6 +813,14 @@ export class UIRenderer {
|
|||
</div>
|
||||
`;
|
||||
document.getElementById('page-album').appendChild(section);
|
||||
|
||||
filtered.forEach(a => {
|
||||
const el = section.querySelector(`[data-album-id="${a.id}"]`);
|
||||
if (el) {
|
||||
trackDataStore.set(el, a);
|
||||
this.updateLikeState(el, 'album', a.id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
renderSection(`More albums from ${album.artist.name}`, artistData.albums);
|
||||
|
|
@ -938,6 +983,14 @@ export class UIRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
artist.albums.forEach(album => {
|
||||
const el = albumsContainer.querySelector(`[data-album-id="${album.id}"]`);
|
||||
if (el) {
|
||||
trackDataStore.set(el, album);
|
||||
this.updateLikeState(el, 'album', album.id);
|
||||
}
|
||||
});
|
||||
|
||||
recentActivityManager.addArtist(artist);
|
||||
|
||||
document.title = `${artist.name} - Monochrome`;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export const SVG_VOLUME = '<svg xmlns="http://www.w3.org/2000/svg" width="20" he
|
|||
export const SVG_MUTE = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><line x1="23" y1="9" x2="17" y2="15"></line><line x1="17" y1="9" x2="23" y2="15"></line></svg>';
|
||||
export const SVG_DOWNLOAD = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>';
|
||||
export const SVG_MENU = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle></svg>';
|
||||
export const SVG_HEART = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="heart-icon"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>';
|
||||
export const SVG_CLOSE = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
|
||||
|
||||
export const formatTime = (seconds) => {
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ body.has-page-background .track-item:hover {
|
|||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.5) !important;
|
||||
background: rgba(0, 0, 0, 0.25) !important;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border-radius: 50% !important;
|
||||
|
|
@ -547,7 +547,7 @@ body.has-page-background .track-item:hover {
|
|||
transition: all 0.2s ease !important;
|
||||
z-index: 10;
|
||||
color: white !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.card:hover .card-like-btn,
|
||||
|
|
@ -779,7 +779,7 @@ body.has-page-background .track-item:hover {
|
|||
.track-actions-inline {
|
||||
display: none; /* Controlled by data-track-actions-mode */
|
||||
gap: 0.25rem;
|
||||
opacity: 0.5;
|
||||
opacity: 0.2;
|
||||
transition: opacity var(--transition);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue