1
+ 'use client'
2
+
3
+ import * as Dialog from '@radix-ui/react-dialog'
4
+ import { memo } from 'react'
5
+ import { AnimatePresence , motion } from 'framer-motion'
6
+ import { atom , useAtom } from 'jotai'
7
+ import Link from 'next/link'
1
8
import type { SVGProps } from 'react'
2
9
10
+ import { CloseIcon } from '~/components/icons/close'
11
+ import { MotionButtonBase } from '~/components/ui/button/MotionButton'
12
+ import { reboundPreset } from '~/constants/spring'
13
+ import { jotaiStore } from '~/lib/store'
14
+
3
15
import { HeaderActionButton } from './HeaderActionButton'
16
+ import { useHeaderConfig } from './HeaderDataConfigureProvider'
4
17
5
18
function IcBaselineMenuOpen ( props : SVGProps < SVGSVGElement > ) {
6
19
return (
@@ -13,10 +26,115 @@ function IcBaselineMenuOpen(props: SVGProps<SVGSVGElement>) {
13
26
)
14
27
}
15
28
29
+ const drawerOpenAtom = atom ( false )
16
30
export const HeaderDrawerButton = ( ) => {
31
+ const [ open , setOpen ] = useAtom ( drawerOpenAtom )
32
+
33
+ return (
34
+ < Dialog . Root open = { open } onOpenChange = { ( open ) => setOpen ( open ) } >
35
+ < Dialog . Trigger asChild >
36
+ < HeaderActionButton >
37
+ < IcBaselineMenuOpen />
38
+ </ HeaderActionButton >
39
+ </ Dialog . Trigger >
40
+ < Dialog . Portal forceMount >
41
+ < AnimatePresence >
42
+ { open && (
43
+ < >
44
+ < Dialog . Overlay asChild >
45
+ < motion . div
46
+ className = "fixed inset-0 z-[11] bg-slate-50/80 backdrop-blur-sm dark:bg-slate-900/80"
47
+ initial = { { opacity : 0 } }
48
+ animate = { { opacity : 1 } }
49
+ exit = { { opacity : 0 } }
50
+ />
51
+ </ Dialog . Overlay >
52
+
53
+ < Dialog . Content >
54
+ < motion . dialog
55
+ className = "fixed inset-0 z-[12] flex max-h-[100vh] min-h-0 items-center justify-center overflow-hidden rounded-xl bg-base-100/90"
56
+ initial = { { opacity : 0.8 } }
57
+ animate = { { opacity : 1 } }
58
+ exit = { { opacity : 0 } }
59
+ >
60
+ < Dialog . DialogClose asChild >
61
+ < MotionButtonBase
62
+ className = "absolute right-4 top-4 p-4"
63
+ onClick = { ( ) => {
64
+ setOpen ( false )
65
+ } }
66
+ >
67
+ < CloseIcon />
68
+ </ MotionButtonBase >
69
+ </ Dialog . DialogClose >
70
+
71
+ < HeaderDrawerContent />
72
+ </ motion . dialog >
73
+ </ Dialog . Content >
74
+ </ >
75
+ ) }
76
+ </ AnimatePresence >
77
+ </ Dialog . Portal >
78
+ </ Dialog . Root >
79
+ )
80
+ }
81
+
82
+ // @ts -ignore
83
+ const LinkInternal : typeof Link = memo ( ( { children, ...rest } ) => {
17
84
return (
18
- < HeaderActionButton >
19
- < IcBaselineMenuOpen />
20
- </ HeaderActionButton >
85
+ < Link
86
+ { ...rest }
87
+ onClick = { ( ) => {
88
+ jotaiStore . set ( drawerOpenAtom , false )
89
+ } }
90
+ >
91
+ { children }
92
+ </ Link >
93
+ )
94
+ } )
95
+
96
+ const HeaderDrawerContent = ( ) => {
97
+ const { config } = useHeaderConfig ( )
98
+
99
+ return (
100
+ < div className = "h-[100vh] w-[90vw] space-y-4 overflow-auto py-8 scrollbar-none" >
101
+ { config . map ( ( section , index ) => {
102
+ return (
103
+ < motion . section
104
+ initial = { { y : 30 , opacity : 0 } }
105
+ animate = { { y : 0 , opacity : 1 } }
106
+ transition = { {
107
+ ...reboundPreset ,
108
+ delay : index * 0.08 ,
109
+ } }
110
+ key = { section . path }
111
+ >
112
+ < LinkInternal className = "block" href = { section . path } >
113
+ < span className = "flex items-center space-x-2 py-2 text-[16px]" >
114
+ < i > { section . icon } </ i >
115
+ < h2 > { section . title } </ h2 >
116
+ </ span >
117
+ </ LinkInternal >
118
+
119
+ { section . subMenu && (
120
+ < ul className = "my-2 grid grid-cols-2 gap-2" >
121
+ { section . subMenu . map ( ( sub ) => {
122
+ return (
123
+ < li key = { sub . path } >
124
+ < LinkInternal
125
+ className = "inline-block p-2"
126
+ href = { sub . path }
127
+ >
128
+ { sub . title }
129
+ </ LinkInternal >
130
+ </ li >
131
+ )
132
+ } ) }
133
+ </ ul >
134
+ ) }
135
+ </ motion . section >
136
+ )
137
+ } ) }
138
+ </ div >
21
139
)
22
140
}
0 commit comments