From 8420ab8d37568424da829278ae03ea1458569bf2 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Thu, 4 Jun 2026 19:28:14 -0400 Subject: [PATCH] Migrate desktop AudioPlayerBar to MudBlazor theme surface --- .../AudioPlayerBar/AudioPlayerBar.razor | 94 +++++------- .../AudioPlayerBar/AudioPlayerBar.razor.css | 135 +++--------------- .../AudioPlayerBar/PlayerControls.razor | 4 +- .../AudioPlayerBar/PlayerControls.razor.css | 8 -- .../AudioPlayerBar/PlayerSeekZone.razor | 18 +++ .../AudioPlayerBar/PlayerSeekZone.razor.cs | 43 ++++++ .../AudioPlayerBar/PlayerTransportZone.razor | 19 +++ .../PlayerTransportZone.razor.cs | 17 +++ .../PlayerTransportZone.razor.css | 4 + .../AudioPlayerBar/PlayerWindowControls.razor | 12 ++ .../PlayerWindowControls.razor.cs | 9 ++ .../SpectrumVisualizer.razor.css | 13 +- .../AudioPlayerBar/TimestampLabel.razor | 6 +- .../AudioPlayerBar/TimestampLabel.razor.css | 9 +- .../AudioPlayerBar/VolumeControls.razor | 6 +- .../AudioPlayerBar/VolumeControls.razor.css | 15 +- 16 files changed, 182 insertions(+), 230 deletions(-) delete mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor.css create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.cs create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.css create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor create mode 100644 DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor.cs diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor index 2660b15..8ef4b53 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor @@ -1,63 +1,42 @@ @if (_isMinimized) { -
- -
+ } -else +else { -
+
-
- + + @if (_isDesktop) { @* Desktop Layout *@ -
-
-
- - @if (IsLoading && !IsStreaming) - { - - } -
- -
+ + -
-
- -
- -
+ -
- -
-
+ + } else { @@ -100,18 +79,9 @@ else
} - @* Control Buttons - positioned absolutely like original *@ -
- - -
-
+ @* Minimize / close — positioned absolutely top-right *@ + + @if (!string.IsNullOrEmpty(ErrorMessage)) diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css index 7978858..7c071c7 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css @@ -1,7 +1,8 @@ -/* Preserve key visual styles while simplifying layout */ +/* Geometry, positioning, and animation only. + Colour, surface, and elevation come from MudBlazor theme props. */ -/* Player outer container - fixed positioning */ -.player-outer-container { +/* Fixed dock to the viewport bottom */ +.player-dock { position: fixed; bottom: 0; left: 0; @@ -11,115 +12,39 @@ margin: 0; } -/* Player inner container */ .player-inner-container { padding: 1rem; padding-bottom: 1.5rem; } -/* Custom backdrop blur container */ -.player-backdrop { +/* The visible surface is a MudPaper; scoped CSS only sets geometry + a hairline accent */ +.player-surface { position: relative; - background: var(--deepdrft-theme-background-gray); - backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); - border-radius: 1rem; - border: 2px solid var(--deepdrft-theme-primary); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); - color: inherit; - transition: all 0.3s ease; + border-radius: 16px; + border: 1px solid var(--mud-palette-primary); overflow: hidden; margin-bottom: 1rem; } -/* Charleston (Light Mode) - Iron frame effect */ -:global(.deepdrft-theme-light) .player-backdrop { - background: color-mix(in srgb, var(--charleston-cream) 92%, transparent); - border: 2px solid var(--charleston-iron); - box-shadow: 0 4px 20px color-mix(in srgb, var(--charleston-iron) 20%, transparent), - inset 0 0 0 1px color-mix(in srgb, var(--charleston-iron) 5%, transparent); - color: var(--charleston-iron); -} - -/* Lowcountry (Dark Mode) - Warm sunset glow effect */ -:global(.deepdrft-theme-dark) .player-backdrop { - background: color-mix(in srgb, var(--lowcountry-night) 88%, transparent); - border: 1px solid color-mix(in srgb, var(--lowcountry-coral) 50%, transparent); - box-shadow: 0 0 20px color-mix(in srgb, var(--lowcountry-coral) 25%, transparent), - 0 0 40px color-mix(in srgb, var(--lowcountry-twilight) 15%, transparent), - 0 4px 20px rgba(0, 0, 0, 0.4); - color: var(--lowcountry-moonlight); -} - -/* Control buttons positioning */ -.player-controls { +/* Minimize / close cluster, pinned top-right of the surface */ +.player-surface ::deep .player-window-controls { position: absolute; top: 0.5rem; right: 0.5rem; } -/* Minimized floating dock with gradient */ +/* Minimized floating dock — positioning + hover only; colour from MudFab */ .minimized-dock { position: fixed; bottom: 60px; right: 60px; z-index: 1300; - width: 60px; - height: 60px; - border-radius: 50%; - cursor: pointer; - background: linear-gradient(135deg, - var(--deepdrft-theme-primary) 0%, - var(--deepdrft-theme-secondary) 50%, - var(--deepdrft-theme-tertiary) 100% - ); - backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); - border: 2px solid var(--deepdrft-theme-secondary); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); - transition: all 0.3s ease; -} - -/* Charleston (Light Mode) - Iron dock */ -:global(.deepdrft-theme-light) .minimized-dock { - background: linear-gradient(135deg, var(--charleston-iron) 0%, var(--charleston-rose) 50%, var(--charleston-gold) 100%); - border: 2px solid var(--charleston-iron); - box-shadow: 0 4px 15px color-mix(in srgb, var(--charleston-iron) 40%, transparent); -} - -/* Lowcountry (Dark Mode) - Warm sunset dock */ -:global(.deepdrft-theme-dark) .minimized-dock { - background: linear-gradient(135deg, var(--lowcountry-coral) 0%, var(--lowcountry-twilight) 50%, var(--lowcountry-gold) 100%); - border: 2px solid color-mix(in srgb, var(--lowcountry-coral) 60%, transparent); - box-shadow: 0 0 20px color-mix(in srgb, var(--lowcountry-coral) 40%, transparent), - 0 0 40px color-mix(in srgb, var(--lowcountry-twilight) 20%, transparent); } .minimized-dock:hover { transform: scale(1.1); } -:global(.deepdrft-theme-light) .minimized-dock:hover { - box-shadow: 0 6px 20px color-mix(in srgb, var(--charleston-iron) 50%, transparent); -} - -:global(.deepdrft-theme-dark) .minimized-dock:hover { - box-shadow: 0 0 30px color-mix(in srgb, var(--lowcountry-coral) 50%, transparent), - 0 0 50px color-mix(in srgb, var(--lowcountry-twilight) 30%, transparent); -} - -/* Minimized button styles */ -.minimized-button { - border-radius: 50% !important; - background: transparent !important; - color: white !important; - transition: all 0.3s ease !important; - box-shadow: none !important; - border: none !important; - width: 48px !important; - height: 48px !important; -} - /* Spacer to prevent content overlap */ .player-spacer { height: 140px; @@ -127,50 +52,22 @@ flex-shrink: 0; } -/* Essential layout adjustments only */ -.controls-left { - min-width: 200px; -} - -.seekbar-visualizer-container { - flex: 1; - display: flex; - flex-direction: column; -} - -.seekbar-flex { - flex: 1; -} - -.volume-right { - /*min-width: 140px;*/ -} - -/* Mobile responsive adjustments */ @media (max-width: 768px) { .minimized-dock { bottom: 15px; right: 15px; - width: 56px; - height: 56px; } - - .minimized-button { - width: 44px !important; - height: 44px !important; - } - + .player-inner-container { padding: 0.75rem; padding-bottom: 1.25rem; } - - .player-backdrop { - border-radius: 1rem; + + .player-surface { margin-bottom: 1.25rem; } - + .player-spacer { height: 160px; } -} \ No newline at end of file +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor index 8c841ce..b091987 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor @@ -1,4 +1,4 @@ -
+ -
\ No newline at end of file + diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor.css deleted file mode 100644 index 70a2300..0000000 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerControls.razor.css +++ /dev/null @@ -1,8 +0,0 @@ -/* PlayerControls Component Styles */ - -/* Button spacing and alignment */ -.player-buttons { - display: flex; - align-items: center; - gap: 0.5rem; -} \ No newline at end of file diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor new file mode 100644 index 0000000..c74ecb0 --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor @@ -0,0 +1,18 @@ +@namespace DeepDrftPublic.Client.Controls.AudioPlayerBar + + +
+ +
+ +
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs new file mode 100644 index 0000000..89c7958 --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Components; + +namespace DeepDrftPublic.Client.Controls.AudioPlayerBar; + +/// +/// Centre zone of the player: seek slider over the spectrum visualizer. +/// Owns the pointer-gesture seek logic (drag-to-seek) in one place so it is no +/// longer duplicated inline between the desktop and mobile branches of the parent. +/// +public partial class PlayerSeekZone : ComponentBase +{ + private double _seekPosition; + + [Parameter] public double DisplayTime { get; set; } + [Parameter] public double? Duration { get; set; } + [Parameter] public bool CanSeek { get; set; } + [Parameter] public EventCallback OnSeekStart { get; set; } + [Parameter] public EventCallback OnSeekEnd { get; set; } + [Parameter] public EventCallback OnSeekChange { get; set; } + [Parameter] public string? Class { get; set; } + + private async Task HandlePointerDown() + { + _seekPosition = DisplayTime; + await OnSeekStart.InvokeAsync(); + } + + private async Task HandlePointerUp() + { + await OnSeekEnd.InvokeAsync(_seekPosition); + } + + private async Task HandlePointerLeave() + { + await OnSeekEnd.InvokeAsync(_seekPosition); + } + + private async Task HandleValueChanged(double value) + { + _seekPosition = value; + await OnSeekChange.InvokeAsync(value); + } +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor new file mode 100644 index 0000000..25a4fd6 --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor @@ -0,0 +1,19 @@ +@namespace DeepDrftPublic.Client.Controls.AudioPlayerBar + + + + + @if (IsLoading && !IsStreaming) + { + + } + + + diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.cs new file mode 100644 index 0000000..9990a2d --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Components; + +namespace DeepDrftPublic.Client.Controls.AudioPlayerBar; + +public partial class PlayerTransportZone : ComponentBase +{ + [Parameter] public bool IsPlaying { get; set; } + [Parameter] public bool IsLoaded { get; set; } + [Parameter] public bool IsLoading { get; set; } + [Parameter] public bool IsStreaming { get; set; } + [Parameter] public double LoadProgress { get; set; } + [Parameter] public double DisplayTime { get; set; } + [Parameter] public double? Duration { get; set; } + [Parameter] public EventCallback TogglePlayPause { get; set; } + [Parameter] public EventCallback Stop { get; set; } + [Parameter] public string? Class { get; set; } +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.css new file mode 100644 index 0000000..32d89a0 --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerTransportZone.razor.css @@ -0,0 +1,4 @@ +/* Stable minimum width so the transport cluster doesn't reflow */ +.controls-left { + min-width: 200px; +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor new file mode 100644 index 0000000..8f13f81 --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor @@ -0,0 +1,12 @@ +@namespace DeepDrftPublic.Client.Controls.AudioPlayerBar + + + + + diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor.cs new file mode 100644 index 0000000..de84f7c --- /dev/null +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerWindowControls.razor.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Components; + +namespace DeepDrftPublic.Client.Controls.AudioPlayerBar; + +public partial class PlayerWindowControls : ComponentBase +{ + [Parameter] public EventCallback OnMinimize { get; set; } + [Parameter] public EventCallback OnClose { get; set; } +} diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/SpectrumVisualizer.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/SpectrumVisualizer.razor.css index 64dbbd2..b366fd9 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/SpectrumVisualizer.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/SpectrumVisualizer.razor.css @@ -26,22 +26,11 @@ min-width: 4px; height: var(--bar-height, 2%); min-height: 2px; - background: var(--deepdrft-theme-secondary); + background: var(--mud-palette-primary); border-radius: 2px 2px 0 0; transition: height 0.05s ease-out; } -/* Charleston (Light Mode) - Iron to gold colored bars */ -:global(.deepdrft-theme-light) .spectrum-bar { - background: linear-gradient(to top, var(--charleston-iron) 0%, var(--charleston-rose) 50%, var(--charleston-gold) 100%); -} - -/* Lowcountry (Dark Mode) - Coral to gold bars with warm glow */ -:global(.deepdrft-theme-dark) .spectrum-bar { - background: linear-gradient(to top, var(--lowcountry-coral) 0%, var(--lowcountry-gold) 100%); - box-shadow: 0 0 4px color-mix(in srgb, var(--lowcountry-gold) 40%, transparent); -} - /* Responsive adjustments */ @media (max-width: 768px) { .spectrum-container { diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor index 23e4fe8..7a3e522 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor @@ -1,5 +1,5 @@ -
- +
+ @FormatTime(CurrentTime) / @(Duration.HasValue ? FormatTime(Duration.Value) : "--:--") -
\ No newline at end of file +
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor.css index 5c39ee9..4b1cea6 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TimestampLabel.razor.css @@ -1,12 +1,5 @@ -/* TimestampLabel Component Styles */ - -/* Timestamp display */ +/* Layout stability so the timestamp doesn't reflow as digits change */ .timestamp-display { min-width: 120px; text-align: center; } - -/* Time text styling */ -.time-text { - font-family: monospace; -} \ No newline at end of file diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor index c2066d6..94be941 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor @@ -1,5 +1,5 @@ -
- + + -
\ No newline at end of file + diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor.css index 7c41b24..c31db9b 100644 --- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor.css +++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeControls.razor.css @@ -1,19 +1,8 @@ -/* VolumeControls Component Styles */ - -/* Volume control container */ +/* Width caps only — layout/colour come from MudStack + theme */ .volume-controls { - display: flex; - align-items: center; - gap: 0.25rem; width: 140px; } -/* Volume icon styling */ -.volume-icon { - margin-right: 4px; -} - -/* Volume slider styling */ .volume-slider { width: 100px; -} \ No newline at end of file +}