commit
e838421b72
|
@ -1,44 +1,20 @@
|
|||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import { COLLECTION_SORT_BY } from 'constants/collection';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import { IconButton, styled } from '@mui/material';
|
||||
import SortIcon from '@mui/icons-material/Sort';
|
||||
import CollectionSortOptions from './options';
|
||||
import OverflowMenu from 'components/OverflowMenu/menu';
|
||||
|
||||
export interface CollectionSortProps {
|
||||
setCollectionSortBy: (sortBy: COLLECTION_SORT_BY) => void;
|
||||
activeSortBy: COLLECTION_SORT_BY;
|
||||
}
|
||||
|
||||
const StyledMenu = styled(Menu)`
|
||||
& .MuiPaper-root {
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
`;
|
||||
|
||||
export default function CollectionSort(props: CollectionSortProps) {
|
||||
const [sortByEl, setSortByEl] = useState(null);
|
||||
const handleClose = () => setSortByEl(null);
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
onClick={(event) => setSortByEl(event.currentTarget)}
|
||||
aria-controls={sortByEl ? 'collection-sort' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={sortByEl ? 'true' : undefined}>
|
||||
<SortIcon />
|
||||
</IconButton>
|
||||
<StyledMenu
|
||||
id="collection-sort"
|
||||
anchorEl={sortByEl}
|
||||
open={Boolean(sortByEl)}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
disablePadding: true,
|
||||
'aria-labelledby': 'collection-sort',
|
||||
}}>
|
||||
<CollectionSortOptions {...props} close={handleClose} />
|
||||
</StyledMenu>
|
||||
</>
|
||||
<OverflowMenu
|
||||
ariaControls="collection-sort"
|
||||
triggerButtonIcon={<SortIcon />}>
|
||||
<CollectionSortOptions {...props} />
|
||||
</OverflowMenu>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,26 @@
|
|||
import React from 'react';
|
||||
import { MenuItem, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import React, { useContext } from 'react';
|
||||
import { COLLECTION_SORT_BY } from 'constants/collection';
|
||||
import TickIcon from '@mui/icons-material/Done';
|
||||
import { CollectionSortProps } from '.';
|
||||
|
||||
export interface SortOptionProps extends CollectionSortProps {
|
||||
close: () => void;
|
||||
}
|
||||
import { OverflowMenuContext } from 'contexts/overflowMenu';
|
||||
import { OverflowMenuOption } from 'components/OverflowMenu/option';
|
||||
|
||||
const SortByOptionCreator =
|
||||
({ setCollectionSortBy, activeSortBy, close }: SortOptionProps) =>
|
||||
({ setCollectionSortBy, activeSortBy }: CollectionSortProps) =>
|
||||
(props: { sortBy: COLLECTION_SORT_BY; children: any }) => {
|
||||
const { close } = useContext(OverflowMenuContext);
|
||||
|
||||
const handleClick = () => {
|
||||
setCollectionSortBy(props.sortBy);
|
||||
close();
|
||||
};
|
||||
|
||||
return (
|
||||
<MenuItem onClick={handleClick} style={{ paddingLeft: '5px' }}>
|
||||
<ListItemIcon style={{ minWidth: '25px' }}>
|
||||
{activeSortBy === props.sortBy && (
|
||||
<TickIcon sx={{ fontSize: 16 }} />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText>{props.children}</ListItemText>
|
||||
</MenuItem>
|
||||
<OverflowMenuOption
|
||||
onClick={handleClick}
|
||||
startIcon={activeSortBy === props.sortBy && <TickIcon />}>
|
||||
{props.children}
|
||||
</OverflowMenuOption>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
import { MenuList } from '@mui/material';
|
||||
import { COLLECTION_SORT_BY } from 'constants/collection';
|
||||
import constants from 'utils/strings/constants';
|
||||
import SortByOptionCreator, { SortOptionProps } from './optionCreator';
|
||||
import SortByOptionCreator from './optionCreator';
|
||||
import { CollectionSortProps } from '.';
|
||||
|
||||
export default function CollectionSortOptions(props: SortOptionProps) {
|
||||
export default function CollectionSortOptions(props: CollectionSortProps) {
|
||||
const SortByOption = SortByOptionCreator(props);
|
||||
|
||||
return (
|
||||
<MenuList>
|
||||
<>
|
||||
<SortByOption sortBy={COLLECTION_SORT_BY.NAME}>
|
||||
{constants.SORT_BY_NAME}
|
||||
</SortByOption>
|
||||
|
@ -21,6 +21,6 @@ export default function CollectionSortOptions(props: SortOptionProps) {
|
|||
<SortByOption sortBy={COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING}>
|
||||
{constants.SORT_BY_UPDATION_TIME_DESCENDING}
|
||||
</SortByOption>
|
||||
</MenuList>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useContext, useState } from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import * as CollectionAPI from 'services/collectionService';
|
||||
import {
|
||||
changeCollectionVisibility,
|
||||
|
@ -8,15 +8,13 @@ import constants from 'utils/strings/constants';
|
|||
import { SetCollectionNamerAttributes } from './CollectionNamer';
|
||||
import { Collection } from 'types/collection';
|
||||
import { IsArchived } from 'utils/magicMetadata';
|
||||
import { InvertedIconButton } from 'components/Container';
|
||||
import OptionIcon from 'components/icons/OptionIcon-2';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import MenuList from '@mui/material/MenuList';
|
||||
import { ListItem, Menu, MenuItem } from '@mui/material';
|
||||
import { GalleryContext } from 'pages/gallery';
|
||||
import { logError } from 'utils/sentry';
|
||||
import { VISIBILITY_STATE } from 'types/magicMetadata';
|
||||
import { AppContext } from 'pages/_app';
|
||||
import OverflowMenu from 'components/OverflowMenu/menu';
|
||||
import { OverflowMenuOption } from 'components/OverflowMenu/option';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
|
||||
interface CollectionOptionsProps {
|
||||
setCollectionNamerAttributes: SetCollectionNamerAttributes;
|
||||
|
@ -44,9 +42,6 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
|
|||
useContext(AppContext);
|
||||
const { syncWithRemote } = useContext(GalleryContext);
|
||||
|
||||
const [optionEl, setOptionEl] = useState(null);
|
||||
const handleClose = () => setOptionEl(null);
|
||||
|
||||
const handleCollectionAction = (action: CollectionActions) => {
|
||||
let callback;
|
||||
switch (action) {
|
||||
|
@ -78,7 +73,6 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
|
|||
startLoading();
|
||||
try {
|
||||
await callback(...args);
|
||||
handleClose();
|
||||
} catch (e) {
|
||||
setDialogMessage({
|
||||
title: constants.ERROR,
|
||||
|
@ -155,71 +149,42 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<InvertedIconButton
|
||||
style={{
|
||||
transform: 'rotate(90deg)',
|
||||
}}
|
||||
onClick={(event) => setOptionEl(event.currentTarget)}
|
||||
aria-controls={optionEl ? 'collection-options' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={optionEl ? 'true' : undefined}>
|
||||
<OptionIcon />
|
||||
</InvertedIconButton>
|
||||
<Menu
|
||||
id="collection-options"
|
||||
anchorEl={optionEl}
|
||||
open={Boolean(optionEl)}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
disablePadding: true,
|
||||
'aria-labelledby': 'collection-options',
|
||||
}}>
|
||||
<Paper>
|
||||
<MenuList>
|
||||
<MenuItem>
|
||||
<ListItem onClick={showRenameCollectionModal}>
|
||||
{constants.RENAME}
|
||||
</ListItem>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<ListItem onClick={showCollectionShareModal}>
|
||||
{constants.SHARE}
|
||||
</ListItem>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<ListItem onClick={confirmDownloadCollection}>
|
||||
{constants.DOWNLOAD}
|
||||
</ListItem>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
{IsArchived(activeCollection) ? (
|
||||
<ListItem
|
||||
onClick={handleCollectionAction(
|
||||
CollectionActions.UNARCHIVE
|
||||
)}>
|
||||
{constants.UNARCHIVE}
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem
|
||||
onClick={handleCollectionAction(
|
||||
CollectionActions.ARCHIVE
|
||||
)}>
|
||||
{constants.ARCHIVE}
|
||||
</ListItem>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<ListItem
|
||||
color="danger"
|
||||
onClick={confirmDeleteCollection}>
|
||||
{constants.DELETE}
|
||||
</ListItem>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Paper>
|
||||
</Menu>
|
||||
</>
|
||||
<OverflowMenu
|
||||
ariaControls={`collection-options-${props.activeCollection.id}`}
|
||||
triggerButtonIcon={<MoreVertIcon />}
|
||||
triggerButtonProps={{
|
||||
sx: {
|
||||
background: (theme) => theme.palette.background.paper,
|
||||
},
|
||||
}}>
|
||||
<OverflowMenuOption onClick={showRenameCollectionModal}>
|
||||
{constants.RENAME}
|
||||
</OverflowMenuOption>
|
||||
<OverflowMenuOption onClick={showCollectionShareModal}>
|
||||
{constants.SHARE}
|
||||
</OverflowMenuOption>
|
||||
<OverflowMenuOption onClick={confirmDownloadCollection}>
|
||||
{constants.DOWNLOAD}
|
||||
</OverflowMenuOption>
|
||||
{IsArchived(activeCollection) ? (
|
||||
<OverflowMenuOption
|
||||
onClick={handleCollectionAction(
|
||||
CollectionActions.UNARCHIVE
|
||||
)}>
|
||||
{constants.UNARCHIVE}
|
||||
</OverflowMenuOption>
|
||||
) : (
|
||||
<OverflowMenuOption
|
||||
onClick={handleCollectionAction(CollectionActions.ARCHIVE)}>
|
||||
{constants.ARCHIVE}
|
||||
</OverflowMenuOption>
|
||||
)}
|
||||
<OverflowMenuOption
|
||||
color="danger"
|
||||
onClick={confirmDeleteCollection}>
|
||||
{constants.DELETE}
|
||||
</OverflowMenuOption>
|
||||
</OverflowMenu>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,22 +1,34 @@
|
|||
import React from 'react';
|
||||
import { IconButton } from '@mui/material';
|
||||
import { SpaceBetweenFlex } from 'components/Container';
|
||||
import { User } from 'types/user';
|
||||
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
||||
import OverflowMenu from 'components/OverflowMenu/menu';
|
||||
|
||||
import NotInterestedIcon from '@mui/icons-material/NotInterested';
|
||||
import constants from 'utils/strings/constants';
|
||||
import { OverflowMenuOption } from 'components/OverflowMenu/option';
|
||||
|
||||
interface IProps {
|
||||
sharee: User;
|
||||
collectionUnshare: (sharee: User) => void;
|
||||
}
|
||||
const ShareeRow = ({ sharee, collectionUnshare }: IProps) => (
|
||||
<SpaceBetweenFlex>
|
||||
{sharee.email}
|
||||
<IconButton
|
||||
sx={{ ml: 2, color: 'text.secondary' }}
|
||||
onClick={() => collectionUnshare(sharee)}>
|
||||
<MoreHorizIcon />
|
||||
</IconButton>
|
||||
</SpaceBetweenFlex>
|
||||
);
|
||||
const ShareeRow = ({ sharee, collectionUnshare }: IProps) => {
|
||||
const handleClick = () => collectionUnshare(sharee);
|
||||
return (
|
||||
<SpaceBetweenFlex>
|
||||
{sharee.email}
|
||||
<OverflowMenu
|
||||
ariaControls={`email-share-${sharee.email}`}
|
||||
triggerButtonIcon={<MoreHorizIcon />}>
|
||||
<OverflowMenuOption
|
||||
color="danger"
|
||||
onClick={handleClick}
|
||||
startIcon={<NotInterestedIcon />}>
|
||||
{constants.REMOVE}
|
||||
</OverflowMenuOption>
|
||||
</OverflowMenu>
|
||||
</SpaceBetweenFlex>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShareeRow;
|
||||
|
|
63
src/components/OverflowMenu/menu.tsx
Normal file
63
src/components/OverflowMenu/menu.tsx
Normal file
|
@ -0,0 +1,63 @@
|
|||
import React, { useState } from 'react';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import { IconButton, styled } from '@mui/material';
|
||||
import { OverflowMenuContext } from 'contexts/overflowMenu';
|
||||
|
||||
export interface Iprops {
|
||||
triggerButtonIcon: React.ReactNode;
|
||||
triggerButtonProps?: any;
|
||||
children?: React.ReactNode;
|
||||
ariaControls: string;
|
||||
}
|
||||
|
||||
const StyledMenu = styled(Menu)`
|
||||
& .MuiPaper-root {
|
||||
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.16),
|
||||
0px 3px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
& .MuiList-root {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function OverflowMenu({
|
||||
children,
|
||||
ariaControls,
|
||||
triggerButtonIcon,
|
||||
triggerButtonProps,
|
||||
}: Iprops) {
|
||||
const [sortByEl, setSortByEl] = useState(null);
|
||||
const handleClose = () => setSortByEl(null);
|
||||
return (
|
||||
<OverflowMenuContext.Provider value={{ close: handleClose }}>
|
||||
<IconButton
|
||||
onClick={(event) => setSortByEl(event.currentTarget)}
|
||||
aria-controls={sortByEl ? ariaControls : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={sortByEl ? 'true' : undefined}
|
||||
{...triggerButtonProps}>
|
||||
{triggerButtonIcon}
|
||||
</IconButton>
|
||||
<StyledMenu
|
||||
id={ariaControls}
|
||||
anchorEl={sortByEl}
|
||||
open={Boolean(sortByEl)}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
disablePadding: true,
|
||||
'aria-labelledby': ariaControls,
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'center',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'center',
|
||||
horizontal: 'right',
|
||||
}}>
|
||||
{children}
|
||||
</StyledMenu>
|
||||
</OverflowMenuContext.Provider>
|
||||
);
|
||||
}
|
37
src/components/OverflowMenu/option.tsx
Normal file
37
src/components/OverflowMenu/option.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { MenuItem, ListItemIcon, ButtonProps, Typography } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
interface Iprops {
|
||||
onClick: () => void;
|
||||
color?: ButtonProps['color'];
|
||||
startIcon?: React.ReactNode;
|
||||
children?: any;
|
||||
}
|
||||
export function OverflowMenuOption({
|
||||
onClick,
|
||||
color = 'primary',
|
||||
startIcon,
|
||||
children,
|
||||
}: Iprops) {
|
||||
return (
|
||||
<MenuItem
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
color: (theme) => theme.palette[color].main,
|
||||
padding: '12px',
|
||||
}}>
|
||||
{startIcon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
color: 'inherit',
|
||||
padding: '0',
|
||||
paddingRight: '12px',
|
||||
fontSize: '20px',
|
||||
}}>
|
||||
{startIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<Typography variant="button">{children}</Typography>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function OptionIcon(props) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height={props.height}
|
||||
viewBox={props.viewBox}
|
||||
width={props.width}
|
||||
fill="currentColor">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />{' '}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
OptionIcon.defaultProps = {
|
||||
height: 20,
|
||||
width: 20,
|
||||
viewBox: '0 0 24 24',
|
||||
};
|
5
src/contexts/overflowMenu.tsx
Normal file
5
src/contexts/overflowMenu.tsx
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
export const OverflowMenuContext = createContext({
|
||||
close: () => null,
|
||||
});
|
|
@ -77,15 +77,6 @@ const darkThemeOptions = createTheme({
|
|||
},
|
||||
},
|
||||
},
|
||||
MuiMenu: {
|
||||
styleOverrides: {
|
||||
paper: { margin: '10px' },
|
||||
list: {
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
|
@ -155,16 +146,17 @@ const darkThemeOptions = createTheme({
|
|||
typography: {
|
||||
body1: {
|
||||
fontSize: '16px',
|
||||
lineHeight: '24px',
|
||||
lineHeight: '20px',
|
||||
},
|
||||
body2: {
|
||||
fontSize: '14px',
|
||||
lineHeight: '20px',
|
||||
lineHeight: '17px',
|
||||
},
|
||||
button: {
|
||||
fontSize: '16px',
|
||||
lineHeight: '19.36px',
|
||||
lineHeight: '20px',
|
||||
fontWeight: 'bold',
|
||||
textTransform: 'none',
|
||||
},
|
||||
title: {
|
||||
fontSize: '32px',
|
||||
|
|
Loading…
Reference in a new issue