From ef6d21b94ee21c2f9c39df72de07a5a818ccd45a Mon Sep 17 00:00:00 2001
From: daniel-c-harvey
Date: Tue, 16 Jun 2026 11:31:02 -0400
Subject: [PATCH] =?UTF-8?q?refactor(public):=20retire=20track-cardinal=20s?=
=?UTF-8?q?tack,=20fold=20Archive/Cuts=20cards=20into=20ReleaseGallery=20(?=
=?UTF-8?q?P11=20W3=20=C2=A74)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../AudioPlayerBar/TrackMetaLabel.razor.css | 4 +-
.../Controls/DeepDrftHero.razor | 2 +-
.../Controls/GalleryViewMode.cs | 7 -
.../Controls/PlayStateIcon.razor.cs | 2 +-
.../Controls/ReleaseDetailScaffold.razor | 2 +-
.../Controls/ReleaseDetailScaffold.razor.cs | 4 +-
.../Controls/ReleaseGallery.razor | 40 +++-
.../Controls/TrackCard.razor | 213 ------------------
.../Controls/TrackCard.razor.cs | 34 ---
.../Controls/TrackCard.razor.css | 197 ----------------
.../Controls/TracksGallery.razor | 36 ---
.../Controls/TracksGallery.razor.cs | 26 ---
.../Controls/TracksGallery.razor.css | 15 --
DeepDrftPublic.Client/Layout/Pages.cs | 4 +-
DeepDrftPublic.Client/Pages/AlbumsView.razor | 67 +-----
.../Pages/AlbumsView.razor.cs | 10 +-
.../Pages/AlbumsView.razor.css | 58 -----
DeepDrftPublic.Client/Pages/ArchiveView.razor | 65 +-----
.../Pages/ArchiveView.razor.cs | 6 +-
.../Pages/ArchiveView.razor.css | 60 -----
DeepDrftPublic.Client/Pages/Home.razor | 2 +-
.../Pages/MediumBrowseBase.cs | 2 +-
.../Pages/ReleaseDetailBase.cs | 2 +-
DeepDrftPublic.Client/Pages/TrackDetail.razor | 101 ---------
.../Pages/TrackDetail.razor.cs | 70 ------
DeepDrftPublic.Client/Pages/TracksView.razor | 92 --------
.../Pages/TracksView.razor.cs | 163 --------------
.../Pages/TracksView.razor.css | 45 ----
DeepDrftPublic.Client/Startup.cs | 2 -
.../ViewModels/ReleaseDetailViewModel.cs | 2 +-
.../ViewModels/TrackDetailViewModel.cs | 45 ----
.../ViewModels/TracksViewModel.cs | 45 ----
32 files changed, 70 insertions(+), 1353 deletions(-)
delete mode 100644 DeepDrftPublic.Client/Controls/GalleryViewMode.cs
delete mode 100644 DeepDrftPublic.Client/Controls/TrackCard.razor
delete mode 100644 DeepDrftPublic.Client/Controls/TrackCard.razor.cs
delete mode 100644 DeepDrftPublic.Client/Controls/TrackCard.razor.css
delete mode 100644 DeepDrftPublic.Client/Controls/TracksGallery.razor
delete mode 100644 DeepDrftPublic.Client/Controls/TracksGallery.razor.cs
delete mode 100644 DeepDrftPublic.Client/Controls/TracksGallery.razor.css
delete mode 100644 DeepDrftPublic.Client/Pages/AlbumsView.razor.css
delete mode 100644 DeepDrftPublic.Client/Pages/TrackDetail.razor
delete mode 100644 DeepDrftPublic.Client/Pages/TrackDetail.razor.cs
delete mode 100644 DeepDrftPublic.Client/Pages/TracksView.razor
delete mode 100644 DeepDrftPublic.Client/Pages/TracksView.razor.cs
delete mode 100644 DeepDrftPublic.Client/Pages/TracksView.razor.css
delete mode 100644 DeepDrftPublic.Client/ViewModels/TrackDetailViewModel.cs
delete mode 100644 DeepDrftPublic.Client/ViewModels/TracksViewModel.cs
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
index 4d4715f..4128169 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
@@ -1,6 +1,6 @@
/* Single space-between row under the waveform: identity on the left, accents on the right.
- Colours come from the MudBlazor theme (the dock surface is theme-aware), so unlike the
- always-dark TrackCard glass we do not hard-code green-accent overrides here. */
+ Colours come from the MudBlazor theme (the dock surface is theme-aware), so we do not
+ hard-code green-accent overrides here. */
.track-meta-row {
display: flex;
align-items: center;
diff --git a/DeepDrftPublic.Client/Controls/DeepDrftHero.razor b/DeepDrftPublic.Client/Controls/DeepDrftHero.razor
index b4a75d3..9b75c67 100644
--- a/DeepDrftPublic.Client/Controls/DeepDrftHero.razor
+++ b/DeepDrftPublic.Client/Controls/DeepDrftHero.razor
@@ -6,7 +6,7 @@
diff --git a/DeepDrftPublic.Client/Controls/ReleaseDetailScaffold.razor.cs b/DeepDrftPublic.Client/Controls/ReleaseDetailScaffold.razor.cs
index f239838..dce760f 100644
--- a/DeepDrftPublic.Client/Controls/ReleaseDetailScaffold.razor.cs
+++ b/DeepDrftPublic.Client/Controls/ReleaseDetailScaffold.razor.cs
@@ -7,8 +7,8 @@ namespace DeepDrftPublic.Client.Controls;
///
/// Shared detail-page chrome for any release medium: back link, masthead, play/share affordance,
/// and hero/meta slots. Owns the play-toggle wiring against the cascaded streaming player so each
-/// detail page supplies only its data and medium-specific visuals. Extracted from the original
-/// TrackDetail page, which is now a thin consumer of this scaffold.
+/// detail page supplies only its data and medium-specific visuals. Each medium's detail page is a
+/// thin consumer of this scaffold.
///
public partial class ReleaseDetailScaffold : ComponentBase
{
diff --git a/DeepDrftPublic.Client/Controls/ReleaseGallery.razor b/DeepDrftPublic.Client/Controls/ReleaseGallery.razor
index 0dd1ede..7d20bad 100644
--- a/DeepDrftPublic.Client/Controls/ReleaseGallery.razor
+++ b/DeepDrftPublic.Client/Controls/ReleaseGallery.razor
@@ -1,9 +1,14 @@
@namespace DeepDrftPublic.Client.Controls
-@* Card grid of releases that open their own detail page (/{DetailRoute}/{id}). Shared by the
- Sessions and Mixes browse pages. Cuts intentionally do not use this — they open the track
- gallery filtered by album, a different navigation target. Fully controlled by the parent:
- loading and item state are passed in. *@
+@* 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/{id}.
+ 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. *@
@@ -33,7 +38,7 @@
{
@@ -68,8 +73,27 @@
[Parameter] public required IReadOnlyList Releases { get; set; }
[Parameter] public bool Loading { get; set; }
- /// Route segment for a card's detail page; a card links to /{DetailRoute}/{id}.
- [Parameter] public required string DetailRoute { get; set; }
+ ///
+ /// 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 is supplied.
+ ///
+ [Parameter] public string? DetailRoute { get; set; }
+
+ ///
+ /// Per-card href resolver. When supplied, a card links to its result instead of the
+ /// -based href, letting Archive route each card by its own medium and
+ /// Cuts route to /cuts/{id} (both via ReleaseRoutes.DetailHref).
+ ///
+ [Parameter] public Func? HrefResolver { get; set; }
+
+ ///
+ /// Optional override for a card's subtitle line (defaults to the release artist). Cuts pass a
+ /// track-count label here.
+ ///
+ [Parameter] public Func? SubtitleResolver { get; set; }
[Parameter] public string EmptyMessage { get; set; } = "Nothing here yet";
+
+ private string CardHref(DeepDrftModels.DTOs.ReleaseDto release)
+ => HrefResolver?.Invoke(release) ?? $"/{DetailRoute}/{release.Id}";
}
diff --git a/DeepDrftPublic.Client/Controls/TrackCard.razor b/DeepDrftPublic.Client/Controls/TrackCard.razor
deleted file mode 100644
index 750119b..0000000
--- a/DeepDrftPublic.Client/Controls/TrackCard.razor
+++ /dev/null
@@ -1,213 +0,0 @@
-@{
- var hasLink = !string.IsNullOrEmpty(TrackModel?.EntryKey);
- var trackHref = hasLink ? $"/track/{TrackModel!.EntryKey}" : null;
- var hasArt = !string.IsNullOrEmpty(TrackModel?.Release?.ImagePath);
-}
-
-@if (ViewMode == GalleryViewMode.Grid)
-{
-
-
- @* 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)
- {
-
- @if (!string.IsNullOrEmpty(TrackModel?.Release?.ImagePath))
- {
-
-
- }
- else
- {
-
- }
-
- }
- else if (!string.IsNullOrEmpty(TrackModel?.Release?.ImagePath))
- {
-
-
- }
- else
- {
-
- }
-
-
-
- @if (hasLink)
- {
-
-
-
- @TrackModel?.TrackName
-
-
-
- @TrackModel?.Release?.Artist
-
-
-
- }
- else
- {
-
-
- @TrackModel?.TrackName
-
-
-
- @TrackModel?.Release?.Artist
-
-
- }
-
-
- @if (!string.IsNullOrEmpty(TrackModel?.Release?.Title))
- {
-
- @TrackModel.Release!.Title
-
- }
-
- @if (!string.IsNullOrEmpty(TrackModel?.Release?.Genre))
- {
-
- @TrackModel.Release!.Genre
-
- }
-
-
-
- @if (TrackModel?.Release?.ReleaseDate.HasValue == true)
- {
-
- @TrackModel.Release!.ReleaseDate!.Value.Year
-
- }
- else
- {
-
- }
-
-
-
-
-
-
-
-}
-else
-{
-
-}
diff --git a/DeepDrftPublic.Client/Controls/TrackCard.razor.cs b/DeepDrftPublic.Client/Controls/TrackCard.razor.cs
deleted file mode 100644
index 3b2dd76..0000000
--- a/DeepDrftPublic.Client/Controls/TrackCard.razor.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using DeepDrftModels.DTOs;
-using Microsoft.AspNetCore.Components;
-using MudBlazor;
-
-namespace DeepDrftPublic.Client.Controls;
-
-public partial class TrackCard : ComponentBase
-{
- [Parameter] public required TrackDto TrackModel { get; set; }
- [Parameter] public EventCallback OnPlay { get; set; }
- [Parameter] public EventCallback OnPause { get; set; }
- [Parameter] public bool IsPlaying { get; set; } = false;
- [Parameter] public bool IsPaused { get; set; } = false;
- [Parameter] public GalleryViewMode ViewMode { get; set; } = GalleryViewMode.Grid;
-
- // 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);
- }
- }
-}
diff --git a/DeepDrftPublic.Client/Controls/TrackCard.razor.css b/DeepDrftPublic.Client/Controls/TrackCard.razor.css
deleted file mode 100644
index 0760684..0000000
--- a/DeepDrftPublic.Client/Controls/TrackCard.razor.css
+++ /dev/null
@@ -1,197 +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: 2px solid var(--mud-palette-secondary);
-}
-
-.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;
- }
-}
-
-/* ── Mode A: hover-reveal overlay (art cards only) ──────────────────────── */
-
-/* Gate the hidden-at-rest rule on (a) art present and (b) a hover-capable pointer.
- Fallback cards (no --art modifier) and touch devices always show the overlay. */
-@media (hover: hover) and (pointer: fine) {
- .deepdrft-track-card-container--art .deepdrft-track-card-content {
- opacity: 0;
- background: transparent;
- transition: opacity 180ms ease, background-color 180ms ease;
- }
- .deepdrft-track-card-container--art:hover .deepdrft-track-card-content {
- opacity: 1;
- background: rgba(22, 36, 55, 0.82);
- transition: opacity 180ms ease, background-color 180ms ease;
- }
-}
-
-/* ── Mode B: list row ───────────────────────────────────────────────────── */
-
-.deepdrft-track-row {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 16px;
- height: 80px;
- padding: 8px 16px;
- background: var(--mud-palette-surface);
- border: 1px solid var(--mud-palette-divider);
- border-radius: 4px;
- box-sizing: border-box;
- width: 100%;
-}
-
-.deepdrft-track-row-link {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 16px;
- flex: 1 1 auto;
- min-width: 0;
- text-decoration: none;
- color: inherit;
-}
-
-::deep .deepdrft-track-row-fab {
- flex: 0 0 auto;
-}
-
-.deepdrft-track-row-thumb {
- flex: 0 0 64px;
- width: 64px;
- height: 64px;
- background-size: cover;
- background-position: center;
- border-radius: 2px;
-}
-
-.deepdrft-track-row-thumb--fallback {
- background: var(--deepdrft-navy-mid);
- border: 1px solid var(--mud-palette-divider);
-}
-
-.deepdrft-track-row-text {
- flex: 1 1 auto;
- min-width: 0;
- display: flex;
- flex-direction: column;
- justify-content: center;
-}
-
-.deepdrft-track-row-meta {
- flex: 0 0 auto;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- justify-content: center;
- gap: 4px;
-}
-
-@media (max-width: 480px) {
- .deepdrft-track-row {
- height: auto;
- min-height: 72px;
- padding: 8px 12px;
- gap: 10px;
- }
- .deepdrft-track-row-thumb {
- flex: 0 0 48px;
- width: 48px;
- height: 48px;
- }
-}
-
-.deepdrft-track-row--playing {
- border-left: 3px solid var(--deepdrft-green-interactive, #3aa163);
-}
-
-/* ── Mode B text: theme-aware overrides (navy on light / off-white on dark) ─ */
-
-/* The global ::deep rules above hard-code off-white for the dark glass grid cards.
- List rows use --mud-palette-surface as their background, so text must follow
- the theme. These selectors have higher specificity (.deepdrft-track-row[b-hash]
- vs plain [b-hash]) and win in the cascade. */
-.deepdrft-track-row ::deep .deepdrft-track-title,
-.deepdrft-track-row ::deep .deepdrft-track-artist,
-.deepdrft-track-row ::deep .deepdrft-track-meta {
- color: var(--mud-palette-text-primary);
-}
diff --git a/DeepDrftPublic.Client/Controls/TracksGallery.razor b/DeepDrftPublic.Client/Controls/TracksGallery.razor
deleted file mode 100644
index db42790..0000000
--- a/DeepDrftPublic.Client/Controls/TracksGallery.razor
+++ /dev/null
@@ -1,36 +0,0 @@
-@if (ViewMode == GalleryViewMode.Grid)
-{
-
-
- @foreach (var track in Tracks)
- {
-
-
-
-
-
- }
-
-
-}
-else
-{
-
-
- @foreach (var track in Tracks)
- {
-
- }
-
-
-}
diff --git a/DeepDrftPublic.Client/Controls/TracksGallery.razor.cs b/DeepDrftPublic.Client/Controls/TracksGallery.razor.cs
deleted file mode 100644
index 47878c7..0000000
--- a/DeepDrftPublic.Client/Controls/TracksGallery.razor.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using DeepDrftModels.DTOs;
-using Microsoft.AspNetCore.Components;
-
-namespace DeepDrftPublic.Client.Controls;
-
-public partial class TracksGallery : ComponentBase
-{
- [Parameter] public IEnumerable 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 GalleryViewMode ViewMode { get; set; } = GalleryViewMode.Grid;
-
- [Parameter] public EventCallback OnPlay { get; set; }
- [Parameter] public EventCallback 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;
-}
diff --git a/DeepDrftPublic.Client/Controls/TracksGallery.razor.css b/DeepDrftPublic.Client/Controls/TracksGallery.razor.css
deleted file mode 100644
index 0d0736c..0000000
--- a/DeepDrftPublic.Client/Controls/TracksGallery.razor.css
+++ /dev/null
@@ -1,15 +0,0 @@
-.tracks-gallery-container {
- box-sizing: border-box;
-}
-
-.deepdrft-track-gallery-item-center {
- display: flex;
- justify-content: center;
-}
-
-.deepdrft-track-list {
- display: flex;
- flex-direction: column;
- gap: 8px;
- width: 100%;
-}
diff --git a/DeepDrftPublic.Client/Layout/Pages.cs b/DeepDrftPublic.Client/Layout/Pages.cs
index 90b5abf..54d3320 100644
--- a/DeepDrftPublic.Client/Layout/Pages.cs
+++ b/DeepDrftPublic.Client/Layout/Pages.cs
@@ -22,8 +22,8 @@ public static class Pages
// ARCHIVE (→ the release-cardinal /archive browser) carries the three medium modes as Children.
// Above the medium breakpoint the desktop nav flattens them into inline appbar links beside
// ARCHIVE (no popover); below the breakpoint the mobile hamburger renders them as an indented
- // sub-list under ARCHIVE. /tracks and /genres are intentionally absent from the nav (8.I) —
- // their routes (TracksView, GenresView) remain reachable by direct URL.
+ // sub-list under ARCHIVE. /genres is intentionally absent from the nav (8.I) — its route
+ // (GenresView) remains reachable by direct URL.
public static readonly List MenuPages =
[
new()
diff --git a/DeepDrftPublic.Client/Pages/AlbumsView.razor b/DeepDrftPublic.Client/Pages/AlbumsView.razor
index ff0743b..536d130 100644
--- a/DeepDrftPublic.Client/Pages/AlbumsView.razor
+++ b/DeepDrftPublic.Client/Pages/AlbumsView.razor
@@ -1,63 +1,12 @@
@page "/cuts"
+@using DeepDrftPublic.Client.Controls
DeepDrft Cuts
-
-
- @if (_loading)
- {
-
- @foreach (var _ in Enumerable.Range(0, 8))
- {
-
-
-
-
-
- }
-
- }
- else if (_albums.Count == 0)
- {
-
- No albums yet
-
- }
- else
- {
-
- @foreach (var album in _albums)
- {
-
-
-
OpenAlbum(album))">
- @if (!string.IsNullOrEmpty(album.ImagePath))
- {
-
-
- }
- else
- {
-
- }
-
-
-
- @album.Title
-
-
- @album.TrackCount @(album.TrackCount == 1 ? "track" : "tracks")
-
-
-
-
-
- }
-
- }
-
-
+@* The shared release-card grid; each card routes to /cuts/{id} via the one ReleaseRoutes table.
+ Cuts show a track count where other media show the artist, supplied via SubtitleResolver. *@
+
diff --git a/DeepDrftPublic.Client/Pages/AlbumsView.razor.cs b/DeepDrftPublic.Client/Pages/AlbumsView.razor.cs
index 8933e77..2210cd5 100644
--- a/DeepDrftPublic.Client/Pages/AlbumsView.razor.cs
+++ b/DeepDrftPublic.Client/Pages/AlbumsView.razor.cs
@@ -19,7 +19,6 @@ public partial class AlbumsView : ComponentBase, IDisposable
[Inject] public required IReleaseDataService ReleaseData { get; set; }
[Inject] public required PersistentComponentState PersistentState { get; set; }
- [Inject] public required NavigationManager Navigation { get; set; }
// The medium whose releases this grid shows. Defaults to Cut for the /cuts route; other media
// can reuse this component by passing a different value. Drives both the fetch filter and the
@@ -34,8 +33,8 @@ public partial class AlbumsView : ComponentBase, IDisposable
protected override async Task OnInitializedAsync()
{
- // Bridge the prerendered fetch across the prerender -> WASM seam (see TracksView). Without
- // this, the WASM pass re-fetches and replays the card entrance animations.
+ // Bridge the prerendered fetch across the prerender -> WASM seam (see MediumBrowseBase).
+ // Without this, the WASM pass re-fetches and replays the card entrance animations.
_persistingSubscription = PersistentState.RegisterOnPersisting(PersistAlbums);
if (PersistentState.TryTakeFromJson>(PersistKey, out var restored) && restored is not null)
@@ -59,8 +58,9 @@ public partial class AlbumsView : ComponentBase, IDisposable
return Task.CompletedTask;
}
- private void OpenAlbum(ReleaseDto album)
- => Navigation.NavigateTo(ReleaseRoutes.DetailHref(album));
+ // Cut cards show track count where the shared card otherwise shows the artist.
+ private static string TrackCountLabel(ReleaseDto album)
+ => $"{album.TrackCount} {(album.TrackCount == 1 ? "track" : "tracks")}";
public void Dispose() => _persistingSubscription.Dispose();
}
diff --git a/DeepDrftPublic.Client/Pages/AlbumsView.razor.css b/DeepDrftPublic.Client/Pages/AlbumsView.razor.css
deleted file mode 100644
index bc97c05..0000000
--- a/DeepDrftPublic.Client/Pages/AlbumsView.razor.css
+++ /dev/null
@@ -1,58 +0,0 @@
-.albums-view-container {
- padding-top: 16px;
-}
-
-.album-card-center {
- display: flex;
- justify-content: center;
- width: 100%;
-}
-
-.album-card {
- display: flex;
- flex-direction: column;
- width: 200px;
- cursor: pointer;
- border-radius: 8px;
- overflow: hidden;
- transition: transform 120ms ease;
-}
-
-.album-card:hover {
- transform: translateY(-4px);
-}
-
-.album-card-cover {
- width: 200px;
- height: 200px;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.album-card-cover--fallback {
- background-color: var(--mud-palette-dark, #1a2238);
-}
-
-.album-card-body {
- padding: 8px 4px 0 4px;
- display: flex;
- flex-direction: column;
- gap: 2px;
-}
-
-/* album-card-title / album-card-count ride on MudText, a child Razor component whose
- root Blazor isolation does not scope-stamp; ::deep pierces into its output. */
-::deep .album-card-title {
- font-weight: 600;
-}
-
-::deep .album-card-count {
- opacity: 0.7;
-}
-
-.albums-empty {
- display: flex;
- justify-content: center;
- padding: 48px 0;
-}
diff --git a/DeepDrftPublic.Client/Pages/ArchiveView.razor b/DeepDrftPublic.Client/Pages/ArchiveView.razor
index 7f67ed4..2a5069e 100644
--- a/DeepDrftPublic.Client/Pages/ArchiveView.razor
+++ b/DeepDrftPublic.Client/Pages/ArchiveView.razor
@@ -1,12 +1,13 @@
@page "/archive"
@using DeepDrftModels.Enums
+@using DeepDrftPublic.Client.Controls
DeepDrft Archive
@* 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.
+ need WASM. During prerender/non-interactive they are hidden behind the interactive gate.
The release grid still prerenders so the archive is meaningful before hydration. *@
@if (RendererInfo.IsInteractive)
{
@@ -59,60 +60,12 @@
}
}
-
- @if (_loading)
- {
-
- @foreach (var _ in Enumerable.Range(0, 8))
- {
-
-
-
-
-
- }
-
- }
- else if (_releases.Count == 0)
- {
-
- No releases found
-
- }
- else
- {
-
- @foreach (var release in _releases)
- {
-
-
-
- }
-
- }
+
+ @* The grid itself is the shared release-card component; each card routes by its own medium through
+ the one ReleaseRoutes table. The Archive-specific search/filter chrome above stays here. *@
+
diff --git a/DeepDrftPublic.Client/Pages/ArchiveView.razor.cs b/DeepDrftPublic.Client/Pages/ArchiveView.razor.cs
index 2a3b6ae..ef5b97d 100644
--- a/DeepDrftPublic.Client/Pages/ArchiveView.razor.cs
+++ b/DeepDrftPublic.Client/Pages/ArchiveView.razor.cs
@@ -9,9 +9,9 @@ namespace DeepDrftPublic.Client.Pages;
/// The public archive: a release-cardinal searchable browser over every release across all media
/// (Phase 9 §8.H, decision H2). Replaces the former three-card medium overview. Search (Title /
/// Artist), an enum-driven medium filter, and a genre filter narrow the release list; each card
-/// routes to its per-medium detail. Mirrors the
seam: the unfiltered first
-/// page is bridged across the prerender -> WASM boundary so hydration neither re-fetches nor replays
-/// the card entrance animations.
+/// routes to its per-medium detail. Mirrors the
seam: the unfiltered
+/// first page is bridged across the prerender -> WASM boundary so hydration neither re-fetches nor
+/// replays the card entrance animations.
///
public partial class ArchiveView : ComponentBase, IDisposable
{
diff --git a/DeepDrftPublic.Client/Pages/ArchiveView.razor.css b/DeepDrftPublic.Client/Pages/ArchiveView.razor.css
index 46473d7..0fa05db 100644
--- a/DeepDrftPublic.Client/Pages/ArchiveView.razor.css
+++ b/DeepDrftPublic.Client/Pages/ArchiveView.razor.css
@@ -50,63 +50,3 @@
flex: 0 1 auto;
}
}
-
-.archive-card-center {
- display: flex;
- justify-content: center;
- width: 100%;
-}
-
-.archive-card-link {
- text-decoration: none;
- color: inherit;
-}
-
-.archive-release-card {
- display: flex;
- flex-direction: column;
- width: 200px;
- cursor: pointer;
- border-radius: 8px;
- overflow: hidden;
- transition: transform 120ms ease;
-}
-
-.archive-release-card:hover {
- transform: translateY(-4px);
-}
-
-.archive-release-cover {
- width: 200px;
- height: 200px;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.archive-release-cover--fallback {
- background-color: var(--mud-palette-dark, #1a2238);
-}
-
-.archive-release-body {
- padding: 8px 4px 0 4px;
- display: flex;
- flex-direction: column;
- gap: 2px;
-}
-
-/* archive-release-title / archive-release-artist ride on MudText (child Razor component); ::deep
- pierces into its output since Blazor isolation does not scope-stamp child component roots. */
-::deep .archive-release-title {
- font-weight: 600;
-}
-
-::deep .archive-release-artist {
- opacity: 0.7;
-}
-
-.archive-empty {
- display: flex;
- justify-content: center;
- padding: 48px 0;
-}
diff --git a/DeepDrftPublic.Client/Pages/Home.razor b/DeepDrftPublic.Client/Pages/Home.razor
index c3a3a96..893533e 100644
--- a/DeepDrftPublic.Client/Pages/Home.razor
+++ b/DeepDrftPublic.Client/Pages/Home.razor
@@ -166,7 +166,7 @@
Immerse yourself. The current is always running.