1- import { useState , useRef , useEffect } from 'react'
1+ import { useState , useRef , useEffect , useMemo } from 'react'
22import { TextInput , ActionMenu , ActionList , Token , Pagination } from '@primer/react'
33import { SearchIcon } from '@primer/octicons-react'
44import cx from 'classnames'
55
66import { Link } from '@/frame/components/Link'
77import { useTranslation } from '@/languages/components/useTranslation'
8- import { ArticleCardItems , ChildTocItem } from '@/landings/types'
8+ import { ArticleCardItems , ChildTocItem , TocItem } from '@/landings/types'
99
1010import styles from './LandingArticleGridWithFilter.module.scss'
1111
1212type ArticleGridProps = {
13- flatArticles : ArticleCardItems
13+ tocItems : TocItem [ ]
1414}
1515
1616const ALL_CATEGORIES = 'all_categories'
1717
18+ // Helper function to recursively flatten nested articles
19+ // Excludes index pages (pages with childTocItems)
20+ const flattenArticlesRecursive = ( articles : ArticleCardItems ) : ArticleCardItems => {
21+ const flattened : ArticleCardItems = [ ]
22+
23+ for ( const article of articles ) {
24+ // If the article has children, recursively process them but don't include the parent (index page)
25+ if ( article . childTocItems && article . childTocItems . length > 0 ) {
26+ flattened . push ( ...flattenArticlesRecursive ( article . childTocItems ) )
27+ } else {
28+ // Only add articles that don't have children (actual article pages, not index pages)
29+ flattened . push ( article )
30+ }
31+ }
32+
33+ return flattened
34+ }
35+
36+ // Wrapper function that flattens and sorts alphabetically by title (only once)
37+ const flattenArticles = ( articles : ArticleCardItems ) : ArticleCardItems => {
38+ const flattened = flattenArticlesRecursive ( articles )
39+ return flattened . sort ( ( a , b ) => a . title . localeCompare ( b . title ) )
40+ }
41+
1842// Hook to get current articles per page based on screen size
1943const useResponsiveArticlesPerPage = ( ) => {
2044 const [ articlesPerPage , setArticlesPerPage ] = useState ( 9 ) // Default to desktop
@@ -42,7 +66,7 @@ const useResponsiveArticlesPerPage = () => {
4266 return articlesPerPage
4367}
4468
45- export const ArticleGrid = ( { flatArticles } : ArticleGridProps ) => {
69+ export const ArticleGrid = ( { tocItems } : ArticleGridProps ) => {
4670 const { t } = useTranslation ( 'product_landing' )
4771 const [ searchQuery , setSearchQuery ] = useState ( '' )
4872 const [ selectedCategory , setSelectedCategory ] = useState ( ALL_CATEGORIES )
@@ -53,6 +77,12 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
5377 const inputRef = useRef < HTMLInputElement > ( null )
5478 const headingRef = useRef < HTMLHeadingElement > ( null )
5579
80+ // Extract child items from tocItems and recursively flatten nested articles to ensure we get all articles with categories
81+ const allArticles = useMemo (
82+ ( ) => flattenArticles ( tocItems . flatMap ( ( item ) => item . childTocItems || [ ] ) ) ,
83+ [ tocItems ] ,
84+ )
85+
5686 // Reset to first page when articlesPerPage changes (screen size changes)
5787 useEffect ( ( ) => {
5888 setCurrentPage ( 1 )
@@ -61,13 +91,13 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
6191 // Extract unique categories from the articles
6292 const categories : string [ ] = [
6393 ALL_CATEGORIES ,
64- ...Array . from ( new Set ( flatArticles . flatMap ( ( item ) => item . category || [ ] ) ) ) . sort ( ( a , b ) =>
94+ ...Array . from ( new Set ( allArticles . flatMap ( ( item ) => item . category || [ ] ) ) ) . sort ( ( a , b ) =>
6595 a . localeCompare ( b ) ,
6696 ) ,
6797 ]
6898
6999 const applyFilters = ( ) => {
70- let results = flatArticles
100+ let results = allArticles
71101
72102 if ( searchQuery ) {
73103 results = results . filter ( ( token ) => {
0 commit comments