Skip to content

Commit 2787892

Browse files
committed
Highlight TopNav dropdown items with sub item selected
1 parent 3a40ff9 commit 2787892

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

src/lib/components/furniture/TopNav.svelte

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { page } from '$app/stores';
3-
import { TOP_NAV, SUB_NAV, isActive, type NavItem, type NavGroup } from '$lib/constants/nav';
3+
import { TOP_NAV, SUB_NAV, isActive, type NavItem, type NavGroup, isGroupWithActiveItem, isGroupWithActiveSubDropdown } from '$lib/constants/nav';
44
import Icon from '$lib/components/global/Icon.svelte';
55
import { navbarDisplay } from '$lib/stores/navbarDisplay';
66
import { bookmarks } from '$lib/stores/bookmarks';
@@ -133,7 +133,9 @@
133133
>
134134
<a
135135
href={item.href}
136-
class="nav-link {isActive(currentPath, item.href) ? 'active' : ''}"
136+
class="nav-link"
137+
class:active={isActive(currentPath, item.href)}
138+
class:dropdown-open={hasSubPages(item.href) && activeDropdown === item.href}
137139
aria-current={isActive(currentPath, item.href) ? 'page' : undefined}
138140
aria-expanded={activeDropdown === item.href}
139141
aria-haspopup={hasSubPages(item.href)}
@@ -182,6 +184,8 @@
182184
<!-- Nav group with secondary dropdown -->
183185
<div
184186
class="nav-group"
187+
class:active={isGroupWithActiveItem(currentPath, subItem)}
188+
class:dropdown-open={isGroupWithActiveSubDropdown(activeSubDropdown, subItem)}
185189
class:has-secondary={subItem.items.length > 0}
186190
role="menuitem"
187191
tabindex="0"
@@ -222,7 +226,8 @@
222226
{#each subItem.items.filter((i) => i.label) as groupItem (groupItem.href)}
223227
<a
224228
href={groupItem.href}
225-
class="dropdown-link {isActive(currentPath, groupItem.href) ? 'active' : ''}"
229+
class="dropdown-link"
230+
class:active={isActive(currentPath, groupItem.href)}
226231
aria-current={isActive(currentPath, groupItem.href) ? 'page' : undefined}
227232
>
228233
<div class="link-content">
@@ -296,7 +301,8 @@
296301
flex-shrink: 0;
297302
}
298303
299-
&:hover {
304+
&:hover,
305+
&.dropdown-open {
300306
color: var(--text-primary);
301307
background: var(--surface-hover);
302308
.dropdown-icon {
@@ -325,6 +331,7 @@
325331
left: 0;
326332
z-index: 5;
327333
overflow: visible;
334+
margin-top: var(--spacing-sm);
328335
}
329336
330337
.primary-dropdown {
@@ -429,19 +436,46 @@
429436
padding-top: var(--spacing-xs);
430437
border-top: 1px solid var(--border-secondary);
431438
}
432-
439+
440+
&:has(+ .dropdown-link) {
441+
margin-bottom: var(--spacing-xs);
442+
padding-bottom: var(--spacing-xs);
443+
border-bottom: 1px solid var(--border-secondary);
444+
}
445+
446+
&.has-secondary,
447+
&.active {
448+
.group-title {
449+
padding: var(--spacing-sm) var(--spacing-md);
450+
border-radius: var(--radius-md);
451+
}
452+
}
453+
433454
&.has-secondary {
434455
cursor: pointer;
435-
456+
436457
.group-title {
437-
border-radius: var(--radius-md);
438458
transition: background-color 0.15s ease;
439-
459+
440460
&:hover {
441461
background: var(--surface-hover);
442462
}
443463
}
444464
}
465+
466+
&.dropdown-open {
467+
.group-title {
468+
transition: background-color none;
469+
background: var(--surface-hover);
470+
}
471+
}
472+
473+
&.active {
474+
.group-title {
475+
color: var(--color-primary);
476+
background: color-mix(in srgb, var(--color-primary), transparent 95%);
477+
}
478+
}
445479
}
446480
447481
.group-title {

src/lib/constants/nav.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,16 @@ export function isActive(pathname: string, href: string): boolean {
19491949
return pathname === href || pathname.startsWith(href + '/');
19501950
}
19511951

1952+
export function isGroupWithActiveItem(pathname: string, groupItem: NavGroup): boolean {
1953+
if (groupItem.items.length === 0) return false;
1954+
return groupItem.items.some((item) => isActive(pathname, item.href));
1955+
}
1956+
1957+
export function isGroupWithActiveSubDropdown(activeSubDropdown: string | null, groupItem: NavGroup): boolean {
1958+
if (groupItem.items.length === 0) return false;
1959+
return 'title' in groupItem && activeSubDropdown === groupItem.title;
1960+
}
1961+
19521962
// Helper function to extract all nav items from mixed structure
19531963
function extractAllNavItems(navStructure: (NavItem | NavGroup)[]): NavItem[] {
19541964
const items: NavItem[] = [];

0 commit comments

Comments
 (0)