feat(cms): Release Archive medium tab strip (ALL · CUTS · SESSIONS · MIXES), retire navigate-away cards

Replace the navigate-away ReleaseArchiveBrowser cards and the redundant top-level Releases
toggle with an in-page MudTabs strip under the Releases mode: ALL (CmsAllReleasesGrid) plus
one enum-driven tab per ReleaseMedium. Sessions/Mixes browsers gain an Embedded flag that
suppresses standalone page chrome when hosted as tab content; CmsCutBrowser is the new
Cut-filtered grid. /tracks/sessions, /tracks/mixes, /tracks/archive stay reachable by URL.
This commit is contained in:
daniel-c-harvey
2026-06-13 22:02:28 -04:00
parent 3f1230fd2d
commit 20084ace4f
7 changed files with 179 additions and 124 deletions
@@ -5,25 +5,58 @@
@attribute [Authorize]
@inject ILogger<CmsMixBrowser> Logger
<PageTitle>Mixes — DeepDrft CMS</PageTitle>
@* Embedded as the MIXES tab content of the Release Archive (Phase 9 §8.A), and still routable at
/tracks/mixes for direct-URL access. When embedded, the page chrome (title, container, the now-
meaningless "Back to Release Archive" button) is suppressed — the host tab strip owns that frame; only
the grid renders. The standalone route keeps the full page chrome. The per-row waveform affordance
(9.5.E) is preserved in both contexts. *@
@if (Embedded)
{
@GridContent
}
else
{
<PageTitle>Mixes — DeepDrft CMS</PageTitle>
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
<MudButton Variant="Variant.Text"
StartIcon="@Icons.Material.Filled.ArrowBack"
Href="/tracks/archive"
Class="mb-4">
Back to Release Archive
</MudButton>
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
<MudButton Variant="Variant.Text"
StartIcon="@Icons.Material.Filled.ArrowBack"
Href="/tracks/archive"
Class="mb-4">
Back to Release Archive
</MudButton>
<MudText Typo="Typo.h4" GutterBottom="true">Mixes</MudText>
<MudText Typo="Typo.h4" GutterBottom="true">Mixes</MudText>
<CmsMediumTable TRow="MixRow"
Rows="Rows"
Loading="Loading"
ReleaseAccessor="@(row => row.Release)"
ThumbUrl="@(key => ThumbUrl(key))"
TitleHeader="Mix"
EmptyMessage="No mixes found.">
@GridContent
</MudContainer>
}
@code {
/// <summary>
/// True when rendered as tab content inside the Release Archive; suppresses the standalone page
/// chrome (title, container, back button). False (default) renders the full routable page.
/// </summary>
[Parameter] public bool Embedded { get; set; }
protected override ReleaseMedium Medium => ReleaseMedium.Mix;
protected override string MediumNoun => "mixes";
protected override MixRow ToRow(ReleaseDto release) => new()
{
Release = release,
HasWaveform = !string.IsNullOrEmpty(release.MixMetadata?.WaveformEntryKey)
};
// The grid itself — identical in the embedded and standalone contexts. Defined once as a fragment so
// both branches above render the same markup without duplication.
private RenderFragment GridContent => @<CmsMediumTable TRow="MixRow"
Rows="Rows"
Loading="Loading"
ReleaseAccessor="@(row => row.Release)"
ThumbUrl="@(key => ThumbUrl(key))"
TitleHeader="Mix"
EmptyMessage="No mixes found.">
<ActionContent Context="row">
@if (row.HasWaveform)
{
@@ -53,18 +86,7 @@
}
</MudButton>
</ActionContent>
</CmsMediumTable>
</MudContainer>
@code {
protected override ReleaseMedium Medium => ReleaseMedium.Mix;
protected override string MediumNoun => "mixes";
protected override MixRow ToRow(ReleaseDto release) => new()
{
Release = release,
HasWaveform = !string.IsNullOrEmpty(release.MixMetadata?.WaveformEntryKey)
};
</CmsMediumTable>;
private async Task GenerateWaveformAsync(MixRow row)
{