chore: Move TrackCard & Friends
This commit is contained in:
@@ -1,109 +0,0 @@
|
||||
@{
|
||||
var hasLink = !string.IsNullOrEmpty(TrackModel?.EntryKey);
|
||||
var trackHref = hasLink ? $"/track/{TrackModel!.EntryKey}" : null;
|
||||
}
|
||||
|
||||
<div class="deepdrft-track-card-container">
|
||||
|
||||
@* Cover and title/artist link to the detail page; the play button (below, outside any
|
||||
anchor) stays the sole playback entry point. display:contents keeps the grid intact. *@
|
||||
@if (hasLink)
|
||||
{
|
||||
<a href="@trackHref" class="deepdrft-track-card-link">
|
||||
@if (!string.IsNullOrEmpty(TrackModel?.ImagePath))
|
||||
{
|
||||
<div class="deepdrft-track-card-bg" style="background-image: url('@TrackModel.ImagePath');">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="deepdrft-track-card-fallback"></div>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(TrackModel?.ImagePath))
|
||||
{
|
||||
<div class="deepdrft-track-card-bg" style="background-image: url('@TrackModel.ImagePath');">
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="deepdrft-track-card-fallback"></div>
|
||||
}
|
||||
|
||||
<div class="deepdrft-track-card-content">
|
||||
|
||||
@if (hasLink)
|
||||
{
|
||||
<a href="@trackHref" class="deepdrft-track-card-link">
|
||||
<div class="deepdrft-track-info-top">
|
||||
<MudText Typo="Typo.subtitle1"
|
||||
Class="deepdrft-track-title text-truncate mb-1">
|
||||
@TrackModel?.TrackName
|
||||
</MudText>
|
||||
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="deepdrft-track-artist text-truncate mb-2">
|
||||
@TrackModel?.Artist
|
||||
</MudText>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="deepdrft-track-info-top">
|
||||
<MudText Typo="Typo.subtitle1"
|
||||
Class="deepdrft-track-title text-truncate mb-1">
|
||||
@TrackModel?.TrackName
|
||||
</MudText>
|
||||
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="deepdrft-track-artist text-truncate mb-2">
|
||||
@TrackModel?.Artist
|
||||
</MudText>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="deepdrft-track-info-middle">
|
||||
@if (!string.IsNullOrEmpty(TrackModel?.Album))
|
||||
{
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="deepdrft-track-meta text-truncate">
|
||||
@TrackModel.Album
|
||||
</MudText>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(TrackModel?.Genre))
|
||||
{
|
||||
<MudChip T="string"
|
||||
Size="Size.Small"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Tertiary"
|
||||
Class="deepdrft-genre-chip">
|
||||
@TrackModel.Genre
|
||||
</MudChip>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="deepdrft-track-info-bottom">
|
||||
@if (TrackModel?.ReleaseDate.HasValue == true)
|
||||
{
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="deepdrft-track-meta">
|
||||
@TrackModel.ReleaseDate.Value.Year
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div></div>
|
||||
}
|
||||
|
||||
<MudFab Color="Color.Tertiary"
|
||||
Size="Size.Medium"
|
||||
StartIcon="@PlayPauseIcon"
|
||||
OnClick="@PlayClick"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using DeepDrftModels.DTOs;
|
||||
using MudBlazor;
|
||||
|
||||
namespace DeepDrftShared.Client.Components;
|
||||
|
||||
public partial class TrackCard : ComponentBase
|
||||
{
|
||||
[Parameter] public required TrackDto TrackModel { get; set; }
|
||||
[Parameter] public EventCallback<TrackDto> OnPlay { get; set; }
|
||||
[Parameter] public EventCallback<TrackDto> OnPause { get; set; }
|
||||
[Parameter] public bool IsPlaying { get; set; } = false;
|
||||
[Parameter] public bool IsPaused { get; set; } = false;
|
||||
|
||||
// Pause only when actively playing; every other state (idle, paused) reads as "press to play".
|
||||
private bool IsActivelyPlaying => IsPlaying && !IsPaused;
|
||||
|
||||
private string PlayPauseIcon =>
|
||||
IsActivelyPlaying ? Icons.Material.Filled.Pause : Icons.Material.Filled.PlayArrow;
|
||||
|
||||
private async Task PlayClick()
|
||||
{
|
||||
if (IsActivelyPlaying)
|
||||
{
|
||||
if (OnPause.HasDelegate)
|
||||
await OnPause.InvokeAsync(TrackModel);
|
||||
}
|
||||
else if (OnPlay.HasDelegate)
|
||||
{
|
||||
await OnPlay.InvokeAsync(TrackModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/* Container — transparent so the absolute-positioned fallback panel or album art
|
||||
controls the card's background. Glass edge matches NowPlayingCard vocabulary. */
|
||||
.deepdrft-track-card-container {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
min-width: 250px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border: 1px solid rgba(250, 250, 248, 0.12);
|
||||
}
|
||||
|
||||
.deepdrft-track-card-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
filter: brightness(0.7);
|
||||
}
|
||||
|
||||
.deepdrft-track-card-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
background: linear-gradient(to top,
|
||||
rgba(13, 27, 42, 0.75) 0%,
|
||||
rgba(13, 27, 42, 0.35) 45%,
|
||||
rgba(13, 27, 42, 0.00) 100%);
|
||||
}
|
||||
|
||||
/* Fallback panel — solid navy, opaque so the card reads correctly on both
|
||||
light and dark page backgrounds. Semi-transparent + blur washes out on white. */
|
||||
.deepdrft-track-card-fallback {
|
||||
position: absolute;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: var(--deepdrft-navy-mid, #162437);
|
||||
border: 1px solid rgba(250, 250, 248, 0.12);
|
||||
}
|
||||
|
||||
/* Title: off-white — matches .np-title.
|
||||
::deep required: MudText renders its own element, so Blazor isolation
|
||||
won't stamp b-{hash} on it; ::deep pierces into child component output. */
|
||||
::deep .deepdrft-track-title { color: var(--deepdrft-white, #FAFAF8); }
|
||||
|
||||
/* Artist: muted off-white — green reserved for interactive elements (FAB, chip). ::deep for same reason. */
|
||||
::deep .deepdrft-track-artist { color: rgba(250, 250, 248, 0.55); }
|
||||
|
||||
/* Meta: muted off-white — matches .np-sub. ::deep for same reason. */
|
||||
::deep .deepdrft-track-meta { color: rgba(250, 250, 248, 0.45); }
|
||||
|
||||
/* FAB always green-interactive — card is always dark glass regardless of page theme.
|
||||
.mud-button-filled-tertiary specificity (0,1,0) in MudBlazor; our (0,1,1) wins. */
|
||||
::deep .mud-button-filled-tertiary {
|
||||
background-color: var(--deepdrft-green-interactive, #3aa163);
|
||||
color: var(--deepdrft-white, #FAFAF8);
|
||||
}
|
||||
|
||||
/* Genre chip always green-accent outline/text on the dark glass card. */
|
||||
::deep .deepdrft-genre-chip.mud-chip-outlined {
|
||||
border-color: var(--deepdrft-green-accent, #3D7A68);
|
||||
color: var(--deepdrft-green-accent, #3D7A68);
|
||||
}
|
||||
::deep .deepdrft-genre-chip.mud-chip-color-tertiary {
|
||||
color: var(--deepdrft-green-accent, #3D7A68);
|
||||
}
|
||||
|
||||
.deepdrft-track-info-middle { margin: 8px 0; }
|
||||
|
||||
.deepdrft-track-info-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.deepdrft-track-card-container {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="tracks-gallery-container">
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var track in Tracks)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4" lg="3" xl="3">
|
||||
<div class="deepdrft-track-gallery-item-center">
|
||||
<TrackCard TrackModel="@track"
|
||||
IsPlaying="@(IsPlaying && ActiveTrack?.Id == track.Id)"
|
||||
IsPaused="@(IsPaused && ActiveTrack?.Id == track.Id)"
|
||||
OnPlay="@HandlePlayClick"
|
||||
OnPause="@HandlePauseClick"/>
|
||||
</div>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
@@ -1,25 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using DeepDrftModels.DTOs;
|
||||
|
||||
namespace DeepDrftShared.Client.Components;
|
||||
|
||||
public partial class TracksGallery : ComponentBase
|
||||
{
|
||||
[Parameter] public IEnumerable<TrackDto> Tracks { get; set; } = [];
|
||||
|
||||
// Controlled play-state inputs: the parent owns playback truth (the player service)
|
||||
// and drives these. The gallery is presentational — it only matches by id to decide
|
||||
// which card reflects the active state.
|
||||
[Parameter] public TrackDto? ActiveTrack { get; set; }
|
||||
[Parameter] public bool IsPlaying { get; set; }
|
||||
[Parameter] public bool IsPaused { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<TrackDto> OnPlay { get; set; }
|
||||
[Parameter] public EventCallback<TrackDto> OnPause { get; set; }
|
||||
|
||||
private Task HandlePlayClick(TrackDto track) =>
|
||||
OnPlay.HasDelegate ? OnPlay.InvokeAsync(track) : Task.CompletedTask;
|
||||
|
||||
private Task HandlePauseClick(TrackDto track) =>
|
||||
OnPause.HasDelegate ? OnPause.InvokeAsync(track) : Task.CompletedTask;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
.tracks-gallery-container {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.deepdrft-track-gallery-item-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
Reference in New Issue
Block a user