1
+ import { useEffect , useState } from "react"
1
2
import Link from "next/link"
2
- import colors from "../../styles/colors"
3
3
import styles from "./SideMenu.module.css"
4
4
import typographyStyles from "../../styles/typography.module.css"
5
- import { useRouter } from "next/router "
5
+ import colors from "../../styles/colors "
6
6
import { Pages } from "../../types/types"
7
7
8
8
function Menu ( { pages = [ ] } : { pages : Pages } ) {
9
- const router = useRouter ( )
10
- const { asPath : pathname } = router
9
+ const [ activeSection , setActiveSection ] = useState < string > ( "" )
10
+
11
+ useEffect ( ( ) => {
12
+ const handleScroll = ( ) => {
13
+ const sections = pages . flatMap ( ( page ) =>
14
+ [ page , ...( page . pages || [ ] ) ] . map ( ( p ) => ( {
15
+ id : p . pathname . replace ( "#" , "" ) ,
16
+ top :
17
+ document . getElementById ( p . pathname . replace ( "#" , "" ) ) ?. offsetTop ||
18
+ 0 ,
19
+ } ) )
20
+ )
21
+
22
+ const currentSection = sections . reduce ( ( acc , section ) => {
23
+ const { id, top } = section
24
+ if ( window . scrollY >= top - 100 ) {
25
+ console . log ( id )
26
+ return id
27
+ }
28
+ return acc
29
+ } , "" )
30
+
31
+ setActiveSection ( currentSection )
32
+ }
33
+
34
+ window . addEventListener ( "scroll" , handleScroll )
35
+
36
+ handleScroll ( )
37
+
38
+ return ( ) => window . removeEventListener ( "scroll" , handleScroll )
39
+ } , [ pages ] )
40
+
41
+ const scrollToSection = ( sectionId : string , event : React . MouseEvent ) => {
42
+ event . preventDefault ( )
43
+ const element = document . getElementById ( sectionId . replace ( "#" , "" ) )
44
+ if ( element ) {
45
+ element . scrollIntoView ( { behavior : "smooth" } )
46
+ }
47
+ }
11
48
12
49
return (
13
50
< aside className = { styles . menu } >
@@ -26,41 +63,57 @@ function Menu({ pages = [] }: { pages: Pages }) {
26
63
27
64
< ul className = "scrollArea" >
28
65
{ pages . map ( ( page ) => {
29
- const isActive = pathname === page . pathname
66
+ const isActive = activeSection === page . pathname . replace ( "#" , "" )
67
+ const hasActiveChild = page . pages ?. some (
68
+ ( subPage ) => activeSection === subPage . pathname . replace ( "#" , "" )
69
+ )
30
70
31
71
return (
32
72
< li
33
73
key = { page . pathname }
34
- className = { styles . menuItem }
74
+ className = { `${ styles . menuItem } ${
75
+ isActive || hasActiveChild ? styles . activeParent : ""
76
+ } `}
35
77
style = { {
36
78
display : page ?. pages ? "block" : "flex" ,
37
79
} }
38
80
>
39
- < code aria-hidden className = { styles . code } > { `</>` } </ code >
40
- < Link
41
- className = { isActive ? styles . isActive : "" }
81
+ < code aria-hidden className = { styles . code } >
82
+ { `</>` }
83
+ </ code >
84
+ < a
42
85
href = { page . pathname }
86
+ className = { isActive ? styles . isActive : "" }
87
+ onClick = { ( e ) => scrollToSection ( page . pathname , e ) }
43
88
>
44
89
{ page . name }
45
- </ Link >
90
+ </ a >
46
91
47
92
{ page ?. pages && (
48
93
< ul >
49
- { page . pages . map ( ( page ) => {
50
- const isActive = pathname === page . pathname
94
+ { page . pages . map ( ( subPage ) => {
95
+ const isSubActive =
96
+ activeSection === subPage . pathname . replace ( "#" , "" )
51
97
52
98
return (
53
- < li key = { page . pathname } className = { styles . menuItem } >
54
- < code
55
- aria-hidden
56
- className = { styles . code }
57
- > { `</>` } </ code > { " " }
58
- < Link
59
- className = { isActive ? styles . isActive : "" }
60
- href = { page . pathname }
99
+ < li
100
+ key = { subPage . pathname }
101
+ className = { `${ styles . menuItem } ${
102
+ isSubActive ? styles . activeItem : ""
103
+ } `}
104
+ >
105
+ < code aria-hidden className = { styles . code } >
106
+ { `</>` }
107
+ </ code >
108
+ < a
109
+ href = { subPage . pathname }
110
+ className = { isSubActive ? styles . isActive : "" }
111
+ onClick = { ( e ) =>
112
+ scrollToSection ( subPage . pathname , e )
113
+ }
61
114
>
62
- { page . name }
63
- </ Link >
115
+ { subPage . name }
116
+ </ a >
64
117
</ li >
65
118
)
66
119
} ) }
0 commit comments