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

@@ -18,6 +18,13 @@
cursor: default; cursor: default;
} }
/* Show pointer cursor for interactive / clickable elements (override global default) */
a, a[href], button, input[type="button"], input[type="submit"],
[role="button"], [onclick], .clickable, .icon-btn, .control-btn, label[for],
.station-item, [tabindex]:not([tabindex="-1"]) {
cursor: pointer !important;
}
/* Hide Scrollbars */ /* Hide Scrollbars */
::-webkit-scrollbar { ::-webkit-scrollbar {
display: none; display: none;
@@ -258,6 +265,22 @@ header {
pointer-events: none; pointer-events: none;
} }
/* 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;
}
.blob { .blob {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;

View File

@@ -63,6 +63,7 @@ async function init() {
restoreSavedVolume(); restoreSavedVolume();
await loadStations(); await loadStations();
setupEventListeners(); setupEventListeners();
ensureArtworkPointerFallback();
updateUI(); updateUI();
} catch (e) { } catch (e) {
console.error('Error during init', e); console.error('Error during init', e);
@@ -413,9 +414,10 @@ function updateNowPlayingUI() {
if (!station) return; if (!station) return;
if (nowPlayingEl && nowArtistEl && nowTitleEl) { if (nowPlayingEl && nowArtistEl && nowTitleEl) {
if (station.currentSongInfo && station.currentSongInfo.artist && station.currentSongInfo.title) { // Show now-playing if we have either an artist or a title (some stations only provide title)
nowArtistEl.textContent = station.currentSongInfo.artist; if (station.currentSongInfo && (station.currentSongInfo.artist || station.currentSongInfo.title)) {
nowTitleEl.textContent = station.currentSongInfo.title; nowArtistEl.textContent = station.currentSongInfo.artist || '';
nowTitleEl.textContent = station.currentSongInfo.title || '';
nowPlayingEl.classList.remove('hidden'); nowPlayingEl.classList.remove('hidden');
} else { } else {
nowArtistEl.textContent = ''; nowArtistEl.textContent = '';
@@ -611,6 +613,45 @@ function setupEventListeners() {
// Hotkeys? // 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) { function loadStation(index) {
if (index < 0 || index >= stations.length) return; if (index < 0 || index >= stations.length) return;
const station = stations[index]; const station = stations[index];
@@ -639,14 +680,13 @@ function loadStation(index) {
} }
}); });
} else { } else {
// Fallback to single-letter/logo text // Fallback: show the full station name when no logo is provided
logoImgEl.src = ''; logoImgEl.src = '';
logoImgEl.classList.add('hidden'); logoImgEl.classList.add('hidden');
const numberMatch = station.name.match(/\d+/); try {
if (numberMatch) { logoTextEl.textContent = (station.name || '').trim();
logoTextEl.textContent = numberMatch[0]; } catch (e) {
} else { logoTextEl.textContent = '';
logoTextEl.textContent = station.name.charAt(0).toUpperCase();
} }
logoTextEl.classList.remove('hidden'); logoTextEl.classList.remove('hidden');
} }

View File

@@ -394,6 +394,22 @@ body {
z-index: 0; 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 */
.track-info { .track-info {
text-align: center; text-align: center;