feat: artist cards navigate-only (no play); add Top Songs + Shuffle buttons to artist detail page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
a907773afb
commit
8a256b9463
3 files changed
+35
-6
No files matched your search
@@ -151,6 +151,7 @@
|
|||||||
<div class="page" id="page-artist-detail">
|
<div class="page" id="page-artist-detail">
|
||||||
<button class="back-btn" id="artist-back-btn"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>Alle Künstler</button>
|
<button class="back-btn" id="artist-back-btn"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>Alle Künstler</button>
|
||||||
<div class="artist-hero" id="artist-detail-hero"><div class="artist-hero-overlay"><div class="artist-hero-name" id="artist-detail-name"></div></div></div>
|
<div class="artist-hero" id="artist-detail-hero"><div class="artist-hero-overlay"><div class="artist-hero-name" id="artist-detail-name"></div></div></div>
|
||||||
|
<div id="artist-action-bar" class="artist-action-bar"></div>
|
||||||
<div id="artist-bio-section"></div>
|
<div id="artist-bio-section"></div>
|
||||||
<div id="artist-similar-section"></div>
|
<div id="artist-similar-section"></div>
|
||||||
<div id="artist-topsongs-section"></div>
|
<div id="artist-topsongs-section"></div>
|
||||||
|
|||||||
+30
-6
@@ -126,8 +126,8 @@ export async function loadArtists() {
|
|||||||
g.innerHTML = '';
|
g.innerHTML = '';
|
||||||
all.forEach(a => {
|
all.forEach(a => {
|
||||||
const c = makeCard(a.name, a.albumCount+' Alben', null, '🎤');
|
const c = makeCard(a.name, a.albumCount+' Alben', null, '🎤');
|
||||||
c.querySelector('.card-art').onclick = (e) => { e.stopPropagation(); quickPlayArtist(a); };
|
c.classList.add('artist-card');
|
||||||
c.querySelector('.card-info').onclick = () => navigate('artist-detail', a);
|
c.onclick = () => navigate('artist-detail', a);
|
||||||
g.appendChild(c);
|
g.appendChild(c);
|
||||||
getArtistImage(a.id).then(imgUrl => {
|
getArtistImage(a.id).then(imgUrl => {
|
||||||
if(!imgUrl) return;
|
if(!imgUrl) return;
|
||||||
@@ -272,6 +272,31 @@ export async function loadArtistDetail(artist) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Action bar ──
|
||||||
|
const actionBar = document.getElementById('artist-action-bar');
|
||||||
|
if(actionBar) {
|
||||||
|
actionBar.innerHTML = '';
|
||||||
|
if(topSongs.length || ndAlbums.length) {
|
||||||
|
const playTopBtn = document.createElement('button');
|
||||||
|
playTopBtn.className = 'artist-action-btn';
|
||||||
|
playTopBtn.innerHTML = `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg> Top Songs`;
|
||||||
|
playTopBtn.onclick = () => topSongs.length ? playQueue(topSongs, 0) : quickPlayArtist(artist);
|
||||||
|
|
||||||
|
const shuffleBtn = document.createElement('button');
|
||||||
|
shuffleBtn.className = 'artist-action-btn';
|
||||||
|
shuffleBtn.innerHTML = `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/></svg> Shuffle`;
|
||||||
|
shuffleBtn.onclick = async () => {
|
||||||
|
S.shuffle = true;
|
||||||
|
localStorage.setItem('ns_shuffle', '1');
|
||||||
|
import('./player.js').then(({ _applyShuffleRepeat }) => _applyShuffleRepeat());
|
||||||
|
await quickPlayArtist(artist);
|
||||||
|
};
|
||||||
|
|
||||||
|
actionBar.appendChild(playTopBtn);
|
||||||
|
actionBar.appendChild(shuffleBtn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Albums ──
|
// ── Albums ──
|
||||||
if(albEl) { albEl.innerHTML = ''; _renderArtistAlbums(albEl, ndAlbums, iAlbums, artist); }
|
if(albEl) { albEl.innerHTML = ''; _renderArtistAlbums(albEl, ndAlbums, iAlbums, artist); }
|
||||||
}
|
}
|
||||||
@@ -574,15 +599,14 @@ export async function doLocalSearch(q) {
|
|||||||
const g = document.createElement('div'); g.className = 'scroll-row';
|
const g = document.createElement('div'); g.className = 'scroll-row';
|
||||||
artists.forEach(a => {
|
artists.forEach(a => {
|
||||||
const c = makeCard(a.name, a.albumCount+' Alben', null, '🎤');
|
const c = makeCard(a.name, a.albumCount+' Alben', null, '🎤');
|
||||||
c.querySelector('.card-art').onclick = (e) => { e.stopPropagation(); quickPlayArtist(a); };
|
c.classList.add('artist-card');
|
||||||
c.querySelector('.card-info').onclick = () => navigate('artist-detail', a);
|
c.onclick = () => navigate('artist-detail', a);
|
||||||
g.appendChild(c);
|
g.appendChild(c);
|
||||||
getArtistImage(a.id).then(img => {
|
getArtistImage(a.id).then(img => {
|
||||||
if(!img) return;
|
if(!img) return;
|
||||||
const artEl = c.querySelector('.card-art');
|
const artEl = c.querySelector('.card-art');
|
||||||
if(!artEl) return;
|
if(!artEl) return;
|
||||||
artEl.innerHTML = `<img src="${img}" loading="lazy" onerror="this.parentNode.innerHTML='<div class=\\'no-art\\'>🎤</div>'"><div class="play-overlay"><button class="play-btn"><svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg></button></div>`;
|
artEl.innerHTML = `<img src="${img}" loading="lazy" onerror="this.parentNode.innerHTML='<div class=\\'no-art\\'>🎤</div>'">`;
|
||||||
artEl.onclick = (e) => { e.stopPropagation(); quickPlayArtist(a); };
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
s.appendChild(g); el.appendChild(s);
|
s.appendChild(g); el.appendChild(s);
|
||||||
|
|||||||
@@ -718,6 +718,10 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
|
|||||||
.np-drag-handle{width:100%;height:36px;display:flex;align-items:center;justify-content:center;cursor:grab;flex-shrink:0;touch-action:none}
|
.np-drag-handle{width:100%;height:36px;display:flex;align-items:center;justify-content:center;cursor:grab;flex-shrink:0;touch-action:none}
|
||||||
.np-drag-handle-bar{width:40px;height:4px;background:rgba(255,255,255,.25);border-radius:2px}
|
.np-drag-handle-bar{width:40px;height:4px;background:rgba(255,255,255,.25);border-radius:2px}
|
||||||
|
|
||||||
|
.artist-card .play-overlay{display:none!important}
|
||||||
|
.artist-action-bar{display:flex;gap:8px;margin-bottom:20px;flex-wrap:wrap}
|
||||||
|
.artist-action-btn{display:flex;align-items:center;gap:6px;padding:9px 18px;border-radius:20px;border:1px solid var(--border2);background:var(--surface);color:var(--text);font-family:var(--font);font-size:13px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s}
|
||||||
|
.artist-action-btn:hover{background:var(--surface2);border-color:var(--accent);color:var(--accent)}
|
||||||
.artist-hero{height:220px;border-radius:14px;overflow:hidden;position:relative;margin-bottom:24px;background:linear-gradient(135deg,var(--surface2),var(--surface))}
|
.artist-hero{height:220px;border-radius:14px;overflow:hidden;position:relative;margin-bottom:24px;background:linear-gradient(135deg,var(--surface2),var(--surface))}
|
||||||
.artist-hero-overlay{position:absolute;inset:0;background:linear-gradient(to right,rgba(7,7,15,.85) 0%,transparent 100%);display:flex;align-items:flex-end;padding:20px 28px}
|
.artist-hero-overlay{position:absolute;inset:0;background:linear-gradient(to right,rgba(7,7,15,.85) 0%,transparent 100%);display:flex;align-items:flex-end;padding:20px 28px}
|
||||||
.artist-hero-name{font-size:32px;font-weight:800;letter-spacing:-1px}
|
.artist-hero-name{font-size:32px;font-weight:800;letter-spacing:-1px}
|
||||||
|
|||||||
Reference in new issue
Block a user