The phone menu closes after a choice
On a phone the menu stayed open over the page after a link was tapped, and only the hamburger closed it. It now closes
on any navigation, on a persona switch, on a tap outside it (a dimmed backdrop) and on Escape; its height is capped at
the screen's (dvh) with its own scroll, and its width follows a narrow screen. The hamburger has a name ("Menu") and says
whether the menu is open. The header's logo is a link home and the persona's picture a 44px link to Settings (it was
30px). From md, the sidebar scrolls on its own when the window is short, as on a phone held sideways.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
6731077191
commit
f1cb90ac03
3 files changed
+50
-17
No files matched your search
@@ -1817,4 +1817,7 @@
|
|||||||
<data name="{0} filtered, waiting for you" xml:space="preserve">
|
<data name="{0} filtered, waiting for you" xml:space="preserve">
|
||||||
<value>{0} filtrate, ti aspettano</value>
|
<value>{0} filtrate, ti aspettano</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Menu" xml:space="preserve">
|
||||||
|
<value>Menu</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1817,4 +1817,7 @@
|
|||||||
<data name="{0} filtered, waiting for you" xml:space="preserve">
|
<data name="{0} filtered, waiting for you" xml:space="preserve">
|
||||||
<value>{0} filtered, waiting for you</value>
|
<value>{0} filtered, waiting for you</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Menu" xml:space="preserve">
|
||||||
|
<value>Menu</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
+44
-17
@@ -1,12 +1,22 @@
|
|||||||
@inherits LocalizableComponentBase
|
@inherits LocalizableComponentBase
|
||||||
|
|
||||||
<nav class="flex justify-between items-center md:items-start pt-3 px-3 md:p-0">
|
@* On a phone the menu opens from the hamburger over the page, and closes after a choice (any navigation, a persona
|
||||||
|
switch), on a tap outside it or on Escape; from md it is the sidebar, which scrolls on its own when the window is
|
||||||
|
short (a phone held sideways). *@
|
||||||
|
<nav class="flex justify-between items-center md:items-start pt-3 px-3 md:p-0 md:h-full md:overflow-y-auto md:overscroll-contain"
|
||||||
|
@onkeydown="OnKeyDown">
|
||||||
|
|
||||||
|
@if (isMenuOpen)
|
||||||
|
{
|
||||||
|
<div class="md:hidden fixed inset-0 z-40 bg-black/30" aria-hidden="true" @onclick="CloseMenu"></div>
|
||||||
|
}
|
||||||
<div class="relative md:w-52">
|
<div class="relative md:w-52">
|
||||||
<DButton Size="DSize.Sm" class="md:hidden" OnClick="ToggleNavMenu">
|
<DButton Size="DSize.Sm" class="md:hidden" OnClick="ToggleNavMenu" aria-label="@Localizer["Menu"]" title="@Localizer["Menu"]"
|
||||||
<i class="ion-md-menu text-lg"></i>
|
aria-expanded="@(isMenuOpen ? "true" : "false")" aria-controls="nav-panel" data-nav-toggle>
|
||||||
|
<i class="ion-md-menu text-lg" aria-hidden="true"></i>
|
||||||
</DButton>
|
</DButton>
|
||||||
<div class="absolute bg-base-100 md:relative top-full md:top-auto mt-2 w-52 md:w-full overflow-y-auto rounded-lg neo-raised neo-sm md:shadow-none! z-50 @menuToggle md:block">
|
<div id="nav-panel" data-nav-panel
|
||||||
|
class="@(isMenuOpen ? "block" : "hidden") md:block absolute bg-base-100 md:relative top-full md:top-auto mt-2 w-[min(18rem,calc(100vw-1.5rem))] md:w-full max-h-[calc(100dvh-5rem)] md:max-h-none overflow-y-auto overscroll-contain rounded-lg neo-raised neo-sm md:shadow-none! z-50">
|
||||||
<div class="flex flex-col gap-3 p-3 md:p-4">
|
<div class="flex flex-col gap-3 p-3 md:p-4">
|
||||||
|
|
||||||
@if (CascadingState.IsSignedIn)
|
@if (CascadingState.IsSignedIn)
|
||||||
@@ -116,21 +126,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="md:hidden">
|
<a class="md:hidden grid place-items-center h-11 w-11" href="" aria-label="@Localizer["Home"]" title="@Localizer["Home"]">
|
||||||
<img alt="" class="h-[30px]" src="imgs/icon-512.png">
|
<img alt="" class="h-[30px]" src="imgs/icon-512.png">
|
||||||
</div>
|
</a>
|
||||||
|
|
||||||
<div class="md:hidden">
|
<a class="md:hidden grid place-items-center h-11 w-11" href="settings" aria-label="@Localizer["Settings"]" title="@Localizer["Settings"]">
|
||||||
<a class="block rounded-full neo-raised neo-2xs" href="settings">
|
<img alt="@CascadingState.Persona?.Name" class="object-cover w-[30px] h-[30px] rounded-full neo-raised neo-2xs"
|
||||||
<img alt="@CascadingState.Persona?.Name" class="object-cover w-[30px] h-[30px] rounded-full"
|
|
||||||
src="@(CascadingState.Persona?.Avatar ?? "imgs/icon-192.png")">
|
src="@(CascadingState.Persona?.Avatar ?? "imgs/icon-192.png")">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
string menuToggle = "hidden";
|
bool isMenuOpen;
|
||||||
bool isPersonaMenuOpen;
|
bool isPersonaMenuOpen;
|
||||||
|
|
||||||
string PersonaBackground => CascadingState.Persona?.Header is { Length: > 0 } header && !header.Contains("/missing-")
|
string PersonaBackground => CascadingState.Persona?.Header is { Length: > 0 } header && !header.Contains("/missing-")
|
||||||
@@ -144,21 +152,40 @@
|
|||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
if (!CascadingState.Status.IsMobileMedia())
|
Navigation.LocationChanged += OnLocationChanged;
|
||||||
menuToggle = default;
|
}
|
||||||
|
|
||||||
|
void OnLocationChanged(object sender, LocationChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!isMenuOpen)
|
||||||
|
return;
|
||||||
|
isMenuOpen = false;
|
||||||
|
InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseMenu() => isMenuOpen = false;
|
||||||
|
|
||||||
|
void OnKeyDown(KeyboardEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == "Escape")
|
||||||
|
isMenuOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
Navigation.LocationChanged -= OnLocationChanged;
|
||||||
|
await base.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task SwitchPersona(string personaId)
|
async Task SwitchPersona(string personaId)
|
||||||
{
|
{
|
||||||
|
isMenuOpen = false;
|
||||||
var result = await CascadingState.SwitchPersona(personaId);
|
var result = await CascadingState.SwitchPersona(personaId);
|
||||||
if (result.IsInvalid)
|
if (result.IsInvalid)
|
||||||
Toast.AddResponseError(result);
|
Toast.AddResponseError(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleNavMenu()
|
private void ToggleNavMenu() => isMenuOpen = !isMenuOpen;
|
||||||
{
|
|
||||||
menuToggle = menuToggle is { Length: > 0 } ? default : "hidden";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ResetToOriginalColour()
|
protected async Task ResetToOriginalColour()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user