Backup & Restore
- Export or import your library and playlists as JSON
+ Export or import your library and history as JSON
Export
diff --git a/js/events.js b/js/events.js
index 16524b5..f3b90bb 100644
--- a/js/events.js
+++ b/js/events.js
@@ -525,7 +525,18 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
}
});
- document.querySelector('.now-playing-bar .artist').addEventListener('click', () => {
+ document.querySelector('.now-playing-bar .artist').addEventListener('click', (e) => {
+ const link = e.target.closest('.artist-link');
+ if (link) {
+ e.stopPropagation();
+ const artistId = link.dataset.artistId;
+ if (artistId) {
+ window.location.hash = `#artist/${artistId}`;
+ }
+ return;
+ }
+
+ // Fallback for non-link clicks (e.g. separators) or single artist legacy
const track = player.currentTrack;
if (track?.artist?.id) {
window.location.hash = `#artist/${track.artist.id}`;
diff --git a/js/player.js b/js/player.js
index 7c2cf1e..74c686c 100644
--- a/js/player.js
+++ b/js/player.js
@@ -1,5 +1,5 @@
//js/player.js
-import { REPEAT_MODE, formatTime, getTrackArtists, getTrackTitle} from './utils.js';
+import { REPEAT_MODE, formatTime, getTrackArtists, getTrackTitle, getTrackArtistsHTML } from './utils.js';
import { queueManager } from './storage.js';
export class Player {
@@ -43,7 +43,7 @@ export class Player {
// Restore UI
const track = this.currentTrack;
const trackTitle = getTrackTitle(track);
- const trackArtists = getTrackArtists(track);
+ const trackArtistsHTML = getTrackArtistsHTML(track);
const coverEl = document.querySelector('.now-playing-bar .cover');
const titleEl = document.querySelector('.now-playing-bar .title');
@@ -51,7 +51,7 @@ export class Player {
if (coverEl) coverEl.src = this.api.getCoverUrl(track.album?.cover, '1280');
if (titleEl) titleEl.textContent = trackTitle;
- if (artistEl) artistEl.textContent = trackArtists;
+ if (artistEl) artistEl.innerHTML = trackArtistsHTML;
const totalDurationEl = document.getElementById('total-duration');
if (totalDurationEl) totalDurationEl.textContent = formatTime(track.duration);
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
@@ -168,12 +168,12 @@ export class Player {
this.currentTrack = track;
const trackTitle = getTrackTitle(track);
- const trackArtists = getTrackArtists(track);
+ const trackArtistsHTML = getTrackArtistsHTML(track);
document.querySelector('.now-playing-bar .cover').src =
this.api.getCoverUrl(track.album?.cover, '1280');
document.querySelector('.now-playing-bar .title').textContent = trackTitle;
- document.querySelector('.now-playing-bar .artist').textContent = trackArtists;
+ document.querySelector('.now-playing-bar .artist').innerHTML = trackArtistsHTML;
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
this.updatePlayingTrackIndicator();
diff --git a/js/utils.js b/js/utils.js
index b225985..ada9b5a 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -176,6 +176,16 @@ export const getTrackArtists = (track = {}, { fallback = 'Unknown Artist' } = {}
return fallback;
};
+export const getTrackArtistsHTML = (track = {}, { fallback = 'Unknown Artist' } = {}) => {
+ if (track?.artists?.length) {
+ return track.artists.map(artist =>
+ `${artist.name} `
+ ).join(', ');
+ }
+
+ return fallback;
+};
+
export const formatTemplate = (template, data) => {
let result = template;
result = result.replace(/\{trackNumber\}/g, data.trackNumber ? String(data.trackNumber).padStart(2, '0') : '00');
diff --git a/styles.css b/styles.css
index 6010b84..95a220c 100644
--- a/styles.css
+++ b/styles.css
@@ -53,7 +53,7 @@
--highlight: #3b82f6;
--highlight-rgb: 59, 130, 246;
--active-highlight: #3b82f6;
- --explicit-badge: #ef4444;
+ --explicit-badge: #750a0a;
}
:root[data-theme="ocean"] {
@@ -133,8 +133,7 @@
--highlight: #2563eb;
--highlight-rgb: 37, 99, 235;
--active-highlight: var(--highlight);
- --explicit-badge: #ef4444;
- --explicit-badge-foreground: #ffffff;
+ --explicit-badge: #f58a8a;
--cover-filter: blur(30px) brightness(1.6) opacity(0.85);
}
@@ -622,7 +621,7 @@ body.has-page-background .track-item:hover {
align-items: center;
justify-content: center;
background-color: var(--explicit-badge);
- color: var(--explicit-badge-foreground, #000);
+ color: var(--background);
font-size: 0.65rem;
font-weight: 700;
padding: 0.15rem 0.35rem;
@@ -1464,14 +1463,14 @@ input:checked + .slider::before {
#fullscreen-track-artist {
font-size: 1.25rem;
- color: var(--primary);
+ color: var(--muted-foreground);
font-weight: 500;
}
#fullscreen-next-track {
margin-top: 1.5rem;
font-size: 0.9rem;
- color: var(--primary);
+ color: var(--muted-foreground);
display: flex;
flex-direction: column;
gap: 0.2rem;
@@ -3207,6 +3206,14 @@ input:checked + .slider::before {
}
}
+.now-playing-bar .artist .artist-link {
+ cursor: pointer;
+ transition: color var(--transition);
+}
+.now-playing-bar .artist .artist-link:hover {
+ color: var(--highlight);
+ text-decoration: underline;
+}
/* Updated Volume Controls Layout */
.volume-controls {