feat(player): docked queue overlay with reorder, remove, jump, and clear-upcoming
Add a Queue toggle to the docked player bar opening a centered editable queue overlay. New additive QueueService.ClearUpcoming keeps the playing track while dropping the rest. Current track is non-removable.
This commit is contained in:
@@ -750,3 +750,158 @@ body:has(.waveform-visualizer-control-overlay) {
|
||||
color: var(--mud-palette-text-primary);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
QUEUE OVERLAY + LIST (Phase 17 wave 17.2 — docked queue panel)
|
||||
|
||||
The overlay is a direct lift of the visualizer-control modal (Phase 15 §4): a centered MudOverlay
|
||||
whose scrim tint + z-index + body-scroll lock match that idiom exactly. The panel chrome (square
|
||||
corners, lighter-navy ground, thin light border) is the NowPlayingCard treatment (§5). MudOverlay
|
||||
portals out of the component subtree to the body, so these are plain GLOBAL rules — CSS isolation
|
||||
cannot reach portaled content.
|
||||
============================================================================= */
|
||||
|
||||
/* Raise the overlay above the sticky header (100), the fixed player dock (1200), and the minimized
|
||||
FAB (1300) — same stacking decision as the visualizer overlay so the scrim tints the whole viewport. */
|
||||
.deepdrft-queue-overlay {
|
||||
z-index: 1400 !important;
|
||||
}
|
||||
|
||||
/* Mild modal tint from the shared scrim token. The doubled selector (0,2,0) outranks MudBlazor's own
|
||||
.mud-overlay-dark (0,1,0) regardless of stylesheet load order. */
|
||||
.deepdrft-queue-overlay .mud-overlay-scrim.mud-overlay-dark {
|
||||
background-color: rgba(var(--deepdrft-scrim-rgb), var(--deepdrft-modal-scrim-alpha));
|
||||
}
|
||||
|
||||
.deepdrft-queue-overlay .mud-overlay-content {
|
||||
max-height: 90vh;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Lock body scroll while the queue overlay is open (matches the visualizer overlay). */
|
||||
body:has(.deepdrft-queue-overlay) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* The mostly-square panel (§3.2: min(90vw, 520px)). NowPlayingCard chrome: square corners, lighter-navy
|
||||
ground, thin light border. Internal column: fixed header over a scrollable list body. */
|
||||
.deepdrft-queue-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(90vw, 520px);
|
||||
height: min(90vw, 520px);
|
||||
max-height: 90vh;
|
||||
background: var(--deepdrft-panel-ground);
|
||||
border: 1px solid var(--deepdrft-border-light);
|
||||
border-radius: 0;
|
||||
backdrop-filter: blur(8px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.deepdrft-queue-modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.85rem 1rem;
|
||||
border-bottom: 1px solid var(--deepdrft-border-light);
|
||||
}
|
||||
|
||||
/* Mono uppercase eyebrow — the NowPlayingCard .np-label typography, recoloured light (static). */
|
||||
.deepdrft-queue-modal-title {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
color: var(--deepdrft-white);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.deepdrft-queue-modal-body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* ── The list itself (consumed by QueueList in both modes; styled here once). ── */
|
||||
.deepdrft-queue-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.deepdrft-queue-zone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.deepdrft-queue-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.45rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
color: var(--deepdrft-white);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.deepdrft-queue-row:hover {
|
||||
background: color-mix(in srgb, var(--deepdrft-white) 6%, transparent);
|
||||
}
|
||||
|
||||
/* Current track: a subtle green wash + left accent, matching the green = active principle. */
|
||||
.deepdrft-queue-row-current {
|
||||
background: color-mix(in srgb, var(--deepdrft-green-accent) 14%, transparent);
|
||||
box-shadow: inset 2px 0 0 0 var(--deepdrft-green-accent);
|
||||
}
|
||||
|
||||
.deepdrft-queue-drag-handle {
|
||||
cursor: grab;
|
||||
opacity: 0.45;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.deepdrft-queue-position {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.72rem;
|
||||
opacity: 0.6;
|
||||
min-width: 1.4rem;
|
||||
text-align: right;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* Row body grows + truncates; clicking it jumps playback (OQ2). */
|
||||
.deepdrft-queue-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.deepdrft-queue-title {
|
||||
font-size: 0.92rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.deepdrft-queue-artist {
|
||||
font-size: 0.74rem;
|
||||
opacity: 0.6;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.deepdrft-queue-nowplaying,
|
||||
.deepdrft-queue-remove {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* Active (open) state for the bar's Queue toggle — a soft green chip behind the glyph, matching the
|
||||
visualizer toggle's on-state idiom. */
|
||||
.deepdrft-queue-toggle-active {
|
||||
background: color-mix(in srgb, var(--deepdrft-green-accent) 22%, transparent);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user