Watchlist scan deck v2: portrait-anchored hero, zero layout shift (#831 polish)
Boulder's screenshots: the v1 deck shifted around depending on what data had
arrived (the album row vanished entirely without art, leaving floating
"Processing…/Processing…" text), the images were small, and the feed header
floated in empty space. Redesigned in the artist-detail-page language:
- Big 148px square portrait (rounded, shadowed) anchors the left side, with
the current album stamped as a 62px overlay badge in its corner — when art
is missing, both keep their slot and show a glyph placeholder instead of
collapsing, so the deck NEVER changes shape mid-scan.
- 24px artist name + uppercase accent phase line + a fixed-height
"now checking" block (accent left rule) for album + track, with stable
placeholders ("Looking for new releases…" / "—") instead of doubled
"Processing…" text.
- The additions feed is an inset fixed-height panel (artist-page sidebar
style): same size whether 0 or 10 tracks, empty state centered.
- JS: hide the artist photo when the CURRENT artist has none (previously the
prior artist's photo lingered), cleaner placeholder copy.
This commit is contained in:
parent
9f12bdfef6
commit
34e0503fad
3 changed files with 139 additions and 56 deletions
|
|
@ -6994,17 +6994,17 @@
|
|||
</div>
|
||||
<div class="wl-scan-progress"><div id="wl-scan-progress-bar" class="wl-scan-progress-bar" style="width: 0%;"></div></div>
|
||||
<div class="wl-scan-deck-body">
|
||||
<div class="wl-scan-stage">
|
||||
<div class="wl-scan-stage-row">
|
||||
<img id="watchlist-artist-img" class="wl-scan-artist-img" src="" alt="" onerror="this.style.display='none';" />
|
||||
<div class="wl-scan-stage-text">
|
||||
<div id="watchlist-artist-name" class="wl-scan-artist-name">Waiting…</div>
|
||||
<div id="wl-scan-phase" class="wl-scan-phase">starting…</div>
|
||||
<div class="wl-scan-hero">
|
||||
<div class="wl-scan-portrait">
|
||||
<img id="watchlist-artist-img" class="wl-scan-portrait-img" src="" alt="" onerror="this.style.display='none';" />
|
||||
<div class="wl-scan-album-thumb">
|
||||
<img id="watchlist-album-img" src="" alt="" onerror="this.style.display='none';" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="wl-scan-stage-row">
|
||||
<img id="watchlist-album-img" class="wl-scan-album-img" src="" alt="" onerror="this.style.display='none';" />
|
||||
<div class="wl-scan-stage-text">
|
||||
<div class="wl-scan-hero-text">
|
||||
<div id="watchlist-artist-name" class="wl-scan-artist-name">Waiting…</div>
|
||||
<div id="wl-scan-phase" class="wl-scan-phase">starting…</div>
|
||||
<div class="wl-scan-now">
|
||||
<div id="watchlist-album-name" class="wl-scan-album-name">—</div>
|
||||
<div id="watchlist-track-name" class="wl-scan-track-name">—</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3276,15 +3276,21 @@ function handleWatchlistScanData(data) {
|
|||
if (liveActivity && data.status === 'scanning') {
|
||||
liveActivity.style.display = liveActivity.classList.contains('wl-scan-deck') ? 'block' : 'flex';
|
||||
|
||||
// Update artist image and name
|
||||
// Update artist image and name (hide the img when THIS artist has no
|
||||
// photo, so the previous artist's portrait doesn't linger and the
|
||||
// glyph placeholder shows instead)
|
||||
const artistImg = document.getElementById('watchlist-artist-img');
|
||||
const artistName = document.getElementById('watchlist-artist-name');
|
||||
if (artistImg && data.current_artist_image_url) {
|
||||
artistImg.src = data.current_artist_image_url;
|
||||
artistImg.style.display = 'block';
|
||||
if (artistImg) {
|
||||
if (data.current_artist_image_url) {
|
||||
artistImg.src = data.current_artist_image_url;
|
||||
artistImg.style.display = 'block';
|
||||
} else {
|
||||
artistImg.style.display = 'none';
|
||||
}
|
||||
}
|
||||
if (artistName) {
|
||||
artistName.textContent = data.current_artist_name || 'Processing...';
|
||||
artistName.textContent = data.current_artist_name || 'Starting…';
|
||||
}
|
||||
|
||||
// Update album image and name
|
||||
|
|
@ -3297,13 +3303,14 @@ function handleWatchlistScanData(data) {
|
|||
albumImg.style.display = 'none';
|
||||
}
|
||||
if (albumName) {
|
||||
albumName.textContent = data.current_album || (data.current_phase === 'fetching_discography' ? 'Fetching releases...' : 'Processing...');
|
||||
albumName.textContent = data.current_album
|
||||
|| (data.current_phase === 'fetching_discography' ? 'Fetching releases…' : 'Looking for new releases…');
|
||||
}
|
||||
|
||||
// Update current track
|
||||
// Update current track ('' keeps the slot without echoing the album line)
|
||||
const trackName = document.getElementById('watchlist-track-name');
|
||||
if (trackName) {
|
||||
trackName.textContent = data.current_track_name || (data.current_phase === 'fetching_discography' ? 'Fetching releases...' : 'Processing...');
|
||||
trackName.textContent = data.current_track_name || '—';
|
||||
}
|
||||
|
||||
// #831 round 2: scan-deck extras — artist progress bar, live counters,
|
||||
|
|
|
|||
|
|
@ -20077,57 +20077,100 @@ body.helper-mode-active #dashboard-activity-feed:hover {
|
|||
|
||||
.wl-scan-deck-body {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(260px, 1fr) minmax(280px, 1.2fr);
|
||||
gap: 20px;
|
||||
grid-template-columns: minmax(320px, 1.1fr) minmax(300px, 1fr);
|
||||
gap: 24px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.wl-scan-deck-body { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.wl-scan-stage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wl-scan-stage-row {
|
||||
/* Hero — big square portrait (artist-page language) with the current album
|
||||
stamped as an overlay badge, so the layout NEVER shifts when album art is
|
||||
missing: the badge keeps its slot and shows a glyph placeholder instead. */
|
||||
.wl-scan-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
gap: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wl-scan-artist-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgb(var(--accent-rgb));
|
||||
box-shadow: 0 0 18px rgba(var(--accent-rgb), 0.3);
|
||||
object-fit: cover;
|
||||
background: #1a1a1a;
|
||||
.wl-scan-portrait {
|
||||
position: relative;
|
||||
width: 148px;
|
||||
height: 148px;
|
||||
border-radius: 16px;
|
||||
background: #181818;
|
||||
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(var(--accent-rgb), 0.25);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wl-scan-album-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
object-fit: cover;
|
||||
background: #1a1a1a;
|
||||
flex-shrink: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
/* glyph placeholder behind the (possibly hidden) artist image */
|
||||
.wl-scan-portrait::before {
|
||||
content: '♪';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 42px;
|
||||
color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.wl-scan-stage-text {
|
||||
.wl-scan-portrait-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 16px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.wl-scan-album-thumb {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
bottom: -12px;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 10px;
|
||||
background: #181818;
|
||||
border: 3px solid #121212;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.55);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wl-scan-album-thumb::before {
|
||||
content: '♪';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.wl-scan-album-thumb img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.wl-scan-hero-text {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.wl-scan-artist-name {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.3px;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
|
@ -20136,14 +20179,27 @@ body.helper-mode-active #dashboard-activity-feed:hover {
|
|||
|
||||
.wl-scan-phase {
|
||||
font-size: 12px;
|
||||
color: rgba(var(--accent-light-rgb), 0.85);
|
||||
margin-top: 2px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.6px;
|
||||
color: rgba(var(--accent-light-rgb), 0.9);
|
||||
}
|
||||
|
||||
/* Fixed-height "now checking" block — placeholders keep the slot when the
|
||||
scan hasn't reached an album/track yet, so nothing jumps. */
|
||||
.wl-scan-now {
|
||||
margin-top: 8px;
|
||||
padding: 8px 12px;
|
||||
border-left: 2px solid rgba(var(--accent-rgb), 0.5);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-radius: 0 8px 8px 0;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.wl-scan-album-name {
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
|
@ -20158,27 +20214,47 @@ body.helper-mode-active #dashboard-activity-feed:hover {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Feed — inset panel (artist-page sidebar language) with a FIXED height so
|
||||
the deck is the same size whether 0 or 10 tracks have been added. */
|
||||
.wl-scan-feed {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 172px;
|
||||
padding: 12px 14px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.wl-scan-feed-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing: 0.6px;
|
||||
color: #6fd99a;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wl-scan-feed-list {
|
||||
max-height: 176px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.wl-scan-feed-list .watchlist-live-addition-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.wl-scan-feed-list .watchlist-live-addition-item {
|
||||
padding: 5px 8px;
|
||||
border-radius: 6px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue