diff --git a/package.json b/package.json index 030467f79..8933cc582 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "@types/react-select": "^4.0.15", "@types/react-window": "^1.8.2", "@types/react-window-infinite-loader": "^1.0.3", - "@types/styled-components": "^5.1.3", + "@types/styled-components": "^5.1.25", "@types/yup": "^0.29.7", "babel-plugin-styled-components": "^1.11.1", "eslint": "^7.27.0", diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx index fa6906375..62f1aa801 100644 --- a/src/components/CodeBlock.tsx +++ b/src/components/CodeBlock.tsx @@ -3,7 +3,7 @@ import { FreeFlowText, IconButton } from './Container'; import CopyIcon from './icons/CopyIcon'; import React, { useState } from 'react'; import { Tooltip, OverlayTrigger } from 'react-bootstrap'; -import TickIcon from './icons/TickIcon'; +import TickIcon from '@mui/icons-material/Done'; import EnteSpinner from './EnteSpinner'; const Wrapper = styled.div` diff --git a/src/components/Collections/AllCollections.tsx b/src/components/Collections/AllCollections.tsx deleted file mode 100644 index 379384fb9..000000000 --- a/src/components/Collections/AllCollections.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { CollectionSummaries } from 'types/collection'; - -interface Iprops { - isOpen: boolean; - close: () => void; - collectionSummaries: CollectionSummaries; - setActiveCollection: (id?: number) => void; -} - -import * as React from 'react'; -import DialogContent from '@mui/material/DialogContent'; -import Typography from '@mui/material/Typography'; -import constants from 'utils/strings/constants'; -import { FlexWrapper, SpaceBetweenFlex } from 'components/Container'; -import { LargerCollectionTile } from './styledComponents'; -import CollectionCard from './CollectionCard'; -import Divider from '@mui/material/Divider'; -import CollectionSort from 'components/pages/gallery/CollectionSort'; -import { CollectionType, COLLECTION_SORT_BY } from 'constants/collection'; -import { DialogTitleWithCloseButton } from 'components/MessageDialog'; -import { sortCollectionSummaries } from 'services/collectionService'; -import { - Transition, - FloatingDrawer, -} from 'components/Collections/FloatingDrawer'; -import { useLocalState } from 'hooks/useLocalState'; -import { LS_KEYS } from 'utils/storage/localStorage'; - -const LeftSlideTransition = Transition('up'); - -export default function AllCollections(props: Iprops) { - const { collectionSummaries, isOpen, close, setActiveCollection } = props; - - const onCollectionClick = (collectionID: number) => { - setActiveCollection(collectionID); - close(); - }; - - const [collectionSortBy, setCollectionSortBy] = - useLocalState( - LS_KEYS.COLLECTION_SORT_BY, - COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING - ); - - return ( - <> - - - - {constants.ALL_ALBUMS} - - - - {`${[...props.collectionSummaries.keys()].length} ${ - constants.ALBUMS - }`} - - - - - - - - {sortCollectionSummaries( - [...collectionSummaries.values()].filter( - (x) => - x.collectionAttributes.type !== - CollectionType.system - ), - collectionSortBy - ).map( - ({ - latestFile, - collectionAttributes, - fileCount, - }) => ( - - onCollectionClick( - collectionAttributes.id - ) - } - customCollectionTile={LargerCollectionTile}> -
- - - {collectionAttributes.name} - - - - {fileCount} {constants.PHOTOS} - -
-
- ) - )} -
-
-
- - ); -} diff --git a/src/components/Collections/AllCollections/CollectionCard.tsx b/src/components/Collections/AllCollections/CollectionCard.tsx new file mode 100644 index 000000000..924972b70 --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionCard.tsx @@ -0,0 +1,37 @@ +import { Typography } from '@mui/material'; +import constants from 'utils/strings/constants'; +import React from 'react'; +import CollectionCard from '../CollectionCard'; + +export default function AllCollectionCard({ + onCollectionClick, + collectionAttributes, + latestFile, + fileCount, +}) { + return ( + onCollectionClick(collectionAttributes.id)}> +
+ + {collectionAttributes.name} + + + {fileCount} {constants.PHOTOS} + +
+
+ ); +} diff --git a/src/components/Collections/AllCollections/CollectionSort/index.tsx b/src/components/Collections/AllCollections/CollectionSort/index.tsx new file mode 100644 index 000000000..5013cd95b --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/index.tsx @@ -0,0 +1,44 @@ +import React, { useState } 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'; + +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 ( + <> + setSortByEl(event.currentTarget)} + aria-controls={sortByEl ? 'collection-sort' : undefined} + aria-haspopup="true" + aria-expanded={sortByEl ? 'true' : undefined}> + + + + + + + ); +} diff --git a/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx b/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx new file mode 100644 index 000000000..795358711 --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { MenuItem, ListItemIcon, ListItemText } from '@mui/material'; +import { COLLECTION_SORT_BY } from 'constants/collection'; +import TickIcon from '@mui/icons-material/Done'; +import { CollectionSortProps } from '.'; + +export interface SortOptionProps extends CollectionSortProps { + close: () => void; +} + +const SortByOptionCreator = + ({ setCollectionSortBy, activeSortBy, close }: SortOptionProps) => + (props: { sortBy: COLLECTION_SORT_BY; children: any }) => { + const handleClick = () => { + setCollectionSortBy(props.sortBy); + close(); + }; + return ( + + + {activeSortBy === props.sortBy && ( + + )} + + {props.children} + + ); + }; + +export default SortByOptionCreator; diff --git a/src/components/Collections/AllCollections/CollectionSort/options.tsx b/src/components/Collections/AllCollections/CollectionSort/options.tsx new file mode 100644 index 000000000..cb6e7c5d3 --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/options.tsx @@ -0,0 +1,26 @@ +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'; + +export default function CollectionSortOptions(props: SortOptionProps) { + const SortByOption = SortByOptionCreator(props); + + return ( + + + {constants.SORT_BY_NAME} + + + {constants.SORT_BY_CREATION_TIME_DESCENDING} + + + {constants.SORT_BY_CREATION_TIME_ASCENDING} + + + {constants.SORT_BY_UPDATION_TIME_DESCENDING} + + + ); +} diff --git a/src/components/Collections/AllCollections/content.tsx b/src/components/Collections/AllCollections/content.tsx new file mode 100644 index 000000000..287e01609 --- /dev/null +++ b/src/components/Collections/AllCollections/content.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { DialogContent } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import AllCollectionCard from './CollectionCard'; + +export default function AllCollectionContent({ + sortedCollectionSummaries, + onCollectionClick, +}) { + return ( + + + {sortedCollectionSummaries.map( + ({ latestFile, collectionAttributes, fileCount }) => ( + + ) + )} + + + ); +} diff --git a/src/components/Collections/AllCollections/header.tsx b/src/components/Collections/AllCollections/header.tsx new file mode 100644 index 000000000..72cf2327d --- /dev/null +++ b/src/components/Collections/AllCollections/header.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { DialogTitle, IconButton, Typography } from '@mui/material'; +import { SpaceBetweenFlex } from 'components/Container'; +import CollectionSort from 'components/Collections/AllCollections/CollectionSort'; +import constants from 'utils/strings/constants'; +import Close from '@mui/icons-material/Close'; + +export default function AllCollectionsHeader({ + onClose, + collectionCount, + collectionSortBy, + setCollectionSortBy, +}) { + return ( + + + + {constants.ALL_ALBUMS} + + + + + + + + {`${collectionCount} ${constants.ALBUMS}`} + + + + + ); +} diff --git a/src/components/Collections/AllCollections/index.tsx b/src/components/Collections/AllCollections/index.tsx new file mode 100644 index 000000000..8196efdca --- /dev/null +++ b/src/components/Collections/AllCollections/index.tsx @@ -0,0 +1,67 @@ +import React, { useMemo } from 'react'; +import Divider from '@mui/material/Divider'; +import { CollectionType, COLLECTION_SORT_BY } from 'constants/collection'; +import { sortCollectionSummaries } from 'services/collectionService'; +import { + Transition, + FloatingDrawer, +} from 'components/Collections/FloatingDrawer'; +import { useLocalState } from 'hooks/useLocalState'; +import { LS_KEYS } from 'utils/storage/localStorage'; +import AllCollectionsHeader from './header'; +import { CollectionSummaries } from 'types/collection'; +import AllCollectionContent from './content'; + +interface Iprops { + isOpen: boolean; + close: () => void; + collectionSummaries: CollectionSummaries; + setActiveCollection: (id?: number) => void; +} + +const LeftSlideTransition = Transition('up'); + +export default function AllCollections(props: Iprops) { + const { collectionSummaries, isOpen, close, setActiveCollection } = props; + + const [collectionSortBy, setCollectionSortBy] = + useLocalState( + LS_KEYS.COLLECTION_SORT_BY, + COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING + ); + + const sortedCollectionSummaries = useMemo( + () => + sortCollectionSummaries( + [...collectionSummaries.values()].filter( + (x) => x.collectionAttributes.type !== CollectionType.system + ), + collectionSortBy + ), + [collectionSortBy, collectionSummaries] + ); + + const onCollectionClick = (collectionID: number) => { + setActiveCollection(collectionID); + close(); + }; + + return ( + + + + + + ); +} diff --git a/src/components/Collections/CollectionCardWithActiveIndicator.tsx b/src/components/Collections/CollectionBar/CollectionCardWithActiveIndicator.tsx similarity index 83% rename from src/components/Collections/CollectionCardWithActiveIndicator.tsx rename to src/components/Collections/CollectionBar/CollectionCardWithActiveIndicator.tsx index 5d54833b6..89238765e 100644 --- a/src/components/Collections/CollectionCardWithActiveIndicator.tsx +++ b/src/components/Collections/CollectionBar/CollectionCardWithActiveIndicator.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { EnteFile } from 'types/file'; -import { CollectionTileWrapper, ActiveIndicator } from './styledComponents'; -import CollectionCard from './CollectionCard'; +import { CollectionTileWrapper, ActiveIndicator } from '../styledComponents'; +import CollectionCard from '../CollectionCard'; const CollectionCardWithActiveIndicator = React.forwardRef( ( diff --git a/src/components/Collections/CreateCollectionTile.tsx b/src/components/Collections/CollectionBar/CreateCollectionTile.tsx similarity index 82% rename from src/components/Collections/CreateCollectionTile.tsx rename to src/components/Collections/CollectionBar/CreateCollectionTile.tsx index 9529a326c..2c03c26b1 100644 --- a/src/components/Collections/CreateCollectionTile.tsx +++ b/src/components/Collections/CollectionBar/CreateCollectionTile.tsx @@ -1,6 +1,6 @@ import React from 'react'; import constants from 'utils/strings/englishConstants'; -import { CollectionTitleWithDashedBorder } from './styledComponents'; +import { CollectionTitleWithDashedBorder } from '../styledComponents'; export const CreateNewCollectionTile = (props) => { return ( diff --git a/src/components/Collections/NavigationButton.tsx b/src/components/Collections/CollectionBar/NavigationButton.tsx similarity index 90% rename from src/components/Collections/NavigationButton.tsx rename to src/components/Collections/CollectionBar/NavigationButton.tsx index 78df7017c..effd16a8d 100644 --- a/src/components/Collections/NavigationButton.tsx +++ b/src/components/Collections/CollectionBar/NavigationButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styled, { css } from 'styled-components'; -import NavigateNext from '../icons/NavigateNext'; +import NavigateNextIcon from '@mui/icons-material/NavigateNext'; export enum SCROLL_DIRECTION { LEFT = -1, @@ -8,15 +8,18 @@ export enum SCROLL_DIRECTION { } const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>` + position: absolute; top: 7px; height: 50px; width: 50px; + border: none; + padding: 0; + margin: 0; border-radius: 50%; background-color: ${({ theme }) => theme.palette.background.paper}; - border: none; color: ${({ theme }) => theme.palette.text.primary}; - position: absolute; + ${(props) => props.direction === SCROLL_DIRECTION.LEFT ? css` @@ -38,15 +41,11 @@ const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>` height: 30px; width: 30px; } - - &:hover { - color: #fff; - } `; const NavigationButton = ({ scrollDirection, ...rest }) => ( - + ); export default NavigationButton; diff --git a/src/components/Collections/CollectionBar.tsx b/src/components/Collections/CollectionBar/index.tsx similarity index 96% rename from src/components/Collections/CollectionBar.tsx rename to src/components/Collections/CollectionBar/index.tsx index be72da4a6..9459a65a4 100644 --- a/src/components/Collections/CollectionBar.tsx +++ b/src/components/Collections/CollectionBar/index.tsx @@ -1,6 +1,6 @@ import NavigationButton, { SCROLL_DIRECTION, -} from 'components/Collections/NavigationButton'; +} from 'components/Collections/CollectionBar/NavigationButton'; import React, { useEffect } from 'react'; import { Collection, CollectionSummaries } from 'types/collection'; import constants from 'utils/strings/constants'; @@ -12,7 +12,7 @@ import { ScrollContainer, PaddedSpaceBetweenFlex, } from 'components/Collections/styledComponents'; -import CollectionCardWithActiveIndicator from 'components/Collections/CollectionCardWithActiveIndicator'; +import CollectionCardWithActiveIndicator from 'components/Collections/CollectionBar/CollectionCardWithActiveIndicator'; import useComponentScroll from 'hooks/useComponentScroll'; import useWindowSize from 'hooks/useWindowSize'; diff --git a/src/components/Collections/CollectionCard.tsx b/src/components/Collections/CollectionCard.tsx index ef5d601f7..cf9b3a4f2 100644 --- a/src/components/Collections/CollectionCard.tsx +++ b/src/components/Collections/CollectionCard.tsx @@ -3,15 +3,15 @@ import { GalleryContext } from 'pages/gallery'; import { useState, useContext, useEffect } from 'react'; import downloadManager from 'services/downloadManager'; import { EnteFile } from 'types/file'; -import { CollectionTile } from './styledComponents'; +import { CollectionTile, LargerCollectionTile } from './styledComponents'; export default function CollectionCard(props: { children?: any; latestFile: EnteFile; onClick: () => void; - customCollectionTile?: any; + large?: boolean; }) { - const { latestFile: file, onClick, children, customCollectionTile } = props; + const { latestFile: file, onClick, children, large } = props; const [coverImageURL, setCoverImageURL] = useState(null); const galleryContext = useContext(GalleryContext); @@ -28,7 +28,7 @@ export default function CollectionCard(props: { }; main(); }, [file]); - const UsedCollectionTile = customCollectionTile ?? CollectionTile; + const UsedCollectionTile = large ? LargerCollectionTile : CollectionTile; return ( {children} diff --git a/src/components/Collections/CollectionInfo.tsx b/src/components/Collections/CollectionInfo.tsx index 1a90dd498..dec0a6fb0 100644 --- a/src/components/Collections/CollectionInfo.tsx +++ b/src/components/Collections/CollectionInfo.tsx @@ -25,10 +25,19 @@ export default function collectionInfo(props: Iprops) { return (
- - {collectionAttributes.name} + + {collectionAttributes.name} - + {fileCount} {constants.PHOTOS}
diff --git a/src/components/Collections/CollectionNamer.tsx b/src/components/Collections/CollectionNamer.tsx index cc9a921e3..70bc88d50 100644 --- a/src/components/Collections/CollectionNamer.tsx +++ b/src/components/Collections/CollectionNamer.tsx @@ -1,10 +1,17 @@ import React from 'react'; -import { Dialog, DialogContent, TextField } from '@mui/material'; +import { + Dialog, + DialogContent, + DialogTitle, + IconButton, + TextField, +} from '@mui/material'; import constants from 'utils/strings/constants'; import SubmitButton from 'components/SubmitButton'; import { Formik } from 'formik'; import * as Yup from 'yup'; -import { DialogTitleWithCloseButton } from 'components/MessageDialog'; +import { SpaceBetweenFlex } from 'components/Container'; +import Close from '@mui/icons-material/Close'; export interface CollectionNamerAttributes { callback: (name) => void; @@ -37,9 +44,14 @@ export default function CollectionNamer({ attributes, ...props }: Props) { return ( - - {attributes?.title} - + + + {attributes?.title} + + + + + initialValues={{ diff --git a/src/components/Collections/CollectionOptions.tsx b/src/components/Collections/CollectionOptions.tsx index 1bc0ecbf6..6ff0db913 100644 --- a/src/components/Collections/CollectionOptions.tsx +++ b/src/components/Collections/CollectionOptions.tsx @@ -172,6 +172,7 @@ const CollectionOptions = (props: CollectionOptionsProps) => { open={Boolean(optionEl)} onClose={handleClose} MenuListProps={{ + disablePadding: true, 'aria-labelledby': 'collection-options', }}> diff --git a/src/components/Collections/FloatingDrawer.tsx b/src/components/Collections/FloatingDrawer.tsx index 9d91ab22c..452fc189b 100644 --- a/src/components/Collections/FloatingDrawer.tsx +++ b/src/components/Collections/FloatingDrawer.tsx @@ -2,22 +2,20 @@ import { Dialog, Slide, styled } from '@mui/material'; import React from 'react'; import PropTypes from 'prop-types'; -export const FloatingDrawer = styled(Dialog)<{ position: 'left' | 'right' }>( - ({ position, theme }) => ({ - '& .MuiDialogContent-root': { - padding: theme.spacing(2), - }, - '& .MuiDialogActions-root': { - padding: theme.spacing(1), - }, - '& .MuiPaper-root': { - maxWidth: '510px', - }, - '& .MuiDialog-container': { - justifyContent: position === 'left' ? 'flex-start' : 'flex-end', - }, - }) -); +export const FloatingDrawer = styled(Dialog)(({ theme }) => ({ + '& .MuiDialog-container': { + justifyContent: 'flex-end', + }, + '& .MuiPaper-root': { + maxWidth: '498px', + }, + '& .MuiDialogTitle-root': { + padding: theme.spacing(3, 2), + }, + '& .MuiDialogContent-root': { + padding: theme.spacing(2), + }, +})); FloatingDrawer.propTypes = { children: PropTypes.node, diff --git a/src/components/Collections/styledComponents.ts b/src/components/Collections/styledComponents.ts index aa87ef032..05ee33603 100644 --- a/src/components/Collections/styledComponents.ts +++ b/src/components/Collections/styledComponents.ts @@ -13,7 +13,7 @@ export const CollectionBarWrapper = styled.div` @media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) { padding: 0 4px; } - border-bottom: 1px solid ${({ theme }) => theme.palette.grey.A400}; + border-bottom: 1px solid ${({ theme }) => theme.palette.grey.A200}; `; export const PaddedSpaceBetweenFlex = styled(SpaceBetweenFlex)` @@ -37,7 +37,6 @@ export const ScrollContainer = styled.div` export const CollectionTile = styled.div<{ coverImgURL?: string; }>` - flex-shrink: 0; display: flex; width: 80px; height: 64px; @@ -50,10 +49,12 @@ export const CollectionTile = styled.div<{ background-image: url(${({ coverImgURL }) => coverImgURL}); background-size: cover; border: 1px solid ${({ theme }) => theme.palette.grey.A200}; + font-size: 14px; + line-height: 20px; `; export const CollectionTileWrapper = styled.div` - margin-right: 6px; + margin-right: 4px; `; export const ActiveIndicator = styled.div` @@ -72,7 +73,7 @@ export const LargerCollectionTile = styled(CollectionTile)` width: 150px; height: 150px; align-items: flex-start; - margin: 4px; + margin: 2px; `; export const CollectionTitleWithDashedBorder = styled(CollectionTile)` diff --git a/src/components/Container.ts b/src/components/Container.ts index a02aebcf4..ce80bc8eb 100644 --- a/src/components/Container.ts +++ b/src/components/Container.ts @@ -1,3 +1,4 @@ +import { Box } from '@mui/material'; import styled from 'styled-components'; const Container = styled.div` @@ -54,9 +55,8 @@ export const Value = styled.div<{ width?: string }>` color: #ddd; `; -export const FlexWrapper = styled.div` +export const FlexWrapper = styled(Box)` display: flex; - flex-wrap: wrap; align-items: center; `; @@ -70,6 +70,14 @@ export const SpaceBetweenFlex = styled(FlexWrapper)` justify-content: space-between; `; +export const CenteredFlex = styled(FlexWrapper)` + justify-content: center; +`; + +export const FluidContainer = styled(FlexWrapper)` + flex: 1; +`; + export const InvertedIconButton = styled(IconButton)` background-color: ${({ theme }) => theme.palette.primary.main}; color: ${({ theme }) => theme.palette.background.default}; diff --git a/src/components/MessageDialog/TitleWithCloseButton.tsx b/src/components/MessageDialog/TitleWithCloseButton.tsx new file mode 100644 index 000000000..b2fa44747 --- /dev/null +++ b/src/components/MessageDialog/TitleWithCloseButton.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { DialogTitle, IconButton } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { SpaceBetweenFlex } from 'components/Container'; + +const DialogTitleWithCloseButton = (props) => { + const { children, onClose, ...other } = props; + + return ( + + + {children} + {onClose && ( + + + + )} + + + ); +}; + +export default DialogTitleWithCloseButton; diff --git a/src/components/MessageDialog.tsx b/src/components/MessageDialog/index.tsx similarity index 80% rename from src/components/MessageDialog.tsx rename to src/components/MessageDialog/index.tsx index 3b7af1a7d..19bfbcef3 100644 --- a/src/components/MessageDialog.tsx +++ b/src/components/MessageDialog/index.tsx @@ -1,8 +1,5 @@ -import DialogTitle from '@mui/material/DialogTitle'; -import IconButton from '@mui/material/IconButton'; import React from 'react'; import constants from 'utils/strings/constants'; -import CloseIcon from '@mui/icons-material/Close'; import { Breakpoint, Button, @@ -12,6 +9,7 @@ import { DialogContentText, Divider, } from '@mui/material'; +import DialogTitleWithCloseButton from './TitleWithCloseButton'; export type ButtonColors = | 'inherit' @@ -46,29 +44,6 @@ type Props = React.PropsWithChildren<{ size?: Breakpoint; }>; -export const DialogTitleWithCloseButton = (props) => { - const { children, onClose, ...other } = props; - - return ( - - {children} - {onClose ? ( - theme.palette.grey[400], - }}> - - - ) : null} - - ); -}; - export default function MessageDialog({ attributes, children, diff --git a/src/components/PhotoSwipe/PhotoSwipe.tsx b/src/components/PhotoSwipe/PhotoSwipe.tsx index 8e699cf42..e8831be91 100644 --- a/src/components/PhotoSwipe/PhotoSwipe.tsx +++ b/src/components/PhotoSwipe/PhotoSwipe.tsx @@ -38,7 +38,7 @@ import { livePhotoBtnHTML } from 'components/LivePhotoBtn'; import { logError } from 'utils/sentry'; import CloseIcon from '@mui/icons-material/Close'; -import TickIcon from 'components/icons/TickIcon'; +import TickIcon from '@mui/icons-material/Done'; import { Formik } from 'formik'; import * as Yup from 'yup'; import EnteSpinner from 'components/EnteSpinner'; diff --git a/src/components/Sidebar/Button.tsx b/src/components/Sidebar/Button.tsx index f6c5e9de0..9539a5374 100644 --- a/src/components/Sidebar/Button.tsx +++ b/src/components/Sidebar/Button.tsx @@ -1,44 +1,38 @@ -import React from 'react'; -import { Button } from '@mui/material'; +import React, { FC } from 'react'; +import { Button, ButtonProps } from '@mui/material'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; +import { FluidContainer } from 'components/Container'; interface IProps { - children: any; - bgDark?: boolean; hideArrow?: boolean; - onClick: () => void; - color?: - | 'inherit' - | 'danger' - | 'primary' - | 'secondary' - | 'success' - | 'error' - | 'info' - | 'warning'; + smallerArrow?: boolean; } -export default function SidebarButton({ +const SidebarButton: FC> = ({ children, - bgDark, hideArrow, + smallerArrow, + sx, ...props -}: IProps) { +}) => { return ( ); -} +}; + +export default SidebarButton; diff --git a/src/components/Sidebar/Header.tsx b/src/components/Sidebar/Header.tsx index 9470cff5c..c075cd370 100644 --- a/src/components/Sidebar/Header.tsx +++ b/src/components/Sidebar/Header.tsx @@ -2,6 +2,7 @@ import { Typography, IconButton } from '@mui/material'; import React from 'react'; import constants from 'utils/strings/constants'; import CloseIcon from '@mui/icons-material/Close'; +import { SpaceBetweenFlex } from 'components/Container'; interface IProps { closeSidebar: () => void; @@ -9,21 +10,18 @@ interface IProps { export default function HeaderSection({ closeSidebar }: IProps) { return ( - <> - - {constants.ENTE} + + + {constants.ENTE} - theme.palette.grey[400], - }}> - + + - + ); } diff --git a/src/components/Sidebar/HelpSection.tsx b/src/components/Sidebar/HelpSection.tsx index 914eac06f..07e8c9dde 100644 --- a/src/components/Sidebar/HelpSection.tsx +++ b/src/components/Sidebar/HelpSection.tsx @@ -10,12 +10,16 @@ import { getToken } from 'utils/common/key'; import isElectron from 'is-electron'; import { downloadApp, initiateEmail } from 'utils/common'; import { GalleryContext } from 'pages/gallery'; +import { useLocalState } from 'hooks/useLocalState'; +import { LS_KEYS } from 'utils/storage/localStorage'; +import { UserDetails } from 'types/user'; -export default function HelpSection({ userDetails }) { - const { setDialogMessage } = useContext(GalleryContext); - +export default function HelpSection() { + const [userDetails] = useLocalState(LS_KEYS.USER_DETAILS); const [exportModalView, setExportModalView] = useState(false); + const { setDialogMessage } = useContext(GalleryContext); + function openFeedbackURL() { const feedbackURL: string = `${getEndpoint()}/users/feedback?token=${encodeURIComponent( getToken() diff --git a/src/components/Sidebar/InfoSection.tsx b/src/components/Sidebar/InfoSection.tsx deleted file mode 100644 index fc56ff8df..000000000 --- a/src/components/Sidebar/InfoSection.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { useState } from 'react'; -import { Typography } from '@mui/material'; -import { SpaceBetweenFlex } from 'components/Container'; -import ThemeToggler from './ThemeToggler'; -import { UserDetails } from 'types/user'; - -interface IProps { - userDetails: UserDetails; -} - -export enum THEMES { - LIGHT, - DARK, -} - -export default function InfoSection({ userDetails }: IProps) { - const [theme, setTheme] = useState(THEMES.DARK); - - return ( - - {userDetails?.email} - - - ); -} diff --git a/src/components/Sidebar/NavigationButton.tsx b/src/components/Sidebar/NavigationButton.tsx new file mode 100644 index 000000000..0a3ee8946 --- /dev/null +++ b/src/components/Sidebar/NavigationButton.tsx @@ -0,0 +1,40 @@ +import React, { FC } from 'react'; +import { Box, ButtonProps } from '@mui/material'; +import SidebarButton from './Button'; +import { DotSeparator } from './styledComponents'; + +interface IProps { + hideArrow?: boolean; + icon: JSX.Element; + label: JSX.Element | string; + count: number; +} +const NavigationButton: FC> = ({ + icon, + label, + count, + ...props +}) => { + return ( + + {icon} + {label} + + + {count} + + + ); +}; + +export default NavigationButton; diff --git a/src/components/Sidebar/NavigationSection.tsx b/src/components/Sidebar/NavigationSection.tsx index 1d83dc93a..1f0e994cc 100644 --- a/src/components/Sidebar/NavigationSection.tsx +++ b/src/components/Sidebar/NavigationSection.tsx @@ -1,66 +1,46 @@ import React, { useContext } from 'react'; -import SidebarButton from './Button'; import constants from 'utils/strings/constants'; import { GalleryContext } from 'pages/gallery'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; import DeleteIcon from '@mui/icons-material/Delete'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; -import { Box, Typography } from '@mui/material'; -import { FlexWrapper } from 'components/Container'; import { CollectionSummaries } from 'types/collection'; - +import NavigationButton from './NavigationButton'; interface Iprops { closeSidebar: () => void; collectionSummaries: CollectionSummaries; } -const DotSeparator = () => ( - - {'ยท'} - -); export default function NavigationSection({ closeSidebar, collectionSummaries, }: Iprops) { const galleryContext = useContext(GalleryContext); - const openArchiveSection = () => { - galleryContext.setActiveCollection(ARCHIVE_SECTION); - closeSidebar(); - }; const openTrashSection = () => { galleryContext.setActiveCollection(TRASH_SECTION); closeSidebar(); }; + + const openArchiveSection = () => { + galleryContext.setActiveCollection(ARCHIVE_SECTION); + closeSidebar(); + }; + return ( <> - - - - - - - {constants.TRASH} - - - {collectionSummaries.get(TRASH_SECTION).fileCount} - - - - - - - - - - {constants.ARCHIVE} - - - {collectionSummaries.get(ARCHIVE_SECTION).fileCount} - - - + } + label={constants.TRASH} + count={collectionSummaries.get(TRASH_SECTION)?.fileCount} + onClick={openTrashSection} + /> + } + label={constants.ARCHIVE} + count={collectionSummaries.get(ARCHIVE_SECTION)?.fileCount} + onClick={openArchiveSection} + /> ); } diff --git a/src/components/Sidebar/ThemeToggler.tsx b/src/components/Sidebar/ThemeSwitcher.tsx similarity index 81% rename from src/components/Sidebar/ThemeToggler.tsx rename to src/components/Sidebar/ThemeSwitcher.tsx index ae4756691..9cbdcbdee 100644 --- a/src/components/Sidebar/ThemeToggler.tsx +++ b/src/components/Sidebar/ThemeSwitcher.tsx @@ -2,19 +2,20 @@ import { ToggleButton, ToggleButtonGroup } from '@mui/material'; import React from 'react'; import DarkModeIcon from '@mui/icons-material/DarkMode'; import LightModeIcon from '@mui/icons-material/LightMode'; -import { THEMES } from './InfoSection'; +import { THEMES } from 'types/theme'; interface Iprops { theme: THEMES; setTheme: (theme: THEMES) => void; } -export default function ThemeToggler({ theme, setTheme }: Iprops) { +export default function ThemeSwitcher({ theme, setTheme }: Iprops) { const handleChange = (event, theme: THEMES) => { - setTheme(theme); + if (theme !== null) { + setTheme(theme); + } }; return ( (null); - useEffect(() => { - setUserDetails(getLocalUserDetails()); - }, []); - - useEffect(() => { - const main = async () => { - const userDetails = await getUserDetails(); - setUserDetails(userDetails); - setData(LS_KEYS.USER_DETAILS, userDetails); - }; - main(); - }, [sidebarView]); return ( - + - - - - + + + - - - + + + - - + {/* + */} ); } diff --git a/src/components/Sidebar/styledComponents.tsx b/src/components/Sidebar/styledComponents.tsx index 97da0b9d5..4e7c1f89f 100644 --- a/src/components/Sidebar/styledComponents.tsx +++ b/src/components/Sidebar/styledComponents.tsx @@ -1,14 +1,30 @@ -import { Drawer, Divider } from '@mui/material'; +import { Drawer, Divider, styled } from '@mui/material'; import { default as MuiStyled } from '@mui/styled-engine'; +import CircleIcon from '@mui/icons-material/Circle'; -export const DrawerSidebar = MuiStyled(Drawer)(() => ({ +export const DrawerSidebar = MuiStyled(Drawer)(({ theme }) => ({ '& .MuiPaper-root': { width: '320px', - padding: '20px', + padding: theme.spacing(2, 1, 4, 1), }, })); -export const DividerWithMargin = MuiStyled(Divider)(() => ({ - marginTop: '20px', - marginBottom: '20px', +DrawerSidebar.defaultProps = { anchor: 'left' }; + +export const PaddedDivider = MuiStyled(Divider)<{ + invisible?: boolean; + spaced?: boolean; +}>(({ theme, invisible, spaced }) => ({ + margin: theme.spacing(spaced ? 2 : 1, 0), + opacity: invisible ? 0 : 1, })); + +export const DotSeparator = styled(CircleIcon)` + height: 4px; + width: 4px; + left: 86px; + top: 18px; + border-radius: 0px; + margin: 0 ${({ theme }) => theme.spacing(1)}; + color: ${({ theme }) => theme.palette.text.secondary}; +`; diff --git a/src/components/Sidebar/userDetailsSection.tsx b/src/components/Sidebar/userDetailsSection.tsx new file mode 100644 index 000000000..837dd5484 --- /dev/null +++ b/src/components/Sidebar/userDetailsSection.tsx @@ -0,0 +1,40 @@ +import React, { useEffect } from 'react'; +import { SpaceBetweenFlex } from 'components/Container'; +import { PaddedDivider } from './styledComponents'; +import SubscriptionDetails from './SubscriptionDetails'; +import { getUserDetails } from 'services/userService'; +import { UserDetails } from 'types/user'; +import { LS_KEYS } from 'utils/storage/localStorage'; +import { useLocalState } from 'hooks/useLocalState'; +import { THEMES } from 'types/theme'; +import ThemeSwitcher from './ThemeSwitcher'; +import Typography from '@mui/material/Typography'; + +export default function UserDetailsSection({ sidebarView }) { + const [userDetails, setUserDetails] = useLocalState( + LS_KEYS.USER_DETAILS + ); + const [theme, setTheme] = useLocalState(LS_KEYS.THEME, THEMES.DARK); + + useEffect(() => { + if (!sidebarView) { + return; + } + const main = async () => { + const userDetails = await getUserDetails(); + setUserDetails(userDetails); + }; + main(); + }, [sidebarView]); + + return ( + <> + + {userDetails?.email} + + + + + + ); +} diff --git a/src/components/icons/NavigateNext.tsx b/src/components/icons/NavigateNext.tsx deleted file mode 100644 index 66b02a9a8..000000000 --- a/src/components/icons/NavigateNext.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -export default function NavigateNext(props) { - return ( - - - - - ); -} - -NavigateNext.defaultProps = { - height: 24, - width: 24, - viewBox: '0 0 24 24', -}; diff --git a/src/components/icons/SortIcon.tsx b/src/components/icons/SortIcon.tsx deleted file mode 100644 index e257396e7..000000000 --- a/src/components/icons/SortIcon.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; - -export default function SortIcon(props) { - return ( - - - - - ); -} - -SortIcon.defaultProps = { - height: 24, - width: 24, - viewBox: '0 0 24 24', -}; diff --git a/src/components/icons/TickIcon.tsx b/src/components/icons/TickIcon.tsx deleted file mode 100644 index 633d869a2..000000000 --- a/src/components/icons/TickIcon.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -export default function TickIcon(props) { - return ( - - - - ); -} - -TickIcon.defaultProps = { - height: 20, - width: 20, - viewBox: '0 0 24 24', -}; diff --git a/src/components/pages/gallery/CollectionSort.tsx b/src/components/pages/gallery/CollectionSort.tsx deleted file mode 100644 index 352c3cd31..000000000 --- a/src/components/pages/gallery/CollectionSort.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useState } from 'react'; -import { COLLECTION_SORT_BY } from 'constants/collection'; -import Menu from '@mui/material/Menu'; -import { IconButton, MenuItem } from '@mui/material'; -import SortIcon from 'components/icons/SortIcon'; -import TickIcon from 'components/icons/TickIcon'; -import constants from 'utils/strings/constants'; -import { ListItemIcon, ListItemText, MenuList, Paper } from '@mui/material'; - -interface Props { - setCollectionSortBy: (sortBy: COLLECTION_SORT_BY) => void; - activeSortBy: COLLECTION_SORT_BY; -} - -interface OptionProps extends Props { - close: () => void; -} - -const SortByOptionCreator = - ({ setCollectionSortBy, activeSortBy, close }: OptionProps) => - (props: { sortBy: COLLECTION_SORT_BY; children: any }) => { - const handleClick = () => { - setCollectionSortBy(props.sortBy); - close(); - }; - return ( - - - {activeSortBy === props.sortBy && } - - - {props.children} - - ); - }; - -const CollectionSortOptions = (props: OptionProps) => { - const SortByOption = SortByOptionCreator(props); - - return ( - - - - {constants.SORT_BY_NAME} - - - {constants.SORT_BY_CREATION_TIME_DESCENDING} - - - {constants.SORT_BY_CREATION_TIME_ASCENDING} - - - {constants.SORT_BY_UPDATION_TIME_DESCENDING} - - - - ); -}; - -export default function CollectionSort(props: Props) { - const [sortByEl, setSortByEl] = useState(null); - const handleClose = () => setSortByEl(null); - return ( - <> - setSortByEl(event.currentTarget)} - aria-controls={sortByEl ? 'collection-sort' : undefined} - aria-haspopup="true" - aria-expanded={sortByEl ? 'true' : undefined}> - - - - - - - ); -} diff --git a/src/darkThemeOptions.tsx b/src/darkThemeOptions.tsx deleted file mode 100644 index 10c2479f4..000000000 --- a/src/darkThemeOptions.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { createTheme } from '@mui/material/styles'; - -declare module '@mui/material/styles' { - interface Palette { - accent: Palette['primary']; - danger: Palette['primary']; - } - interface PaletteOptions { - accent: PaletteOptions['primary']; - danger: PaletteOptions['primary']; - } -} - -declare module '@mui/material/Button' { - export interface ButtonPropsColorOverrides { - danger: true; - } -} - -// Create a theme instance. -const darkThemeOptions = createTheme({ - components: { - MuiPaper: { - styleOverrides: { root: { backgroundImage: 'none' } }, - }, - MuiLink: { - styleOverrides: { - root: { - color: '#fff', - textDecoration: 'none', - '&:hover': { - color: '#fff', - textDecoration: 'underline', - textDecorationColor: '#fff', - }, - }, - }, - }, - }, - - palette: { - mode: 'dark', - primary: { - main: '#fff', - }, - text: { - primary: 'hsla(0, 0%, 100%, 1)', - secondary: 'hsla(0, 0%, 100%, 0.5)', - }, - accent: { - main: '#43BA6C', - dark: '#369556', - }, - - danger: { - main: '#c93f3f', - }, - background: { default: '#191919', paper: '#191919' }, - }, -}); - -export default darkThemeOptions; diff --git a/src/hooks/useComponentScroll.tsx b/src/hooks/useComponentScroll.tsx index 531c44668..4b7e033f0 100644 --- a/src/hooks/useComponentScroll.tsx +++ b/src/hooks/useComponentScroll.tsx @@ -1,4 +1,4 @@ -import { SCROLL_DIRECTION } from 'components/Collections/NavigationButton'; +import { SCROLL_DIRECTION } from 'components/Collections/CollectionBar/NavigationButton'; import { useRef, useState, useEffect } from 'react'; export default function useComponentScroll({ @@ -15,14 +15,17 @@ export default function useComponentScroll({ }>({}); const updateScrollObj = () => { - if (componentRef.current) { - const { scrollLeft, scrollWidth, clientWidth } = - componentRef.current; - setScrollObj({ scrollLeft, scrollWidth, clientWidth }); + if (!componentRef.current) { + return; } + const { scrollLeft, scrollWidth, clientWidth } = componentRef.current; + setScrollObj({ scrollLeft, scrollWidth, clientWidth }); }; useEffect(() => { + if (!componentRef.current) { + return; + } // Add event listener componentRef.current?.addEventListener('scroll', updateScrollObj); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 93792600a..c1a7cf6f1 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -24,9 +24,11 @@ import MessageDialog, { SetDialogMessage, } from 'components/MessageDialog'; import { ThemeProvider as MThemeProvider } from '@mui/material/styles'; -import darkThemeOptions from 'darkThemeOptions'; +import darkThemeOptions from 'themes/darkThemeOptions'; import { CssBaseline } from '@mui/material'; import SidebarToggler from 'components/Navbar/SidebarToggler'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import * as types from 'styled-components/cssprop'; export const LogoImage = styled.img` max-height: 28px; diff --git a/src/themes/darkThemeOptions.tsx b/src/themes/darkThemeOptions.tsx new file mode 100644 index 000000000..6a2d48fdc --- /dev/null +++ b/src/themes/darkThemeOptions.tsx @@ -0,0 +1,96 @@ +import { + createTheme, + PaletteColor, + PaletteColorOptions, +} from '@mui/material/styles'; + +declare module '@mui/material/styles' { + interface Palette { + accent: PaletteColor; + danger: PaletteColor; + } + interface PaletteOptions { + accent?: PaletteColorOptions; + danger?: PaletteColorOptions; + } +} + +declare module '@mui/material/Button' { + export interface ButtonPropsColorOverrides { + accent: true; + danger: true; + } +} + +declare module '@mui/material/ToggleButtonGroup' { + export interface ToggleButtonGroupPropsColorOverrides { + negative: true; + } +} + +// Create a theme instance. +const darkThemeOptions = createTheme({ + components: { + MuiPaper: { + styleOverrides: { root: { backgroundImage: 'none' } }, + }, + MuiLink: { + styleOverrides: { + root: { + textDecoration: 'none', + '&:hover': { + textDecoration: 'underline', + }, + }, + }, + }, + MuiMenu: { + styleOverrides: { paper: { margin: '10px' } }, + }, + MuiButton: { + styleOverrides: { + root: { + fontSize: '18px', + lineHeight: '21.78px', + padding: '16px', + textTransform: 'none', + borderRadius: '8px', + }, + }, + }, + }, + + palette: { + mode: 'dark', + primary: { + main: '#f0f0f0', + }, + secondary: { + main: 'rgba(256, 256, 256, 0.12)', + contrastText: '#fff', + }, + text: { + primary: '#fff', + secondary: '#808080', + }, + accent: { + main: '#43BA6C', + dark: '#369556', + }, + + danger: { + main: '#c93f3f', + }, + background: { default: '#000000', paper: '#1b1b1b' }, + grey: { + A100: '#ccc', + A200: 'rgba(256, 256, 256, 0.24)', + }, + divider: 'rgba(255, 255, 255, 0.24)', + }, + shape: { + borderRadius: 8, + }, +}); + +export default darkThemeOptions; diff --git a/src/types/theme/index.ts b/src/types/theme/index.ts new file mode 100644 index 000000000..8657aac77 --- /dev/null +++ b/src/types/theme/index.ts @@ -0,0 +1,4 @@ +export enum THEMES { + LIGHT, + DARK, +} diff --git a/src/utils/storage/localStorage.ts b/src/utils/storage/localStorage.ts index 9e5cbc74d..79b9c6aee 100644 --- a/src/utils/storage/localStorage.ts +++ b/src/utils/storage/localStorage.ts @@ -18,6 +18,7 @@ export enum LS_KEYS { LOGS = 'logs', USER_DETAILS = 'userDetails', COLLECTION_SORT_BY = 'collectionSortBy', + THEME = 'theme', } export const setData = (key: LS_KEYS, value: object) => { diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 1d3dff95e..a0dd135d2 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -32,6 +32,7 @@ const Trigger = styled.span` `; const englishConstants = { + ENTE: 'ente', HERO_HEADER: () => (
with @@ -718,7 +719,6 @@ const englishConstants = { VIEW_ALL_ALBUMS: 'View all Albums', ALL_ALBUMS: 'All Albums', PHOTOS: 'Photos', - ENTE: 'ente', ENDS: 'Ends', }; diff --git a/yarn.lock b/yarn.lock index 73b72c3eb..96099ee78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1634,10 +1634,10 @@ resolved "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz" integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== -"@types/styled-components@^5.1.3": - version "5.1.14" - resolved "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.14.tgz" - integrity sha512-d6P1/tyNytqKwam3cQXq7a9uPtovc/mdAs7dBiz1YbDdNIT3X4WmuFU78YdSYh84TXVuhOwezZ3EeKuNBhwsHQ== +"@types/styled-components@^5.1.25": + version "5.1.25" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.25.tgz#0177c4ab5fa7c6ed0565d36f597393dae3f380ad" + integrity sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ== dependencies: "@types/hoist-non-react-statics" "*" "@types/react" "*"