forked from Keelrleek/SoulStream
dj sets + lyrics: a mix that names its own tracks, and words pulled off the separated voice
This commit is contained in:
1 parent
4efe85b6bf
commit
1dd8573808
41 files changed
+9288
-647
No files matched your search
@@ -51,6 +51,7 @@
|
||||
import { openPreview } from "../lib/preview/previewSession.svelte.js";
|
||||
import { traceToSvg, svgDataUrl } from "../lib/trace.js";
|
||||
import Icon from "../components/Icon.svelte";
|
||||
import PlaylistMenu from "../components/PlaylistMenu.svelte";
|
||||
import { consumeScroll, restoreScroll } from "../lib/navigation.svelte.js";
|
||||
import HeroGpuCanvas from "../components/HeroGpuCanvas.svelte";
|
||||
|
||||
@@ -5071,6 +5072,19 @@
|
||||
<span class="track-album">{track.album}</span>
|
||||
<span class="lis" class:unknown={track.listeners == null} title={track.listeners == null ? "No Last.fm listener data for this track" : `${track.listeners.toLocaleString()} Last.fm listeners`}>{fmtListeners(track.listeners)}</span>
|
||||
<span class="tdur">{fmtDuration(track.duration_secs)}</span>
|
||||
<PlaylistMenu
|
||||
compact
|
||||
iconSize={13}
|
||||
align="right"
|
||||
tracks={() => [{
|
||||
title: track.title,
|
||||
artist: page.artist.name,
|
||||
album: track.album ?? null,
|
||||
duration_secs: track.duration_secs ?? null,
|
||||
trackId: track.id ?? null,
|
||||
artUrl: track.cover ?? null,
|
||||
}]}
|
||||
/>
|
||||
<button
|
||||
class="mini-get"
|
||||
title="Save to library"
|
||||
@@ -5425,6 +5439,19 @@
|
||||
<span class="tdur">{fmtDuration(t.duration_secs)}</span>
|
||||
{/if}
|
||||
{#if !locked}
|
||||
<PlaylistMenu
|
||||
compact
|
||||
iconSize={13}
|
||||
align="right"
|
||||
tracks={() => [{
|
||||
title: t.title,
|
||||
artist: page.artist.name,
|
||||
album: openAlbum?.title ?? null,
|
||||
duration_secs: t.duration_secs ?? null,
|
||||
trackId: t.id ?? null,
|
||||
artUrl: t.cover ?? openAlbum?.cover ?? null,
|
||||
}]}
|
||||
/>
|
||||
<button
|
||||
class="mini-btn play"
|
||||
title="Play"
|
||||
@@ -7633,6 +7660,11 @@
|
||||
}
|
||||
|
||||
.popular-row {
|
||||
/* The anchor the absolute row actions were always written against —
|
||||
without it the save button resolved against the page and its
|
||||
reveal rules never existed, so it was dead UI. The 24px last
|
||||
column is the space the overlaid actions land on. */
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 26px 40px minmax(130px, 1fr) minmax(100px, 0.75fr) 62px 40px 24px;
|
||||
align-items: center;
|
||||
@@ -7647,6 +7679,56 @@
|
||||
background: var(--bg-highlight);
|
||||
}
|
||||
|
||||
/* Hover slides the actions over the right end and the duration gets out
|
||||
of the way — the album page's treatment. The listener count stays: the
|
||||
list is ordered by it. */
|
||||
.popular-row :global(.plm) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 36px;
|
||||
transform: translateY(-50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.12s ease;
|
||||
}
|
||||
.popular-row :global(.plm-trigger) {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.popular-row :global(.plm-trigger:hover) {
|
||||
color: var(--accent-hover);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.popular-row:hover .mini-get,
|
||||
.popular-row:focus-within .mini-get,
|
||||
.popular-row:hover :global(.plm),
|
||||
.popular-row:focus-within :global(.plm) {
|
||||
opacity: 1;
|
||||
}
|
||||
.popular-row:hover .tdur,
|
||||
.popular-row:focus-within .tdur {
|
||||
/* pointer-events too: the faded duration is a stacking context and
|
||||
must never eat clicks meant for the buttons over it. */
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* While its menu is open the pointer is off in the portaled dropdown, so
|
||||
hover alone would drop the cluster mid-interaction. */
|
||||
.popular-row:has(:global(.plm-trigger[aria-expanded="true"])) :global(.plm),
|
||||
.popular-row:has(:global(.plm-trigger[aria-expanded="true"])) .mini-get {
|
||||
opacity: 1;
|
||||
}
|
||||
.popular-row:has(:global(.plm-trigger[aria-expanded="true"])) .tdur {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.popular-row:has(:global(.plm-trigger[aria-expanded="true"])) {
|
||||
background: var(--bg-highlight);
|
||||
}
|
||||
|
||||
.popular-row.now .rank,
|
||||
.popular-row.now .track-name {
|
||||
color: var(--accent-hover);
|
||||
@@ -8984,6 +9066,45 @@
|
||||
.trow:hover .tdur,
|
||||
.trow:focus-within .tdur {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Add-to-playlist joins the expander row's overlay pair, one slot left of
|
||||
Play; its menu is portaled, so hover alone would drop the cluster while
|
||||
the menu is open — the aria-expanded rules hold it. */
|
||||
.trow :global(.plm) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 64px;
|
||||
transform: translateY(-50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.12s ease;
|
||||
}
|
||||
.trow :global(.plm-trigger) {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.trow :global(.plm-trigger:hover) {
|
||||
color: var(--accent-hover);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.trow:hover :global(.plm),
|
||||
.trow:focus-within :global(.plm),
|
||||
.trow:has(:global(.plm-trigger[aria-expanded="true"])) :global(.plm),
|
||||
.trow:has(:global(.plm-trigger[aria-expanded="true"])) .mini-btn,
|
||||
.trow:has(:global(.plm-trigger[aria-expanded="true"])) .mini-get {
|
||||
opacity: 1;
|
||||
}
|
||||
.trow:has(:global(.plm-trigger[aria-expanded="true"])) .tdur {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.trow:has(:global(.plm-trigger[aria-expanded="true"])) {
|
||||
background: var(--bg-highlight);
|
||||
}
|
||||
|
||||
.trow.locked {
|
||||
|
||||
Reference in new issue
Block a user