refactor: replace eval dark-mode body-class with TS theme interop helper

Extracts setBodyThemeClass into DeepDrftShared.Client/Interop/theme/theme.ts;
MainLayout lazy-imports the compiled module and calls it, matching the
established knob/parallax IJSObjectReference pattern. DisposeAsync added.
This commit is contained in:
daniel-c-harvey
2026-06-20 00:26:52 -04:00
parent 30999b038c
commit 2591710f09
2 changed files with 29 additions and 2 deletions
+14 -2
View File
@@ -6,6 +6,7 @@
@using Microsoft.AspNetCore.Components @using Microsoft.AspNetCore.Components
@inherits LayoutComponentBase @inherits LayoutComponentBase
@implements IDisposable @implements IDisposable
@implements IAsyncDisposable
<MudThemeProvider Theme="@DeepDrftPalettes.Default" IsDarkMode="_isDarkMode" /> <MudThemeProvider Theme="@DeepDrftPalettes.Default" IsDarkMode="_isDarkMode" />
<MudPopoverProvider /> <MudPopoverProvider />
@@ -44,6 +45,7 @@
private bool _isDarkMode = false; private bool _isDarkMode = false;
private bool? _lastAppliedDarkMode = null; private bool? _lastAppliedDarkMode = null;
private PersistingComponentStateSubscription _persistingSubscription; private PersistingComponentStateSubscription _persistingSubscription;
private IJSObjectReference? _themeModule;
[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; }
@@ -80,8 +82,9 @@
if (firstRender || _isDarkMode != _lastAppliedDarkMode) if (firstRender || _isDarkMode != _lastAppliedDarkMode)
{ {
_lastAppliedDarkMode = _isDarkMode; _lastAppliedDarkMode = _isDarkMode;
await JS.InvokeVoidAsync("eval", _themeModule ??= await JS.InvokeAsync<IJSObjectReference>(
$"document.body.classList.toggle('deepdrft-theme-dark', {_isDarkMode.ToString().ToLower()})"); "import", "./_content/DeepDrftShared.Client/js/theme/theme.js");
await _themeModule.InvokeVoidAsync("setBodyThemeClass", _isDarkMode);
} }
} }
@@ -99,6 +102,15 @@
_persistingSubscription.Dispose(); _persistingSubscription.Dispose();
} }
public async ValueTask DisposeAsync()
{
if (_themeModule != null)
{
try { await _themeModule.DisposeAsync(); }
catch (JSDisconnectedException) { /* circuit torn down */ }
}
}
private void ToggleAudioPlayerMinimized(bool isMinimized) private void ToggleAudioPlayerMinimized(bool isMinimized)
{ {
_audioPlayerClass = isMinimized ? "minimized" : "expanded"; _audioPlayerClass = isMinimized ? "minimized" : "expanded";
@@ -0,0 +1,15 @@
/**
* theme - body-class helpers for dark-mode theme toggling.
*
* Single Responsibility: apply or remove the deepdrft-theme-dark class on
* document.body so that 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.
*/
/** Toggle the deepdrft-theme-dark class on document.body.
* @param isDark true to add the class, false to remove it. */
export function setBodyThemeClass(isDark: boolean): void {
document.body.classList.toggle('deepdrft-theme-dark', isDark);
}