Files
decePubClient/Components/PhoneSheet.razor
T
thepraandClaude Opus 5.5 f1ac5eaad2 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
2026-10-06 23:49:49 +02:00

60 lines
2.1 KiB
Plaintext

@inherits LocalizableComponentBase
@* What opens in place on a desktop (the composer at the top of the feed, a reply under its post) and as a sheet from the
bottom of a phone's screen (below md), over a dimmed page, with its heading and a close button; a tap outside it or
Escape closes it too. Class is the inline look from md (padding, a raised panel). *@
@if (IsOpen)
{
<div class="max-md:fixed max-md:inset-0 max-md:z-[60] max-md:flex max-md:flex-col max-md:justify-end" @onkeydown="OnKeyDown">
<div class="md:hidden absolute inset-0 bg-black/40" aria-hidden="true" @onclick="Close"></div>
<div class="@($"relative max-md:max-h-[85dvh] max-md:overflow-y-auto max-md:overscroll-contain max-md:rounded-t-box max-md:bg-base-100 max-md:p-4 max-md:pb-[max(1rem,env(safe-area-inset-bottom))] {Class}")"
data-sheet>
<div class="md:hidden flex items-center gap-3 mb-3">
<b class="flex-1 min-w-0 truncate">@Heading</b>
<button type="button" class="btn btn-sm btn-circle btn-ghost flex-none" aria-label="@Localizer["Close"]" title="@Localizer["Close"]"
@onclick="Close" data-sheet-close>
<i class="ion-md-close" aria-hidden="true"></i>
</button>
</div>
@ChildContent
</div>
</div>
}
@code {
[Parameter] public bool IsOpen { get; set; }
[Parameter] public EventCallback OnClose { get; set; }
/// <summary>The sheet's heading on a phone.</summary>
[Parameter] public string Heading { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Class { get; set; }
[Inject] OverlayService Overlays { get; set; }
IDisposable overlay;
protected override void OnInitialized() => IsLoading = false;
// open, the Back button closes it
protected override void OnParametersSet()
{
if (IsOpen && overlay is null)
overlay = Overlays.Open(() => InvokeAsync(Close));
else if (!IsOpen && overlay is not null)
{
overlay.Dispose();
overlay = null;
}
}
public override async ValueTask DisposeAsync()
{
overlay?.Dispose();
await base.DisposeAsync();
}
Task Close() => OnClose.InvokeAsync();
Task OnKeyDown(KeyboardEventArgs e) => e.Key == "Escape" ? Close() : Task.CompletedTask;
}