feat: replace /archive with release-cardinal searchable browser (Phase 9 §8.H)
Retire the three-card overview for a search + medium + genre browser over all releases. Adds q/genre filter params to the api/release paged read path, mirroring the existing api/track/page TrackFilter pattern.
This commit is contained in:
@@ -1,31 +1,116 @@
|
||||
@page "/archive"
|
||||
@using DeepDrftModels.Enums
|
||||
|
||||
<PageTitle>DeepDrft Archive</PageTitle>
|
||||
|
||||
<div>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="archive-view-container">
|
||||
<div class="archive-grid">
|
||||
@foreach (var medium in _media)
|
||||
@* Search + filter affordances are interactive-only: the debounce timer and chip selection
|
||||
need WASM. During prerender/non-interactive they are hidden, matching TracksView's gate.
|
||||
The release grid still prerenders so the archive is meaningful before hydration. *@
|
||||
@if (RendererInfo.IsInteractive)
|
||||
{
|
||||
<div class="archive-search-row">
|
||||
<MudTextField T="string"
|
||||
Value="@SearchText"
|
||||
ValueChanged="@OnSearchInput"
|
||||
Immediate="true"
|
||||
DebounceInterval="400"
|
||||
Placeholder="Search releases or artists"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Clearable="true"
|
||||
Class="archive-search-field"/>
|
||||
</div>
|
||||
|
||||
<div class="archive-filter-row">
|
||||
<MudToggleGroup T="ReleaseMedium?"
|
||||
Value="@_selectedMedium"
|
||||
ValueChanged="@OnMediumSelected"
|
||||
SelectionMode="SelectionMode.SingleSelection"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small"
|
||||
Class="archive-medium-toggle">
|
||||
<MudToggleItem T="ReleaseMedium?" Value="@(null)">All</MudToggleItem>
|
||||
@foreach (var medium in _media)
|
||||
{
|
||||
<MudToggleItem T="ReleaseMedium?" Value="@medium">@MediumLabel(medium)</MudToggleItem>
|
||||
}
|
||||
</MudToggleGroup>
|
||||
</div>
|
||||
|
||||
@if (_genres.Count > 0)
|
||||
{
|
||||
<a href="@medium.Route" class="archive-card-link">
|
||||
<div class="archive-card">
|
||||
<MudIcon Icon="@medium.Icon" Class="archive-card-icon" />
|
||||
<MudText Typo="Typo.h5" Class="archive-card-title">@medium.Title</MudText>
|
||||
<MudText Typo="Typo.body2" Class="archive-card-blurb">@medium.Blurb</MudText>
|
||||
</div>
|
||||
</a>
|
||||
<div class="archive-filter-row">
|
||||
<MudChipSet T="string"
|
||||
SelectedValue="@_selectedGenre"
|
||||
SelectedValueChanged="@OnGenreSelected"
|
||||
SelectionMode="SelectionMode.ToggleSelection"
|
||||
Class="archive-genre-chips">
|
||||
@foreach (var genre in _genres)
|
||||
{
|
||||
<MudChip T="string" Value="@genre.Genre">@genre.Genre</MudChip>
|
||||
}
|
||||
</MudChipSet>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (_loading)
|
||||
{
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var _ in Enumerable.Range(0, 8))
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4" lg="3" xl="3">
|
||||
<div class="archive-card-center">
|
||||
<MudSkeleton Width="200px" Height="200px" SkeletonType="SkeletonType.Rectangle"/>
|
||||
</div>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
else if (_releases.Count == 0)
|
||||
{
|
||||
<div class="archive-empty">
|
||||
<MudText Typo="Typo.h6">No releases found</MudText>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var release in _releases)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4" lg="3" xl="3">
|
||||
<div class="archive-card-center">
|
||||
<a href="@DetailHref(release)" class="archive-card-link">
|
||||
<div class="archive-release-card">
|
||||
@if (!string.IsNullOrEmpty(release.ImagePath))
|
||||
{
|
||||
<div class="archive-release-cover"
|
||||
style="background-image: url('api/image/@Uri.EscapeDataString(release.ImagePath)');">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="archive-release-cover archive-release-cover--fallback"></div>
|
||||
}
|
||||
|
||||
<div class="archive-release-body">
|
||||
<MudText Typo="Typo.subtitle1" Class="archive-release-title text-truncate">
|
||||
@release.Title
|
||||
</MudText>
|
||||
<MudText Typo="Typo.caption" Class="archive-release-artist text-truncate">
|
||||
@release.Artist
|
||||
</MudText>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
</MudContainer>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private record MediumCard(string Title, string Blurb, string Route, string Icon);
|
||||
|
||||
private static readonly MediumCard[] _media =
|
||||
[
|
||||
new("Cuts", "Studio recordings — singles, EPs, and albums.", "/cuts", Icons.Material.Filled.Album),
|
||||
new("Sessions", "Single live takes, each with its own hero image.", "/sessions", Icons.Material.Filled.Piano),
|
||||
new("Mixes", "Long-form continuous mixes with high-resolution waveforms.", "/mixes", Icons.Material.Filled.GraphicEq),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user