diff --git a/web/apps/photos/src/components/Collections/CollectionHeader.tsx b/web/apps/photos/src/components/Collections/CollectionHeader.tsx index 505a557c846..706de41ac78 100644 --- a/web/apps/photos/src/components/Collections/CollectionHeader.tsx +++ b/web/apps/photos/src/components/Collections/CollectionHeader.tsx @@ -1,5 +1,6 @@ import { assertionFailed } from "@/base/assert"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; +import { SpaceBetweenFlex } from "@/base/components/mui/Container"; import { useModalVisibility } from "@/base/components/utils/modal"; import log from "@/base/log"; import type { Collection } from "@/media/collection"; @@ -8,7 +9,6 @@ import { GalleryItemsHeaderAdapter, GalleryItemsSummary, } from "@/new/photos/components/gallery/ListHeader"; -import { SpaceBetweenFlex } from "@/new/photos/components/mui"; import { ALL_SECTION, HIDDEN_ITEMS_SECTION, diff --git a/web/apps/photos/src/components/Sidebar/AdvancedSettings.tsx b/web/apps/photos/src/components/Sidebar/AdvancedSettings.tsx index 8e1bac65f86..cbc5a1f0167 100644 --- a/web/apps/photos/src/components/Sidebar/AdvancedSettings.tsx +++ b/web/apps/photos/src/components/Sidebar/AdvancedSettings.tsx @@ -1,12 +1,12 @@ import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { NestedSidebarDrawer, + SidebarDrawerTitlebar, type NestedSidebarDrawerVisibilityProps, } from "@/base/components/mui/SidebarDrawer"; -import { Titlebar } from "@/base/components/Titlebar"; import { AppContext } from "@/new/photos/types/context"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; -import { Box, Stack } from "@mui/material"; +import { Stack } from "@mui/material"; import { t } from "i18next"; import React, { useContext } from "react"; @@ -31,30 +31,28 @@ export const AdvancedSettings: React.FC = ({ {...{ open, onClose }} onRootClose={handleRootClose} > - - + - - - - - - - + + + - + + - + ); diff --git a/web/apps/photos/src/components/Sidebar/MapSetting.tsx b/web/apps/photos/src/components/Sidebar/MapSetting.tsx deleted file mode 100644 index c7098ab4f8f..00000000000 --- a/web/apps/photos/src/components/Sidebar/MapSetting.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import { MenuItemGroup } from "@/base/components/Menu"; -import { - NestedSidebarDrawer, - type NestedSidebarDrawerVisibilityProps, -} from "@/base/components/mui/SidebarDrawer"; -import { Titlebar } from "@/base/components/Titlebar"; -import log from "@/base/log"; -import { AppContext } from "@/new/photos/types/context"; -import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; -import { Box, Button, Link, Stack, Typography } from "@mui/material"; -import { t } from "i18next"; -import React, { useContext, useEffect, useState } from "react"; -import { Trans } from "react-i18next"; -import { getMapEnabledStatus } from "services/userService"; - -export const MapSettings: React.FC = ({ - open, - onClose, - onRootClose, -}) => { - const { mapEnabled, updateMapEnabled } = useContext(AppContext); - const [modifyMapEnabledView, setModifyMapEnabledView] = useState(false); - - const openModifyMapEnabled = () => setModifyMapEnabledView(true); - const closeModifyMapEnabled = () => setModifyMapEnabledView(false); - - useEffect(() => { - if (!open) { - return; - } - const main = async () => { - const remoteMapValue = await getMapEnabledStatus(); - updateMapEnabled(remoteMapValue); - }; - main(); - }, [open]); - - const handleRootClose = () => { - onClose(); - onRootClose(); - }; - - return ( - - - - - - - - - - - - - - - - - ); -}; - -const ModifyMapEnabled = ({ open, onClose, onRootClose, mapEnabled }) => { - const { somethingWentWrong, updateMapEnabled } = useContext(AppContext); - - const disableMap = async () => { - try { - await updateMapEnabled(false); - onClose(); - } catch (e) { - log.error("Disable Map failed", e); - somethingWentWrong(); - } - }; - - const enableMap = async () => { - try { - await updateMapEnabled(true); - onClose(); - } catch (e) { - log.error("Enable Map failed", e); - somethingWentWrong(); - } - }; - - const handleRootClose = () => { - onClose(); - onRootClose(); - }; - - return ( - - {mapEnabled ? ( - - ) : ( - - )} - - ); -}; - -function EnableMap({ onClose, enableMap, onRootClose }) { - return ( - - - - - {" "} - - - ), - }} - /> - - - - - - - - - ); -} - -function DisableMap({ onClose, disableMap, onRootClose }) { - return ( - - - - - - - - - - - - - - - ); -} diff --git a/web/apps/photos/src/components/Sidebar/MapSettings.tsx b/web/apps/photos/src/components/Sidebar/MapSettings.tsx new file mode 100644 index 00000000000..839e0ea5e9d --- /dev/null +++ b/web/apps/photos/src/components/Sidebar/MapSettings.tsx @@ -0,0 +1,210 @@ +import { MenuItemGroup } from "@/base/components/Menu"; +import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; +import { + NestedSidebarDrawer, + SidebarDrawerTitlebar, + type NestedSidebarDrawerVisibilityProps, +} from "@/base/components/mui/SidebarDrawer"; +import log from "@/base/log"; +import type { ButtonishProps } from "@/new/photos/components/mui"; +import { AppContext } from "@/new/photos/types/context"; +import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; +import { Box, Button, Link, Stack, Typography } from "@mui/material"; +import { t } from "i18next"; +import React, { useContext, useEffect, useState } from "react"; +import { Trans } from "react-i18next"; +import { getMapEnabledStatus } from "services/userService"; + +export const MapSettings: React.FC = ({ + open, + onClose, + onRootClose, +}) => { + const { mapEnabled, updateMapEnabled } = useContext(AppContext); + const [modifyMapEnabledView, setModifyMapEnabledView] = useState(false); + + const openModifyMapEnabled = () => setModifyMapEnabledView(true); + const closeModifyMapEnabled = () => setModifyMapEnabledView(false); + + useEffect(() => { + if (!open) { + return; + } + const main = async () => { + const remoteMapValue = await getMapEnabledStatus(); + updateMapEnabled(remoteMapValue); + }; + main(); + }, [open]); + + const handleRootClose = () => { + onClose(); + onRootClose(); + }; + + return ( + + + + + + + + + + + + + ); +}; + +const ModifyMapSettings = ({ open, onClose, onRootClose, mapEnabled }) => { + const { somethingWentWrong, updateMapEnabled } = useContext(AppContext); + + const disableMap = async () => { + try { + await updateMapEnabled(false); + onClose(); + } catch (e) { + log.error("Disable Map failed", e); + somethingWentWrong(); + } + }; + + const enableMap = async () => { + try { + await updateMapEnabled(true); + onClose(); + } catch (e) { + log.error("Enable Map failed", e); + somethingWentWrong(); + } + }; + + const handleRootClose = () => { + onClose(); + onRootClose(); + }; + + return ( + + {mapEnabled ? ( + + ) : ( + + )} + + ); +}; + +type ConfirmStepProps = Pick< + NestedSidebarDrawerVisibilityProps, + "onClose" | "onRootClose" +> & + ButtonishProps; + +const ConfirmEnableMap: React.FC = ({ + onClose, + onRootClose, + onClick, +}) => ( + + + + + {" "} + + + ), + }} + /> + + + + + + + + +); + +const ConfirmDisableMap: React.FC = ({ + onClose, + onRootClose, + onClick, +}) => ( + + + + + + + + + + + {t("disable")} + + + {t("cancel")} + + + + +); diff --git a/web/apps/photos/src/components/Sidebar/Preferences.tsx b/web/apps/photos/src/components/Sidebar/Preferences.tsx index 18f1545e2cc..1fd9ec89fc3 100644 --- a/web/apps/photos/src/components/Sidebar/Preferences.tsx +++ b/web/apps/photos/src/components/Sidebar/Preferences.tsx @@ -1,9 +1,9 @@ import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { - SidebarDrawer, + NestedSidebarDrawer, + SidebarDrawerTitlebar, type NestedSidebarDrawerVisibilityProps, } from "@/base/components/mui/SidebarDrawer"; -import { Titlebar } from "@/base/components/Titlebar"; import { useModalVisibility } from "@/base/components/utils/modal"; import { getLocaleInUse, @@ -17,12 +17,12 @@ import { syncSettings } from "@/new/photos/services/settings"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import ChevronRight from "@mui/icons-material/ChevronRight"; import ScienceIcon from "@mui/icons-material/Science"; -import { Box, DialogProps, Stack } from "@mui/material"; +import { Box, Stack } from "@mui/material"; import DropdownInput from "components/DropdownInput"; import { t } from "i18next"; import React, { useEffect } from "react"; import { AdvancedSettings } from "./AdvancedSettings"; -import { MapSettings } from "./MapSetting"; +import { MapSettings } from "./MapSettings"; export const Preferences: React.FC = ({ open, @@ -47,61 +47,42 @@ export const Preferences: React.FC = ({ onRootClose(); }; - const handleDrawerClose: DialogProps["onClose"] = (_, reason) => { - console.log(reason); - if (reason === "backdropClick") { - handleRootClose(); - } else { - onClose(); - } - }; - return ( - - - + + - - - - } - label={t("map")} - /> - } - label={t("advanced")} - /> - {isMLSupported && ( - - } + + + } + label={t("map")} + /> + } + label={t("advanced")} + /> + {isMLSupported && ( + + } + /> + + } + onClick={showMLSettings} + label={t("ml_search")} /> - - } - onClick={showMLSettings} - label={t("ml_search")} - /> - - - )} - - + + + )} + = ({ {...mlSettingsVisibilityProps} onRootClose={handleRootClose} /> - + ); }; diff --git a/web/apps/photos/src/components/Sidebar/TwoFactorModal.tsx b/web/apps/photos/src/components/Sidebar/TwoFactorSettings.tsx similarity index 71% rename from web/apps/photos/src/components/Sidebar/TwoFactorModal.tsx rename to web/apps/photos/src/components/Sidebar/TwoFactorSettings.tsx index 953d22439a9..6a81d53380a 100644 --- a/web/apps/photos/src/components/Sidebar/TwoFactorModal.tsx +++ b/web/apps/photos/src/components/Sidebar/TwoFactorSettings.tsx @@ -1,31 +1,22 @@ import { disableTwoFactor } from "@/accounts/api/user"; +import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { NestedSidebarDrawer, + SidebarDrawerTitlebar, type NestedSidebarDrawerVisibilityProps, } from "@/base/components/mui/SidebarDrawer"; -import { Titlebar } from "@/base/components/Titlebar"; import { AppContext } from "@/new/photos/types/context"; import { VerticallyCentered } from "@ente/shared/components/Container"; +import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages"; import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage"; import LockIcon from "@mui/icons-material/Lock"; -import { Button, Grid, Stack, Typography } from "@mui/material"; +import { Button, Stack, Typography } from "@mui/material"; import { t } from "i18next"; import router, { useRouter } from "next/router"; import { useContext, useEffect, useState } from "react"; import { getTwoFactorStatus } from "services/userService"; -// TODO: Revisit these comments -// const TwoFactorDialog = styled(Dialog)(({ theme }) => ({ -// "& .MuiDialogContent-root": { -// padding: theme.spacing(2, 4), -// }, -// })); - -// type TwoFactorModalProps = ModalVisibilityProps & { -// closeSidebar: () => void; -// }; - export const TwoFactorSettings: React.FC< NestedSidebarDrawerVisibilityProps > = ({ open, onClose, onRootClose }) => { @@ -62,15 +53,13 @@ export const TwoFactorSettings: React.FC< {...{ open, onClose }} onRootClose={handleRootClose} > - - + - {/* {component} */} - {/* */} {isTwoFactorEnabled ? ( )} - {/* */} ); @@ -173,47 +161,27 @@ function TwoFactorModalManageSection(props: TwoFactorModalManageSectionProps) { }; return ( - <> - - - {t("UPDATE_TWO_FACTOR_LABEL")} - - - - - - - - {t("DISABLE_TWO_FACTOR_LABEL")}{" "} - - - - - - - + variant="primary" + checked={true} + label={t("reconfigure")} + /> + + + + ); } diff --git a/web/apps/photos/src/components/Sidebar/index.tsx b/web/apps/photos/src/components/Sidebar/index.tsx index c0eacee9b2d..78557e1c15a 100644 --- a/web/apps/photos/src/components/Sidebar/index.tsx +++ b/web/apps/photos/src/components/Sidebar/index.tsx @@ -47,7 +47,7 @@ import { } from "@mui/material"; import Typography from "@mui/material/Typography"; import DeleteAccountModal from "components/DeleteAccountModal"; -import TwoFactorModal from "components/Sidebar/TwoFactorModal"; +import TwoFactorModal from "components/Sidebar/TwoFactorSettings"; import { WatchFolder } from "components/WatchFolder"; import LinkButton from "components/pages/gallery/LinkButton"; import { t } from "i18next"; diff --git a/web/apps/photos/src/components/Upload/UploadTypeSelector.tsx b/web/apps/photos/src/components/Upload/UploadTypeSelector.tsx index 3d267cab03d..2aec5562f0f 100644 --- a/web/apps/photos/src/components/Upload/UploadTypeSelector.tsx +++ b/web/apps/photos/src/components/Upload/UploadTypeSelector.tsx @@ -1,6 +1,6 @@ +import { SpaceBetweenFlex } from "@/base/components/mui/Container"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { useIsTouchscreen } from "@/base/hooks"; -import { SpaceBetweenFlex } from "@/new/photos/components/mui"; import { DialogCloseIconButton } from "@/new/photos/components/mui/Dialog"; import DialogTitleWithCloseButton, { dialogCloseHandler, diff --git a/web/apps/photos/src/pages/shared-albums.tsx b/web/apps/photos/src/pages/shared-albums.tsx index 24ca230b2f9..66b851dcb82 100644 --- a/web/apps/photos/src/pages/shared-albums.tsx +++ b/web/apps/photos/src/pages/shared-albums.tsx @@ -1,5 +1,6 @@ import { EnteLogoSVG } from "@/base/components/EnteLogo"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; +import { SpaceBetweenFlex } from "@/base/components/mui/Container"; import { NavbarBase, SelectionBar } from "@/base/components/Navbar"; import { sharedCryptoWorker } from "@/base/crypto"; import { useIsSmallWidth, useIsTouchscreen } from "@/base/hooks"; @@ -10,7 +11,6 @@ import { GalleryItemsHeaderAdapter, GalleryItemsSummary, } from "@/new/photos/components/gallery/ListHeader"; -import { SpaceBetweenFlex } from "@/new/photos/components/mui"; import { ALL_SECTION, isHiddenCollection, diff --git a/web/packages/base/components/Titlebar.tsx b/web/packages/base/components/Titlebar.tsx index e46fb92ce0d..1029dff467d 100644 --- a/web/packages/base/components/Titlebar.tsx +++ b/web/packages/base/components/Titlebar.tsx @@ -13,6 +13,8 @@ interface TitlebarProps { actionButton?: JSX.Element; } +// TODO: Deprecated in favor of SidebarDrawerTitlebarProps where possible (will +// revisit the remaining use cases once those have migrated). export const Titlebar: React.FC = ({ title, caption, diff --git a/web/packages/base/components/mui/Container.tsx b/web/packages/base/components/mui/Container.tsx index 45e6e2913e6..d985fc033a6 100644 --- a/web/packages/base/components/mui/Container.tsx +++ b/web/packages/base/components/mui/Container.tsx @@ -1,5 +1,19 @@ import { styled } from "@mui/material"; +/** + * A flexbox with justify content set to space-between and center alignment. + * + * There is also another SpaceBetweenFlex in the old shared package, but that + * one also sets width: 100%. As such, that one should be considered deprecated + * and its uses moved to this one when possible (so that we can then see where + * the width: 100% is essential). + */ +export const SpaceBetweenFlex = styled("div")` + display: flex; + justify-content: space-between; + align-items: center; +`; + /** * A flex child that fills the entire flex direction, and shows its children * after centering them both vertically and horizontally. diff --git a/web/packages/base/components/mui/SidebarDrawer.tsx b/web/packages/base/components/mui/SidebarDrawer.tsx index 2f9bf86a7b3..5ce5d12559b 100644 --- a/web/packages/base/components/mui/SidebarDrawer.tsx +++ b/web/packages/base/components/mui/SidebarDrawer.tsx @@ -1,5 +1,17 @@ -import { Drawer, styled, type DrawerProps } from "@mui/material"; +import ArrowBack from "@mui/icons-material/ArrowBack"; +import Close from "@mui/icons-material/Close"; +import { + Box, + Drawer, + IconButton, + Stack, + styled, + Typography, + type DrawerProps, +} from "@mui/material"; +import React from "react"; import type { ModalVisibilityProps } from "../utils/modal"; +import { SpaceBetweenFlex } from "./Container"; /** * A MUI {@link Drawer} with a standard set of styling that we use for our left @@ -74,3 +86,56 @@ export const NestedSidebarDrawer: React.FC< /> ); }; + +type SidebarDrawerTitlebarProps = Pick< + NestedSidebarDrawerVisibilityProps, + "onClose" | "onRootClose" +> & { + /** Title for the drawer. */ + title: string; + /** An optional secondary caption shown below the title. */ + caption?: string; + /** + * An optional action button shown alongwith the close button at the + * trailing edge of the sidebar. + */ + actionButton?: React.ReactNode; +}; + +/** + * A bar with a title and back / close buttons, suitable for being used in + * tandem with a {@link NestedSidebarDrawer}. + */ +export const SidebarDrawerTitlebar: React.FC = ({ + title, + caption, + onClose, + onRootClose, + actionButton, +}) => ( + + + + + + + {actionButton && actionButton} + + + + + + + + {title} + + + {caption} + + + +); diff --git a/web/packages/new/photos/components/CollectionMappingChoiceDialog.tsx b/web/packages/new/photos/components/CollectionMappingChoiceDialog.tsx index eb52dd7aabd..5859c2b8f57 100644 --- a/web/packages/new/photos/components/CollectionMappingChoiceDialog.tsx +++ b/web/packages/new/photos/components/CollectionMappingChoiceDialog.tsx @@ -1,3 +1,4 @@ +import { SpaceBetweenFlex } from "@/base/components/mui/Container"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import type { ModalVisibilityProps } from "@/base/components/utils/modal"; import type { CollectionMapping } from "@/base/types/ipc"; @@ -12,7 +13,6 @@ import { } from "@mui/material"; import { t } from "i18next"; import React from "react"; -import { SpaceBetweenFlex } from "./mui"; import { DialogCloseIconButton } from "./mui/Dialog"; type CollectionMappingChoiceModalProps = ModalVisibilityProps & { diff --git a/web/packages/new/photos/components/CollectionSelector.tsx b/web/packages/new/photos/components/CollectionSelector.tsx index cb052c71860..3619b3ab0a1 100644 --- a/web/packages/new/photos/components/CollectionSelector.tsx +++ b/web/packages/new/photos/components/CollectionSelector.tsx @@ -1,3 +1,4 @@ +import { SpaceBetweenFlex } from "@/base/components/mui/Container"; import type { ModalVisibilityProps } from "@/base/components/utils/modal"; import type { Collection } from "@/media/collection"; import { @@ -24,7 +25,7 @@ import { } from "@mui/material"; import { t } from "i18next"; import React, { useEffect, useState } from "react"; -import { SpaceBetweenFlex, type ButtonishProps } from "./mui"; +import { type ButtonishProps } from "./mui"; import { DialogCloseIconButton } from "./mui/Dialog"; export type CollectionSelectorAction = diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index f93c5341a35..21a09ce312c 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -2,9 +2,9 @@ import { MenuItemGroup } from "@/base/components/Menu"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { NestedSidebarDrawer, + SidebarDrawerTitlebar, type NestedSidebarDrawerVisibilityProps, } from "@/base/components/mui/SidebarDrawer"; -import { Titlebar } from "@/base/components/Titlebar"; import { disableML, enableML, type MLStatus } from "@/new/photos/services/ml"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { @@ -67,11 +67,11 @@ export const MLSettings: React.FC = ({ {...{ open, onClose }} onRootClose={handleRootClose} > - - + {component} @@ -165,10 +165,10 @@ const FaceConsent: React.FC = ({ onRootClose={handleRootClose} > - diff --git a/web/packages/new/photos/components/gallery/PeopleHeader.tsx b/web/packages/new/photos/components/gallery/PeopleHeader.tsx index 79a17945c3c..2629c9f8686 100644 --- a/web/packages/new/photos/components/gallery/PeopleHeader.tsx +++ b/web/packages/new/photos/components/gallery/PeopleHeader.tsx @@ -2,7 +2,7 @@ import { ActivityIndicator, ErrorIndicator, } from "@/base/components/mui/ActivityIndicator"; -import { CenteredBox } from "@/base/components/mui/Container"; +import { CenteredBox, SpaceBetweenFlex } from "@/base/components/mui/Container"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { LoadingButton } from "@/base/components/mui/LoadingButton"; import { @@ -61,7 +61,7 @@ import { t } from "i18next"; import React, { useEffect, useReducer, useState } from "react"; import type { FaceCluster } from "../../services/ml/cluster"; import { useAppContext } from "../../types/context"; -import { SpaceBetweenFlex, type ButtonishProps } from "../mui"; +import { type ButtonishProps } from "../mui"; import { DialogCloseIconButton } from "../mui/Dialog"; import { SuggestionFaceList } from "../PeopleList"; import { SingleInputDialog } from "../SingleInputForm"; diff --git a/web/packages/new/photos/components/mui/index.tsx b/web/packages/new/photos/components/mui/index.tsx index 735de83bd4c..f39034bd117 100644 --- a/web/packages/new/photos/components/mui/index.tsx +++ b/web/packages/new/photos/components/mui/index.tsx @@ -1,4 +1,4 @@ -import { Box, IconButton, styled } from "@mui/material"; +import { IconButton, styled } from "@mui/material"; /** Convenience typed props for a component that acts like a push button. */ export interface ButtonishProps { @@ -11,17 +11,3 @@ export interface ButtonishProps { export const FilledIconButton = styled(IconButton)(({ theme }) => ({ backgroundColor: theme.colors.fill.faint, })); - -/** - * A flexbox with justify content set to space-between and center alignment. - * - * There is also another SpaceBetweenFlex in the old shared package, but that - * one also sets width: 100%. As such, that one should be considered deprecated - * and its uses moved to this one when possible (so that we can then see where - * the width: 100% is essential). - */ -export const SpaceBetweenFlex = styled(Box)` - display: flex; - justify-content: space-between; - align-items: center; -`;