Move NowPlaying waveform visualizer to full-bleed hero-right background

Lift the WaveformVisualizer + control popover out of the 120px NowPlayingCard box into NowPlaying as a full-panel background layer; migrate the hero-right wrapper and its scoped styles from Home into NowPlaying.
This commit is contained in:
daniel-c-harvey
2026-06-17 13:06:48 -04:00
parent 0dce46bcab
commit 528f09d96a
6 changed files with 77 additions and 64 deletions
@@ -1,11 +1,42 @@
@* Pulsing rings *@
<div class="circle-deco"></div>
<div class="circle-deco"></div>
<div class="circle-deco"></div>
@using DeepDrftPublic.Client.Services
<div class="now-playing-content">
<NowPlayingCard />
@* Hero-right panel (owns the navy backdrop + clipping, formerly Home.razor's .hero-right wrapper). *@
<div class="now-playing-panel">
@* Full-bleed waveform background. The visualizer mounts with Fill="true" (position:absolute; inset:0),
so .np-visualizer-bg is the positioned, sized ancestor that lets the lava fill the whole hero-right
panel. Driven by the live cascaded player — keyed on the current track via ReleaseEntryKey/TrackId/
TrackEntryKey so it scrolls to the real signal and sits at-rest when nothing plays. Read-only: the
background visualizes, it never seeks. Sits behind the rings + content (z-order via stacking below). *@
<div class="np-visualizer-bg">
<WaveformVisualizer Fill="true"
ReleaseEntryKey="@(Player?.CurrentTrack?.Release?.EntryKey ?? string.Empty)"
TrackId="@Player?.CurrentTrack?.Id"
TrackEntryKey="@Player?.CurrentTrack?.EntryKey" />
</div>
@* Stat row - hard-coded for now. TODO Phase 2: wire to real track count / identity model. *@
<NowPlayingStats />
</div>
@* The lava-lamp popover trigger lands in the panel's top-right corner (full parity, §8e). Above the
canvas and pointer-enabled so the icon is clickable even though the visualizer layer is
pointer-events:none. *@
<div class="np-visualizer-controls">
<WaveformVisualizerControlPopover IconSize="Size.Small"
AnchorOrigin="Origin.BottomRight"
TransformOrigin="Origin.TopLeft" />
</div>
@* Pulsing rings *@
<div class="circle-deco"></div>
<div class="circle-deco"></div>
<div class="circle-deco"></div>
<div class="now-playing-content">
<NowPlayingCard />
@* Stat row - hard-coded for now. TODO Phase 2: wire to real track count / identity model. *@
<NowPlayingStats />
</div>
</div>
@code {
[CascadingParameter] public IStreamingPlayerService? Player { get; set; }
}
@@ -3,6 +3,41 @@
50% { opacity: 0.4; transform: translate(-50%, -50%) scale(1.03); }
}
/* Hero-right panel (migrated from Home.razor's .hero-right). Owns the navy backdrop, clips the
full-bleed visualizer + ring overflow, and is the positioned ancestor for the inset:0 layers. */
.now-playing-panel {
background: var(--deepdrft-navy);
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
height: 100%;
}
@media (max-width: 960px) {
.now-playing-panel { min-height: 50vh; }
}
/* Full-bleed waveform background. WaveformVisualizer Fill="true" renders its layer as
position:absolute; inset:0, so this box only needs to be a positioned, sized ancestor. z-index:0
pins it to the bottom of the panel's stacking order, beneath the rings and the now-playing-content. */
.np-visualizer-bg {
position: absolute;
inset: 0;
z-index: 0;
}
/* The lava-lamp popover trigger overlays the panel's top-right corner (full parity, §8e). Above the
canvas (z-index) and pointer-enabled so the icon is clickable even though the visualizer layer below
it is pointer-events:none. */
.np-visualizer-controls {
position: absolute;
top: 1rem;
right: 1rem;
z-index: 3;
}
.now-playing-content {
position: relative;
z-index: 2;
@@ -22,4 +57,4 @@
.circle-deco:nth-child(1) { width: 320px; height: 320px; animation-delay: 0s; }
.circle-deco:nth-child(2) { width: 520px; height: 520px; animation-delay: 0.8s; }
.circle-deco:nth-child(3) { width: 720px; height: 720px; animation-delay: 1.6s; }
.circle-deco:nth-child(3) { width: 720px; height: 720px; animation-delay: 1.6s; }
@@ -7,23 +7,6 @@
? $"{Player.CurrentTrack.Release?.Artist} · {Player.CurrentTrack.Release?.Title ?? "Single"}"
: "Select a track to begin")
</div>
@* Mode C (§3f, §6c): the real waveform visualizer, contained to this card and driven by the live
cascaded player. Fill="true" sizes the canvas to this positioned box instead of the viewport.
The bridge follows whatever is playing — keyed on the current track via ReleaseEntryKey/TrackId/
TrackEntryKey — so it scrolls to the real signal and sits at-rest when nothing plays. Read-only:
the card visualizes, it never seeks. The lava-lamp popover sits in the corner (full parity, §8e). *@
<div class="np-visualizer">
<WaveformVisualizer Fill="true"
ReleaseEntryKey="@(Player?.CurrentTrack?.Release?.EntryKey ?? string.Empty)"
TrackId="@Player?.CurrentTrack?.Id"
TrackEntryKey="@Player?.CurrentTrack?.EntryKey" />
<div class="np-visualizer-controls">
<WaveformVisualizerControlPopover IconSize="Size.Small"
AnchorOrigin="Origin.BottomRight"
TransformOrigin="Origin.TopLeft" />
</div>
</div>
</div>
@@ -45,26 +45,3 @@
color: rgba(250, 250, 248, 0.45);
letter-spacing: 0.08em;
}
/* Contained visualizer region (Phase 12 mode C). The visualizer mounts with Fill="true", whose
layer is `position: absolute; inset: 0` — so this box must be a positioned, sized ancestor for the
canvas to fill. `overflow: hidden` keeps the lava inside the card's rounded chrome. The height is the
card's bounded live readout — taller than the old synthetic-bar strip so the real waveform reads, but
still compact for a home-page hero panel. */
.np-visualizer {
position: relative;
height: 120px;
margin-top: 1.2rem;
overflow: hidden;
border-radius: 2px;
}
/* The lava-lamp popover trigger overlays the visualizer's top-right corner (full parity, §8e). Above
the canvas (z-index) and pointer-enabled so the icon is clickable even though the canvas layer below
it is pointer-events:none. */
.np-visualizer-controls {
position: absolute;
top: 0.25rem;
right: 0.25rem;
z-index: 1;
}
+1 -3
View File
@@ -14,9 +14,7 @@
</MudItem>
<MudItem xs="12" md="6">
<div class="hero-right">
<NowPlaying />
</div>
<NowPlaying />
</MudItem>
</MudGrid>
<ParallaxImage Image1="img/dd-duo-hero-bw.jpeg"
@@ -19,20 +19,9 @@
height: 100%;
}
.hero-right {
background: var(--deepdrft-navy);
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
height: 100%;
}
@media (max-width: 960px) {
.hero { min-height: auto; }
.hero-left { padding: 4rem 1.5rem 3rem; }
.hero-right { min-height: 50vh; }
}
/* ── DIVIDER ── */