Fix LB Sync tab card styling — dead CSS + ID collision

Two interacting bugs that left LB Sync-tab cards rendering with a
solid orange gradient background instead of the dark glass style
every other Sync-page card uses:

1. **Duplicate element id** ``listenbrainz-tab-content``: the new
   Sync-tab content div reused the same id the Discover page's
   pre-existing LB section already owned. Two elements with the
   same id is invalid HTML, and ``getElementById`` in the refresh
   loop was hitting the Sync version first while ``initialize
   SyncPage``'s ``${tabId}-tab-content`` lookup could race against
   it. Renamed the Sync-page tab id + ``data-tab`` attribute to
   ``listenbrainz-sync`` (matches the existing ``${tabId}-tab-
   content`` convention so the lookup becomes
   ``listenbrainz-sync-tab-content``). Discover-page LB tab
   keeps its original id untouched.

2. **Dead ``.listenbrainz-playlist-card`` rule** at style.css
   L36155 painting a solid ``linear-gradient(#eb743b → #d26230)``
   over the card. That class was orphaned — no JS or HTML
   instantiated it before Phase 1c.1 — but it sat at higher
   source order than my unified ``.youtube-playlist-card,
   .tidal-playlist-card, ...`` rule, so the bare-class selector
   won the cascade and overwrote the dark glass background.
   Also removed the matching dead ``.listenbrainz-icon { font-
   size: 48px }`` rule and its local ``@keyframes pulse`` copy
   (the keyframes are defined in four other live blocks).

3. **Missing LB selectors in unified inner-element rules**:
   ``.listenbrainz-playlist-card`` was only added to the OUTER
   card selector group in the first pass — the inner
   ``.playlist-card-icon`` / ``.playlist-card-content`` /
   ``.playlist-card-name`` / ``.playlist-card-info`` /
   ``.playlist-card-action-btn`` (+ ::before, :hover, :disabled)
   selector groups were left out, so the inner elements lost all
   their styling. Bulk-added LB to every group so the card
   inherits the full glass shell the other sources get, with a
   brand-orange ``rgba(235, 116, 59, ...)`` accent matching the
   Tidal / Deezer / Spotify-public pattern.
This commit is contained in:
Broque Thomas 2026-05-26 14:41:57 -07:00
parent 55583c1db3
commit 969d5ffc1b
4 changed files with 32 additions and 53 deletions

View file

@ -1027,7 +1027,7 @@
<button class="sync-tab-button" data-tab="beatport">
<span class="tab-icon beatport-icon"></span> Beatport
</button>
<button class="sync-tab-button" data-tab="listenbrainz">
<button class="sync-tab-button" data-tab="listenbrainz-sync">
<span class="tab-icon listenbrainz-icon"></span> ListenBrainz
</button>
<button class="sync-tab-button" data-tab="import-file">
@ -1915,8 +1915,8 @@
</div>
</div>
<!-- ListenBrainz Tab Content -->
<div class="sync-tab-content" id="listenbrainz-tab-content">
<!-- ListenBrainz Sync Tab Content (separate ID from Discover-page LB UI) -->
<div class="sync-tab-content" id="listenbrainz-sync-tab-content">
<div class="playlist-header">
<h3>Your ListenBrainz Playlists</h3>
<div class="listenbrainz-sub-tabs">

View file

@ -17611,21 +17611,25 @@ body.helper-mode-active #dashboard-activity-feed:hover {
.tidal-playlist-card .playlist-card-icon { background: rgba(255, 102, 0, 0.12); border: 1px solid rgba(255, 102, 0, 0.2); color: #ff6600; font-size: 16px; }
.deezer-playlist-card .playlist-card-icon { background: rgba(162, 56, 255, 0.12); border: 1px solid rgba(162, 56, 255, 0.2); color: #a238ff; }
.spotify-public-card .playlist-card-icon { background: rgba(29, 185, 84, 0.12); border: 1px solid rgba(29, 185, 84, 0.2); color: #1DB954; }
.listenbrainz-playlist-card .playlist-card-icon { background: rgba(235, 116, 59, 0.12); border: 1px solid rgba(235, 116, 59, 0.2); color: #eb743b; }
.youtube-playlist-card .playlist-card-content,
.tidal-playlist-card .playlist-card-content,
.deezer-playlist-card .playlist-card-content,
.spotify-public-card .playlist-card-content { flex: 1; min-width: 0; }
.spotify-public-card .playlist-card-content,
.listenbrainz-playlist-card .playlist-card-content { flex: 1; min-width: 0; }
.youtube-playlist-card .playlist-card-name,
.tidal-playlist-card .playlist-card-name,
.deezer-playlist-card .playlist-card-name,
.spotify-public-card .playlist-card-name { font-size: 15px; font-weight: 600; color: rgba(255, 255, 255, 0.9); margin-bottom: 4px; }
.spotify-public-card .playlist-card-name,
.listenbrainz-playlist-card .playlist-card-name { font-size: 15px; font-weight: 600; color: rgba(255, 255, 255, 0.9); margin-bottom: 4px; }
.youtube-playlist-card .playlist-card-info,
.tidal-playlist-card .playlist-card-info,
.deezer-playlist-card .playlist-card-info,
.spotify-public-card .playlist-card-info { font-size: 13px; color: rgba(255, 255, 255, 0.4); display: flex; align-items: center; gap: 10px; }
.spotify-public-card .playlist-card-info,
.listenbrainz-playlist-card .playlist-card-info { font-size: 13px; color: rgba(255, 255, 255, 0.4); display: flex; align-items: center; gap: 10px; }
.youtube-playlist-card .playlist-card-track-count { color: rgba(255, 255, 255, 0.7); }
.youtube-playlist-card .playlist-card-phase-text { font-weight: 500; }
@ -17635,7 +17639,8 @@ body.helper-mode-active #dashboard-activity-feed:hover {
.youtube-playlist-card .playlist-card-action-btn,
.tidal-playlist-card .playlist-card-action-btn,
.deezer-playlist-card .playlist-card-action-btn,
.spotify-public-card .playlist-card-action-btn {
.spotify-public-card .playlist-card-action-btn,
.listenbrainz-playlist-card .playlist-card-action-btn {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.02) 100%);
border: 1px solid rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.8);
@ -17654,7 +17659,8 @@ body.helper-mode-active #dashboard-activity-feed:hover {
.youtube-playlist-card .playlist-card-action-btn::before,
.tidal-playlist-card .playlist-card-action-btn::before,
.deezer-playlist-card .playlist-card-action-btn::before,
.spotify-public-card .playlist-card-action-btn::before {
.spotify-public-card .playlist-card-action-btn::before,
.listenbrainz-playlist-card .playlist-card-action-btn::before {
content: '';
position: absolute;
inset: 0;
@ -17667,21 +17673,25 @@ body.helper-mode-active #dashboard-activity-feed:hover {
.tidal-playlist-card .playlist-card-action-btn::before { background: linear-gradient(135deg, rgba(255, 102, 0, 0.2), rgba(255, 102, 0, 0.05)); }
.deezer-playlist-card .playlist-card-action-btn::before { background: linear-gradient(135deg, rgba(162, 56, 255, 0.2), rgba(162, 56, 255, 0.05)); }
.spotify-public-card .playlist-card-action-btn::before { background: linear-gradient(135deg, rgba(29, 185, 84, 0.2), rgba(29, 185, 84, 0.05)); }
.listenbrainz-playlist-card .playlist-card-action-btn::before { background: linear-gradient(135deg, rgba(235, 116, 59, 0.2), rgba(235, 116, 59, 0.05)); }
.youtube-playlist-card .playlist-card-action-btn:hover:not(:disabled)::before,
.tidal-playlist-card .playlist-card-action-btn:hover:not(:disabled)::before,
.deezer-playlist-card .playlist-card-action-btn:hover:not(:disabled)::before,
.spotify-public-card .playlist-card-action-btn:hover:not(:disabled)::before { opacity: 1; }
.spotify-public-card .playlist-card-action-btn:hover:not(:disabled)::before,
.listenbrainz-playlist-card .playlist-card-action-btn:hover:not(:disabled)::before { opacity: 1; }
.youtube-playlist-card .playlist-card-action-btn:hover:not(:disabled) { color: #fff; border-color: rgba(255, 0, 0, 0.35); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(255, 0, 0, 0.15); }
.tidal-playlist-card .playlist-card-action-btn:hover:not(:disabled) { color: #fff; border-color: rgba(255, 102, 0, 0.35); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(255, 102, 0, 0.15); }
.deezer-playlist-card .playlist-card-action-btn:hover:not(:disabled) { color: #fff; border-color: rgba(162, 56, 255, 0.35); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(162, 56, 255, 0.15); }
.spotify-public-card .playlist-card-action-btn:hover:not(:disabled) { color: #fff; border-color: rgba(29, 185, 84, 0.35); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(29, 185, 84, 0.15); }
.listenbrainz-playlist-card .playlist-card-action-btn:hover:not(:disabled) { color: #fff; border-color: rgba(235, 116, 59, 0.35); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(235, 116, 59, 0.15); }
.youtube-playlist-card .playlist-card-action-btn:disabled,
.tidal-playlist-card .playlist-card-action-btn:disabled,
.deezer-playlist-card .playlist-card-action-btn:disabled,
.spotify-public-card .playlist-card-action-btn:disabled {
.spotify-public-card .playlist-card-action-btn:disabled,
.listenbrainz-playlist-card .playlist-card-action-btn:disabled {
background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.2);
@ -36142,44 +36152,10 @@ div.artist-hero-badge {
margin-top: 60px;
}
.listenbrainz-playlist-card {
background: linear-gradient(135deg, #eb743b 0%, #d26230 100%);
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.listenbrainz-playlist-card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
animation: pulse 3s ease-in-out infinite;
}
.listenbrainz-icon {
font-size: 48px;
position: relative;
z-index: 1;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
@keyframes pulse {
0%,
100% {
opacity: 0.5;
}
50% {
opacity: 0.8;
}
}
/* (Removed dead Discover-page LB card styling solid orange gradient
* + .listenbrainz-icon { font-size: 48px } were orphaned rules that
* collided with the Sync-page LB tab cards. The legacy class was
* never instantiated in JS or HTML outside the new Sync tab.) */
/* ========================================= */
/* ========================================= */

View file

@ -148,7 +148,7 @@ function renderListenBrainzSyncPlaylists() {
// If the tab is currently visible, kick the refresh loop so cards
// start showing live state immediately. ``_startLbSyncCardRefreshLoop``
// is idempotent + self-stops when the tab loses focus.
const tab = document.getElementById('listenbrainz-tab-content');
const tab = document.getElementById('listenbrainz-sync-tab-content');
if (tab && tab.classList.contains('active')) {
_startLbSyncCardRefreshLoop();
}
@ -282,14 +282,14 @@ function _refreshOneLbSyncCard(card) {
}
function _refreshAllLbSyncCards() {
document.querySelectorAll('#listenbrainz-tab-content .listenbrainz-playlist-card')
document.querySelectorAll('#listenbrainz-sync-tab-content .listenbrainz-playlist-card')
.forEach(_refreshOneLbSyncCard);
}
function _startLbSyncCardRefreshLoop() {
if (_lbSyncCardRefreshInterval) return;
_lbSyncCardRefreshInterval = setInterval(() => {
const tab = document.getElementById('listenbrainz-tab-content');
const tab = document.getElementById('listenbrainz-sync-tab-content');
if (!tab || !tab.classList.contains('active')) {
_stopLbSyncCardRefreshLoop();
return;
@ -309,7 +309,7 @@ function _stopLbSyncCardRefreshLoop() {
// Sub-tab switching (For You / My Playlists / Collaborative).
function _initListenBrainzSyncSubTabs() {
const subTabContainer = document.querySelector('#listenbrainz-tab-content .listenbrainz-sub-tabs');
const subTabContainer = document.querySelector('#listenbrainz-sync-tab-content .listenbrainz-sub-tabs');
if (!subTabContainer) return;
subTabContainer.addEventListener('click', (e) => {
const btn = e.target.closest('.listenbrainz-sub-tab-btn');

View file

@ -3735,7 +3735,10 @@ function initializeSyncPage() {
// Auto-load ListenBrainz Sync-tab playlists on first activation.
// Reuses the LB discovery + sync flow already wired up for the
// Discover page — the tab is purely a Sync-page entry point.
if (tabId === 'listenbrainz') {
// Tab id is ``listenbrainz-sync`` (not ``listenbrainz``) so the
// ``${tabId}-tab-content`` lookup doesn't collide with the
// Discover page's own ``id="listenbrainz-tab-content"``.
if (tabId === 'listenbrainz-sync') {
if (typeof loadListenBrainzSyncPlaylists === 'function'
&& !window._listenbrainzSyncTabLoaded) {
window._listenbrainzSyncTabLoaded = true;