b5106d090f
MudBlazor popovers portal to <body>, outside the theme wrapper, so the dark token was unreachable. MainLayout now stamps deepdrft-theme-dark on <body>. Light: 8%->4% navy (near page background); dark: navy-mid + 20% green-accent (bluer).
101 lines
3.5 KiB
Plaintext
101 lines
3.5 KiB
Plaintext
@using DeepDrftPublic.Client.Controls
|
|
@using DeepDrftPublic.Client.Controls.AudioPlayerBar
|
|
@using DeepDrftPublic.Client.Services
|
|
@using DeepDrftPublic.Client.Common
|
|
@using DeepDrftShared.Client.Common
|
|
@using Microsoft.AspNetCore.Components
|
|
@inherits LayoutComponentBase
|
|
@implements IDisposable
|
|
|
|
<MudThemeProvider Theme="@DeepDrftPalettes.Default" IsDarkMode="_isDarkMode" />
|
|
<MudPopoverProvider />
|
|
<MudDialogProvider />
|
|
<MudSnackbarProvider />
|
|
<div class="@ThemeWrapperClass">
|
|
<MudLayout Style="display: flex; flex-direction: column; min-height: 100vh">
|
|
<AudioPlayerProvider>
|
|
<DeepDrftMenu Elevation="4" @bind-IsDarkMode="_isDarkMode" />
|
|
<MudMainContent Class="flex-grow-1 pb-8 dd-main-content">
|
|
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
|
|
@Body
|
|
</MudContainer>
|
|
</MudMainContent>
|
|
<DeepDrftFooter />
|
|
<AudioPlayerBar OnMinimized="ToggleAudioPlayerMinimized" />
|
|
|
|
@* Spacer to prevent content overlap. Height tracks the fixed player
|
|
dock's live size via the --player-height var the player publishes
|
|
(see AudioPlayerBar / Interop/layout/spacer.ts). *@
|
|
<div class="player-spacer @_audioPlayerClass"></div>
|
|
</AudioPlayerProvider>
|
|
</MudLayout>
|
|
</div>
|
|
|
|
|
|
<div id="blazor-error-ui" data-nosnippet>
|
|
An unhandled error has occurred.
|
|
<a href="." class="reload">Reload</a>
|
|
<span class="dismiss">🗙</span>
|
|
</div>
|
|
|
|
@code {
|
|
private string _audioPlayerClass = "minimized";
|
|
private const string DarkModeKey = "darkMode";
|
|
private bool _isDarkMode = false;
|
|
private PersistingComponentStateSubscription _persistingSubscription;
|
|
|
|
[Inject] public required PersistentComponentState PersistentState { get; set; }
|
|
[Inject] public required DarkModeSettings DarkModeSettings { get; set; }
|
|
[Inject] public required IJSRuntime JS { get; set; }
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
base.OnInitialized();
|
|
|
|
// Restore persisted dark mode state (from server prerender)
|
|
if (PersistentState.TryTakeFromJson<bool>(DarkModeKey, out var restored))
|
|
{
|
|
_isDarkMode = restored;
|
|
DarkModeSettings.IsDarkMode = restored;
|
|
}
|
|
else
|
|
{
|
|
_isDarkMode = DarkModeSettings.IsDarkMode;
|
|
}
|
|
|
|
// Register to persist state when prerendering completes
|
|
_persistingSubscription = PersistentState.RegisterOnPersisting(PersistDarkMode);
|
|
}
|
|
|
|
// Sync dark mode class on <body> so portaled MudBlazor elements (popovers, menus, selects)
|
|
// inherit --deepdrft-popover-surface from body.deepdrft-theme-dark rather than from :root only.
|
|
// Popovers portal outside the ThemeWrapperClass div, so only a body-level class can reach them.
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
await JS.InvokeVoidAsync("eval",
|
|
$"document.body.classList.toggle('deepdrft-theme-dark', {_isDarkMode.ToString().ToLower()})");
|
|
}
|
|
|
|
// Theme wrapper class for CSS targeting
|
|
private string ThemeWrapperClass => _isDarkMode ? "deepdrft-theme-dark" : "deepdrft-theme-light";
|
|
|
|
private Task PersistDarkMode()
|
|
{
|
|
PersistentState.PersistAsJson(DarkModeKey, _isDarkMode);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_persistingSubscription.Dispose();
|
|
}
|
|
|
|
private void ToggleAudioPlayerMinimized(bool isMinimized)
|
|
{
|
|
_audioPlayerClass = isMinimized ? "minimized" : "expanded";
|
|
}
|
|
|
|
}
|
|
|
|
|