Back closes what is open

On a phone the Back button left the page under an open menu, sheet or dialog. An open overlay now says so (new
IDOverlayHost, cascaded by MainLayout; OverlayService keeps them newest last): DModal and DDropdown through the
cascade, so the D components stay free of app services, and the nav menu, PhoneSheet and the full-screen globe through
the service. MainLayout's location-changing handler lets Back close the newest overlay instead of leaving the page; a
link followed or the app's own navigation (signing out after its question, say) closes them all and goes on. Blazor
can't tell Back from the app's navigation, so a capture-phase popstate listener in main.js marks Back
(AppStatusService.TookBack). No history entries are pushed. Phone flow: Back closes the menu, a card's More sheet, the
composer and the full-screen globe one after another without leaving the feed, and with nothing open goes back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-06 23:49:49 +02:00
1 parent 5522fe4fbb
commit f1ac5eaad2
12 files changed
+290 -17

No files matched your search

+27 -6
View File
@@ -141,7 +141,27 @@
@code {
[Inject] ConfirmService Confirm { get; set; }
[Inject] OverlayService Overlays { get; set; }
bool isMenuOpen;
IDisposable overlay;
// open, the Back button closes it
void SetMenu(bool open)
{
isMenuOpen = open;
if (open && overlay is null)
overlay = Overlays.Open(() => InvokeAsync(() =>
{
SetMenu(false);
StateHasChanged();
}));
else if (!open && overlay is not null)
{
overlay.Dispose();
overlay = null;
}
}
bool isPersonaMenuOpen;
string PersonaBackground => CascadingState.Persona?.Header is { Length: > 0 } header && !header.Contains("/missing-")
@@ -162,37 +182,38 @@
{
if (!isMenuOpen)
return;
isMenuOpen = false;
SetMenu(false);
InvokeAsync(StateHasChanged);
}
void CloseMenu() => isMenuOpen = false;
void CloseMenu() => SetMenu(false);
void OnKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Escape")
isMenuOpen = false;
SetMenu(false);
}
public override async ValueTask DisposeAsync()
{
Navigation.LocationChanged -= OnLocationChanged;
overlay?.Dispose();
await base.DisposeAsync();
}
async Task SwitchPersona(string personaId)
{
isMenuOpen = false;
SetMenu(false);
var result = await CascadingState.SwitchPersona(personaId);
if (result.IsInvalid)
Toast.AddResponseError(result);
}
private void ToggleNavMenu() => isMenuOpen = !isMenuOpen;
private void ToggleNavMenu() => SetMenu(!isMenuOpen);
async Task Logout()
{
isMenuOpen = false;
SetMenu(false);
if (!await Confirm.Ask(Localizer["Log out?"], Localizer["Every persona of this login is signed out on this device."], Localizer["Logout"], true))
return;
Navigation.NavigateTo("logout");