1 import React from 'react'
2 import {Heading, Details, useDetails, Button, NavList} from '@primer/react'
3 import {ChevronDownIcon, ChevronRightIcon} from '@primer/octicons-react'
4 import usePage from '../hooks/use-page'
5
6 import * as styles from './table-of-contents.module.css'
7 import {clsx} from 'clsx'
8
9 const TableOfContentsItems = ({items, depth}) => (
10 <>
11 {items.map((item, index) => (
12 <React.Fragment key={item.title}>
13 <NavList.Item
14 href={item.url}
15 aria-label={`${item.title}, ${index + 1} of ${items.length}`}
16 aria-labelledby={null}
17 >
18 {item.title}
19 {item.items ? (
20 <NavList.SubNav>
21 <TableOfContentsItems items={item.items} depth={depth + 1} />
22 </NavList.SubNav>
23 ) : null}
24 </NavList.Item>
25 </React.Fragment>
26 ))}
27 </>
28 )
29
30 const TableOfContents = ({'aria-labelledby': ariaLabelledBy, items, depth = 1, className, ...props}) => (
31 <NavList aria-labelledby={ariaLabelledBy} {...props} className={clsx(styles.NavList, className)}>
32 <TableOfContentsItems items={items} depth={depth} />
33 </NavList>
34 )
35
36 const withTableOfContents = Component => {
37 const WithTableOfContents = props => {
38 const {tableOfContents} = usePage().pageContext
39 return tableOfContents ? <Component {...props} items={tableOfContents} /> : null
40 }
41 return WithTableOfContents
42 }
43
44 export const Mobile = withTableOfContents(({items}) => {
45 const {getDetailsProps, open} = useDetails({defaultOpen: true})
46 return (
47 <div className={styles.tocMobile}>
48 <Details {...getDetailsProps()} className={styles.Details}>
49 <Button
50 as="summary"
51 leadingIcon={open ? ChevronDownIcon : ChevronRightIcon}
52 className={`${styles.Button} ${open ? styles.buttonOpen : styles.buttonClosed}`}
53 >
54 Table of contents
55 </Button>
56 <TableOfContents items={items} />
57 </Details>
58 </div>
59 )
60 })
61
62 export const Desktop = withTableOfContents(({items}) => (
63 <div className={styles.tocDesktop}>
64 <Heading as="h2" id="toc-heading" className={styles.Heading}>
65 Table of contents
66 </Heading>
67 <div className={styles.Box}>
68 <TableOfContents aria-labelledby="toc-heading" items={items} className={styles.TableOfContents} />
69 </div>
70 </div>
71 ))