Add tablet navigation drawer to shell

This commit is contained in:
2026-03-21 13:32:44 +01:00
parent a7bacbabfc
commit 4934c39f9f
3 changed files with 146 additions and 0 deletions

View File

@@ -1,3 +1,6 @@
@implements IDisposable
@inject NavigationManager NavigationManager
<div class="app-shell">
<a class="skip-link" href="#app-main">Skip to main content</a>
@@ -39,6 +42,17 @@
</div>
<div class="app-shell-header-actions">
<button
type="button"
class="app-shell-menu-toggle"
aria-expanded="@isNavMenuOpen"
aria-controls="app-shell-drawer"
@onclick="ToggleNavMenu">
<span class="app-shell-menu-toggle-bar"></span>
<span class="app-shell-menu-toggle-bar"></span>
<span class="app-shell-menu-toggle-bar"></span>
<span class="visually-hidden">Toggle navigation</span>
</button>
@UtilityContent
</div>
</div>
@@ -57,6 +71,26 @@
</div>
</main>
@if (isNavMenuOpen)
{
<button
type="button"
class="app-shell-drawer-backdrop"
aria-label="Close navigation"
@onclick="CloseNavMenu"></button>
<aside id="app-shell-drawer" class="app-shell-drawer" aria-label="Primary navigation">
<div class="app-shell-drawer-header">
<strong>Navigate</strong>
<button type="button" class="app-shell-drawer-close" @onclick="CloseNavMenu">
Close
</button>
</div>
<ShellPrimaryNav />
</aside>
}
<nav class="app-shell-mobile-nav" aria-label="Primary">
<ShellPrimaryNav IsBottomNav="true" />
</nav>
@@ -80,4 +114,32 @@
[Parameter]
public RenderFragment? UtilityContent { get; set; }
private bool isNavMenuOpen;
protected override void OnInitialized()
{
NavigationManager.LocationChanged += HandleLocationChanged;
}
private void ToggleNavMenu()
{
isNavMenuOpen = !isNavMenuOpen;
}
private void CloseNavMenu()
{
isNavMenuOpen = false;
}
private void HandleLocationChanged(object? sender, LocationChangedEventArgs args)
{
isNavMenuOpen = false;
_ = InvokeAsync(StateHasChanged);
}
public void Dispose()
{
NavigationManager.LocationChanged -= HandleLocationChanged;
}
}

View File

@@ -103,6 +103,28 @@
min-height: 2.75rem;
}
.app-shell-menu-toggle {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.24rem;
width: 2.75rem;
height: 2.75rem;
border: 1px solid var(--border-default);
border-radius: 16px;
background: color-mix(in srgb, var(--surface-2) 84%, transparent);
color: var(--text-primary);
padding: 0;
}
.app-shell-menu-toggle-bar {
width: 1rem;
height: 2px;
border-radius: 999px;
background: currentColor;
}
.app-shell-shortcuts {
margin-top: 0.75rem;
}
@@ -128,6 +150,55 @@
margin-top: auto;
}
.app-shell-drawer-backdrop {
position: fixed;
inset: 0;
z-index: 45;
border: none;
background: var(--bg-overlay);
padding: 0;
}
.app-shell-drawer {
position: fixed;
top: 1rem;
right: 1rem;
z-index: 50;
width: min(24rem, calc(100vw - 2rem));
padding: 1rem;
border: 1px solid var(--border-default);
border-radius: 24px;
background: color-mix(in srgb, var(--bg-elevated) 94%, transparent);
box-shadow: var(--shadow-2);
backdrop-filter: blur(18px);
}
.app-shell-drawer .shell-primary-nav {
flex-direction: column;
align-items: stretch;
}
.app-shell-drawer .shell-primary-nav-link {
justify-content: flex-start;
}
.app-shell-drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.app-shell-drawer-close {
border: 1px solid var(--border-default);
border-radius: 999px;
background: color-mix(in srgb, var(--surface-2) 84%, transparent);
color: var(--text-primary);
min-height: 2.5rem;
padding: 0.45rem 0.85rem;
}
@media (max-width: 767.98px) {
.app-shell-header {
padding: 0.65rem 0.75rem 0;
@@ -170,4 +241,15 @@
.app-shell-header-nav {
display: none;
}
.app-shell-menu-toggle {
display: inline-flex;
}
}
@media (min-width: 1024px) {
.app-shell-drawer,
.app-shell-drawer-backdrop {
display: none;
}
}