@@ -2,56 +2,106 @@ import { appConfig } from "@root/app.config";
22import { appNavigation } from "@root/app.navigation" ;
33
44/**
5- * Returns the parent of a navigation item based on the given pathname.
6- * @param pathname - The pathname to find the parent for.
7- * @returns The parent navigation item or undefined if none is found.
5+ * Normalizes a path by removing trailing slashes.
6+ *
7+ * @param path - The path to normalize
8+ * @returns The normalized path without trailing slashes
89 */
9- export function getNavigationItemParent (
10- pathname : string ,
11- ) : NavigationItem | undefined {
12- const { basePath } = appConfig ;
13- const _pathname = pathname . replace ( / \/ + $ / , "" ) ;
14-
15- return appNavigation . filter ( ( item ) => {
16- const children = [ ...( item . children ?? [ ] ) , ...( item . subNavigation ?? [ ] ) ] ;
17- if ( children . length > 0 ) {
18- return children . some ( ( child ) => {
19- const fullPath = `${ basePath } ${ child . path } ` . replace ( / \/ + $ / , "" ) ;
20- return fullPath === _pathname ;
21- } ) ;
22- }
23- return false ;
24- } ) [ 0 ] ;
10+ const norm = ( path : string ) => path . replace ( / \/ + $ / , "" ) ;
11+
12+ /**
13+ * Prepends the base path to a relative path and normalizes the result.
14+ *
15+ * @param relPath - The relative path to prepend the base path to
16+ * @returns The normalized absolute path including the base path
17+ */
18+ function withBase ( relPath : string ) {
19+ const base = norm ( appConfig . basePath || "/" ) ;
20+ const rel = relPath . startsWith ( "/" ) ? relPath : `/${ relPath } ` ;
21+ return norm ( `${ base } ${ rel } ` ) ;
2522}
2623
2724/**
28- * Recursively searches for a subNavigation array with at least one entry for the given pathname .
29- * @param pathname - The pathname to check .
30- * @returns The subNavigation array if found, otherwise undefined.
25+ * Returns the path of the first child navigation item, if any .
26+ * @param children - An array of navigation items .
27+ * @returns The path of the first child navigation item or undefined if there are no children .
3128 */
32- export function findSubNavigation (
33- pathname : string ,
34- ) : NavigationItem [ ] | undefined {
35- const { basePath } = appConfig ;
36- const _pathname = pathname . replace ( / \/ + $ / , "" ) ;
29+ export function getFirstChildPath ( children ?: NavigationItem [ ] ) : string | undefined {
30+ return children && children . length > 0 ? children [ 0 ] ?. path : undefined ;
31+ }
32+
33+ /**
34+ * Checks if a navigation item or any of its descendants covers the current path.
35+ * A path is considered "covered" if it either exactly matches or is a sub-path of the navigation item's path.
36+ *
37+ * @param item - The navigation item to check
38+ * @param currentPath - The current path to compare against
39+ * @returns {boolean } True if the item or its descendants cover the current path, false otherwise
40+ */
41+ export function covers ( item : NavigationItem , currentPath : string ) : boolean {
42+ if ( item . path ) {
43+ const full = withBase ( item . path ) ;
44+ if ( currentPath === full || currentPath . startsWith ( full + "/" ) ) return true ;
45+ }
46+ for ( const child of item . children ?? [ ] ) {
47+ if ( covers ( child , currentPath ) ) return true ;
48+ }
49+ return false ;
50+ }
3751
38- function checkRecursive ( item : NavigationItem | undefined ) : NavigationItem [ ] | undefined {
39- if ( ! item ) return undefined ;
40- const fullPath = `${ basePath } ${ item . path } ` . replace ( / \/ + $ / , "" ) ;
41- if ( fullPath === _pathname && Array . isArray ( item . subNavigation ) && item . subNavigation . length > 0 ) {
42- return item . subNavigation ;
52+ /**
53+ * Finds the children of the deepest sub-navigation item that covers the current pathname.
54+ *
55+ * @param currentPathname - The current pathname to find sub-navigation for
56+ * @returns An array of navigation items if a matching sub-navigation is found, undefined otherwise
57+ */
58+ export function findSubNavigation ( currentPathname : string ) : NavigationItem [ ] | undefined {
59+ const current = norm ( currentPathname ) ;
60+ let match : { node : NavigationItem ; depth : number } | undefined ;
61+
62+ const walk = ( node : NavigationItem , depth : number ) => {
63+ if ( node . isSubNavigation && covers ( node , current ) ) {
64+ if ( ! match || depth > match . depth ) match = { node, depth } ;
4365 }
44- const children = [ ...( item . children ?? [ ] ) , ...( item . subNavigation ?? [ ] ) ] ;
45- for ( const child of children ) {
46- const result = checkRecursive ( child ) ;
47- if ( result ) return result ;
66+ for ( const child of node . children ?? [ ] ) walk ( child , depth + 1 ) ;
67+ } ;
68+
69+ for ( const top of appNavigation ) walk ( top , 0 ) ;
70+ return match ?. node . children ;
71+ }
72+
73+ /**
74+ * Finds the parent navigation item for a given pathname.
75+ *
76+ * @param pathname - The pathname to find the parent for
77+ * @returns The parent navigation item if found, undefined otherwise
78+ */
79+ export function getNavigationItemParent ( pathname : string ) : NavigationItem | undefined {
80+ const { basePath } = appConfig ;
81+ const norm = ( p : string ) => p . replace ( / \/ + $ / , "" ) ;
82+ const _pathname = norm ( pathname ) ;
83+
84+ const withBase = ( relPath ?: string ) => {
85+ if ( ! relPath ) return undefined ;
86+ const base = norm ( basePath || "/" ) ;
87+ const rel = relPath . startsWith ( "/" ) ? relPath : `/${ relPath } ` ;
88+ return norm ( `${ base } ${ rel } ` ) ;
89+ } ;
90+
91+ const findParent = ( nodes : NavigationItem [ ] ) : NavigationItem | undefined => {
92+ for ( const node of nodes ) {
93+ const children = node . children ?? [ ] ;
94+ for ( const child of children ) {
95+ const full = withBase ( child . path ) ;
96+ if ( full && full === _pathname ) {
97+ return node ;
98+ }
99+ }
100+ const found = findParent ( children ) ;
101+ if ( found ) return found ;
48102 }
49103 return undefined ;
50- }
104+ } ;
51105
52- for ( const navItem of appNavigation ) {
53- const result = checkRecursive ( navItem ) ;
54- if ( result ) return result ;
55- }
56- return undefined ;
106+ return findParent ( appNavigation ) ;
57107}
0 commit comments