Files
crewli/apps/app/src/components-v2/layout/sidebarNavActive.ts
bert.hausmans 8a8e419ed1 feat(gui-v2): port SidebarNav to TypeScript
Ports crewli-starter's sidebar nav into the SPA as production TS:
V2NavGroup/V2NavItem types, a pure toV2NavGroups adapter wrapped by
useV2Nav(items) (composables zone can't import @/navigation, so the
v1 nav array is passed in — the layout supplies orgNavItems in Task 7),
a pure isNavItemActive helper, and SidebarNav.vue (props-only,
router-driven nav, route-based active state, collapsed mode, main.css
translated to Tailwind inline). 16 unit tests. Icon import is
allowed via the components-foundation bridge (no eslint-disable).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 19:23:10 +02:00

38 lines
1.2 KiB
TypeScript

import type { V2NavItem } from '@/types/v2/nav'
/**
* Pure helper — determines whether a V2NavItem is "active" given the current
* route name.
*
* Active rules (simplest correct definition):
* 1. Exact match: currentRouteName === item.to.name
* 2. Prefix match for nested routes: currentRouteName starts with
* item.to.name + '-' (e.g. item "organisation" is active on
* "organisation-settings"). The dash boundary prevents "org" from
* spuriously matching "organisation-settings".
*
* Only `to` values that are a plain object with a string `name` property are
* compared — string/array `to` values always return false (router-push
* style not used in v1 nav).
*/
export function isNavItemActive(
item: V2NavItem,
currentRouteName: string | symbol | null | undefined,
): boolean {
if (typeof currentRouteName !== 'string')
return false
const to = item.to
if (typeof to !== 'object' || to === null || Array.isArray(to))
return false
const itemName = (to as { name?: unknown }).name
if (typeof itemName !== 'string')
return false
return currentRouteName === itemName
|| currentRouteName.startsWith(`${itemName}-`)
}