100 lines
4.7 KiB
Plaintext
100 lines
4.7 KiB
Plaintext
@namespace DeepDrftPublic.Client.Controls
|
|
|
|
@* The single release-card grid for every browse surface (Sessions, Mixes, Cuts, Archive). Cards
|
|
open a detail page; how a card computes its href is the only real divergence across surfaces, so
|
|
the parent supplies it one of two ways:
|
|
- DetailRoute (the simple default): every card links /{DetailRoute}/{id} (Sessions, Mixes).
|
|
- HrefResolver (per-card): each card links HrefResolver(release), so Archive routes each card by
|
|
its own medium through the one ReleaseRoutes table, and Cuts routes to /cuts/{entryKey}.
|
|
HrefResolver wins when both are supplied. The card subtitle defaults to the artist; SubtitleResolver
|
|
overrides it (Cuts shows a track count instead). Fully controlled by the parent: loading and item
|
|
state are passed in. *@
|
|
|
|
<div>
|
|
<MudContainer MaxWidth="MaxWidth.Large" Class="release-gallery-container">
|
|
@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="release-card-center">
|
|
<MudSkeleton Width="200px" Height="200px" SkeletonType="SkeletonType.Rectangle"/>
|
|
</div>
|
|
</MudItem>
|
|
}
|
|
</MudGrid>
|
|
}
|
|
else if (Releases.Count == 0)
|
|
{
|
|
<div class="release-gallery-empty">
|
|
<MudText Typo="Typo.h6">@EmptyMessage</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="release-card-center">
|
|
<a href="@CardHref(release)" class="release-card-link">
|
|
<div class="release-card">
|
|
@if (!string.IsNullOrEmpty(release.ImagePath))
|
|
{
|
|
<div class="release-card-cover"
|
|
style="background-image: url('api/image/@Uri.EscapeDataString(release.ImagePath)');">
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="release-card-cover release-card-cover--fallback"></div>
|
|
}
|
|
|
|
<div class="release-card-body">
|
|
<MudText Typo="Typo.subtitle1" Class="release-card-title text-truncate">
|
|
@release.Title
|
|
</MudText>
|
|
<MudText Typo="Typo.caption" Class="release-card-artist text-truncate">
|
|
@(SubtitleResolver?.Invoke(release) ?? release.Artist)
|
|
</MudText>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</MudItem>
|
|
}
|
|
</MudGrid>
|
|
}
|
|
</MudContainer>
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter] public required IReadOnlyList<DeepDrftModels.DTOs.ReleaseDto> Releases { get; set; }
|
|
[Parameter] public bool Loading { get; set; }
|
|
|
|
/// <summary>
|
|
/// Route segment for a card's detail page; a card links to /{DetailRoute}/{id}. The simple
|
|
/// fixed-route default used by Sessions/Mixes. Ignored when <see cref="HrefResolver"/> is supplied.
|
|
/// </summary>
|
|
[Parameter] public string? DetailRoute { get; set; }
|
|
|
|
/// <summary>
|
|
/// Per-card href resolver. When supplied, a card links to its result instead of the
|
|
/// <see cref="DetailRoute"/>-based href, letting Archive route each card by its own medium and
|
|
/// Cuts route to /cuts/{entryKey} (both via <c>ReleaseRoutes.DetailHref</c>).
|
|
/// </summary>
|
|
[Parameter] public Func<DeepDrftModels.DTOs.ReleaseDto, string>? HrefResolver { get; set; }
|
|
|
|
/// <summary>
|
|
/// Optional override for a card's subtitle line (defaults to the release artist). Cuts pass a
|
|
/// track-count label here.
|
|
/// </summary>
|
|
[Parameter] public Func<DeepDrftModels.DTOs.ReleaseDto, string>? SubtitleResolver { get; set; }
|
|
|
|
[Parameter] public string EmptyMessage { get; set; } = "Nothing here yet";
|
|
|
|
private string CardHref(DeepDrftModels.DTOs.ReleaseDto release)
|
|
=> HrefResolver?.Invoke(release) ?? $"/{DetailRoute}/{release.EntryKey}";
|
|
}
|