}
else if (ViewModel.NotFound || ViewModel.Release is null)
{
Mix not found.
All mixes
}
else
{
var release = ViewModel.Release;
@* Full-page waveform sits behind the scaffold content. The scaffold's container is positioned
above it via the mix-detail-foreground stacking context. TrackId lets the visualizer couple to
playback only when the player is on this mix's track; TrackEntryKey is the datum to render at rest
(before playback) — the mix's single track, so the lava shows immediately on page load (§4). *@
@* Mix keeps the scaffold solely for the Phase 10 top row (back link | controls | lava-lamp).
Title/artist/genre/date/share/play all move into the overlaid hero, so the scaffold's
default header and meta regions are suppressed (ShowHeader/ShowMeta=false) and the share
row stays off (ShowShareRow=false). *@
@* Theater toggle sits immediately LEFT of the lava-lamp popover (Phase 20 §3). Both stay
visible in Theater Mode — controls over the experience, not release content (§4/OQ4).
Wrapped so they cluster on the right rather than spreading across the SpaceBetween row. *@
@* Theater toggle only appears when this Mix is the currently-playing release
(Phase 20 Wave 2 §3). ShowTheaterToggle folds in the subsystem + release-playing gate. *@
@* Lava-lamp icon → popover panel, top-right across from the back link (Phase 12
§3d-revised). Replaces the former inline TopContent knob-bar: the icon IS the toggle
and the popover IS the panel. Mix takes the cleanest anchor case (§8e) — the popover's
default bottom-right anchor opens down over the full-bleed field. *@
@* Theater Mode (Phase 20 §4, Wave 2 §2): the hero overlay stays mounted and eases out via
a collapsing wrapper so it does not pop — collapsed to zero height when Theater is on AND
this Mix is the playing release. OFF eases the full-bleed visualizer back behind the hero. *@
@* Cover-as-background hero with all metadata overlaid, square `mix-hero` sizing. The
cover art IS the background, so no separate cover thumbnail (CoverThumbKey defaults
to null). Share and play ride in as slots, matching Sessions. *@
@* Release-mode share: copies the canonical /mixes/{entryKey} URL, not a single track (§3b). *@
@if (ViewModel.Track is not null)
{
@* Append-only: queues the mix's single track without starting playback. *@
}
@* Blurb sits below the hero, inside the scaffold's foreground stacking context. *@
}
@code {
protected override string PersistKey => "mix-detail";
// PlayerService is cascaded by ReleaseDetailBase (used there for the Theater release-playing predicate).
[CascadingParameter] public IQueueService? Queue { get; set; }
// The hero now carries the play affordance (the scaffold's header is suppressed), so the
// play-toggle is wired here directly — mirroring SessionDetail. Toggle if this track is already
// active, otherwise PLAY it: prepend to the queue's front (deque PLAY semantics) so it becomes
// current and the existing queue stays intact behind it. Falls back to a direct stream when the
// queue cascade is absent (prerender / non-interactive).
private async Task PlayTrack()
{
var track = ViewModel.Track;
if (track is null || PlayerService is null) return;
var isThisTrack = PlayerService.CurrentTrack?.Id == track.Id;
if (isThisTrack && (PlayerService.IsPlaying || PlayerService.IsPaused))
{
await PlayerService.TogglePlayPause();
}
else if (Queue is not null)
{
await Queue.PlayTrack(track);
}
else
{
await PlayerService.SelectTrackStreaming(track);
}
}
}