Skip to content

Commit d3810b8

Browse files
authored
fix: mobile drawer (#170)
1 parent 613e60f commit d3810b8

File tree

8 files changed

+93
-35
lines changed

8 files changed

+93
-35
lines changed

src/components/_shared/mobile-drawer/MobileDrawer.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export function MobileDrawer ({
7777
swipeAreaHeight,
7878
maxHeight,
7979
showPuller = true,
80+
topOffset = 0,
8081
}: {
8182
children: React.ReactNode;
8283
triggerNode: ReactElement;
@@ -88,6 +89,7 @@ export function MobileDrawer ({
8889
swipeAreaHeight?: number | undefined;
8990
maxHeight?: number | undefined;
9091
showPuller?: boolean;
92+
topOffset?: number;
9193
}) {
9294

9395
const toggleDrawer = useCallback((open: boolean) => {
@@ -118,6 +120,22 @@ export function MobileDrawer ({
118120
</>
119121
);
120122

123+
const paperStyle: React.CSSProperties = {
124+
width: swipeAreaWidth,
125+
height: swipeAreaHeight,
126+
maxHeight: maxHeight,
127+
};
128+
129+
if (topOffset && (anchor === 'left' || anchor === 'right')) {
130+
paperStyle.top = topOffset;
131+
132+
if (!swipeAreaHeight) {
133+
paperStyle.height = `calc(100% - ${topOffset}px)`;
134+
} else if (typeof swipeAreaHeight === 'number') {
135+
paperStyle.height = Math.max(0, swipeAreaHeight - topOffset);
136+
}
137+
}
138+
121139
return (
122140
<>
123141
{React.cloneElement(triggerNode, { ...triggerNode.props, onClick: toggleDrawer(true) })}
@@ -132,11 +150,7 @@ export function MobileDrawer ({
132150
},
133151
}}
134152
PaperProps={{
135-
style: {
136-
width: swipeAreaWidth,
137-
height: swipeAreaHeight,
138-
maxHeight: maxHeight,
139-
},
153+
style: paperStyle,
140154
}}
141155
>
142156
{drawerContent}
@@ -145,4 +159,4 @@ export function MobileDrawer ({
145159
);
146160
}
147161

148-
export default MobileDrawer;
162+
export default MobileDrawer;

src/components/_shared/mobile-topbar/MobileFolder.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ function MobileFolder({ onClose }: { onClose: () => void }) {
2929
return (
3030
<AFScroller overflowXHidden className={'flex w-full flex-1 flex-col gap-2'}>
3131
<div className={'sticky top-0 z-[10] w-full bg-background-primary p-2 pb-0'}>
32-
<div className={'mb-2 flex items-center justify-between'}>
33-
<div className={'flex-1 p-2'}>
32+
<div className={'mb-2 flex items-start justify-between gap-2'}>
33+
<div className={'flex-1'}>
3434
<MobileWorkspaces onClose={onClose} />
3535
</div>
3636
<MobileMore onClose={onClose} />

src/components/_shared/mobile-topbar/MobileTopBar.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IconButton } from '@mui/material';
2-
import React, { useCallback } from 'react';
2+
import React, { useCallback, useMemo } from 'react';
33

44
import { HEADER_HEIGHT } from '@/application/constants';
55
import { UIVariant } from '@/application/types';
@@ -14,13 +14,23 @@ import MobileFolder from '@/components/_shared/mobile-topbar/MobileFolder';
1414
import PublishMobileFolder from '@/components/_shared/mobile-topbar/PublishMobileFolder';
1515
import MoreActionsContent from '@/components/_shared/more-actions/MoreActionsContent';
1616
import { openOrDownload } from '@/utils/open_schema';
17+
import { getPlatform } from '@/utils/platform';
1718

1819
const PublishBreadcrumb = withPublishBreadcrumb(Breadcrumb);
1920
const AppBreadcrumb = withAppBreadcrumb(Breadcrumb);
2021

2122
function MobileTopBar({ variant }: { variant?: UIVariant }) {
2223
const [openFolder, setOpenFolder] = React.useState(false);
2324
const [openMore, setOpenMore] = React.useState(false);
25+
const isMobile = getPlatform().isMobile;
26+
const folderDrawerWidth = useMemo(() => {
27+
if (typeof window === 'undefined') return undefined;
28+
const availableWidth = Math.max(0, window.innerWidth - 56);
29+
30+
if (isMobile) return availableWidth;
31+
32+
return Math.min(420, availableWidth);
33+
}, [isMobile]);
2434

2535
const handleOpenFolder = useCallback(() => {
2636
setOpenFolder(true);
@@ -50,12 +60,13 @@ function MobileTopBar({ variant }: { variant?: UIVariant }) {
5060
}
5161
>
5262
<MobileDrawer
53-
swipeAreaWidth={window.innerWidth - 56}
63+
swipeAreaWidth={folderDrawerWidth}
5464
onOpen={handleOpenFolder}
5565
onClose={handleCloseFolder}
5666
open={openFolder}
5767
anchor={'left'}
5868
showPuller={false}
69+
topOffset={HEADER_HEIGHT}
5970
triggerNode={
6071
<IconButton>
6172
<MenuIcon />

src/components/app/workspaces/CurrentWorkspace.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ function CurrentWorkspace({
88
selectedWorkspace,
99
onChangeWorkspace,
1010
changeLoading,
11+
avatarSize = 'xs',
1112
}: {
1213
userWorkspaceInfo?: UserWorkspaceInfo;
1314
selectedWorkspace?: Workspace;
1415
onChangeWorkspace: (selectedId: string) => void;
15-
avatarSize?: number;
16+
avatarSize?: 'xs' | 'sm' | 'md' | 'xl';
1617
changeLoading?: boolean;
1718
}) {
1819
if (!userWorkspaceInfo || !selectedWorkspace) {
@@ -33,19 +34,21 @@ function CurrentWorkspace({
3334
}
3435

3536
return (
36-
<>
37-
<Avatar shape={'square'} size={'xs'}>
38-
<AvatarImage src={selectedWorkspace.icon} alt={''} />
39-
<AvatarFallback name={selectedWorkspace.name}>
40-
{selectedWorkspace.icon ? <span className='text-lg'>{selectedWorkspace.icon}</span> : selectedWorkspace.name}
41-
</AvatarFallback>
42-
</Avatar>
37+
<div className={'flex w-full min-h-[48px] items-center gap-2'}>
38+
{(
39+
<Avatar shape={'square'} size={avatarSize}>
40+
<AvatarImage src={selectedWorkspace.icon} alt={''} />
41+
<AvatarFallback name={selectedWorkspace.name}>
42+
{selectedWorkspace.icon ? <span className='text-lg'>{selectedWorkspace.icon}</span> : selectedWorkspace.name}
43+
</AvatarFallback>
44+
</Avatar>
45+
)}
4346

4447
<div data-testid='current-workspace-name' className={'flex-1 truncate font-medium text-text-primary'}>
4548
{selectedWorkspace.name}
4649
</div>
4750
{changeLoading && <Progress variant={'primary'} />}
48-
</>
51+
</div>
4952
);
5053
}
5154

src/components/app/workspaces/MobileWorkspaces.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ function MobileWorkspaces({ onClose }: { onClose: () => void }) {
104104
onChange={handleChange}
105105
changeLoading={changeLoading || undefined}
106106
showActions={false}
107+
useDropdownItem={false}
107108
/>
108109
)}
109110
</div>

src/components/app/workspaces/WorkspaceItem.tsx

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { CircularProgress } from '@mui/material';
2-
import { useMemo, useState } from 'react';
2+
import { useCallback, useMemo, useState } from 'react';
33
import { useTranslation } from 'react-i18next';
44

55
import { Role, Workspace } from '@/application/types';
66
import MoreActions from '@/components/app/workspaces/MoreActions';
77
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
8-
import { DropdownMenuItem, DropdownMenuItemTick } from '@/components/ui/dropdown-menu';
8+
import { DropdownMenuItem, DropdownMenuItemTick, dropdownMenuItemVariants } from '@/components/ui/dropdown-menu';
99
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
1010

1111
export function WorkspaceItem({
@@ -17,6 +17,7 @@ export function WorkspaceItem({
1717
onUpdate,
1818
onDelete,
1919
onLeave,
20+
useDropdownItem = true,
2021
}: {
2122
showActions?: boolean;
2223
workspace: Workspace;
@@ -26,6 +27,7 @@ export function WorkspaceItem({
2627
onUpdate?: (workspace: Workspace) => void;
2728
onDelete?: (workspace: Workspace) => void;
2829
onLeave?: (workspace: Workspace) => void;
30+
useDropdownItem?: boolean;
2931
}) {
3032
const { t } = useTranslation();
3133
const [hovered, setHovered] = useState(false);
@@ -69,18 +71,13 @@ export function WorkspaceItem({
6971
);
7072
}, [changeLoading, currentWorkspaceId, hovered, onDelete, onLeave, onUpdate, showActions, workspace]);
7173

72-
return (
73-
<DropdownMenuItem
74-
key={workspace.id}
75-
data-testid='workspace-item'
76-
className={'relative'}
77-
onSelect={async () => {
78-
if (workspace.id === currentWorkspaceId) return;
79-
void onChange(workspace.id);
80-
}}
81-
onMouseEnter={() => setHovered(true)}
82-
onMouseLeave={() => setHovered(false)}
83-
>
74+
const handleSelect = useCallback(() => {
75+
if (workspace.id === currentWorkspaceId) return;
76+
void onChange(workspace.id);
77+
}, [currentWorkspaceId, onChange, workspace.id]);
78+
79+
const content = (
80+
<>
8481
<Avatar shape={'square'} size={'xs'}>
8582
<AvatarFallback name={workspace.name}>
8683
{workspace.icon ? <span className='text-lg'>{workspace.icon}</span> : workspace.name}
@@ -112,6 +109,35 @@ export function WorkspaceItem({
112109
)}
113110
</div>
114111
{renderActions}
115-
</DropdownMenuItem>
112+
</>
113+
);
114+
115+
if (useDropdownItem) {
116+
return (
117+
<DropdownMenuItem
118+
key={workspace.id}
119+
data-testid='workspace-item'
120+
className={'relative'}
121+
onSelect={handleSelect}
122+
onMouseEnter={() => setHovered(true)}
123+
onMouseLeave={() => setHovered(false)}
124+
>
125+
{content}
126+
</DropdownMenuItem>
127+
);
128+
}
129+
130+
return (
131+
<button
132+
type='button'
133+
key={workspace.id}
134+
data-testid='workspace-item'
135+
className={dropdownMenuItemVariants({ variant: 'default', className: 'relative w-full text-left' })}
136+
onClick={handleSelect}
137+
onMouseEnter={() => setHovered(true)}
138+
onMouseLeave={() => setHovered(false)}
139+
>
140+
{content}
141+
</button>
116142
);
117143
}

src/components/app/workspaces/WorkspaceList.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function WorkspaceList({
1313
onUpdate,
1414
onDelete,
1515
onLeave,
16+
useDropdownItem = true,
1617
}: {
1718
currentWorkspaceId?: string;
1819
changeLoading?: string;
@@ -23,6 +24,7 @@ function WorkspaceList({
2324
onUpdate?: (workspace: Workspace) => void;
2425
onDelete?: (workspace: Workspace) => void;
2526
onLeave?: (workspace: Workspace) => void;
27+
useDropdownItem?: boolean;
2628
}) {
2729
const service = useService();
2830
const [workspaces, setWorkspaces] = useState<Workspace[]>(defaultWorkspaces || []);
@@ -55,6 +57,7 @@ function WorkspaceList({
5557
onDelete={onDelete}
5658
onLeave={onLeave}
5759
showActions={showActions}
60+
useDropdownItem={useDropdownItem}
5861
/>
5962
);
6063
})}

src/components/app/workspaces/Workspaces.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export function Workspaces() {
146146
userWorkspaceInfo={userWorkspaceInfo}
147147
selectedWorkspace={currentWorkspace}
148148
onChangeWorkspace={handleChange}
149-
avatarSize={24}
149+
avatarSize='sm'
150150
changeLoading={changeLoading ? true : false}
151151
/>
152152

0 commit comments

Comments
 (0)