11import { User } from '@idea2app/data-server' ;
2- import { Box , List , ListItem , ListItemButton , ListItemText , Modal } from '@mui/material' ;
2+ import {
3+ Box ,
4+ Drawer ,
5+ IconButton ,
6+ List ,
7+ ListItem ,
8+ ListItemButton ,
9+ ListItemText ,
10+ Modal ,
11+ } from '@mui/material' ;
312import { observable } from 'mobx' ;
413import { observer } from 'mobx-react' ;
514import Link from 'next/link' ;
615import { JWTProps } from 'next-ssr-middleware' ;
716import { Component , HTMLAttributes , JSX } from 'react' ;
817
9- import { PageHead } from '../PageHead' ;
1018import { SessionForm } from './SessionForm' ;
1119
20+ const MenuIcon = ( ) => (
21+ < svg
22+ xmlns = "http://www.w3.org/2000/svg"
23+ viewBox = "0 0 24 24"
24+ fill = "currentColor"
25+ width = "24"
26+ height = "24"
27+ >
28+ < path d = "M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />
29+ </ svg >
30+ ) ;
31+
1232export type MenuItem = Pick < JSX . IntrinsicElements [ 'a' ] , 'href' | 'title' > ;
1333
1434export interface SessionBoxProps extends HTMLAttributes < HTMLDivElement > , JWTProps < User > {
@@ -21,52 +41,135 @@ export class SessionBox extends Component<SessionBoxProps> {
2141 @observable
2242 accessor modalShown = false ;
2343
44+ @observable
45+ accessor mobileMenuOpen = false ;
46+
2447 componentDidMount ( ) {
2548 this . modalShown = ! this . props . jwtPayload ;
2649 }
2750
51+ toggleMobileMenu = ( ) => {
52+ this . mobileMenuOpen = ! this . mobileMenuOpen ;
53+ } ;
54+
55+ closeMobileMenu = ( ) => {
56+ this . mobileMenuOpen = false ;
57+ } ;
58+
59+ renderMenuItems ( ) {
60+ const { path, menu = [ ] } = this . props ;
61+
62+ return (
63+ < List component = "nav" sx = { { px : 2 } } >
64+ { menu . map ( ( { href, title } ) => (
65+ < ListItem key = { href } disablePadding >
66+ < ListItemButton
67+ component = { Link }
68+ href = { href || '#' }
69+ selected = { path ?. split ( '?' ) [ 0 ] . startsWith ( href || '' ) }
70+ sx = { { borderRadius : 1 } }
71+ onClick = { this . closeMobileMenu }
72+ >
73+ < ListItemText primary = { title } />
74+ </ ListItemButton >
75+ </ ListItem >
76+ ) ) }
77+ </ List >
78+ ) ;
79+ }
80+
2881 render ( ) {
29- const { className = '' , title , children, path , menu = [ ] , jwtPayload, ...props } = this . props ;
82+ const { className = '' , children, jwtPayload, ...props } = this . props ;
3083
3184 return (
32- < div className = { `flex ${ className } ` } { ...props } >
33- < div >
34- < List
35- component = "nav"
36- className = "sticky-top flex-col px-3"
37- style = { { top : '5rem' , minWidth : '200px' } }
85+ < Box
86+ sx = { {
87+ display : 'flex' ,
88+ flexDirection : { xs : 'column' , md : 'row' } ,
89+ } }
90+ className = { className }
91+ { ...props }
92+ >
93+ { /* Mobile Menu Button */ }
94+ < Box
95+ sx = { {
96+ display : { xs : 'flex' , md : 'none' } ,
97+ position : 'sticky' ,
98+ top : 0 ,
99+ zIndex : 1100 ,
100+ bgcolor : 'background.paper' ,
101+ borderBottom : 1 ,
102+ borderColor : 'divider' ,
103+ p : 1 ,
104+ } }
105+ >
106+ < IconButton
107+ edge = "start"
108+ color = "inherit"
109+ aria-label = "menu"
110+ onClick = { this . toggleMobileMenu }
38111 >
39- { menu . map ( ( { href, title } ) => (
40- < ListItem key = { href } disablePadding >
41- < ListItemButton
42- component = { Link }
43- href = { href || '#' }
44- selected = { path ?. split ( '?' ) [ 0 ] . startsWith ( href || '' ) }
45- className = "rounded"
46- >
47- < ListItemText primary = { title } />
48- </ ListItemButton >
49- </ ListItem >
50- ) ) }
51- </ List >
52- </ div >
53- < main className = "flex-1 pb-3" >
112+ < MenuIcon />
113+ </ IconButton >
114+ </ Box >
115+
116+ { /* Mobile Drawer */ }
117+ < Drawer
118+ anchor = "left"
119+ open = { this . mobileMenuOpen }
120+ sx = { { display : { xs : 'block' , md : 'none' } } }
121+ onClose = { this . closeMobileMenu }
122+ >
123+ < Box sx = { { width : 250 } } > { this . renderMenuItems ( ) } </ Box >
124+ </ Drawer >
125+
126+ { /* Desktop Sidebar */ }
127+ < Box
128+ sx = { {
129+ display : { xs : 'none' , md : 'block' } ,
130+ minWidth : 200 ,
131+ } }
132+ >
133+ < Box
134+ sx = { {
135+ position : 'sticky' ,
136+ top : '5rem' ,
137+ } }
138+ >
139+ { this . renderMenuItems ( ) }
140+ </ Box >
141+ </ Box >
142+
143+ { /* Main Content */ }
144+ < Box
145+ component = "main"
146+ sx = { {
147+ flex : 1 ,
148+ pb : 3 ,
149+ px : { xs : 2 , sm : 3 } ,
150+ } }
151+ >
54152 { children }
55153
56154 < Modal open = { this . modalShown } >
57155 < Box
58- className = "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded p-4 shadow-lg"
59156 sx = { {
60- width : '400px' ,
61- maxWidth : '90vw' ,
157+ position : 'absolute' ,
158+ top : '50%' ,
159+ left : '50%' ,
160+ transform : 'translate(-50%, -50%)' ,
161+ width : { xs : '90vw' , sm : 400 } ,
62162 bgcolor : 'background.paper' ,
163+ borderRadius : 1 ,
164+ boxShadow : 24 ,
165+ p : 4 ,
63166 } }
64167 >
65168 < SessionForm onSignIn = { ( ) => ( this . modalShown = false ) } />
66169 </ Box >
67170 </ Modal >
68- </ main >
69- </ div >
171+ </ Box >
172+ </ Box >
70173 ) ;
71174 }
72175}
0 commit comments