[web] Deduplicate buttons (#3622)
And some fixes / tweaks to the recently added fav overlay.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import log from "@/base/log";
|
||||
import type { TwoFactorAuthorizationResponse } from "@/base/types/credentials";
|
||||
import { ensure } from "@/utils/ensure";
|
||||
import { nullToUndefined } from "@/utils/transform";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
import EnteButton from "@ente/shared/components/EnteButton";
|
||||
import EnteSpinner from "@ente/shared/components/EnteSpinner";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import KeyIcon from "@mui/icons-material/Key";
|
||||
@@ -366,15 +366,9 @@ const Verify: React.FC<VerifyProps> = ({ onVerify }) => {
|
||||
{t("passkey_verify_description")}
|
||||
</Typography>
|
||||
<ButtonStack>
|
||||
<EnteButton
|
||||
onClick={onVerify}
|
||||
fullWidth
|
||||
color="accent"
|
||||
type="button"
|
||||
variant="contained"
|
||||
>
|
||||
<FocusVisibleButton onClick={onVerify} fullWidth color="accent">
|
||||
{t("VERIFY")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
</ButtonStack>
|
||||
</Content>
|
||||
);
|
||||
@@ -416,25 +410,22 @@ const RetriableFailed: React.FC<RetriableFailedProps> = ({
|
||||
: t("passkey_login_generic_error")}
|
||||
</Typography>
|
||||
<ButtonStack>
|
||||
<EnteButton
|
||||
<FocusVisibleButton
|
||||
onClick={onRetry}
|
||||
fullWidth
|
||||
color="secondary"
|
||||
type="button"
|
||||
variant="contained"
|
||||
>
|
||||
{t("try_again")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
{onRecover && (
|
||||
<EnteButton
|
||||
<FocusVisibleButton
|
||||
onClick={onRecover}
|
||||
fullWidth
|
||||
color="primary"
|
||||
type="button"
|
||||
variant="text"
|
||||
>
|
||||
{t("RECOVER_TWO_FACTOR")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
)}
|
||||
</ButtonStack>
|
||||
</Content>
|
||||
@@ -504,15 +495,14 @@ const RedirectingApp: React.FC<RedirectingAppProps> = ({ onRetry }) => {
|
||||
{t("redirect_close_instructions")}
|
||||
</Typography>
|
||||
<ButtonStack>
|
||||
<EnteButton
|
||||
<FocusVisibleButton
|
||||
onClick={onRetry}
|
||||
fullWidth
|
||||
color="primary"
|
||||
type="button"
|
||||
variant="text"
|
||||
>
|
||||
{t("redirect_again")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
</ButtonStack>
|
||||
</Content>
|
||||
);
|
||||
|
||||
@@ -3,11 +3,12 @@ import {
|
||||
MenuItemGroup,
|
||||
MenuSectionTitle,
|
||||
} from "@/base/components/Menu";
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import { FlexWrapper } from "@ente/shared/components/Container";
|
||||
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
|
||||
import SubmitButton from "@ente/shared/components/SubmitButton";
|
||||
import DoneIcon from "@mui/icons-material/Done";
|
||||
import { Button, FormHelperText, Stack } from "@mui/material";
|
||||
import { FormHelperText, Stack } from "@mui/material";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Avatar from "components/pages/gallery/Avatar";
|
||||
import { Formik, type FormikHelpers } from "formik";
|
||||
@@ -204,7 +205,7 @@ export default function AddParticipantForm(props: AddParticipantFormProps) {
|
||||
>
|
||||
<Stack direction={"column"} px={"8px"} width={"100%"}>
|
||||
{props.secondaryButtonAction && (
|
||||
<Button
|
||||
<FocusVisibleButton
|
||||
onClick={props.secondaryButtonAction}
|
||||
size="large"
|
||||
color="secondary"
|
||||
@@ -219,20 +220,20 @@ export default function AddParticipantForm(props: AddParticipantFormProps) {
|
||||
{...restSubmitButtonProps}
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</FocusVisibleButton>
|
||||
)}
|
||||
|
||||
<SubmitButton
|
||||
sx={{
|
||||
"&&&": {
|
||||
mt: 2,
|
||||
...buttonSx,
|
||||
},
|
||||
}}
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
color="accent"
|
||||
fullWidth
|
||||
buttonText={props.buttonText}
|
||||
loading={loading}
|
||||
sx={{ mt: 2, mb: 4 }}
|
||||
{...restSubmitButtonProps}
|
||||
/>
|
||||
>
|
||||
{props.buttonText}
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</FlexWrapper>
|
||||
</form>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import log from "@/base/log";
|
||||
import { initiateEmail } from "@/new/photos/utils/web";
|
||||
import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
|
||||
import EnteButton from "@ente/shared/components/EnteButton";
|
||||
import { Button, Link, Stack, useMediaQuery } from "@mui/material";
|
||||
import { Link, Stack, useMediaQuery } from "@mui/material";
|
||||
import { Formik, type FormikHelpers } from "formik";
|
||||
import { t } from "i18next";
|
||||
import { AppContext } from "pages/_app";
|
||||
@@ -200,7 +201,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => {
|
||||
)}
|
||||
/>
|
||||
<Stack spacing={"8px"}>
|
||||
<EnteButton
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
size="large"
|
||||
color="critical"
|
||||
@@ -208,14 +209,14 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => {
|
||||
loading={loading}
|
||||
>
|
||||
{t("delete_account_confirm")}
|
||||
</EnteButton>
|
||||
<Button
|
||||
</LoadingButton>
|
||||
<FocusVisibleButton
|
||||
size="large"
|
||||
color={"secondary"}
|
||||
onClick={onClose}
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</FocusVisibleButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</form>
|
||||
|
||||
@@ -323,7 +323,7 @@ const PhotoFrame = ({
|
||||
}
|
||||
activeCollectionID={activeCollectionID}
|
||||
showPlaceholder={isScrolling}
|
||||
isFav={favItemIds.has(item.id)}
|
||||
isFav={favItemIds?.has(item.id)}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
CenteredFlex,
|
||||
HorizontalFlex,
|
||||
} from "@ente/shared/components/Container";
|
||||
import EnteButton from "@ente/shared/components/EnteButton";
|
||||
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
|
||||
import { downloadUsingAnchor } from "@ente/shared/utils";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
@@ -26,6 +25,7 @@ import MenuIcon from "@mui/icons-material/Menu";
|
||||
import {
|
||||
Backdrop,
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
IconButton,
|
||||
Tab,
|
||||
@@ -493,6 +493,30 @@ const ImageEditorOverlay = (props: IProps) => {
|
||||
log.error("Error saving copy to ente", e);
|
||||
}
|
||||
};
|
||||
|
||||
const applyCrop = () => {
|
||||
if (!cropBoxRef.current || !canvasRef.current) return;
|
||||
|
||||
const { x1, x2, y1, y2 } = getCropRegionArgs(
|
||||
cropBoxRef.current,
|
||||
canvasRef.current,
|
||||
);
|
||||
setCanvasLoading(true);
|
||||
setTransformationPerformed(true);
|
||||
cropRegionOfCanvas(canvasRef.current, x1, y1, x2, y2);
|
||||
cropRegionOfCanvas(
|
||||
originalSizeCanvasRef.current,
|
||||
x1 / previewCanvasScale,
|
||||
y1 / previewCanvasScale,
|
||||
x2 / previewCanvasScale,
|
||||
y2 / previewCanvasScale,
|
||||
);
|
||||
resetCropBox();
|
||||
setCanvasLoading(false);
|
||||
|
||||
setCurrentTab("transform");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Backdrop
|
||||
@@ -540,7 +564,7 @@ const ImageEditorOverlay = (props: IProps) => {
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
height="90%"
|
||||
height="88%"
|
||||
width="100%"
|
||||
ref={parentRef}
|
||||
display="flex"
|
||||
@@ -580,45 +604,13 @@ const ImageEditorOverlay = (props: IProps) => {
|
||||
</Box>
|
||||
{currentTab === "crop" && (
|
||||
<CenteredFlex marginTop="1rem">
|
||||
<EnteButton
|
||||
<Button
|
||||
color="accent"
|
||||
startIcon={<CropIcon />}
|
||||
onClick={() => {
|
||||
if (
|
||||
!cropBoxRef.current ||
|
||||
!canvasRef.current
|
||||
)
|
||||
return;
|
||||
|
||||
const { x1, x2, y1, y2 } =
|
||||
getCropRegionArgs(
|
||||
cropBoxRef.current,
|
||||
canvasRef.current,
|
||||
);
|
||||
setCanvasLoading(true);
|
||||
setTransformationPerformed(true);
|
||||
cropRegionOfCanvas(
|
||||
canvasRef.current,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
);
|
||||
cropRegionOfCanvas(
|
||||
originalSizeCanvasRef.current,
|
||||
x1 / previewCanvasScale,
|
||||
y1 / previewCanvasScale,
|
||||
x2 / previewCanvasScale,
|
||||
y2 / previewCanvasScale,
|
||||
);
|
||||
resetCropBox();
|
||||
setCanvasLoading(false);
|
||||
|
||||
setCurrentTab("transform");
|
||||
}}
|
||||
onClick={applyCrop}
|
||||
>
|
||||
{t("APPLY_CROP")}
|
||||
</EnteButton>
|
||||
</Button>
|
||||
</CenteredFlex>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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 { FocusVisibleButton } from "@/new/photos/components/mui/FocusVisibleButton";
|
||||
import DialogTitleWithCloseButton, {
|
||||
dialogCloseHandler,
|
||||
} from "@ente/shared/components/DialogBox/TitleWithCloseButton";
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Overlay } from "@ente/shared/components/Container";
|
||||
import { CustomError } from "@ente/shared/error";
|
||||
import useLongPress from "@ente/shared/hooks/useLongPress";
|
||||
import AlbumOutlined from "@mui/icons-material/AlbumOutlined";
|
||||
import Favorite from "@mui/icons-material/FavoriteRounded";
|
||||
import PlayCircleOutlineOutlinedIcon from "@mui/icons-material/PlayCircleOutlineOutlined";
|
||||
import { Tooltip, styled } from "@mui/material";
|
||||
import i18n from "i18next";
|
||||
@@ -23,7 +24,6 @@ import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { TRASH_SECTION } from "utils/collection";
|
||||
import { shouldShowAvatar } from "utils/file";
|
||||
import Avatar from "./Avatar";
|
||||
import Favorite from "@mui/icons-material/FavoriteRounded";
|
||||
|
||||
interface IProps {
|
||||
file: EnteFile;
|
||||
@@ -129,6 +129,7 @@ export const FavOverlay = styled(Overlay)`
|
||||
align-items: flex-end;
|
||||
padding-left: 5px;
|
||||
padding-bottom: 5px;
|
||||
opacity: 0.9;
|
||||
`;
|
||||
|
||||
export const InSelectRangeOverLay = styled("div")<{ $active: boolean }>`
|
||||
@@ -363,7 +364,7 @@ export default function PreviewCard(props: IProps) {
|
||||
)}
|
||||
{props.isFav && (
|
||||
<FavOverlay>
|
||||
<Favorite/>
|
||||
<Favorite />
|
||||
</FavOverlay>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isWeakPassword } from "@/accounts/utils";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
|
||||
import SubmitButton from "@ente/shared/components/SubmitButton";
|
||||
import { Box, Input, TextField, Typography } from "@mui/material";
|
||||
import { Formik } from "formik";
|
||||
import { t } from "i18next";
|
||||
@@ -137,12 +137,15 @@ function SetPasswordForm(props: SetPasswordFormProps) {
|
||||
</Typography>
|
||||
|
||||
<Box my={4}>
|
||||
<SubmitButton
|
||||
sx={{ my: 0 }}
|
||||
<LoadingButton
|
||||
fullWidth
|
||||
color="accent"
|
||||
type="submit"
|
||||
loading={loading}
|
||||
buttonText={props.buttonText}
|
||||
disabled={isWeakPassword(values.passphrase)}
|
||||
/>
|
||||
>
|
||||
{props.buttonText}
|
||||
</LoadingButton>
|
||||
{loading && (
|
||||
<Typography
|
||||
textAlign="center"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PasswordStrengthHint } from "@/accounts/components/PasswordStrength";
|
||||
import { PAGES } from "@/accounts/constants/pages";
|
||||
import { isWeakPassword } from "@/accounts/utils";
|
||||
import { generateKeyAndSRPAttributes } from "@/accounts/utils/srp";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import log from "@/base/log";
|
||||
import { LS_KEYS, setLSUser } from "@ente/shared//storage/localStorage";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
@@ -10,7 +11,6 @@ import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
|
||||
import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title";
|
||||
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
|
||||
import LinkButton from "@ente/shared/components/LinkButton";
|
||||
import SubmitButton from "@ente/shared/components/SubmitButton";
|
||||
import {
|
||||
generateAndSaveIntermediateKeyAttributes,
|
||||
saveKeyInSessionStore,
|
||||
@@ -289,15 +289,18 @@ export const SignUp: React.FC<SignUpProps> = ({ router, login, host }) => {
|
||||
</FormGroup>
|
||||
</VerticallyCentered>
|
||||
<Box mb={4}>
|
||||
<SubmitButton
|
||||
sx={{ my: 0 }}
|
||||
buttonText={t("CREATE_ACCOUNT")}
|
||||
<LoadingButton
|
||||
fullWidth
|
||||
color="accent"
|
||||
type="submit"
|
||||
loading={loading}
|
||||
disabled={
|
||||
!acceptTerms ||
|
||||
isWeakPassword(values.passphrase)
|
||||
}
|
||||
/>
|
||||
>
|
||||
{t("CREATE_ACCOUNT")}
|
||||
</LoadingButton>
|
||||
{loading && (
|
||||
<Typography
|
||||
mt={1}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import InvalidInputMessage from "@/accounts/components/two-factor/InvalidInputMessage";
|
||||
import { wait } from "@/utils/promise";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import {
|
||||
CenteredFlex,
|
||||
VerticallyCentered,
|
||||
} from "@ente/shared/components/Container";
|
||||
import SubmitButton from "@ente/shared/components/SubmitButton";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Formik, type FormikHelpers } from "formik";
|
||||
import { t } from "i18next";
|
||||
@@ -27,12 +26,9 @@ export type VerifyTwoFactorCallback = (
|
||||
export default function VerifyTwoFactor(props: Props) {
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const otpInputRef = useRef<OtpInput>(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const markSuccessful = async () => {
|
||||
setWaiting(false);
|
||||
setSuccess(true);
|
||||
await wait(1000);
|
||||
};
|
||||
|
||||
const submitForm = async (
|
||||
@@ -95,12 +91,16 @@ export default function VerifyTwoFactor(props: Props) {
|
||||
</CenteredFlex>
|
||||
)}
|
||||
</Box>
|
||||
<SubmitButton
|
||||
buttonText={props.buttonText}
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
color="accent"
|
||||
fullWidth
|
||||
sx={{ my: 4 }}
|
||||
loading={waiting}
|
||||
success={success}
|
||||
disabled={values.otp.length < 6}
|
||||
/>
|
||||
>
|
||||
{props.buttonText}
|
||||
</LoadingButton>
|
||||
</form>
|
||||
</VerticallyCentered>
|
||||
)}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { changeEmail, sendOTTForEmailChange } from "@/accounts/api/user";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import { ensure } from "@/utils/ensure";
|
||||
import { wait } from "@/utils/promise";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
import FormPaper from "@ente/shared/components/Form/FormPaper";
|
||||
import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
|
||||
import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title";
|
||||
import LinkButton from "@ente/shared/components/LinkButton";
|
||||
import SubmitButton from "@ente/shared/components/SubmitButton";
|
||||
import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
|
||||
import { Alert, Box, TextField } from "@mui/material";
|
||||
import { Formik, type FormikHelpers } from "formik";
|
||||
@@ -50,7 +49,6 @@ const ChangeEmailForm: React.FC = () => {
|
||||
const [ottInputVisible, setShowOttInputVisibility] = useState(false);
|
||||
const [email, setEmail] = useState<string | null>(null);
|
||||
const [showMessage, setShowMessage] = useState(false);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -84,8 +82,6 @@ const ChangeEmailForm: React.FC = () => {
|
||||
await changeEmail(email, ensure(ott));
|
||||
await setLSUser({ ...getData(LS_KEYS.USER), email });
|
||||
setLoading(false);
|
||||
setSuccess(true);
|
||||
await wait(1000);
|
||||
goToApp();
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
@@ -165,16 +161,15 @@ const ChangeEmailForm: React.FC = () => {
|
||||
disabled={loading}
|
||||
/>
|
||||
)}
|
||||
<SubmitButton
|
||||
success={success}
|
||||
sx={{ mt: 2 }}
|
||||
<LoadingButton
|
||||
fullWidth
|
||||
color="accent"
|
||||
type="submit"
|
||||
sx={{ mt: 2, mb: 4 }}
|
||||
loading={loading}
|
||||
buttonText={
|
||||
!ottInputVisible
|
||||
? t("SEND_OTT")
|
||||
: t("VERIFY")
|
||||
}
|
||||
/>
|
||||
>
|
||||
{!ottInputVisible ? t("SEND_OTT") : t("VERIFY")}
|
||||
</LoadingButton>
|
||||
</VerticallyCentered>
|
||||
</form>
|
||||
|
||||
|
||||
38
web/packages/base/components/mui/LoadingButton.tsx
Normal file
38
web/packages/base/components/mui/LoadingButton.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { CircularProgress, type ButtonProps } from "@mui/material";
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* A button that shows a indeterminate progress indicator if the {@link loading}
|
||||
* prop is set.
|
||||
*
|
||||
* The button is also disabled when in the loading state.
|
||||
*/
|
||||
export const LoadingButton: React.FC<ButtonProps & { loading?: boolean }> = ({
|
||||
loading,
|
||||
disabled,
|
||||
color,
|
||||
sx,
|
||||
children,
|
||||
...rest
|
||||
}) =>
|
||||
loading ? (
|
||||
<FocusVisibleButton
|
||||
{...{ color }}
|
||||
disabled
|
||||
sx={{
|
||||
"&.Mui-disabled": {
|
||||
backgroundColor: `${color}.main`,
|
||||
color: `${color}.contrastText`,
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<CircularProgress size={20} />
|
||||
</FocusVisibleButton>
|
||||
) : (
|
||||
<FocusVisibleButton {...{ color, disabled, sx }} {...rest}>
|
||||
{children}
|
||||
</FocusVisibleButton>
|
||||
);
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import type { CollectionMapping } from "@/base/types/ipc";
|
||||
import FolderIcon from "@mui/icons-material/Folder";
|
||||
import FolderCopyIcon from "@mui/icons-material/FolderCopy";
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
DialogCloseIconButton,
|
||||
type DialogVisibilityProps,
|
||||
} from "./mui/Dialog";
|
||||
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
|
||||
|
||||
type CollectionMappingChoiceModalProps = DialogVisibilityProps & {
|
||||
didSelect: (mapping: CollectionMapping) => void;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { useIsMobileWidth } from "@/base/hooks";
|
||||
import { ensureOk } from "@/base/http";
|
||||
import { getKVS, removeKV, setKV } from "@/base/kv";
|
||||
@@ -18,7 +19,6 @@ import { useFormik } from "formik";
|
||||
import { t } from "i18next";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
|
||||
import { SlideUpTransition } from "./mui/SlideUpTransition";
|
||||
|
||||
interface DevSettingsProps {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import log from "@/base/log";
|
||||
import { wait } from "@/utils/promise";
|
||||
import {
|
||||
@@ -12,8 +14,6 @@ import { useFormik } from "formik";
|
||||
import { t } from "i18next";
|
||||
import React from "react";
|
||||
import type { DialogVisibilityProps } from "./mui/Dialog";
|
||||
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "./mui/LoadingButton";
|
||||
|
||||
type SingleInputFormProps = Pick<
|
||||
TextFieldProps,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { ensureElectron } from "@/base/electron";
|
||||
import { useIsMobileWidth } from "@/base/hooks";
|
||||
import { ut } from "@/base/i18n";
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
} from "@mui/material";
|
||||
import React, { useEffect } from "react";
|
||||
import { didShowWhatsNew } from "../services/changelog";
|
||||
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
|
||||
import { SlideUpTransition } from "./mui/SlideUpTransition";
|
||||
|
||||
interface WhatsNewProps {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { CircularProgress, type ButtonProps } from "@mui/material";
|
||||
import React from "react";
|
||||
import { FocusVisibleButton } from "./FocusVisibleButton";
|
||||
|
||||
/**
|
||||
* A button that shows a indeterminate progress indicator if the {@link loading}
|
||||
* prop is set.
|
||||
*
|
||||
* The button is also disabled when in the loading state.
|
||||
*
|
||||
* TODO: This duplicates the existing SubmitButton and EnteButton. Merge these
|
||||
* three gradually (didn't want to break existing layouts, so will do it
|
||||
* piecewise).
|
||||
*/
|
||||
export const LoadingButton: React.FC<ButtonProps & { loading?: boolean }> = ({
|
||||
loading,
|
||||
disabled,
|
||||
color,
|
||||
sx,
|
||||
children,
|
||||
...rest
|
||||
}) => (
|
||||
<FocusVisibleButton
|
||||
{...{ color }}
|
||||
disabled={loading ?? disabled}
|
||||
sx={{
|
||||
"&.Mui-disabled": {
|
||||
backgroundColor: `${color}.main`,
|
||||
color: `${color}.contrastText`,
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{loading ? <CircularProgress size={20} /> : children}
|
||||
</FocusVisibleButton>
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FocusVisibleButton } from "@/new/photos/components/mui/FocusVisibleButton";
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import {
|
||||
Breakpoint,
|
||||
DialogActions,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import { dialogCloseHandler } from "@ente/shared/components/DialogBox/TitleWithCloseButton";
|
||||
import EnteButton from "@ente/shared/components/EnteButton";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
Stack,
|
||||
Typography,
|
||||
@@ -91,7 +91,7 @@ export default function DialogBoxV2({
|
||||
flex={1}
|
||||
>
|
||||
{attributes.proceed && (
|
||||
<EnteButton
|
||||
<LoadingButton
|
||||
loading={loading}
|
||||
size="large"
|
||||
color={attributes.proceed?.variant}
|
||||
@@ -105,10 +105,10 @@ export default function DialogBoxV2({
|
||||
disabled={attributes.proceed.disabled}
|
||||
>
|
||||
{attributes.proceed.text}
|
||||
</EnteButton>
|
||||
</LoadingButton>
|
||||
)}
|
||||
{attributes.close && (
|
||||
<Button
|
||||
<FocusVisibleButton
|
||||
size="large"
|
||||
color={attributes.close?.variant ?? "secondary"}
|
||||
onClick={() => {
|
||||
@@ -118,11 +118,11 @@ export default function DialogBoxV2({
|
||||
}}
|
||||
>
|
||||
{attributes.close?.text ?? t("ok")}
|
||||
</Button>
|
||||
</FocusVisibleButton>
|
||||
)}
|
||||
{attributes.buttons &&
|
||||
attributes.buttons.map((b) => (
|
||||
<Button
|
||||
<FocusVisibleButton
|
||||
size="large"
|
||||
key={b.text}
|
||||
color={b.variant}
|
||||
@@ -133,7 +133,7 @@ export default function DialogBoxV2({
|
||||
disabled={b.disabled}
|
||||
>
|
||||
{b.text}
|
||||
</Button>
|
||||
</FocusVisibleButton>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { ensure } from "@/utils/ensure";
|
||||
import Done from "@mui/icons-material/Done";
|
||||
import { Button, CircularProgress, type ButtonProps } from "@mui/material";
|
||||
|
||||
interface Iprops extends ButtonProps {
|
||||
loading?: boolean;
|
||||
success?: boolean;
|
||||
}
|
||||
|
||||
export default function EnteButton({
|
||||
children,
|
||||
loading,
|
||||
success,
|
||||
disabled,
|
||||
sx,
|
||||
...props
|
||||
}: Iprops) {
|
||||
return (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
sx={{
|
||||
...sx,
|
||||
...((loading || success) && {
|
||||
"&.Mui-disabled": (theme) => ({
|
||||
// TODO: Refactor to not need this ensure.
|
||||
backgroundColor:
|
||||
theme.palette[ensure(props.color)].main,
|
||||
color: theme.palette[ensure(props.color)].contrastText,
|
||||
}),
|
||||
}),
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{loading ? (
|
||||
<CircularProgress size={20} sx={{ color: "inherit" }} />
|
||||
) : success ? (
|
||||
<Done sx={{ fontSize: 20 }} />
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -3,9 +3,9 @@ import {
|
||||
passkeySessionExpiredErrorMessage,
|
||||
saveCredentialsAndNavigateTo,
|
||||
} from "@/accounts/services/passkey";
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import log from "@/base/log";
|
||||
import { customAPIHost } from "@/base/origins";
|
||||
import EnteButton from "@ente/shared/components/EnteButton";
|
||||
import { CircularProgress, Stack, Typography, styled } from "@mui/material";
|
||||
import { t } from "i18next";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -140,23 +140,21 @@ export const VerifyingPasskey: React.FC<VerifyingPasskeyProps> = ({
|
||||
</VerifyingPasskeyStatus>
|
||||
|
||||
<ButtonStack>
|
||||
<EnteButton
|
||||
<FocusVisibleButton
|
||||
onClick={handleRetry}
|
||||
fullWidth
|
||||
color="secondary"
|
||||
type="button"
|
||||
>
|
||||
{t("try_again")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
|
||||
<EnteButton
|
||||
<FocusVisibleButton
|
||||
onClick={handleCheckStatus}
|
||||
fullWidth
|
||||
color="accent"
|
||||
type="button"
|
||||
>
|
||||
{t("check_status")}
|
||||
</EnteButton>
|
||||
</FocusVisibleButton>
|
||||
</ButtonStack>
|
||||
</VerifyingPasskeyMiddle>
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
import { FlexWrapper } from "@ente/shared/components/Container";
|
||||
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
|
||||
import { Button, FormHelperText } from "@mui/material";
|
||||
import { FormHelperText } from "@mui/material";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { Formik, type FormikHelpers, type FormikState } from "formik";
|
||||
import { t } from "i18next";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import SubmitButton from "./SubmitButton";
|
||||
|
||||
interface formValues {
|
||||
inputValue: string;
|
||||
@@ -170,7 +171,7 @@ export default function SingleInputForm(props: SingleInputFormProps) {
|
||||
flexWrap={props.blockButton ? "wrap-reverse" : "nowrap"}
|
||||
>
|
||||
{props.secondaryButtonAction && (
|
||||
<Button
|
||||
<FocusVisibleButton
|
||||
onClick={props.secondaryButtonAction}
|
||||
size="large"
|
||||
color="secondary"
|
||||
@@ -185,19 +186,24 @@ export default function SingleInputForm(props: SingleInputFormProps) {
|
||||
{...restSubmitButtonProps}
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</FocusVisibleButton>
|
||||
)}
|
||||
<SubmitButton
|
||||
<LoadingButton
|
||||
sx={{
|
||||
"&&&": {
|
||||
mt: 2,
|
||||
...buttonSx,
|
||||
},
|
||||
}}
|
||||
buttonText={props.buttonText}
|
||||
size="large"
|
||||
variant="contained"
|
||||
color="accent"
|
||||
type="submit"
|
||||
loading={loading}
|
||||
{...restSubmitButtonProps}
|
||||
/>
|
||||
>
|
||||
{props.buttonText}
|
||||
</LoadingButton>
|
||||
</FlexWrapper>
|
||||
</form>
|
||||
)}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import Done from "@mui/icons-material/Done";
|
||||
import { Button, CircularProgress, type ButtonProps } from "@mui/material";
|
||||
import React from "react";
|
||||
|
||||
export interface SubmitButtonProps {
|
||||
loading: boolean;
|
||||
buttonText: string;
|
||||
|
||||
disabled?: boolean;
|
||||
success?: boolean;
|
||||
}
|
||||
const SubmitButton: React.FC<ButtonProps<"button", SubmitButtonProps>> = ({
|
||||
loading,
|
||||
buttonText,
|
||||
disabled,
|
||||
success,
|
||||
sx,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
size="large"
|
||||
variant="contained"
|
||||
color="accent"
|
||||
type="submit"
|
||||
disabled={disabled || loading || success}
|
||||
sx={{
|
||||
my: 4,
|
||||
...(loading
|
||||
? {
|
||||
"&.Mui-disabled": {
|
||||
backgroundColor: (theme) =>
|
||||
theme.colors.accent.A500,
|
||||
color: (theme) => theme.colors.text.base,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...sx,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{loading ? (
|
||||
<CircularProgress size={20} />
|
||||
) : success ? (
|
||||
<Done sx={{ fontSize: 20 }} />
|
||||
) : (
|
||||
buttonText
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubmitButton;
|
||||
Reference in New Issue
Block a user