forked from Keelrleek/SoulStream
now playing: the transfer moves into the bar, and the panel speaks the app's headings
The hover popover is deleted. It showed the peer, the rate, a percentage and a second progress bar — every one of which the status line and the hairline beside it already carry — so it was a duplicate you had to hover for. The two things unique to it move up: the save action into the bar, and nothing else. Deleted with it, the reveal action, its 250ms close grace and the `.np-statuswrap` hit area, all of which existed only to make a popover reachable across the 25px gap between the status line and itself. Release sections were the one heading in the app that was 13px, Title Case, full white on an opaque sticky bar; every other one — `.lab` here, `.disc-head` and `.rail-lab` on the catalog pages — is 11px uppercase muted. They now match, with the hairline rule the catalog pages use, and they no longer pin: the bar existed only to hide rows sliding under a sticky heading. Those headings sit on the blurred record, not a flat page, so `--text-muted` and #5c5c5c were chosen against a background that is not there. Each carries a dark plate now, years get the album page's over-artwork treatment, and the hairline goes 0.07 -> 0.14, which over a bright cover was the difference between a faint line and no line. "From the album" rendered `player.queue`, which the album fill grows ONE TRACK AT A TIME as each Soulseek source resolves — a nine-track record read "5 tracks" while you watched the rest arrive. It renders the record's own tracklist now, matched to queue items by provider id, and a row with no source yet resolves on demand when clicked. The About pane gains a record head, a lede, stat tiles, pills and a source line, all re-laid-out from data already in hand. The artist page's expander gets the same lede and pills — no record head or tiles there, because its rail already carries them.
This commit is contained in:
1 parent
a6b585303e
commit
3f4f5c305a
2 files changed
+459
-185
No files matched your search
@@ -38,6 +38,7 @@
|
||||
editionLabel,
|
||||
isEdition,
|
||||
releaseFamilies,
|
||||
splitDescription,
|
||||
} from "../lib/editions.js";
|
||||
import { listenerHeat, listenerPeak, listenerShare } from "../lib/listenerBars.js";
|
||||
import { buildArtistManifest } from "../lib/preview/manifest.js";
|
||||
@@ -2450,6 +2451,27 @@
|
||||
return sized;
|
||||
}
|
||||
|
||||
/** Lede + body for the open record, from the shared splitter. */
|
||||
const railDesc = $derived(splitDescription(openInfo?.description));
|
||||
|
||||
/** What the expander is already showing, handed to the album page so its
|
||||
* skeleton opens holding this record's artwork instead of a grey block.
|
||||
* `railCover` on purpose: that exact URL is the one already decoded and in
|
||||
* memory for the rail, so the seeded cover costs no request and cannot
|
||||
* flash on its way in. */
|
||||
function albumSeed(album) {
|
||||
if (!album?.cover || artBroken[album.cover]) return null;
|
||||
return {
|
||||
cover: railCover(album.cover),
|
||||
title: album.title ?? null,
|
||||
artist: album.artist ?? page?.artist?.name ?? null,
|
||||
kind: album.record_type ?? null,
|
||||
// The open expander has already fetched the real tracks; its count
|
||||
// beats the card's metadata, which is missing on some rows.
|
||||
tracks: openTracks.length || album.track_count || null,
|
||||
};
|
||||
}
|
||||
|
||||
function handleCoverError(node, originalCover, title = "") {
|
||||
const fallback = coverLoadError(
|
||||
originalCover,
|
||||
@@ -4746,7 +4768,10 @@
|
||||
<button
|
||||
class="rail-title-link"
|
||||
title="Open album"
|
||||
onclick={() => openAlbumId != null && openCatalogAlbum(openAlbumId)}
|
||||
onclick={() => openAlbumId != null
|
||||
&& openCatalogAlbum(openAlbumId, {
|
||||
seed: albumSeed(railArtAlbum ?? openAlbum),
|
||||
})}
|
||||
>{openAlbum?.title ?? openFamily?.baseTitle ?? ""}</button>
|
||||
</h3>
|
||||
<p class="rail-meta">
|
||||
@@ -4787,13 +4812,31 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if openInfo?.description}
|
||||
<p class="rail-desc" class:clamped={!descExpanded} in:partIn={{ delay: 60 }}>{openInfo.description}</p>
|
||||
<button
|
||||
class="rail-more"
|
||||
class:open={descExpanded}
|
||||
in:partIn={{ delay: 85 }}
|
||||
onclick={() => (descExpanded = !descExpanded)}
|
||||
>{descExpanded ? "Show less" : "Show more"} <Icon name="chevron-down" size={13} /></button>
|
||||
<!-- The description's own first
|
||||
sentence, promoted. Same
|
||||
splitter the album page and
|
||||
the Now Playing panel use;
|
||||
nothing is written. The body
|
||||
keeps its 4-line clamp and
|
||||
its mask fade. -->
|
||||
{#if railDesc.lede}
|
||||
<p class="rail-lede" in:partIn={{ delay: 55 }}>{railDesc.lede}</p>
|
||||
{/if}
|
||||
{#if railDesc.rest}
|
||||
<p class="rail-desc" class:clamped={!descExpanded} in:partIn={{ delay: 60 }}>{railDesc.rest}</p>
|
||||
<button
|
||||
class="rail-more"
|
||||
class:open={descExpanded}
|
||||
in:partIn={{ delay: 85 }}
|
||||
onclick={() => (descExpanded = !descExpanded)}
|
||||
>{descExpanded ? "Show less" : "Show more"} <Icon name="chevron-down" size={13} /></button>
|
||||
{/if}
|
||||
{#if openInfo.genre || openInfo.label}
|
||||
<div class="rail-pills" in:partIn={{ delay: 100 }}>
|
||||
{#if openInfo.genre}<span class="gpill accent">{openInfo.genre}</span>{/if}
|
||||
{#if openInfo.label}<span class="gpill">{openInfo.label}</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if openFamily && openFamily.editions.length > 1}
|
||||
<div class="rail-eds">
|
||||
@@ -7904,6 +7947,39 @@
|
||||
|
||||
/* Clamped description dissolves at its bottom edge; the quiet text button
|
||||
below expands it, its chevron rotating. */
|
||||
/* The promoted first sentence. Only a little larger than the body: the rail
|
||||
is 250px wide and the title above it is already 17px, so a bigger lede
|
||||
would compete with the record's own name. */
|
||||
.rail-lede {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
/* Genre and label only — the date is already in `.rail-meta` directly
|
||||
above, and repeating it cost a second wrapped row in a 210px column. */
|
||||
.rail-pills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
}
|
||||
.gpill {
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 3px 9px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
.gpill.accent {
|
||||
background: color-mix(in srgb, var(--accent) 30%, rgba(10, 10, 12, 0.4));
|
||||
border-color: color-mix(in srgb, var(--accent) 50%, transparent);
|
||||
color: #fff;
|
||||
}
|
||||
.rail-desc {
|
||||
margin: 0;
|
||||
font-size: 12.5px;
|
||||
|
||||
Reference in new issue
Block a user