Merge pull request #578 from Nezreka/feature/download-modal-visual-redesign

Polish Download Missing modal tracklist
pull/579/head
BoulderBadgeDad 1 day ago committed by GitHub
commit b6b0366b64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3416,6 +3416,7 @@ const WHATS_NEW = {
'2.5.2': [
// --- May 13, 2026 — 2.5.2 release ---
{ date: 'May 13, 2026 — 2.5.2 release' },
{ title: 'Download Missing Modal: Tracklist Got A Polish Pass', desc: 'visual tune-up only — column layout untouched. hairline row dividers, accent gradient + edge bar on hover, monospace track numbers (glow accent on row hover), monospace tabular duration. status text in both library-match + download-status columns picks up a leading colored dot with a soft halo (green found / amber missing / blue checking / orange downloading / red failed) and pulses while in-flight. artist column centered. soft scrollbar.', page: 'downloads' },
{ title: 'Search Source Picker: Fix Default Always Sticking To Spotify', desc: 'enhanced search + global search source picker always defaulted to spotify even when the user\'s primary metadata source was deezer / itunes / discogs / etc. trace: `shared-helpers.js:createSearchController` reads `/status.metadata_source` to pick the initial active icon, then checks `SOURCE_LABELS[src]` to validate. backend was returning `metadata_source` as a dict (`{source, connected, response_time, ...}` — used elsewhere for connection-state display), so `SOURCE_LABELS[<dict>]` was always undefined, the `if` guard never fired, and `state.activeSource` silently stayed at the hardcoded `\'spotify\'` default. fix: read `.source` off the dict (with forward-compat fallback to plain-string in case any older /status response shape predates the dict change). other consumers (core.js sidebar tile, helper.js status checker, search.js display) already used `?.source` correctly — this was the only stale call site.', page: 'search' },
{ title: 'Download Discography: No Longer Caps Prolific Artists At 50 Releases', desc: 'discord report: clicking "download discography" on an artist with a deep catalogue (bach, beatles complete box, dance / electronic artists with hundreds of remixes) only showed ~50 albums in the modal. trace: `MetadataLookupOptions(limit=50, max_pages=0)` was hardcoded at the discography endpoint and the artist-detail discography view. spotify\'s `max_pages=0` already paginates through everything (per-page is clamped to 10 internally) so spotify-primary users were unaffected. but deezer / itunes / discogs / hydrabase all honor the outer `limit` as a hard cap. fix: bump `limit` from 50 to 200 at all three call sites (`web_server.py` discography endpoint + artist-detail view + `core/artist_source_detail.py`). 200 matches iTunes\'s and Discogs\'s own internal caps and covers near-everyone\'s full catalogue. spotify behavior unchanged.', page: 'library' },
{ title: 'Artist Page: "Write Artist Image" Button (Real Artist Photos For Navidrome)', desc: 'github issue #572 (rhwc): navidrome shows album-art-derived thumbnails as artist photos because navidrome has no api for setting an artist image — it only reads `artist.jpg` from the artist folder during library scans. soulsync\'s `update_artist_poster` for navidrome was a no-op. new button on the artist detail page header writes `artist.jpg` to the artist\'s folder on disk: looks up any album track, resolves it through the path resolver (handles docker mount translation like #558 settled on), goes up one level to the artist folder, fetches the artist photo from the configured metadata source priority chain (spotify primary, fallback to deezer / discogs / etc), downloads with content-type validation + atomic write via `<filename>.tmp + os.replace`. when active server is navidrome, triggers a library scan immediately so the new file gets indexed. respects existing `artist.jpg` files (asks before overwriting) so user-supplied photos aren\'t clobbered. works for plex / jellyfin too as a fallback layer — both servers also read `artist.jpg` from disk. 26 tests pin the pure helpers in `core/library/artist_image.py`: folder derivation (trailing slash / backslash / empty / non-string), image url picking (missing attr / whitespace strip / non-string), download (non-image content-type / 404 / timeout / empty body), and write (atomic replace / temp-cleanup-on-failure / overwrite guard / missing folder).', page: 'library' },

@ -20007,6 +20007,186 @@ body.helper-mode-active #dashboard-activity-feed:hover {
box-shadow: none;
}
/* =====================================================================
Download-Missing tracklist polish pure visual tune-up.
Keeps column layout intact (no grid restructure, no cell reflow).
Refines: header chrome, row hairlines, hover states, typography
(mono numbers/duration, weight tightening), status pill polish,
pulse on checking/downloading, soft scrollbar.
All overrides scoped to `.download-missing-modal-content` so they
only affect this modal never the standalone Albums page tables.
===================================================================== */
/* Header chrome — refined uppercase micro-caps for column labels */
.download-missing-modal-content .download-tracks-table thead th {
background: linear-gradient(180deg, rgba(28,28,28,0.95), rgba(22,22,22,0.95));
color: rgba(255, 255, 255, 0.5);
font-weight: 600;
font-size: 10.5px;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 11px 14px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
text-align: center;
}
/* Cell baseline — tighter padding, hairline divider */
.download-missing-modal-content .download-tracks-table td {
padding: 11px 14px;
border-bottom: 1px solid rgba(255, 255, 255, 0.045);
color: rgba(255, 255, 255, 0.85);
font-size: 13px;
transition: color 0.15s ease;
}
.download-missing-modal-content .download-tracks-table tbody tr:last-child td {
border-bottom: none;
}
/* Row hover — subtle accent gradient + left-edge accent bar via box-shadow inset */
.download-missing-modal-content .download-tracks-table tbody tr {
transition: background 0.18s ease, box-shadow 0.18s ease;
position: relative;
}
.download-missing-modal-content .download-tracks-table tbody tr:hover {
background: linear-gradient(90deg,
rgba(var(--accent-rgb), 0.07) 0%,
rgba(255, 255, 255, 0.03) 60%,
transparent 100%);
box-shadow: inset 3px 0 0 rgb(var(--accent-rgb));
}
/* Track number — mono, dim, tabular */
.download-missing-modal-content .download-tracks-table .track-number {
color: rgba(255, 255, 255, 0.32);
font-weight: 500;
font-size: 12px;
font-variant-numeric: tabular-nums;
font-family: 'SF Mono', Menlo, Consolas, ui-monospace, monospace;
}
.download-missing-modal-content .download-tracks-table tbody tr:hover .track-number {
color: rgb(var(--accent-rgb));
}
/* Title — bold white, slight negative tracking */
.download-missing-modal-content .download-tracks-table .track-name {
font-weight: 600;
color: #fff;
letter-spacing: -0.005em;
}
/* Artist — dim, centered */
.download-missing-modal-content .download-tracks-table .track-artist {
color: rgba(255, 255, 255, 0.55);
font-weight: 400;
text-align: center;
}
/* Duration — mono dim tabular */
.download-missing-modal-content .download-tracks-table .track-duration {
color: rgba(255, 255, 255, 0.4);
font-size: 12px;
font-variant-numeric: tabular-nums;
font-family: 'SF Mono', Menlo, Consolas, ui-monospace, monospace;
}
/* Status cells — uppercase micro-caps with leading colored dot */
.download-missing-modal-content .download-tracks-table .track-match-status,
.download-missing-modal-content .download-tracks-table .track-download-status {
font-weight: 700;
font-size: 10.5px;
letter-spacing: 0.08em;
text-transform: uppercase;
text-align: center;
}
/* Leading colored dot before status text — uses currentColor so it matches state */
.download-missing-modal-content .download-tracks-table .match-found::before,
.download-missing-modal-content .download-tracks-table .match-missing::before,
.download-missing-modal-content .download-tracks-table .match-checking::before,
.download-missing-modal-content .download-tracks-table .download-searching::before,
.download-missing-modal-content .download-tracks-table .download-downloading::before,
.download-missing-modal-content .download-tracks-table .download-complete::before,
.download-missing-modal-content .download-tracks-table .download-failed::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
margin-right: 7px;
vertical-align: 1px;
box-shadow: 0 0 8px currentColor, 0 0 2px currentColor;
}
.download-missing-modal-content .download-tracks-table .match-found {
color: #4ade80;
text-shadow: 0 0 12px rgba(74, 222, 128, 0.35);
}
.download-missing-modal-content .download-tracks-table .match-missing {
color: #facc15;
text-shadow: 0 0 12px rgba(250, 204, 21, 0.35);
}
.download-missing-modal-content .download-tracks-table .match-checking {
color: #60a5fa;
text-shadow: 0 0 12px rgba(96, 165, 250, 0.35);
animation: dms-status-pulse 1.5s ease-in-out infinite;
}
.download-missing-modal-content .download-tracks-table .download-searching {
color: #60a5fa;
text-shadow: 0 0 12px rgba(96, 165, 250, 0.35);
animation: dms-status-pulse 1.5s ease-in-out infinite;
}
.download-missing-modal-content .download-tracks-table .download-downloading {
color: #fb923c;
text-shadow: 0 0 12px rgba(251, 146, 60, 0.4);
animation: dms-status-pulse 1s ease-in-out infinite;
}
.download-missing-modal-content .download-tracks-table .download-complete {
color: #4ade80;
text-shadow: 0 0 12px rgba(74, 222, 128, 0.4);
}
.download-missing-modal-content .download-tracks-table .download-failed {
color: #f87171;
text-shadow: 0 0 12px rgba(248, 113, 113, 0.4);
}
@keyframes dms-status-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.55; }
}
/* Checkbox column — accent + hover scale */
.download-missing-modal-content .download-tracks-table .track-select-cb {
accent-color: rgb(var(--accent-rgb));
transition: transform 0.12s ease;
}
.download-missing-modal-content .download-tracks-table tbody tr:hover .track-select-cb {
transform: scale(1.08);
}
/* Deselected — fade title/artist, keep status visible */
.download-missing-modal-content .download-tracks-table .track-deselected .track-name,
.download-missing-modal-content .download-tracks-table .track-deselected .track-artist {
text-decoration: line-through;
text-decoration-color: rgba(255, 255, 255, 0.25);
text-decoration-thickness: 1px;
}
/* Soft scrollbar for the track scroll area */
.download-missing-modal-content .download-tracks-table-container::-webkit-scrollbar {
width: 8px;
}
.download-missing-modal-content .download-tracks-table-container::-webkit-scrollbar-track {
background: transparent;
}
.download-missing-modal-content .download-tracks-table-container::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.08);
border-radius: 999px;
transition: background 0.2s ease;
}
.download-missing-modal-content .download-tracks-table-container::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.18);
}
/* Force Download Toggle Styling */
.force-download-toggle-container {
display: flex;

Loading…
Cancel
Save