@using DeepDrftPublic.Client.Common @using DeepDrftPublic.Client.Services @implements IAsyncDisposable @code { [Inject] public required IBrowserViewportService BrowserViewportService { get; set; } [Inject] public required DarkModeCookieService DarkModeCookieService { get; set; } // Elevation is vestigial under the frosted-glass design but kept on the parameter // surface so MainLayout's call site stays intact. [Parameter] public int Elevation { get; set; } [Parameter] public required bool IsDarkMode { get; set; } [Parameter] public required EventCallback IsDarkModeChanged { get; set; } private bool _isDesktop = true; private bool _mobileMenuOpen; private Guid _viewportSubscriptionId; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { // Runs here (not OnInitializedAsync) because OnAfterRenderAsync(firstRender) // is guaranteed not to execute during any SSR prerender pass. During prerender // (now interactive across all of Routes), awaiting IsDarkModeChanged.InvokeAsync // triggers a parent re-render cycle that cannot complete on the prerender renderer // and hangs the response. Server-side DarkModeService has already seeded // DarkModeSettings via PersistentComponentState, so the prerender paint is // already correct; this call reads that persisted value and propagates it to the // parent so the menu's IsDarkMode parameter stays consistent with DarkModeSettings. IsDarkMode = DarkModeCookieService.GetDarkMode(); await IsDarkModeChanged.InvokeAsync(IsDarkMode); _viewportSubscriptionId = Guid.NewGuid(); await BrowserViewportService.SubscribeAsync( _viewportSubscriptionId, args => { _isDesktop = args.Breakpoint >= Breakpoint.Sm; if (_isDesktop) { _mobileMenuOpen = false; } InvokeAsync(StateHasChanged); }, new ResizeOptions { NotifyOnBreakpointOnly = true }, fireImmediately: true); } } public async ValueTask DisposeAsync() { if (_viewportSubscriptionId != Guid.Empty) await BrowserViewportService.UnsubscribeAsync(_viewportSubscriptionId); } private string NavClass => IsDarkMode ? "dd-nav dd-nav-dark" : "dd-nav dd-nav-light"; private string DarkLightModeIconSvg => IsDarkMode ? DDIcons.GasLampLit : DDIcons.GasLamp; private async Task DarkModeToggle() { IsDarkMode = !IsDarkMode; await DarkModeCookieService.SetDarkModeAsync(IsDarkMode); await IsDarkModeChanged.InvokeAsync(IsDarkMode); } private void ToggleMobileMenu() => _mobileMenuOpen = !_mobileMenuOpen; private void CloseMobileMenu() => _mobileMenuOpen = false; }