@@ -4,14 +4,21 @@ import {
44 Label ,
55 Nav ,
66 NavList ,
7+ NavGroup ,
78 NavExpandable ,
89 PageContextConsumer ,
910 capitalize ,
1011 Flex ,
11- FlexItem
12+ FlexItem ,
13+ Divider
1214} from '@patternfly/react-core' ;
1315import { css } from '@patternfly/react-styles' ;
1416import { Location } from '@reach/router' ;
17+
18+ const DIVIDER_STYLES = {
19+ marginTop : 'var(--pf-t--global--spacer--md)' ,
20+ marginBottom : 'var(--pf-t--global--spacer--md)'
21+ } ;
1522import { makeSlug } from '../../helpers' ;
1623import globalBreakpointXl from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_xl' ;
1724import { trackEvent } from '../../helpers' ;
@@ -163,20 +170,45 @@ export const SideNav = ({ groupedRoutes = {}, navItems = [] }) => {
163170 }
164171 } , [ ] ) ;
165172
173+ const groupedItems = React . useMemo ( ( ) =>
174+ ( navItems || [ ] ) . filter ( entry => entry && entry . title ) , [ navItems ] ) ;
175+ const ungroupedItems = React . useMemo ( ( ) =>
176+ ( navItems || [ ] ) . filter ( entry => entry && ! entry . title ) , [ navItems ] ) ;
177+
178+ const renderNavItem = React . useCallback ( ( item ) => {
179+ if ( ! item ) return null ;
180+
181+ return item . section ? (
182+ < Location key = { item . section } >
183+ { ( { location } ) => ExpandableNav ( { groupedRoutes, location, section : item . section } ) }
184+ </ Location >
185+ ) : NavItem ( {
186+ key : item . href || `nav-item-${ Math . random ( ) } ` ,
187+ text : item . text || ( item . href ? capitalize ( item . href . replace ( / \/ / g, '' ) . replace ( / - / g, ' ' ) ) : 'Untitled' ) ,
188+ href : item . href
189+ } ) ;
190+ } , [ groupedRoutes ] ) ;
191+
166192 return (
167193 < Nav aria-label = "Side Nav" theme = "light" >
168- < NavList className = "ws-side-nav-list" >
169- { navItems . map ( ( { section, text, href } ) =>
170- section ? (
171- < Location key = { section } > { ( { location } ) => ExpandableNav ( { groupedRoutes, location, section } ) } </ Location >
172- ) : (
173- NavItem ( {
174- text : text || capitalize ( href . replace ( / \/ / g, '' ) . replace ( / - / g, ' ' ) ) ,
175- href : href
176- } )
177- )
178- ) }
179- </ NavList >
194+ { /* Render grouped items */ }
195+ { groupedItems . map ( ( group ) => (
196+ < React . Fragment key = { group . title } >
197+ < NavGroup title = { group . title } >
198+ < NavList className = "ws-side-nav-list" aria-label = { `${ group . title } navigation` } >
199+ { group . items . map ( renderNavItem ) }
200+ </ NavList >
201+ </ NavGroup >
202+ { group . hasDivider && < Divider style = { DIVIDER_STYLES } /> }
203+ </ React . Fragment >
204+ ) ) }
205+
206+ { /* Render ungrouped items - this handles the current flat structure */ }
207+ { ungroupedItems . length > 0 && (
208+ < NavList className = "ws-side-nav-list" >
209+ { ungroupedItems . map ( renderNavItem ) }
210+ </ NavList >
211+ ) }
180212 </ Nav >
181213 ) ;
182- } ;
214+ } ;
0 commit comments