feat: player drag feedback, global search fixes, iTunes artist discovery

- Player bar: drag handle pill + live lift/peek animation when swiping up to NP
- Global search: now includes Navidrome library results alongside iTunes; fix songs not showing (filter wrapperType=track)
- iTunes artist page: hero banner with album art, top songs section
- Artist detail: iTunes global top tracks + extra albums not on server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-26 17:26:50 +02:00
1 parent ca21b98a19
commit fa7e980f1a
4 files changed
+168 -31

No files matched your search

+32 -6
View File
@@ -112,20 +112,46 @@ window.addEventListener('load', () => {
// Click player-art to open Now Playing
document.getElementById('player-art')?.addEventListener('click', openNowPlaying);
// Swipe-up on player bar to open Now Playing
// Swipe-up on player bar to open Now Playing (with drag visual feedback)
const playerBar = document.querySelector('.player');
const npOverlay = document.getElementById('np-overlay');
if(playerBar) {
let _sy=0, _st=0;
let _sy=0, _dragging=false;
function _resetDrag(open) {
playerBar.classList.remove('dragging');
playerBar.style.transform = '';
if(npOverlay) { npOverlay.style.transition = ''; npOverlay.style.transform = ''; }
if(open) openNowPlaying();
_sy=0; _dragging=false;
}
playerBar.addEventListener('touchstart', e => {
if(e.target.closest('button') || e.target.closest('.progress-bar') || e.target.closest('.volume-wrap')) return;
_sy=e.touches[0].clientY; _st=Date.now();
_sy=e.touches[0].clientY; _dragging=false;
}, {passive:true});
playerBar.addEventListener('touchmove', e => {
if(!_sy) return;
const dy = _sy - e.touches[0].clientY;
if(dy < 5) return;
_dragging = true;
playerBar.classList.add('dragging');
const lift = Math.min(Math.max(dy, 0), 160);
playerBar.style.transform = `translateY(${-lift}px)`;
if(npOverlay) {
npOverlay.style.transition = 'none';
npOverlay.style.transform = `translateY(${Math.max(0, window.innerHeight - lift * 1.6)}px)`;
}
}, {passive:true});
playerBar.addEventListener('touchend', e => {
if(!_sy) return;
const dy=_sy-e.changedTouches[0].clientY, dt=Date.now()-_st;
if(dy>40 || (dt<300&&dy>15)) openNowPlaying();
_sy=0;
const dy = _sy - e.changedTouches[0].clientY;
_resetDrag(_dragging ? dy > 60 : dy > 15);
}, {passive:true});
playerBar.addEventListener('touchcancel', () => _resetDrag(false), {passive:true});
}
});