feat(mix-detail): extract shared ReleaseHeroOverlay; Mix cover becomes overlaid 600px square hero (Direction B)
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
@namespace DeepDrftPublic.Client.Controls
|
||||
|
||||
@* Shared background-image hero with all release metadata overlaid: top row (genre/date + share),
|
||||
bottom row (optional cover thumb + title/artist + play). Single source of truth for the overlay
|
||||
composition consumed by both Session and Mix detail. Purely presentational — owns no data fetch
|
||||
and no player wiring; play/share ride in as slots so each page keeps its own toggle. Per-page
|
||||
aspect/sizing variance rides the Class parameter (e.g. Mix's square `mix-hero`), never a fork. *@
|
||||
|
||||
@{
|
||||
var hasGenre = !string.IsNullOrEmpty(Genre);
|
||||
var hasDate = ReleaseDate is not null;
|
||||
// Show the cover thumbnail only when it differs from the hero background — otherwise it would
|
||||
// duplicate the same image. Mix passes CoverThumbKey=null, so this is false there for free.
|
||||
var showCover = !string.IsNullOrEmpty(CoverThumbKey) && CoverThumbKey != HeroImageKey;
|
||||
}
|
||||
|
||||
@* The hero is the positioning context for every overlay row; the gradient shim and the
|
||||
top/bottom overlays are absolutely positioned children of this wrapper. *@
|
||||
<div class="release-hero @Class">
|
||||
@if (!string.IsNullOrEmpty(HeroImageKey))
|
||||
{
|
||||
<div class="release-hero-img"
|
||||
style="@($"background-image: url('api/image/{Uri.EscapeDataString(HeroImageKey)}');")"></div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="release-hero-placeholder deepdrft-gradient-soft-secondary">
|
||||
<MudIcon Icon="@PlaceholderIcon" Color="Color.Primary" />
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Darkening shim so overlaid text/controls stay legible over any image. *@
|
||||
<div class="release-hero-shim"></div>
|
||||
|
||||
@* Top overlay: secondary details (genre, release date) and the share affordance. *@
|
||||
<div class="release-hero-top">
|
||||
<MudStack Row AlignItems="AlignItems.Center" Spacing="3" Class="release-hero-meta">
|
||||
@if (hasGenre)
|
||||
{
|
||||
<MudChip T="string" Variant="Variant.Outlined" Class="release-overlay-chip">
|
||||
@Genre
|
||||
</MudChip>
|
||||
}
|
||||
@if (hasDate)
|
||||
{
|
||||
<div class="release-overlay-date">
|
||||
<span class="release-overlay-label">Released</span>
|
||||
<span class="release-overlay-value">@ReleaseDate!.Value.ToString("MMMM yyyy")</span>
|
||||
</div>
|
||||
}
|
||||
</MudStack>
|
||||
@if (ShareContent is not null)
|
||||
{
|
||||
<div class="release-hero-share">
|
||||
@ShareContent
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@* Bottom overlay: cover thumbnail, title/artist, and the play affordance in one row. *@
|
||||
<div class="release-hero-bottom">
|
||||
<MudStack Row AlignItems="AlignItems.Center" Spacing="4" Class="release-hero-bottom-row">
|
||||
@if (showCover)
|
||||
{
|
||||
<div class="release-cover-thumb">
|
||||
<div class="deepdrft-track-detail-cover-art"
|
||||
style="@($"background-image: url('api/image/{Uri.EscapeDataString(CoverThumbKey!)}');")"></div>
|
||||
</div>
|
||||
}
|
||||
<div class="release-hero-titles">
|
||||
<div class="release-overlay-title">@Title</div>
|
||||
<div class="release-overlay-artist">@Artist</div>
|
||||
</div>
|
||||
@if (PlayContent is not null)
|
||||
{
|
||||
<div class="release-hero-play">
|
||||
@PlayContent
|
||||
</div>
|
||||
}
|
||||
</MudStack>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
/// <summary>Background image entry key. Null renders the placeholder treatment.</summary>
|
||||
[Parameter] public string? HeroImageKey { get; set; }
|
||||
|
||||
/// <summary>Material icon for the no-image placeholder (Session: Piano; Mix: Album).</summary>
|
||||
[Parameter] public required string PlaceholderIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional small cover thumbnail in the bottom row. Shown only when it differs from
|
||||
/// <see cref="HeroImageKey"/> (otherwise it would duplicate the background). Mix passes null.
|
||||
/// </summary>
|
||||
[Parameter] public string? CoverThumbKey { get; set; }
|
||||
|
||||
[Parameter] public required string Title { get; set; }
|
||||
[Parameter] public string? Artist { get; set; }
|
||||
[Parameter] public string? Genre { get; set; }
|
||||
[Parameter] public DateOnly? ReleaseDate { get; set; }
|
||||
|
||||
/// <summary>Share affordance slot — each page passes its own SharePopover with the right params.</summary>
|
||||
[Parameter] public RenderFragment? ShareContent { get; set; }
|
||||
|
||||
/// <summary>Play affordance slot — each page passes its PlayStateIcon wired to its own toggle.</summary>
|
||||
[Parameter] public RenderFragment? PlayContent { get; set; }
|
||||
|
||||
/// <summary>Extra class for per-page aspect/sizing variance (e.g. Mix's square `mix-hero`).</summary>
|
||||
[Parameter] public string? Class { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user