1
1
'use client' ;
2
2
3
- import type React from 'react' ;
4
-
5
- import { MobileMenuSheet } from '@/components/MobileMenu' ;
6
- import { useIsMobile } from '@/hooks/useIsMobile' ;
3
+ import { MobileMenuScript , useMobileMenuSheet } from '@/components/MobileMenu' ;
4
+ import { Button } from '@/components/primitives' ;
7
5
import { tcls } from '@/lib/tailwind' ;
6
+ import type React from 'react' ;
8
7
import { TableOfContentsScript } from './TableOfContentsScript' ;
9
8
10
9
export function TableOfContents ( props : {
11
10
header ?: React . ReactNode ; // Displayed outside the scrollable TOC as a sticky header
12
11
children : React . ReactNode ;
13
12
} ) {
14
13
const { header, children } = props ;
15
- const isMobile = useIsMobile ( ) ;
16
-
17
- // If the screen is mobile, we use the mobile menu sheet to display the table of contents.
18
- if ( isMobile ) {
19
- return < MobileMenuSheet > { children } </ MobileMenuSheet > ;
20
- }
14
+ const { open, setOpen } = useMobileMenuSheet ( ) ;
21
15
22
16
return (
23
17
< >
18
+ < div
19
+ className = "fixed inset-0 z-40 bg-tint-12/4 backdrop-blur-lg data-[state=closed]:pointer-events-none data-[state=closed]:invisible data-[state=closed]:animate-fadeOut data-[state=open]:animate-fadeIn data-[state=open]:animate-in lg:hidden dark:bg-tint-1/6"
20
+ data-state = { open ? 'open' : 'closed' }
21
+ onClick = { ( ) => setOpen ( false ) }
22
+ />
24
23
< aside // Sidebar container, responsible for setting the right dimensions and position for the sidebar.
25
24
data-testid = "table-of-contents"
26
25
id = "table-of-contents"
26
+ data-state = { open ? 'open' : 'closed' }
27
27
className = { tcls (
28
28
'group' ,
29
+
30
+ 'flex' ,
31
+ 'flex-col' ,
32
+
33
+ 'max-lg:fixed' ,
34
+ 'max-lg:z-50' ,
35
+
36
+ 'max-lg:transition' ,
37
+ 'max-lg:ease-in-out' ,
38
+ 'max-lg:duration-500' ,
39
+
40
+ 'max-lg:rounded-xl' ,
41
+ 'max-lg:circular-corners:rounded-2xl' ,
42
+ 'max-lg:straight-corners:rounded-none' ,
43
+ 'max-lg:bg-tint-base' ,
44
+ 'max-lg:sidebar-filled:bg-tint-subtle' ,
45
+ 'max-lg:theme-muted:bg-tint-subtle' ,
46
+ 'max-lg:[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle' ,
47
+ 'max-lg:[html.sidebar-filled.theme-muted_&]:bg-tint-base' ,
48
+ 'max-lg:[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base' ,
49
+
50
+ 'max-lg:w-10/12' ,
51
+ 'max-lg:shadow-lg' ,
52
+ 'max-lg:depth-flat:shadow-none' ,
53
+ 'max-lg:inset-1.5' ,
54
+ 'max-lg:transition-all' ,
55
+ 'max-lg:duration-300' ,
56
+ 'max-lg:max-w-sm' ,
57
+ 'max-lg:data-[state=open]:left-1.5' ,
58
+ 'max-lg:data-[state=closed]:-left-full' ,
59
+
29
60
'text-sm' ,
30
61
31
62
'grow-0' ,
32
63
'shrink-0' ,
33
- 'basis-full' ,
34
64
'lg:basis-72' ,
35
65
'page-no-toc:lg:basis-56' ,
36
66
37
- 'relative' ,
38
- 'z-[1]' ,
39
67
'lg:sticky' ,
40
68
'lg:mr-12' ,
41
69
@@ -56,25 +84,37 @@ export function TableOfContents(props: {
56
84
'[html[style*="--toc-top-offset"]_&]:lg:!top-[var(--toc-top-offset)]' ,
57
85
'[html[style*="--toc-height"]_&]:lg:!h-[var(--toc-height)]' ,
58
86
59
- 'pt-6' ,
60
- 'pb-4' ,
87
+ 'lg: pt-6' ,
88
+ 'lg: pb-4' ,
61
89
'sidebar-filled:lg:pr-6' ,
62
90
'page-no-toc:lg:pr-0' ,
63
91
64
- 'hidden' ,
65
- 'lg:flex' ,
66
92
'page-no-toc:lg:hidden' ,
67
93
'page-no-toc:xl:flex' ,
68
94
'site-header-none:page-no-toc:lg:flex' ,
69
- 'flex-col' ,
70
95
'gap-4' ,
71
96
'border-tint-subtle'
72
97
) }
73
98
>
74
99
{ header && header }
100
+
101
+ { open ? (
102
+ < Button
103
+ variant = "secondary"
104
+ icon = "close"
105
+ iconOnly
106
+ autoFocus = { false }
107
+ className = "absolute top-2 right-2 z-50 bg-transparent text-tint opacity-8 shadow-none ring-transparent"
108
+ onClick = { ( ) => setOpen ( false ) }
109
+ >
110
+ < span className = "sr-only" > Close</ span >
111
+ </ Button >
112
+ ) : null }
113
+
75
114
{ children }
76
115
</ aside >
77
116
< TableOfContentsScript />
117
+ < MobileMenuScript />
78
118
</ >
79
119
) ;
80
120
}
0 commit comments