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"> <button class="sync-tab-button" data-tab="beatport">
<span class="tab-icon beatport-icon"></span> Beatport <span class="tab-icon beatport-icon"></span> Beatport
</button> </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 <span class="tab-icon listenbrainz-icon"></span> ListenBrainz
</button> </button>
<button class="sync-tab-button" data-tab="import-file"> <button class="sync-tab-button" data-tab="import-file">
@ -1915,8 +1915,8 @@
</div> </div>
</div> </div>
<!-- ListenBrainz Tab Content --> <!-- ListenBrainz Sync Tab Content (separate ID from Discover-page LB UI) -->
<div class="sync-tab-content" id="listenbrainz-tab-content"> <div class="sync-tab-content" id="listenbrainz-sync-tab-content">
<div class="playlist-header"> <div class="playlist-header">
<h3>Your ListenBrainz Playlists</h3> <h3>Your ListenBrainz Playlists</h3>
<div class="listenbrainz-sub-tabs"> <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; } .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; } .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; } .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, .youtube-playlist-card .playlist-card-content,
.tidal-playlist-card .playlist-card-content, .tidal-playlist-card .playlist-card-content,
.deezer-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, .youtube-playlist-card .playlist-card-name,
.tidal-playlist-card .playlist-card-name, .tidal-playlist-card .playlist-card-name,
.deezer-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, .youtube-playlist-card .playlist-card-info,
.tidal-playlist-card .playlist-card-info, .tidal-playlist-card .playlist-card-info,
.deezer-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-track-count { color: rgba(255, 255, 255, 0.7); }
.youtube-playlist-card .playlist-card-phase-text { font-weight: 500; } .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, .youtube-playlist-card .playlist-card-action-btn,
.tidal-playlist-card .playlist-card-action-btn, .tidal-playlist-card .playlist-card-action-btn,
.deezer-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%); 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); border: 1px solid rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.8); 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, .youtube-playlist-card .playlist-card-action-btn::before,
.tidal-playlist-card .playlist-card-action-btn::before, .tidal-playlist-card .playlist-card-action-btn::before,
.deezer-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: ''; content: '';
position: absolute; position: absolute;
inset: 0; 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)); } .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)); } .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)); } .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, .youtube-playlist-card .playlist-card-action-btn:hover:not(:disabled)::before,
.tidal-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, .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); } .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); } .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); } .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); } .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, .youtube-playlist-card .playlist-card-action-btn:disabled,
.tidal-playlist-card .playlist-card-action-btn:disabled, .tidal-playlist-card .playlist-card-action-btn:disabled,
.deezer-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); background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.2); color: rgba(255, 255, 255, 0.2);
@ -36142,44 +36152,10 @@ div.artist-hero-badge {
margin-top: 60px; margin-top: 60px;
} }
.listenbrainz-playlist-card { /* (Removed dead Discover-page LB card styling solid orange gradient
background: linear-gradient(135deg, #eb743b 0%, #d26230 100%); * + .listenbrainz-icon { font-size: 48px } were orphaned rules that
display: flex; * collided with the Sync-page LB tab cards. The legacy class was
align-items: center; * never instantiated in JS or HTML outside the new Sync tab.) */
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;
}
}
/* ========================================= */ /* ========================================= */
/* ========================================= */ /* ========================================= */

View file

@ -148,7 +148,7 @@ function renderListenBrainzSyncPlaylists() {
// If the tab is currently visible, kick the refresh loop so cards // If the tab is currently visible, kick the refresh loop so cards
// start showing live state immediately. ``_startLbSyncCardRefreshLoop`` // start showing live state immediately. ``_startLbSyncCardRefreshLoop``
// is idempotent + self-stops when the tab loses focus. // 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')) { if (tab && tab.classList.contains('active')) {
_startLbSyncCardRefreshLoop(); _startLbSyncCardRefreshLoop();
} }
@ -282,14 +282,14 @@ function _refreshOneLbSyncCard(card) {
} }
function _refreshAllLbSyncCards() { function _refreshAllLbSyncCards() {
document.querySelectorAll('#listenbrainz-tab-content .listenbrainz-playlist-card') document.querySelectorAll('#listenbrainz-sync-tab-content .listenbrainz-playlist-card')
.forEach(_refreshOneLbSyncCard); .forEach(_refreshOneLbSyncCard);
} }
function _startLbSyncCardRefreshLoop() { function _startLbSyncCardRefreshLoop() {
if (_lbSyncCardRefreshInterval) return; if (_lbSyncCardRefreshInterval) return;
_lbSyncCardRefreshInterval = setInterval(() => { _lbSyncCardRefreshInterval = setInterval(() => {
const tab = document.getElementById('listenbrainz-tab-content'); const tab = document.getElementById('listenbrainz-sync-tab-content');
if (!tab || !tab.classList.contains('active')) { if (!tab || !tab.classList.contains('active')) {
_stopLbSyncCardRefreshLoop(); _stopLbSyncCardRefreshLoop();
return; return;
@ -309,7 +309,7 @@ function _stopLbSyncCardRefreshLoop() {
// Sub-tab switching (For You / My Playlists / Collaborative). // Sub-tab switching (For You / My Playlists / Collaborative).
function _initListenBrainzSyncSubTabs() { 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; if (!subTabContainer) return;
subTabContainer.addEventListener('click', (e) => { subTabContainer.addEventListener('click', (e) => {
const btn = e.target.closest('.listenbrainz-sub-tab-btn'); 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. // Auto-load ListenBrainz Sync-tab playlists on first activation.
// Reuses the LB discovery + sync flow already wired up for the // Reuses the LB discovery + sync flow already wired up for the
// Discover page — the tab is purely a Sync-page entry point. // 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' if (typeof loadListenBrainzSyncPlaylists === 'function'
&& !window._listenbrainzSyncTabLoaded) { && !window._listenbrainzSyncTabLoaded) {
window._listenbrainzSyncTabLoaded = true; window._listenbrainzSyncTabLoaded = true;