feat: add CmsGenreBrowser genre browse mode to CMS track list

fix: add @key="ExpandedGenre" to CmsTrackGrid so genre switch forces fresh component instance
This commit is contained in:
daniel-c-harvey
2026-06-11 16:42:46 -04:00
parent 55b26b2e41
commit b22c3f96d7
3 changed files with 72 additions and 1 deletions
@@ -0,0 +1,52 @@
@using DeepDrftModels.DTOs
@if (IsLoading)
{
<MudProgressCircular Indeterminate="true" Class="mt-4" />
}
else if (Genres.Count == 0)
{
<MudText Typo="Typo.body1" Class="mt-4">No genres found.</MudText>
}
else
{
<MudGrid Spacing="3" Class="mt-2">
@foreach (var genre in Genres)
{
var isExpanded = ExpandedGenre == genre.Genre;
<MudItem xs="12" sm="6" md="4">
<MudCard Elevation="@(isExpanded ? 4 : 1)"
Style="cursor: pointer;"
@onclick="@(() => ToggleGenre(genre.Genre))">
<div class="@SwatchClass(isExpanded)"></div>
<MudCardContent>
<MudText Typo="Typo.h6">@genre.Genre</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary">@genre.TrackCount track(s)</MudText>
</MudCardContent>
</MudCard>
</MudItem>
}
</MudGrid>
@if (ExpandedGenre is not null)
{
<MudDivider Class="my-4" />
<MudText Typo="Typo.h6" Class="mb-2">@ExpandedGenre</MudText>
<CmsTrackGrid @key="ExpandedGenre" GenreFilter="ExpandedGenre" ShowAddButton="false" />
}
}
@code {
[Parameter] public IReadOnlyList<GenreSummaryDto> Genres { get; set; } = Array.Empty<GenreSummaryDto>();
[Parameter] public bool IsLoading { get; set; }
[Parameter] public string? ExpandedGenre { get; set; }
[Parameter] public EventCallback<string?> OnExpandedGenreChanged { get; set; }
// The view model owns the toggle (selecting the open genre collapses it), so we pass the raw
// clicked genre rather than pre-computing the next state here — keeps the toggle logic single-sourced.
private async Task ToggleGenre(string genre) =>
await OnExpandedGenreChanged.InvokeAsync(genre);
private static string SwatchClass(bool isExpanded) =>
isExpanded ? "cms-genre-swatch cms-genre-swatch--active" : "cms-genre-swatch";
}
@@ -0,0 +1,10 @@
.cms-genre-swatch {
width: 100%;
height: 80px;
background-color: var(--mud-palette-action-default-hover);
transition: background-color 0.2s ease;
}
.cms-genre-swatch--active {
background-color: var(--mud-palette-primary-hover);
}
@@ -57,7 +57,10 @@
}
else
{
<MudAlert Severity="Severity.Info" Class="mt-4">Genre browser — coming in the next wave.</MudAlert>
<CmsGenreBrowser Genres="VM.Genres"
IsLoading="VM.GenresLoading"
ExpandedGenre="VM.ExpandedGenre"
OnExpandedGenreChanged="OnExpandedGenreChanged" />
}
</MudContainer>
@@ -93,6 +96,12 @@
StateHasChanged();
}
private void OnExpandedGenreChanged(string? genre)
{
VM.SetExpandedGenre(genre);
StateHasChanged();
}
/// <summary>
/// Backfill every track missing a waveform profile, one request at a time so a large backfill
/// does not flood the API with concurrent WAV decodes. On completion, refreshes the grid's