diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor index 051827b..02067ad 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor @@ -27,8 +27,11 @@ else - + + + + diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs index 6fa678e..d2f8366 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs @@ -38,7 +38,7 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable /// Display time - shows seek position while dragging, otherwise current playback time. /// private double DisplayTime => _isSeeking ? _seekPosition : (PlayerService?.CurrentTime ?? 0); - private string PlayerModeClass => Fixed ? "player-fixed" : "player-docked"; + private string PlayerModeClass => Fixed ? "player-fixed" : "player-dock"; protected override void OnParametersSet() { diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css index 49a9d6d..f9b9fcb 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css @@ -71,29 +71,53 @@ } } -/* Unified responsive player layout. - Wide and narrow shapes are pure CSS — no runtime breakpoint subscription. - Children are targeted by their stable classes (transport-zone, volume-zone, - seek-zone) rather than positional nth-child, since all three render a .mud-stack - root and positional selectors would be fragile. */ +/* Unified responsive player layout — CSS Grid with named areas redefined per breakpoint. + The metadata (meta-zone) detaches from the waveform (seek-zone) in the mid band, which a + flex order-swap can't express, so each of the four zones is placed by grid-area and the three + shapes are pure template-area swaps — no runtime breakpoint subscription. min-width:0 on the + shrinkable centre zones lets the title truncate and the waveform shrink instead of overflowing. */ .player-layout { - display: flex; - flex-wrap: wrap; + display: grid; align-items: center; gap: 8px; padding-right: 2.5rem; /* clear the abs-positioned PlayerWindowControls */ } -/* Wide (>= 600px): single row, seek zone grows and sits between transport and volume */ -@media (min-width: 600px) { - ::deep .transport-zone { order: 1; } - ::deep .seek-zone { order: 2; flex-grow: 1; flex-basis: 0; } - ::deep .volume-zone { order: 3; flex-shrink: 0; } +::deep .transport-zone { grid-area: transport; } +::deep .meta-zone { grid-area: meta; min-width: 0; } +::deep .seek-zone { grid-area: waveform; min-width: 0; } +::deep .volume-zone { grid-area: volume; } + +/* Wide (>= 900px): single row — transport and volume flank the centre column; the metadata + sits directly under the waveform (transport/volume span both rows, centred). */ +@media (min-width: 900px) { + .player-layout { + grid-template-columns: auto minmax(360px, 1fr) auto; + grid-template-areas: + "transport waveform volume" + "transport meta volume"; + } } -/* Narrow (< 600px): transport + volume on top row, seek full-width below */ -@media (max-width: 599.98px) { - ::deep .transport-zone { order: 1; } - ::deep .volume-zone { order: 2; } - ::deep .seek-zone { flex-basis: 100%; order: 3; } +/* Mid (600–900px): metadata rides the top row between transport and volume; the waveform gets + the whole bottom row to itself rather than being squeezed beside the metadata. */ +@media (min-width: 600px) and (max-width: 899.98px) { + .player-layout { + grid-template-columns: auto minmax(0, 1fr) auto; + grid-template-areas: + "transport meta volume" + "waveform waveform waveform"; + } +} + +/* Narrow (< 600px): transport + volume share the top row; waveform then metadata stack full-width + below — the most compressed shape. */ +@media (max-width: 599.98px) { + .player-layout { + grid-template-columns: auto 1fr auto; + grid-template-areas: + "transport . volume" + "waveform waveform waveform" + "meta meta meta"; + } } diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor index 10a0688..0232f65 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor @@ -5,5 +5,4 @@ OnSeekChange="OnSeekChange" OnSeekEnd="OnSeekEnd" Class="seek-waveform"/> - diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs index eccf29d..b290448 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs @@ -1,17 +1,16 @@ -using DeepDrftModels.DTOs; using Microsoft.AspNetCore.Components; namespace DeepDrftPublic.Client.Controls.AudioPlayerBar; /// -/// Centre zone of the player: the over the now-playing metadata row -/// (). The seeker owns the pointer-gesture seek logic and reads playback -/// state off the cascaded player service directly; this zone just forwards the seek callbacks up to -/// (whose wiring is unchanged) and renders the current track's metadata. +/// Centre zone of the player: the . The seeker owns the pointer-gesture +/// seek logic and reads playback state off the cascaded player service directly; this zone just +/// forwards the seek callbacks up to (whose wiring is unchanged). +/// The now-playing metadata () is a sibling zone in the grid, not nested +/// here, so the responsive layouts can place it independently of the waveform. /// public partial class PlayerSeekZone : ComponentBase { - [Parameter] public TrackDto? CurrentTrack { get; set; } [Parameter] public EventCallback OnSeekStart { get; set; } [Parameter] public EventCallback OnSeekEnd { get; set; } [Parameter] public EventCallback OnSeekChange { get; set; } diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor index 5748711..a4909d9 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor @@ -7,7 +7,7 @@ @Track.TrackName - - + - @Track.Artist diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css index caaa3bc..0bb89d1 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css @@ -40,3 +40,56 @@ ::deep .track-meta-year { opacity: 0.75; } + +/* The metadata's three shapes track the dock's layout bands (same breakpoints as the grid in + AudioPlayerBar.razor.css), not the label's own slot width — in the <600 band the slot is actually + full-width yet we still want it fully vertical, which a container query can't express. + + Mid band (600–900): 2×2 — title over artist on the left (start-justified), genre over year on the + right (end-justified). The row stays a row; only the two inner groups go vertical. */ +@media (min-width: 600px) and (max-width: 899.98px) { + .track-meta-row { + align-items: flex-start; + } + + .track-meta-identity { + flex-direction: column; + align-items: flex-start; + gap: 0; + } + + .track-meta-accents { + flex-direction: column; + align-items: flex-end; + gap: 2px; + } + + ::deep .track-meta-sep { + display: none; + } +} + +/* Narrow band (<600): fully vertical — title / artist / genre / year all stacked, left-aligned. */ +@media (max-width: 599.98px) { + .track-meta-row { + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + + .track-meta-identity { + flex-direction: column; + align-items: flex-start; + gap: 0; + } + + .track-meta-accents { + flex-direction: column; + align-items: flex-start; + gap: 2px; + } + + ::deep .track-meta-sep { + display: none; + } +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor index a1e6a22..e3e1d71 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor @@ -1,7 +1,7 @@ @namespace DeepDrftPublic.Client.Controls.AudioPlayerBar - +