fix: popover surface — body-class bridge for portal scope, retune light/dark

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).
This commit is contained in:
daniel-c-harvey
2026-06-20 00:15:42 -04:00
parent 9300c794b4
commit b5106d090f
2 changed files with 31 additions and 9 deletions
@@ -46,6 +46,7 @@
[Inject] public required PersistentComponentState PersistentState { get; set; } [Inject] public required PersistentComponentState PersistentState { get; set; }
[Inject] public required DarkModeSettings DarkModeSettings { get; set; } [Inject] public required DarkModeSettings DarkModeSettings { get; set; }
[Inject] public required IJSRuntime JS { get; set; }
protected override void OnInitialized() protected override void OnInitialized()
{ {
@@ -66,6 +67,15 @@
_persistingSubscription = PersistentState.RegisterOnPersisting(PersistDarkMode); _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 // Theme wrapper class for CSS targeting
private string ThemeWrapperClass => _isDarkMode ? "deepdrft-theme-dark" : "deepdrft-theme-light"; private string ThemeWrapperClass => _isDarkMode ? "deepdrft-theme-dark" : "deepdrft-theme-light";
@@ -85,10 +85,13 @@
--deepdrft-play-chip-soft: var(--deepdrft-soft); --deepdrft-play-chip-soft: var(--deepdrft-soft);
/* Popover surface (Phase 18). Default MudBlazor popovers (selects/menus/tooltips/share /* Popover surface (Phase 18). Default MudBlazor popovers (selects/menus/tooltips/share
body) bind this. Light is a soft desaturated-navy wash so they read as a calm light body) bind this. Light uses a very subtle navy wash (4%) — near the page background but
surface; dark uses the existing panel-ground charcoal. Bespoke dark-glass panels just perceptibly off-white so the popover reads as an elevated surface. Dark uses a
(visualizer/queue/privacy) do NOT bind this — they keep --deepdrft-panel-ground directly. */ bluer navy (colour-mix of navy-mid + green-accent at 20%), defined in the
--deepdrft-popover-surface: color-mix(in srgb, var(--deepdrft-navy) 8%, var(--deepdrft-white)); body.deepdrft-theme-dark block below so it reaches portaled popover content (popovers
portal to <body>, outside the .deepdrft-theme-dark wrapper div). Bespoke dark-glass
panels (visualizer/queue/privacy) do NOT bind this — they keep --deepdrft-panel-ground. */
--deepdrft-popover-surface: color-mix(in srgb, var(--deepdrft-navy) 4%, var(--deepdrft-white));
/* Fixed-nav height — single source of truth shared by the frosted-glass nav /* Fixed-nav height — single source of truth shared by the frosted-glass nav
(DeepDrftMenu.razor.css pins .dd-nav to this) and the main-content clearance (DeepDrftMenu.razor.css pins .dd-nav to this) and the main-content clearance
@@ -163,9 +166,18 @@
--deepdrft-play-glyph: var(--deepdrft-navy); --deepdrft-play-glyph: var(--deepdrft-navy);
--deepdrft-play-chip-soft: color-mix(in srgb, var(--deepdrft-green-accent) 30%, transparent); --deepdrft-play-chip-soft: color-mix(in srgb, var(--deepdrft-green-accent) 30%, transparent);
/* Popover surface (Phase 18). Symptom #1 is a LIGHT-mode complaint and the acceptance bar /* Popover surface (Phase 18) — within .deepdrft-theme-dark wrapper this value applies to
requires dark popovers to stay unchanged, so dark binds the exact current MudBlazor dark non-portaled elements only. Portaled MudBlazor popovers live at <body> level; the
Surface (#162437, DeepDrftPalettes.Dark.Surface) — NOT §3's suggested panel-ground (#1a1c22), body.deepdrft-theme-dark block below is the authoritative dark value for those. Keep
which would have shifted dark popovers a shade. Pixel-identical dark; only light is retoned. */ this in sync with that block for non-portaled surfaces (drawers, inline menus). */
--deepdrft-popover-surface: #162437; --deepdrft-popover-surface: color-mix(in srgb, var(--deepdrft-navy-mid) 80%, var(--deepdrft-green-accent) 20%);
}
/* Portal-scope dark popover surface. MudBlazor popovers (selects, menus, share body) portal
to <body>, placing them outside the .deepdrft-theme-dark wrapper div. MainLayout.razor syncs
deepdrft-theme-dark onto <body> via JS after each render, so this selector reaches portaled
content. The value mirrors the .deepdrft-theme-dark block above — bluer navy
(navy-mid + 20% green-accent tint) rather than the pure charcoal #162437. */
body.deepdrft-theme-dark {
--deepdrft-popover-surface: color-mix(in srgb, var(--deepdrft-navy-mid) 80%, var(--deepdrft-green-accent) 20%);
} }