This commit is contained in:
2026-01-02 20:31:15 +01:00
parent 7c0a202f16
commit f2732b36f2
3 changed files with 88 additions and 9 deletions

View File

@@ -63,6 +63,7 @@ async function init() {
restoreSavedVolume();
await loadStations();
setupEventListeners();
ensureArtworkPointerFallback();
updateUI();
} catch (e) {
console.error('Error during init', e);
@@ -413,9 +414,10 @@ function updateNowPlayingUI() {
if (!station) return;
if (nowPlayingEl && nowArtistEl && nowTitleEl) {
if (station.currentSongInfo && station.currentSongInfo.artist && station.currentSongInfo.title) {
nowArtistEl.textContent = station.currentSongInfo.artist;
nowTitleEl.textContent = station.currentSongInfo.title;
// Show now-playing if we have either an artist or a title (some stations only provide title)
if (station.currentSongInfo && (station.currentSongInfo.artist || station.currentSongInfo.title)) {
nowArtistEl.textContent = station.currentSongInfo.artist || '';
nowTitleEl.textContent = station.currentSongInfo.title || '';
nowPlayingEl.classList.remove('hidden');
} else {
nowArtistEl.textContent = '';
@@ -611,6 +613,45 @@ function setupEventListeners() {
// Hotkeys?
}
// If CSS doesn't produce a pointer, this helper forces a pointer when the
// mouse is inside the artwork placeholder's bounding rect. This handles
// cases where an invisible overlay or ancestor blocks pointer styling.
function ensureArtworkPointerFallback() {
try {
const ap = artworkPlaceholder;
if (!ap) return;
// Quick inline style fallback (helps when CSS is overridden)
try { ap.style.cursor = 'pointer'; } catch (e) {}
try { if (logoImgEl) logoImgEl.style.cursor = 'pointer'; } catch (e) {}
try { if (logoTextEl) logoTextEl.style.cursor = 'pointer'; } catch (e) {}
let active = false;
const onMove = (ev) => {
try {
const r = ap.getBoundingClientRect();
const x = ev.clientX, y = ev.clientY;
const inside = x >= r.left && x <= r.right && y >= r.top && y <= r.bottom;
if (inside && !active) {
document.body.style.cursor = 'pointer';
active = true;
} else if (!inside && active) {
document.body.style.cursor = '';
active = false;
}
} catch (e) {}
};
window.addEventListener('mousemove', onMove);
// remove on unload
window.addEventListener('beforeunload', () => {
try { window.removeEventListener('mousemove', onMove); } catch (e) {}
});
} catch (e) {
console.debug('ensureArtworkPointerFallback failed', e);
}
}
function loadStation(index) {
if (index < 0 || index >= stations.length) return;
const station = stations[index];
@@ -639,14 +680,13 @@ function loadStation(index) {
}
});
} else {
// Fallback to single-letter/logo text
// Fallback: show the full station name when no logo is provided
logoImgEl.src = '';
logoImgEl.classList.add('hidden');
const numberMatch = station.name.match(/\d+/);
if (numberMatch) {
logoTextEl.textContent = numberMatch[0];
} else {
logoTextEl.textContent = station.name.charAt(0).toUpperCase();
try {
logoTextEl.textContent = (station.name || '').trim();
} catch (e) {
logoTextEl.textContent = '';
}
logoTextEl.classList.remove('hidden');
}

View File

@@ -394,6 +394,22 @@ body {
z-index: 0;
}
/* Make artwork/logo clickable: show pointer cursor */
.artwork-placeholder,
.artwork-placeholder:hover,
.station-logo-img,
.station-logo-text {
cursor: pointer !important;
pointer-events: auto;
}
/* Subtle hover affordance to make clickability clearer */
.artwork-placeholder:hover .station-logo-img,
.artwork-placeholder:hover .station-logo-text {
transform: scale(1.03);
transition: transform 160ms ease;
}
/* Track Info */
.track-info {
text-align: center;