[web] Refactoring - Nested left sidebar drawer (#3928)

This commit is contained in:
Manav Rathi
2024-11-04 15:27:08 +05:30
committed by GitHub
8 changed files with 176 additions and 187 deletions

View File

@@ -1,14 +1,16 @@
import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import {
NestedSidebarDrawer,
type NestedSidebarDrawerVisibilityProps,
} from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import type { NestedDrawerVisibilityProps } from "@/base/components/utils/modal";
import { AppContext } from "@/new/photos/types/context";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import { Box, DialogProps, Stack } from "@mui/material";
import { Box, Stack } from "@mui/material";
import { t } from "i18next";
import React, { useContext } from "react";
export const AdvancedSettings: React.FC<NestedDrawerVisibilityProps> = ({
export const AdvancedSettings: React.FC<NestedSidebarDrawerVisibilityProps> = ({
open,
onClose,
onRootClose,
@@ -20,26 +22,14 @@ export const AdvancedSettings: React.FC<NestedDrawerVisibilityProps> = ({
onRootClose();
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
handleRootClose();
} else {
onClose();
}
};
const toggleCFProxy = () => {
appContext.setIsCFProxyDisabled(!appContext.isCFProxyDisabled);
};
return (
<SidebarDrawer
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
BackdropProps={{
sx: { "&&&": { backgroundColor: "transparent" } },
}}
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
@@ -66,6 +56,6 @@ export const AdvancedSettings: React.FC<NestedDrawerVisibilityProps> = ({
</Stack>
</Box>
</Stack>
</SidebarDrawer>
</NestedSidebarDrawer>
);
};

View File

@@ -1,24 +1,19 @@
import { MenuItemGroup } from "@/base/components/Menu";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import {
NestedSidebarDrawer,
type NestedSidebarDrawerVisibilityProps,
} from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import type { NestedDrawerVisibilityProps } from "@/base/components/utils/modal";
import log from "@/base/log";
import { AppContext } from "@/new/photos/types/context";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import {
Box,
Button,
DialogProps,
Link,
Stack,
Typography,
} from "@mui/material";
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<NestedDrawerVisibilityProps> = ({
export const MapSettings: React.FC<NestedSidebarDrawerVisibilityProps> = ({
open,
onClose,
onRootClose,
@@ -45,22 +40,10 @@ export const MapSettings: React.FC<NestedDrawerVisibilityProps> = ({
onRootClose();
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
handleRootClose();
} else {
onClose();
}
};
return (
<SidebarDrawer
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
BackdropProps={{
sx: { "&&&": { backgroundColor: "transparent" } },
}}
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
@@ -90,7 +73,7 @@ export const MapSettings: React.FC<NestedDrawerVisibilityProps> = ({
onClose={closeModifyMapEnabled}
onRootClose={handleRootClose}
/>
</SidebarDrawer>
</NestedSidebarDrawer>
);
};
@@ -122,42 +105,25 @@ const ModifyMapEnabled = ({ open, onClose, onRootClose, mapEnabled }) => {
onRootClose();
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason === "backdropClick") {
handleRootClose();
} else {
onClose();
}
};
return (
<Box>
<SidebarDrawer
anchor="left"
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
slotProps={{
backdrop: {
sx: { "&&&": { backgroundColor: "transparent" } },
},
}}
>
{mapEnabled ? (
<DisableMap
onClose={onClose}
disableMap={disableMap}
onRootClose={handleRootClose}
/>
) : (
<EnableMap
onClose={onClose}
enableMap={enableMap}
onRootClose={handleRootClose}
/>
)}
</SidebarDrawer>
</Box>
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
{mapEnabled ? (
<DisableMap
onClose={onClose}
disableMap={disableMap}
onRootClose={handleRootClose}
/>
) : (
<EnableMap
onClose={onClose}
enableMap={enableMap}
onRootClose={handleRootClose}
/>
)}
</NestedSidebarDrawer>
);
};

View File

@@ -1,10 +1,10 @@
import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import {
useModalVisibility,
type NestedDrawerVisibilityProps,
} from "@/base/components/utils/modal";
SidebarDrawer,
type NestedSidebarDrawerVisibilityProps,
} from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import { useModalVisibility } from "@/base/components/utils/modal";
import {
getLocaleInUse,
setLocaleInUse,
@@ -24,7 +24,7 @@ import React, { useEffect } from "react";
import { AdvancedSettings } from "./AdvancedSettings";
import { MapSettings } from "./MapSetting";
export const Preferences: React.FC<NestedDrawerVisibilityProps> = ({
export const Preferences: React.FC<NestedSidebarDrawerVisibilityProps> = ({
open,
onClose,
onRootClose,
@@ -48,6 +48,7 @@ export const Preferences: React.FC<NestedDrawerVisibilityProps> = ({
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
console.log(reason);
if (reason === "backdropClick") {
handleRootClose();
} else {
@@ -60,9 +61,10 @@ export const Preferences: React.FC<NestedDrawerVisibilityProps> = ({
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
BackdropProps={{
sx: { "&&&": { backgroundColor: "transparent" } },
}}
// hideBackdrop
// BackdropProps={{
// sx: { "&&&": { backgroundColor: "transparent" } },
// }}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar

View File

@@ -1,35 +1,34 @@
import { disableTwoFactor } from "@/accounts/api/user";
import type { ModalVisibilityProps } from "@/base/components/utils/modal";
import {
NestedSidebarDrawer,
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 DialogTitleWithCloseButton from "@ente/shared/components/DialogBox/TitleWithCloseButton";
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,
Dialog,
DialogContent,
Grid,
Typography,
styled,
} from "@mui/material";
import { Button, Grid, 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";
const TwoFactorDialog = styled(Dialog)(({ theme }) => ({
"& .MuiDialogContent-root": {
padding: theme.spacing(2, 4),
},
}));
// TODO: Revisit these comments
// const TwoFactorDialog = styled(Dialog)(({ theme }) => ({
// "& .MuiDialogContent-root": {
// padding: theme.spacing(2, 4),
// },
// }));
type Props = ModalVisibilityProps & {
closeSidebar: () => void;
};
// type TwoFactorModalProps = ModalVisibilityProps & {
// closeSidebar: () => void;
// };
function TwoFactorModal(props: Props) {
export const TwoFactorSettings: React.FC<
NestedSidebarDrawerVisibilityProps
> = ({ open, onClose, onRootClose }) => {
const [isTwoFactorEnabled, setTwoFactorStatus] = useState(false);
useEffect(() => {
@@ -39,7 +38,7 @@ function TwoFactorModal(props: Props) {
}, []);
useEffect(() => {
if (!props.open) {
if (!open) {
return;
}
const main = async () => {
@@ -51,34 +50,41 @@ function TwoFactorModal(props: Props) {
});
};
main();
}, [props.open]);
}, [open]);
const closeDialog = () => {
props.onClose();
props.closeSidebar();
const handleRootClose = () => {
onClose();
onRootClose();
};
return (
<TwoFactorDialog
maxWidth="xs"
open={props.open}
onClose={props.onClose}
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
<DialogTitleWithCloseButton onClose={props.onClose}>
{t("TWO_FACTOR_AUTHENTICATION")}
</DialogTitleWithCloseButton>
<DialogContent sx={{ px: 4 }}>
{isTwoFactorEnabled ? (
<TwoFactorModalManageSection closeDialog={closeDialog} />
) : (
<TwoFactorModalSetupSection closeDialog={closeDialog} />
)}
</DialogContent>
</TwoFactorDialog>
);
}
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={onClose}
title={t("TWO_FACTOR_AUTHENTICATION")}
onRootClose={handleRootClose}
/>
{/* {component} */}
export default TwoFactorModal;
{/* <DialogContent sx={{ px: 4 }}> */}
{isTwoFactorEnabled ? (
<TwoFactorModalManageSection
closeDialog={handleRootClose}
/>
) : (
<TwoFactorModalSetupSection closeDialog={handleRootClose} />
)}
{/* </DialogContent> */}
</Stack>
</NestedSidebarDrawer>
);
};
export default TwoFactorSettings;
interface TwoFactorModalSetupSectionProps {
closeDialog: () => void;

View File

@@ -47,7 +47,7 @@ import {
} from "@mui/material";
import Typography from "@mui/material/Typography";
import DeleteAccountModal from "components/DeleteAccountModal";
import TwoFactorModal from "components/TwoFactor/Modal";
import TwoFactorModal from "components/Sidebar/TwoFactorModal";
import { WatchFolder } from "components/WatchFolder";
import LinkButton from "components/pages/gallery/LinkButton";
import { t } from "i18next";
@@ -532,7 +532,7 @@ const UtilitySection: React.FC<UtilitySectionProps> = ({ closeSidebar }) => {
/>
<TwoFactorModal
{...twoFactorVisibilityProps}
closeSidebar={closeSidebar}
onRootClose={closeSidebar}
/>
{isElectron() && (
<WatchFolder

View File

@@ -1,4 +1,5 @@
import { Drawer, styled } from "@mui/material";
import { Drawer, styled, type DrawerProps } from "@mui/material";
import type { ModalVisibilityProps } from "../utils/modal";
/**
* A MUI {@link Drawer} with a standard set of styling that we use for our left
@@ -15,3 +16,61 @@ export const SidebarDrawer = styled(Drawer)(({ theme }) => ({
padding: theme.spacing(1),
},
}));
/**
* Common props for a {@link NestedSidebarDrawer} component. In addition to the
* regular modal visibility controls for opening and closing itself, these also
* surface an option to close the entire drawer.
*/
export type NestedSidebarDrawerVisibilityProps = ModalVisibilityProps & {
/**
* Called when the user wants to close the entire stack of drawers.
*
* Note that this does not automatically imply onClose. Each step in the
* nesting will have to chain their own onCloses to construct a new
* `onRootClose` suitable for passing to its children.
*/
onRootClose: () => void;
};
/**
* A variant of {@link SidebarDrawer} for second level, nested drawers that are
* shown atop an already visible {@link SidebarDrawer}.
*/
export const NestedSidebarDrawer: React.FC<
NestedSidebarDrawerVisibilityProps & DrawerProps
> = ({ onClose, onRootClose, ...rest }) => {
// Intercept backdrop taps and repurpose them to close the entire stack.
const handleClose: DrawerProps["onClose"] = (_, reason) => {
if (reason == "backdropClick") {
onClose();
onRootClose();
} else {
onClose();
}
};
// MUI doesn't (currently, AFAIK) have support for nested drawers, so we
// emulate that by showing a drawer atop another. To make it fit, we need to
// modify a few knobs.
return (
<SidebarDrawer
// Disable the transition (otherwise our nested drawer visibly
// slides in from the wrong direction).
transitionDuration={0}
// Make the backdrop transparent (otherwise we end up with two of
// them - one from the original drawer, and one from this nested
// one).
//
// Note that there is an easy way to hide the backdrop (using the
// `hideBackdrop` attribute), but that takes away our ability to
// intercept backdrop clicks to close it.
slotProps={{
backdrop: { sx: { "&&&": { backgroundColor: "transparent" } } },
}}
onClose={handleClose}
{...rest}
/>
);
};

View File

@@ -11,22 +11,6 @@ export interface ModalVisibilityProps {
onClose: () => void;
}
/**
* Common props for a nested drawer component. In addition to the regular modal
* visibility controls for opening and closing itself, these also surface an
* option to close the entire drawer.
*/
export type NestedDrawerVisibilityProps = ModalVisibilityProps & {
/**
* Called when the user wants to close the entire stack of drawers.
*
* Note that this does not automatically imply onClose. Each step in the
* nesting will have to chain their own onCloses to construct a new
* `onRootClose` suitable for passing to its children.
*/
onRootClose: () => void;
};
/**
* A convenience hook for keeping the state for opening and closing a modal, and
* exposing a function to close the modal whose identity is stable.

View File

@@ -1,8 +1,10 @@
import { MenuItemGroup } from "@/base/components/Menu";
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
import { SidebarDrawer } from "@/base/components/mui/SidebarDrawer";
import {
NestedSidebarDrawer,
type NestedSidebarDrawerVisibilityProps,
} from "@/base/components/mui/SidebarDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import type { NestedDrawerVisibilityProps } from "@/base/components/utils/modal";
import { disableML, enableML, type MLStatus } from "@/new/photos/services/ml";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import {
@@ -16,7 +18,6 @@ import {
Paper,
Stack,
Typography,
type DialogProps,
} from "@mui/material";
import { t } from "i18next";
import React, { useEffect, useState } from "react";
@@ -26,7 +27,7 @@ import { openURL } from "../utils/web";
import { useMLStatusSnapshot } from "./utils/ml";
import { useWrapAsyncOperation } from "./utils/use-wrap-async";
export const MLSettings: React.FC<NestedDrawerVisibilityProps> = ({
export const MLSettings: React.FC<NestedSidebarDrawerVisibilityProps> = ({
open,
onClose,
onRootClose,
@@ -39,11 +40,6 @@ export const MLSettings: React.FC<NestedDrawerVisibilityProps> = ({
onRootClose();
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason == "backdropClick") handleRootClose();
else onClose();
};
const handleEnableML = () => setOpenFaceConsent(true);
const handleConsent = useWrapAsyncOperation(async () => {
@@ -66,25 +62,20 @@ export const MLSettings: React.FC<NestedDrawerVisibilityProps> = ({
}
return (
<Box>
<SidebarDrawer
anchor="left"
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
BackdropProps={{
sx: { "&&&": { backgroundColor: "transparent" } },
}}
<>
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={onClose}
title={t("ml_search")}
onRootClose={onRootClose}
onRootClose={handleRootClose}
/>
{component}
</Stack>
</SidebarDrawer>
</NestedSidebarDrawer>
<FaceConsent
open={openFaceConsent}
@@ -92,7 +83,7 @@ export const MLSettings: React.FC<NestedDrawerVisibilityProps> = ({
onRootClose={handleRootClose}
onConsent={handleConsent}
/>
</Box>
</>
);
};
@@ -134,7 +125,7 @@ const EnableML: React.FC<EnableMLProps> = ({ onEnable }) => {
);
};
type FaceConsentProps = NestedDrawerVisibilityProps & {
type FaceConsentProps = NestedSidebarDrawerVisibilityProps & {
/** Called when the user provides their consent. */
onConsent: () => void;
};
@@ -156,11 +147,6 @@ const FaceConsent: React.FC<FaceConsentProps> = ({
onRootClose();
};
const handleDrawerClose: DialogProps["onClose"] = (_, reason) => {
if (reason == "backdropClick") handleRootClose();
else onClose();
};
const privacyPolicyLink = (
<Link
target="_blank"
@@ -174,13 +160,9 @@ const FaceConsent: React.FC<FaceConsentProps> = ({
);
return (
<SidebarDrawer
transitionDuration={0}
open={open}
onClose={handleDrawerClose}
BackdropProps={{
sx: { "&&&": { backgroundColor: "transparent" } },
}}
<NestedSidebarDrawer
{...{ open, onClose }}
onRootClose={handleRootClose}
>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
@@ -233,7 +215,7 @@ const FaceConsent: React.FC<FaceConsentProps> = ({
</Stack>
</Stack>
</Stack>
</SidebarDrawer>
</NestedSidebarDrawer>
);
};