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

+42 -10
View File
@@ -1,15 +1,47 @@
@inherits LayoutComponentBase
@inherits LayoutComponentBase
@implements IDisposable
<div class="relative flex flex-col md:flex-row w-full h-full">
<NavMenu />
@* The page and its menu. The overlays it holds (dialogs, menus, sheets: IDOverlayHost, cascaded) close with the phone's
Back button: while one is open, Back closes the newest instead of leaving the page; a link followed or the app's own
navigation closes them all and goes on. *@
<CascadingValue Value="(IDOverlayHost)Overlays" IsFixed="true">
<div class="relative flex flex-col md:flex-row w-full h-full">
<NavMenu />
<div class="block flex-1 relative w-full h-full">
<div class="block absolute overflow-y-auto w-full h-full p-3 md:py-4 md:pl-2 md:pr-4">
@Body
<div class="block flex-1 relative w-full h-full">
<div class="block absolute overflow-y-auto w-full h-full p-3 md:py-4 md:pl-2 md:pr-4">
@Body
</div>
</div>
</div>
</div>
<ToastHost />
<PublicNoticeHost />
<ConfirmHost />
<ToastHost />
<PublicNoticeHost />
<ConfirmHost />
</CascadingValue>
@code {
[Inject] OverlayService Overlays { get; set; }
[Inject] NavigationManager Navigation { get; set; }
[Inject] AppStatusService Status { get; set; }
IDisposable changing;
protected override void OnInitialized() => changing = Navigation.RegisterLocationChangingHandler(OnLocationChanging);
async ValueTask OnLocationChanging(LocationChangingContext context)
{
var back = !context.IsNavigationIntercepted && Status.TookBack();
if (!Overlays.HasOpen)
return;
if (back)
{
context.PreventNavigation();
await Overlays.CloseTop(context.CancellationToken);
return;
}
await Overlays.CloseAll(context.CancellationToken);
}
public void Dispose() => changing?.Dispose();
}