feat(public-nav): slim appbar to ARCHIVE + inline CUTS/SESSIONS/MIXES, drop GENRES and Tracks (8.I)
Desktop flattens the ARCHIVE popover into inline appbar links above the medium breakpoint; mobile keeps the indented sub-list under ARCHIVE. GENRES and /tracks removed from nav only — routes (GenresView, TracksView) remain reachable by URL. Retires the now-dead desktop hover-popover and its 8.J collapse-state machinery (mobile drawer still dismisses on click).
This commit is contained in:
@@ -10,32 +10,17 @@
|
||||
<ul class="dd-nav-links">
|
||||
@foreach (var navPage in Pages.MenuPages)
|
||||
{
|
||||
@if (navPage.HasChildren)
|
||||
{
|
||||
@* Dual-role node: the parent anchor navigates to its own route on click,
|
||||
while hover/focus reveals the child dropdown (pure CSS, no JS).
|
||||
dd-nav-item-collapsed is added on child click to force-hide the
|
||||
dropdown after SPA navigation (which keeps the DOM and may leave
|
||||
:hover true). It is cleared on mouseleave so the next hover works. *@
|
||||
<li class="dd-nav-item-parent @(_collapsedDropdowns.Contains(navPage.Route) ? "dd-nav-item-collapsed" : "")"
|
||||
@onmouseleave="() => ResetDropdown(navPage.Route)"
|
||||
@onfocusout="() => ResetDropdown(navPage.Route)">
|
||||
<a href="@navPage.Route" class="dd-nav-link">@navPage.Name</a>
|
||||
<ul class="dd-nav-dropdown">
|
||||
@foreach (var child in navPage.Children)
|
||||
{
|
||||
<li>
|
||||
<a href="@child.Route" class="dd-nav-link dd-nav-dropdown-link"
|
||||
@onclick="() => CollapseDropdown(navPage.Route)">@child.Name</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
@* Above the medium breakpoint the medium modes ride inline beside their parent:
|
||||
the parent link renders, then each child renders as its own sibling appbar link.
|
||||
No popover — so the 8.J stuck-open dismissal applies only to the mobile drawer
|
||||
below, where clicks close the menu. *@
|
||||
<li>
|
||||
<a href="@navPage.Route" class="dd-nav-link">@navPage.Name</a>
|
||||
</li>
|
||||
@foreach (var child in navPage.Children)
|
||||
{
|
||||
<li>
|
||||
<a href="@navPage.Route" class="dd-nav-link">@navPage.Name</a>
|
||||
<a href="@child.Route" class="dd-nav-link">@child.Name</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
@@ -96,7 +81,6 @@
|
||||
[Parameter] public required EventCallback<bool> IsDarkModeChanged { get; set; }
|
||||
|
||||
private bool _mobileMenuOpen;
|
||||
private readonly HashSet<string> _collapsedDropdowns = [];
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -129,8 +113,4 @@
|
||||
private void ToggleMobileMenu() => _mobileMenuOpen = !_mobileMenuOpen;
|
||||
|
||||
private void CloseMobileMenu() => _mobileMenuOpen = false;
|
||||
|
||||
private void CollapseDropdown(string route) => _collapsedDropdowns.Add(route);
|
||||
|
||||
private void ResetDropdown(string route) => _collapsedDropdowns.Remove(route);
|
||||
}
|
||||
|
||||
@@ -82,66 +82,6 @@
|
||||
color: var(--deepdrft-white);
|
||||
}
|
||||
|
||||
/* Dual-role parent node: anchor for the parent route, positioning context for the dropdown. */
|
||||
.dd-nav-item-parent {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Hover-revealed child dropdown. Pure CSS — hidden by default, shown when the parent item is
|
||||
hovered or contains keyboard focus. Sits directly beneath the parent link, frosted to match
|
||||
the bar. */
|
||||
.dd-nav-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(0.25rem);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.75rem;
|
||||
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 1rem 1.5rem;
|
||||
min-width: 9rem;
|
||||
|
||||
background: rgba(250, 250, 248, 0.96);
|
||||
border: 1px solid var(--deepdrft-border);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
backdrop-filter: blur(18px);
|
||||
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.18s ease, visibility 0.18s ease;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
.dd-nav-dark .dd-nav-dropdown {
|
||||
background: rgba(13, 13, 18, 0.95);
|
||||
}
|
||||
|
||||
.dd-nav-item-parent:hover .dd-nav-dropdown,
|
||||
.dd-nav-item-parent:focus-within .dd-nav-dropdown {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Force-close the dropdown immediately after a child link is clicked (SPA navigation
|
||||
keeps the DOM and :hover may remain true). Cleared on mouseleave so the next
|
||||
hover cycle works normally. */
|
||||
.dd-nav-item-parent.dd-nav-item-collapsed .dd-nav-dropdown {
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.dd-nav-dropdown-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Right-side cluster */
|
||||
.dd-nav-actions {
|
||||
display: flex;
|
||||
|
||||
@@ -19,6 +19,11 @@ public class PageRoute
|
||||
|
||||
public static class Pages
|
||||
{
|
||||
// ARCHIVE (→ the release-cardinal /archive browser) carries the three medium modes as Children.
|
||||
// Above the medium breakpoint the desktop nav flattens them into inline appbar links beside
|
||||
// ARCHIVE (no popover); below the breakpoint the mobile hamburger renders them as an indented
|
||||
// sub-list under ARCHIVE. /tracks and /genres are intentionally absent from the nav (8.I) —
|
||||
// their routes (TracksView, GenresView) remain reachable by direct URL.
|
||||
public static readonly List<PageRoute> MenuPages =
|
||||
[
|
||||
new()
|
||||
@@ -31,8 +36,6 @@ public static class Pages
|
||||
new() { Name = "Mixes", Route = "/mixes", Icon = Icons.Material.Filled.GraphicEq },
|
||||
],
|
||||
},
|
||||
new() { Name = "Tracks", Route = "/tracks", Icon = Icons.Material.Filled.MusicNote },
|
||||
new() { Name = "Genres", Route = "/genres", Icon = Icons.Material.Filled.Category },
|
||||
];
|
||||
|
||||
public static readonly List<PageRoute> AllPages =
|
||||
|
||||
Reference in New Issue
Block a user