@@ -31,6 +31,7 @@ interface TocItem {
3131 name ?: string ;
3232 href ?: string ;
3333 header ?: boolean ;
34+ sortable ?: boolean ;
3435 items ?: TocItem [ ] ;
3536 new ?: boolean ;
3637 preview ?: boolean ;
@@ -74,6 +75,26 @@ function collapsedForDepth(depth: number): boolean {
7475 return depth > 0 ;
7576}
7677
78+ function sortableLabel ( label : string ) : string {
79+ return label . replace ( / [ - : ( ) [ \] / & ] + / g, ' ' ) ;
80+ }
81+
82+ function sortSidebarEntries ( entries : SidebarEntry [ ] ) : SidebarEntry [ ] {
83+ return entries . sort ( ( a , b ) => sortableLabel ( a . label ) . localeCompare ( sortableLabel ( b . label ) , undefined , {
84+ sensitivity : 'base' ,
85+ numeric : true ,
86+ } ) ) ;
87+ }
88+
89+ function sortGroupItems ( group : SidebarGroup ) : void {
90+ const [ first , ...rest ] = group . items ;
91+ if ( first && 'slug' in first && first . label === 'Overview' ) {
92+ group . items = [ first , ...sortSidebarEntries ( rest ) ] ;
93+ return ;
94+ }
95+ group . items = sortSidebarEntries ( group . items ) ;
96+ }
97+
7798function convertTocItem (
7899 docsDir : string ,
79100 item : TocItem ,
@@ -95,6 +116,7 @@ function convertTocItem(
95116 const entry = convertTocItem ( docsDir , child , exclude , depth + 1 ) ;
96117 if ( entry ) group . items . push ( entry ) ;
97118 }
119+ if ( item . sortable ) sortGroupItems ( group ) ;
98120 return group . items . length > 0 ? group : null ;
99121 }
100122
@@ -139,12 +161,17 @@ export function buildSidebarFromToc({ tocPath, docsDir, exclude = [] }: BuildSid
139161
140162 const sidebar : SidebarEntry [ ] = [ ] ;
141163 let currentGroup : SidebarGroup | null = null ;
164+ let currentGroupSortable = false ;
142165
143166 for ( const item of tocItems ) {
144167 if ( item . header ) {
145- if ( currentGroup ) sidebar . push ( currentGroup ) ;
168+ if ( currentGroup ) {
169+ if ( currentGroupSortable ) sortGroupItems ( currentGroup ) ;
170+ sidebar . push ( currentGroup ) ;
171+ }
146172 // Root-level header section — open by default.
147173 currentGroup = { label : item . name ! , items : [ ] , collapsed : collapsedForDepth ( 0 ) } ;
174+ currentGroupSortable = item . sortable === true ;
148175 if ( item . href && docExists ( docsDir , item . href , exclude ) ) {
149176 currentGroup . items . push ( { label : 'Overview' , slug : hrefToSlug ( item . href ) } ) ;
150177 }
@@ -159,6 +186,9 @@ export function buildSidebarFromToc({ tocPath, docsDir, exclude = [] }: BuildSid
159186 else sidebar . push ( entry ) ;
160187 }
161188
162- if ( currentGroup ) sidebar . push ( currentGroup ) ;
189+ if ( currentGroup ) {
190+ if ( currentGroupSortable ) sortGroupItems ( currentGroup ) ;
191+ sidebar . push ( currentGroup ) ;
192+ }
163193 return sidebar ;
164194}
0 commit comments