4
4
* See License.AGPL.txt in the project root for license information.
5
5
*/
6
6
7
+ import classNames from "classnames" ;
8
+ import { FC , useEffect , useRef } from "react" ;
7
9
import { useLocation } from "react-router" ;
8
10
import { Link } from "react-router-dom" ;
9
11
import Header , { TabEntry } from "../components/Header" ;
12
+ import { Separator } from "./Separator" ;
10
13
11
14
export interface PageWithSubMenuProps {
12
15
title : string ;
@@ -20,30 +23,64 @@ export interface PageWithSubMenuProps {
20
23
}
21
24
22
25
export function PageWithSubMenu ( p : PageWithSubMenuProps ) {
23
- const location = useLocation ( ) ;
24
26
return (
25
27
< div className = "w-full" >
26
28
< Header title = { p . title } subtitle = { p . subtitle } tabs = { p . tabs } />
27
- < div className = "app-container flex pt-9" >
29
+ < div className = "app-container flex md:pt-9 flex-col md:flex-row" >
30
+ { /* TODO: extract into SubMenu component and show scrolling indicators */ }
28
31
< div >
29
- < ul className = "flex flex-col text tracking-wide text-gray-500 pt-4 lg:pt-0 w-52 space-y-2" >
32
+ < ul
33
+ className = { classNames (
34
+ // Handle flipping between row and column layout
35
+ "flex flex-row md:flex-col items-center" ,
36
+ "w-full md:w-52 overflow-auto md:overflow-visible" ,
37
+ "pt-4 pb-4 md:pb-0" ,
38
+ "space-x-2 md:space-x-0 md:space-y-2" ,
39
+ "tracking-wide text-gray-500" ,
40
+ ) }
41
+ >
30
42
{ p . subMenu . map ( ( e ) => {
31
- let classes = "flex block py-2 px-4 rounded-md" ;
32
- if ( e . link . some ( ( l ) => l === location . pathname ) ) {
33
- classes += " bg-gray-300 text-gray-800 dark:bg-gray-800 dark:text-gray-50" ;
34
- } else {
35
- classes += " hover:bg-gray-100 dark:hover:bg-gray-800" ;
36
- }
37
- return (
38
- < Link to = { e . link [ 0 ] } key = { e . title } >
39
- < li className = { classes } > { e . title } </ li >
40
- </ Link >
41
- ) ;
43
+ return < SubmenuItem title = { e . title } link = { e . link } key = { e . title } /> ;
42
44
} ) }
43
45
</ ul >
44
46
</ div >
45
- < div className = "ml-16 lg:ml-32 w-full pt-1 mb-40" > { p . children } </ div >
47
+ < div className = "md:ml-16 lg:ml-32 w-full pt-1 mb-40" >
48
+ < Separator className = "md:hidden" />
49
+ < div className = "pt-4 md:pt-0" > { p . children } </ div >
50
+ </ div >
46
51
</ div >
47
52
</ div >
48
53
) ;
49
54
}
55
+
56
+ type SubmenuItemProps = {
57
+ title : string ;
58
+ link : string [ ] ;
59
+ } ;
60
+
61
+ const SubmenuItem : FC < SubmenuItemProps > = ( { title, link } ) => {
62
+ const location = useLocation ( ) ;
63
+ const itemRef = useRef < HTMLLIElement > ( null ) ;
64
+
65
+ // TODO: can remove this once we use sub-routes and don't re-render the whole page for each sub-route
66
+ useEffect ( ( ) => {
67
+ if ( itemRef . current && link . some ( ( l ) => l === location . pathname ) ) {
68
+ itemRef . current . scrollIntoView ( { behavior : "auto" , block : "nearest" , inline : "start" } ) ;
69
+ }
70
+ } , [ link , location . pathname ] ) ;
71
+
72
+ let classes = "flex block py-2 px-4 rounded-md whitespace-nowrap max-w-52" ;
73
+
74
+ if ( link . some ( ( l ) => l === location . pathname ) ) {
75
+ classes += " bg-gray-300 text-gray-800 dark:bg-gray-800 dark:text-gray-50" ;
76
+ } else {
77
+ classes += " hover:bg-gray-100 dark:hover:bg-gray-800" ;
78
+ }
79
+ return (
80
+ < Link to = { link [ 0 ] } key = { title } className = "md:w-full" >
81
+ < li ref = { itemRef } className = { classes } >
82
+ { title }
83
+ </ li >
84
+ </ Link >
85
+ ) ;
86
+ } ;
0 commit comments