2026-10-06 23:15:54 +02:00
|
|
|
@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; }
|
|
|
|
|
|
2026-10-06 23:49:49 +02:00
|
|
|
[Inject] OverlayService Overlays { get; set; }
|
|
|
|
|
|
|
|
|
|
IDisposable overlay;
|
|
|
|
|
|
2026-10-06 23:15:54 +02:00
|
|
|
protected override void OnInitialized() => IsLoading = false;
|
|
|
|
|
|
2026-10-06 23:49:49 +02:00
|
|
|
// 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();
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-06 23:15:54 +02:00
|
|
|
Task Close() => OnClose.InvokeAsync();
|
|
|
|
|
|
|
|
|
|
Task OnKeyDown(KeyboardEventArgs e) => e.Key == "Escape" ? Close() : Task.CompletedTask;
|
|
|
|
|
}
|