1- import { Box , toRem , Text , color , config , Menu , Icon , Icons , Line , MenuItem } from 'folds' ;
2- import { SquaresFour , sizedIcon } from '$components/icons/phosphor' ;
1+ import {
2+ Box ,
3+ toRem ,
4+ Text ,
5+ color ,
6+ config ,
7+ Menu ,
8+ Icon ,
9+ Icons ,
10+ Line ,
11+ MenuItem ,
12+ Button ,
13+ OverlayBackdrop ,
14+ Overlay ,
15+ OverlayCenter ,
16+ } from 'folds' ;
17+ import { SquaresFour , menuIcon , settingsNavIcon , sizedIcon } from '$components/icons/phosphor' ;
318import { PageNav , PageNavHeader } from '$components/page' ;
4- import { useEffect , useState } from 'react' ;
19+ import { useEffect , useMemo , useState } from 'react' ;
520import { ScreenSize , useScreenSizeContext } from '$hooks/useScreenSize' ;
621import { useSetting } from '$state/hooks/settings' ;
722import { settingsAtom } from '$state/settings' ;
@@ -19,8 +34,14 @@ import { getMxIdLocalPart, mxcUrlToHttp } from '$utils/matrix';
1934import { useMediaAuthentication } from '$hooks/useMediaAuthentication' ;
2035import { useUserPresence } from '$hooks/useUserPresence' ;
2136import { useUserProfile } from '$hooks/useUserProfile' ;
22- import { useOpenSettings } from '$features/settings' ;
37+ import type { SettingsMenuItem } from '$features/settings' ;
38+ import { settingsMenuIcons , settingsSections , useOpenSettings } from '$features/settings' ;
2339import { UserQuickTools } from '../sidebar/UserQuickTools' ;
40+ import { SignOutIcon } from '@phosphor-icons/react' ;
41+ import { UseStateProvider } from '$components/UseStateProvider' ;
42+ import { FocusTrap } from 'focus-trap-react' ;
43+ import { LogoutDialog } from '$components/LogoutDialog' ;
44+ import { stopPropagation } from '$utils/keyboard' ;
2445
2546export function ProfileMobile ( ) {
2647 const mx = useMatrixClient ( ) ;
@@ -31,6 +52,7 @@ export function ProfileMobile() {
3152 const userId = mx . getUserId ( ) ?? '' ;
3253 const profile = useUserProfile ( userId ) ;
3354 const presence = useUserPresence ( userId ) ;
55+ const [ isSettingsOpen , setIsSettingsOpen ] = useState ( true ) ;
3456
3557 const displayName = profile . displayName ?? getMxIdLocalPart ( userId ) ?? userId ;
3658 const heroAvatarUrl = profile . avatarUrl
@@ -54,6 +76,18 @@ export function ProfileMobile() {
5476 const isMobile = screenSize === ScreenSize . Mobile ;
5577 const hideText = curWidth <= 80 && ! isMobile ;
5678
79+ const [ showPersona ] = useSetting ( settingsAtom , 'showPersonaSetting' ) ;
80+ const menuItems = useMemo < SettingsMenuItem [ ] > (
81+ ( ) =>
82+ settingsSections
83+ . filter ( ( section ) => showPersona || section . id !== 'persona' )
84+ . map ( ( section ) => {
85+ const icon = settingsMenuIcons [ section . id ] ;
86+ return { id : section . id , name : section . label , ...icon } ;
87+ } ) ,
88+ [ showPersona ]
89+ ) ;
90+
5791 return (
5892 < >
5993 { ! isMobile && (
@@ -99,9 +133,18 @@ export function ProfileMobile() {
99133 direction = "Column"
100134 gap = "0"
101135 alignItems = "Center"
136+ justifyContent = "SpaceBetween"
102137 style = { { width : '100%' , minWidth : '100%' } }
103138 >
104- < Menu style = { { minWidth : '100%' , overflowY : 'scroll' } } >
139+ < Menu
140+ style = { {
141+ minWidth : '100%' ,
142+ minHeight : '100%' ,
143+ overflowY : 'scroll' ,
144+ border : 'none' ,
145+ background : color . Background . Container ,
146+ } }
147+ >
105148 < UserHero
106149 userId = { userId }
107150 avatarUrl = { heroAvatarUrl }
@@ -119,7 +162,10 @@ export function ProfileMobile() {
119162 < UnverifiedMenuOption />
120163 </ Box >
121164 < Line variant = "Surface" size = "300" />
122- < PresenceMenuOption initialOpen isMobile />
165+
166+ < Box direction = "Column" gap = "100" style = { { padding : config . space . S100 } } >
167+ < PresenceMenuOption isMobile />
168+ </ Box >
123169 < AccountMenuOption isMobile />
124170
125171 < Line variant = "Surface" size = "300" />
@@ -128,13 +174,73 @@ export function ProfileMobile() {
128174 < MenuItem
129175 size = "300"
130176 radii = "300"
177+ variant = "Background"
131178 before = { < Icon size = "100" src = { Icons . Setting } /> }
132- onClick = { ( ) => openSettings ( ) }
179+ after = {
180+ < Icon
181+ size = "100"
182+ src = { isSettingsOpen && isMobile ? Icons . ChevronBottom : Icons . ChevronRight }
183+ />
184+ }
185+ onClick = { ( ) => setIsSettingsOpen ( ! isSettingsOpen ) }
133186 >
134187 < Text style = { { flexGrow : 1 } } size = "T300" >
135188 Settings
136189 </ Text >
137190 </ MenuItem >
191+ { isSettingsOpen && (
192+ < div style = { { paddingLeft : config . space . S100 } } >
193+ { menuItems . map ( ( item ) => {
194+ const IconComponent = item . icon ;
195+
196+ return (
197+ < MenuItem
198+ key = { item . id }
199+ radii = "400"
200+ size = "300"
201+ variant = "Background"
202+ before = { settingsNavIcon ( IconComponent , false ) }
203+ onClick = { ( ) => openSettings ( item . id ) }
204+ >
205+ < Text size = "T300" truncate >
206+ { item . name }
207+ </ Text >
208+ </ MenuItem >
209+ ) ;
210+ } ) }
211+
212+ < UseStateProvider initial = { false } >
213+ { ( logout , setLogout ) => (
214+ < >
215+ < MenuItem
216+ size = "300"
217+ variant = "Background"
218+ style = { { color : color . Critical . OnContainer } }
219+ before = { menuIcon ( SignOutIcon ) }
220+ onClick = { ( ) => setLogout ( true ) }
221+ >
222+ < Text size = "B400" > Logout</ Text >
223+ </ MenuItem >
224+ { logout && (
225+ < Overlay open backdrop = { < OverlayBackdrop /> } >
226+ < OverlayCenter >
227+ < FocusTrap
228+ focusTrapOptions = { {
229+ onDeactivate : ( ) => setLogout ( false ) ,
230+ clickOutsideDeactivates : true ,
231+ escapeDeactivates : stopPropagation ,
232+ } }
233+ >
234+ < LogoutDialog handleClose = { ( ) => setLogout ( false ) } />
235+ </ FocusTrap >
236+ </ OverlayCenter >
237+ </ Overlay >
238+ ) }
239+ </ >
240+ ) }
241+ </ UseStateProvider >
242+ </ div >
243+ ) }
138244 </ Box >
139245 </ Menu >
140246 </ Box >
0 commit comments