@page "/cuts/{EntryKey}" @using DeepDrftModels.DTOs @using DeepDrftPublic.Client.Controls @using DeepDrftPublic.Client.Services @inherits CutDetailBase @(ViewModel.Release?.Title ?? "Cut") - DeepDrft @if (ViewModel.IsLoading) {
} else if (ViewModel.NotFound || ViewModel.Release is null) {
Cut not found.
All cuts
} else { var release = ViewModel.Release; var hasGenre = release.Genre is not null; var hasYear = release.ReleaseDate is not null; var firstTrack = ViewModel.Tracks.Count > 0 ? ViewModel.Tracks[0] : null; @* Ambient living waveform behind the album hero + track list (Phase 12 §3c/§3f mode B). Cut is multi-track: anchor to the release's EntryKey and default to the first track by TrackNumber. The bridge follows the live playing track within the release automatically (keys on TrackId match OR shared ReleaseEntryKey), so the field re-renders to whichever track the listener starts; TrackEntryKey is the at-rest datum before playback. *@ @* Lava-lamp icon → popover panel (full parity, §3d-revised). Sits top-right across from the back link, clear of the header's own Play/Share affordances below. *@
@* Header split: meta + Play/Share on the LEFT, bordered cover on the RIGHT (spec §3.1). *@
@release.Title @release.Artist @if (hasGenre || hasYear) {
@if (hasGenre) { @release.Genre } @if (hasGenre && hasYear) { · } @if (hasYear) { @release.ReleaseDate!.Value.Year }
}
@* Header Play loads the full album into the queue at index 0 (§3.4 seam, closed P11 W1). Disabled until at least one streamable track is resolved. *@ Play @* Append the whole album (TrackNumber order) to the queue — same ordered list header Play uses. Append-only: does not start playback (AC7/AC8). *@ @* Release-mode share: copies the canonical /cuts/{entryKey} URL, not a single track (§3b). *@
@if (!string.IsNullOrEmpty(release.ImagePath)) { } else { }
@* Blurb sits between the header and the track-list divider. *@ @if (ViewModel.Tracks.Count == 0) { No tracks in this cut yet. } else {
@for (var i = 0; i < ViewModel.Tracks.Count; i++) { var track = ViewModel.Tracks[i]; var index = i;
@track.TrackNumber
@track.TrackName @* Append this single track to the queue (append-only, does not play). *@
}
}
} @code { [CascadingParameter] public IStreamingPlayerService? PlayerService { get; set; } [CascadingParameter] public IQueueService? Queue { get; set; } // Header Play: load the full album into the queue starting at track 0. private Task PlayAlbum() { if (ViewModel.Tracks.Count == 0) return Task.CompletedTask; if (Queue is not null) return Queue.PlayRelease(ViewModel.Tracks, 0); // Queue cascade absent (prerender or non-interactive): fall back to direct single-track play. return PlayerService is not null ? PlayerService.SelectTrackStreaming(ViewModel.Tracks[0]) : Task.CompletedTask; } // Row play: toggle if this track is already playing/paused, otherwise load the album at this // row's index so playback continues to the end from the chosen track. private async Task PlayTrack(TrackDto track, int index) { if (PlayerService is null) return; var isThisTrack = PlayerService.CurrentTrack?.Id == track.Id; if (isThisTrack && (PlayerService.IsPlaying || PlayerService.IsPaused)) { await PlayerService.TogglePlayPause(); return; } if (Queue is not null) { await Queue.PlayRelease(ViewModel.Tracks, index); } else { // Queue cascade absent: fall back to direct single-track play. await PlayerService.SelectTrackStreaming(track); } } }