new crop-modal

This commit is contained in:
Tamara 2024-06-08 03:02:53 +03:00
parent 19e7dab62c
commit c979280d45
11 changed files with 545 additions and 170 deletions

@ -5,7 +5,7 @@ import {
uploadQuestionImage, uploadQuestionImage,
} from "@root/questions/actions"; } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal/CropModal";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon";
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg"; import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";

@ -4,7 +4,7 @@ import {
uploadQuestionImage, uploadQuestionImage,
} from "@root/questions/actions"; } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal/CropModal";
import { useState } from "react"; import { useState } from "react";
import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon";
import type { QuizQuestionImages } from "../../../model/questionTypes/images"; import type { QuizQuestionImages } from "../../../model/questionTypes/images";

@ -10,7 +10,7 @@ import {
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal/CropModal";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { useState } from "react"; import { useState } from "react";
import { UploadImageModal } from "../../pages/Questions/UploadImage/UploadImageModal"; import { UploadImageModal } from "../../pages/Questions/UploadImage/UploadImageModal";

@ -9,7 +9,7 @@ import {
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { updateQuestion, uploadQuestionImage } from "@root/questions/actions"; import { updateQuestion, uploadQuestionImage } from "@root/questions/actions";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal/CropModal";
import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton"; import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton";
import { UploadImageModal } from "../pages/Questions/UploadImage/UploadImageModal"; import { UploadImageModal } from "../pages/Questions/UploadImage/UploadImageModal";

@ -1,14 +1,8 @@
import { devlog } from "@frontend/kitui"; import { devlog } from "@frontend/kitui";
import { ResetIcon } from "@icons/ResetIcon";
import DeleteIcon from "@mui/icons-material/Delete";
import { import {
Box, Box,
Button, Button,
IconButton,
Modal, Modal,
Slider,
SxProps,
Theme,
Typography, Typography,
useMediaQuery, useMediaQuery,
useTheme, useTheme,
@ -22,35 +16,17 @@ import ReactCrop, {
makeAspectCrop, makeAspectCrop,
} from "react-image-crop"; } from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css"; import "react-image-crop/dist/ReactCrop.css";
import { isImageBlobAGifFile } from "../../utils/isImageBlobAGifFile"; import { isImageBlobAGifFile } from "@utils/isImageBlobAGifFile";
import { import {
getModifiedImageBlob, getModifiedImageBlob,
getRotatedImageBlob, getRotatedImageBlob,
} from "./utils/imageManipulation"; } from "../utils/imageManipulation";
import DevaceMobileIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceMobileIcon";
const styleSlider: SxProps<Theme> = { import BackArrowIcon from "@icons/BackArrowIcon";
color: "#7E2AEA", import DevaceDesktopIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceDesktopIcon";
height: "12px", import DevaceTabletIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceTabletIcon";
"& .MuiSlider-track": { import DevaceSmallIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceSmallIcon";
border: "none", import SwitchCaseCrop from "@ui_kit/Modal/CropModal/SwitchCaseCrop";
},
"& .MuiSlider-rail": {
backgroundColor: "#F2F3F7",
border: `1px solid #9A9AAF`,
},
"& .MuiSlider-thumb": {
height: 26,
width: 26,
border: `6px solid #7E2AEA`,
backgroundColor: "white",
boxShadow: `0px 0px 0px 3px white,
0px 4px 4px 3px #C3C8DD`,
"&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
boxShadow: `0px 0px 0px 3px white,
0px 4px 4px 3px #C3C8DD`,
},
},
};
interface Props { interface Props {
isOpen: boolean; isOpen: boolean;
@ -65,6 +41,7 @@ interface Props {
height: number; height: number;
}; };
} }
const stepsScreen: string[] = ["desktop", "tablet", "mobile", "small"]
export const CropModal: FC<Props> = ({ export const CropModal: FC<Props> = ({
isOpen, isOpen,
@ -80,11 +57,44 @@ export const CropModal: FC<Props> = ({
const [percentCrop, setPercentCrop] = useState<PercentCrop | undefined>( const [percentCrop, setPercentCrop] = useState<PercentCrop | undefined>(
undefined, undefined,
); );
const [darken, setDarken] = useState(0); const [darken, setDarken] = useState(0);
const [imageWidth, setImageWidth] = useState<number | null>(null); const [imageWidth, setImageWidth] = useState<number | null>(null);
const [imageHeight, setImageHeight] = useState<number | null>(null); const [imageHeight, setImageHeight] = useState<number | null>(null);
const [modalStep, setModalStep] = useState<string>(stepsScreen[0]);
const [lastStep, setLastStep] = useState<boolean>(null)
const cropImageElementRef = useRef<HTMLImageElement>(null); const cropImageElementRef = useRef<HTMLImageElement>(null);
const isMobile = useMediaQuery(theme.breakpoints.down(786)); const isMobile = useMediaQuery(theme.breakpoints.down(786));
let stepIndex = stepsScreen.indexOf(modalStep)
const modalTitle = {
"desktop": {name: "Десктоп", icon: <DevaceDesktopIcon/>},
"tablet": {name:"Планшет", icon: <DevaceTabletIcon/>},
"mobile": {name:"Телефон", icon: <DevaceMobileIcon/>},
"small": {name:"Самые узкие экраны", icon: <DevaceSmallIcon/>}
}
const handleNextStep = () => {
if (stepIndex === stepsScreen.length - 1) {
onClose()
return
}
if (stepIndex === stepsScreen.length - 2) {
setLastStep(true)
}
let nextStepIndex = stepIndex + 1
setModalStep(stepsScreen[nextStepIndex]);
};
const handlePrevStep = () => {
if (stepIndex === 0) return
if (stepIndex === stepsScreen.length - 1) {
setLastStep(false)
}
let nextStepIndex = stepIndex - 1
setModalStep(stepsScreen[nextStepIndex]);
};
const imageUrl = useMemo( const imageUrl = useMemo(
() => imageBlob && URL.createObjectURL(imageBlob), () => imageBlob && URL.createObjectURL(imageBlob),
@ -196,7 +206,6 @@ export const CropModal: FC<Props> = ({
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
bgcolor: "background.paper", bgcolor: "background.paper",
boxShadow: 24, boxShadow: 24,
padding: "20px",
borderRadius: "8px", borderRadius: "8px",
width: isMobile ? "343px" : "620px", width: isMobile ? "343px" : "620px",
height: isMobile ? "80vh" : undefined, height: isMobile ? "80vh" : undefined,
@ -208,131 +217,36 @@ export const CropModal: FC<Props> = ({
> >
<Box <Box
sx={{ sx={{
height: "320px", height: isMobile ? "91px" : "70px",
backgroundSize: "cover", backgroundColor: "#F2F3F7",
backgroundRepeat: "no-repeat", padding: "20px",
display: "flex", borderRadius: "8px 8px 0px 0px",
alignItems: "center",
justifyContent: "center",
}} }}
> >
{imageUrl && ( <Typography sx={{ color: "#9A9AAF", fontSize: "18px" }}>
<ReactCrop Настройте вариант отображения картинки на разных девайсах
crop={percentCrop}
onChange={(_, percentCrop) => setPercentCrop(percentCrop)}
minWidth={5}
minHeight={5}
locked
aspect={
cropAspectRatio
? cropAspectRatio.width / cropAspectRatio.height
: undefined
}
>
<img
onLoad={(e) => {
setImageWidth(e.currentTarget.naturalWidth);
setImageHeight(e.currentTarget.naturalHeight);
if (cropImageElementRef.current) {
setPercentCrop(
getInitialCrop(
cropImageElementRef.current.width,
cropImageElementRef.current.height,
cropAspectRatio
? cropAspectRatio.width / cropAspectRatio.height
: 1,
),
);
}
}}
ref={cropImageElementRef}
alt="Crop me"
src={imageUrl}
style={{
filter: `brightness(${100 - darken}%)`,
maxWidth: "100%",
maxHeight: "320px",
display: "block",
objectFit: "contain",
}}
/>
</ReactCrop>
)}
</Box>
<Box
sx={{
mt: "40px",
display: isMobile ? "block" : "flex",
alignItems: "end",
justifyContent: "space-between",
}}
>
<IconButton onClick={handleRotateClick}>
<ResetIcon />
</IconButton>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
Размер
</Typography> </Typography>
<Slider </Box>
sx={[ <SwitchCaseCrop
styleSlider, imageUrl={imageUrl}
{ handleSizeChange={handleSizeChange}
width: isMobile ? undefined : "200px", handleRotateClick={handleRotateClick}
}, getInitialCrop={getInitialCrop}
]} cropAspectRatio={cropAspectRatio}
value={percentCrop?.width ?? 1} onDeleteClick={onDeleteClick}
min={1} onClose={onClose}
max={100} modalProps={modalTitle}
step={0.1} modalStep={modalStep}
onChange={(_, newValue) => { stepIndex={stepIndex}
if (typeof newValue === "number") handleSizeChange(newValue); cropImageElementRef={cropImageElementRef}
}}
/> />
</Box>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
Затемнение
</Typography>
<Slider
sx={[
styleSlider,
{
width: isMobile ? undefined : "200px",
},
]}
value={darken}
min={0}
max={100}
step={1}
onChange={(_, newValue) => setDarken(newValue as number)}
/>
</Box>
{onDeleteClick && (
<IconButton
onClick={() => {
onDeleteClick?.();
onClose();
}}
sx={{
height: "48px",
width: "48px",
p: 0,
color: theme.palette.orange.main,
borderRadius: "50%",
}}
>
<DeleteIcon />
</IconButton>
)}
</Box>
<Box <Box
sx={{ sx={{
marginTop: "40px", marginTop: "40px",
padding: "0 20px 20px",
width: "100%", width: "100%",
display: "flex", display: "flex",
gap: "10px", gap: "5px",
flexWrap: isMobile ? "wrap" : undefined, flexWrap: isMobile ? "wrap" : undefined,
}} }}
> >
@ -345,26 +259,60 @@ export const CropModal: FC<Props> = ({
borderRadius: "8px", borderRadius: "8px",
border: "1px solid #7E2AEA", border: "1px solid #7E2AEA",
px: "20px", px: "20px",
width: isMobile ? "100%" : undefined,
}} }}
> >
Сохранить оригинал Сохранить оригинал
</Button> </Button>
<Box
sx={{
display: "flex",
gap: "5px",
ml: "auto",
}}
>
<Button <Button
onClick={handleSaveModifiedImage} onClick={()=> handlePrevStep()}
variant="contained"
sx={{
fontSize: "16px",
padding: "10px 15px",
color: "#FFFFFF",
border: "1px solid #9A9AAF",
background: "#FFFFFF",
"&:hover": {
color: "#FFFFFF",
border: `1px solid ${theme.palette.primary.dark}`,
},
}}
>
<BackArrowIcon color={"#7E2AEA"}/>
</Button>
<Button
onClick={() => {
handleNextStep()
// handleSaveModifiedImage()
}
}
disableRipple disableRipple
variant="contained" variant="contained"
sx={{ sx={{
height: "48px", height: "48px",
borderRadius: "8px", borderRadius: "8px",
border: "1px solid #7E2AEA", border: "1px solid #7E2AEA",
marginRight: "10px", p: "10px 15px",
px: "20px", width: isMobile ? "100%" : undefined,
ml: "auto", // ml: "auto",
}} }}
> >
Сохранить редактированное {lastStep ?
"Сохранить редактированное" : "Далее"
}
</Button> </Button>
</Box> </Box>
</Box>
</Box> </Box>
</Modal> </Modal>
); );

@ -0,0 +1,24 @@
import {Box} from "@mui/material";
export default function DevaceDesktopIcon() {
return (
<Box
sx={{
height: "36px",
width: "36px",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "6px",
backgroundColor: "#EEE4FC"
}}
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="17" width="20" height="3" rx="1" stroke="#7E2AEA" strokeWidth="1.5"/>
<rect x="3" y="5" width="18" height="12" rx="1" stroke="#7E2AEA" strokeWidth="1.5"/>
<path d="M14 5.5L10 5.5" stroke="#7E2AEA" strokeWidth="2.5" strokeLinecap="round"/>
</svg>
</Box>
);
}

@ -0,0 +1,23 @@
import {Box} from "@mui/material";
export default function DevaceMobileIcon() {
return (
<Box
sx={{
height: "36px",
width: "36px",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "6px",
backgroundColor: "#EEE4FC"
}}
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="6" y="2" width="12" height="20" rx="3" stroke="#7E2AEA" strokeWidth="1.5"/>
<path d="M14 2.5L10 2.5" stroke="#7E2AEA" strokeWidth="2.5" strokeLinecap="round"/>
</svg>
</Box>
);
}

@ -0,0 +1,23 @@
import {Box} from "@mui/material";
export default function DevaceSmallIcon() {
return (
<Box
sx={{
height: "36px",
width: "36px",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "6px",
backgroundColor: "#EEE4FC"
}}
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="7.5" y="2" width="9" height="20" rx="3" stroke="#7E2AEA" strokeWidth="1.5"/>
<path d="M13.5 2.5L10.5 2.5" stroke="#7E2AEA" strokeWidth="2.5" strokeLinecap="round"/>
</svg>
</Box>
);
}

@ -0,0 +1,24 @@
import {Box} from "@mui/material";
export default function DevaceTabletIcon() {
return (
<Box
sx={{
height: "36px",
width: "36px",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "6px",
backgroundColor: "#EEE4FC"
}}
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5 19.5V4.5C19.5 3.67157 18.8284 3 18 3L6 3C5.17157 3 4.5 3.67157 4.5 4.5L4.5 19.5C4.5 20.3284 5.17157 21 6 21H18C18.8284 21 19.5 20.3284 19.5 19.5Z" stroke="#7E2AEA" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M14 4L10 4" stroke="#7E2AEA" strokeWidth="2.5" strokeLinecap="round"/>
<path d="M4.5 18H19.5" stroke="#7E2AEA" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</Box>
);
}

@ -0,0 +1,116 @@
import CropGeneral from "@ui_kit/Modal/CropModal/cropGeneral";
import DevaceDesktopIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceDesktopIcon";
import DevaceTabletIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceTabletIcon";
import DevaceMobileIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceMobileIcon";
import DevaceSmallIcon from "@ui_kit/Modal/CropModal/IconCropModal/DevaceSmallIcon";
import {PercentCrop} from "react-image-crop";
import {MutableRefObject} from "react";
const modalProps = {
"desktop": {name: "Десктоп", icon: <DevaceDesktopIcon/>},
"tablet": {name:"Планшет", icon: <DevaceTabletIcon/>},
"mobile": {name:"Телефон", icon: <DevaceMobileIcon/>},
"small": {name:"Самые узкие экраны", icon: <DevaceSmallIcon/>}
}
interface Props{
imageUrl: null | string;
handleSizeChange: (a: number)=> void;
handleRotateClick: Promise<void>;
getInitialCrop: (imageWidth: number, imageHeight: number, aspectRatio: number)=> PercentCrop;
modalProps: {string:{}};
modalStep: string;
stepIndex: number;
onClose: () => void;
cropImageElementRef: MutableRefObject<HTMLImageElement>;
onDeleteClick?: () => void;
cropAspectRatio?: {
width: number;
height: number;
};
}
export default function SwitchCaseCrop ({imageUrl,
cropAspectRatio,
handleSizeChange,
handleRotateClick,
getInitialCrop,
onDeleteClick,
onClose,
modalStep,
stepIndex,
cropImageElementRef}: Props) {
switch (modalStep) {
case "desktop": {
return(
<>
<CropGeneral
imageUrl={imageUrl}
handleSizeChange={handleSizeChange}
handleRotateClick={handleRotateClick}
getInitialCrop={getInitialCrop}
cropAspectRatio={cropAspectRatio}
onDeleteClick={onDeleteClick}
onClose={onClose}
modalProps={modalProps.desktop}
modalStep={stepIndex}
cropImageElementRef={cropImageElementRef}
/>
</>
)
}
case "tablet": {
return(
<>
<CropGeneral
imageUrl={imageUrl}
handleSizeChange={handleSizeChange}
handleRotateClick={handleRotateClick}
getInitialCrop={getInitialCrop}
cropAspectRatio={cropAspectRatio}
onDeleteClick={onDeleteClick}
onClose={onClose}
modalProps={modalProps.tablet}
modalStep={stepIndex}
cropImageElementRef={cropImageElementRef}
/>
</>
)
}
case "mobile": {
return(
<CropGeneral
imageUrl={imageUrl}
handleSizeChange={handleSizeChange}
handleRotateClick={handleRotateClick}
getInitialCrop={getInitialCrop}
cropAspectRatio={cropAspectRatio}
onDeleteClick={onDeleteClick}
onClose={onClose}
modalProps={modalProps.mobile}
modalStep={stepIndex}
cropImageElementRef={cropImageElementRef}
/>
)
}
case "small": {
return(
<CropGeneral
imageUrl={imageUrl}
handleSizeChange={handleSizeChange}
handleRotateClick={handleRotateClick}
getInitialCrop={getInitialCrop}
cropAspectRatio={cropAspectRatio}
onDeleteClick={onDeleteClick}
onClose={onClose}
modalProps={modalProps.small}
modalStep={stepIndex}
cropImageElementRef={cropImageElementRef}
/>
)
}
}
}

@ -0,0 +1,217 @@
import {Box, IconButton, Slider, SxProps, Theme, Typography, useMediaQuery, useTheme} from "@mui/material";
import ReactCrop, {PercentCrop} from "react-image-crop";
import {ResetIcon} from "@icons/ResetIcon";
import DeleteIcon from "@mui/icons-material/Delete";
import {MutableRefObject, useRef, useState} from "react";
interface Props{
imageUrl: null | string;
handleSizeChange: (a: number)=> void;
handleRotateClick: Promise<void>;
getInitialCrop: (imageWidth: number, imageHeight: number, aspectRatio: number)=> PercentCrop;
modalProps: any;
modalStep: number;
onClose: () => void;
cropImageElementRef: MutableRefObject<HTMLImageElement>;
onDeleteClick?: () => void;
cropAspectRatio?: {
width: number;
height: number;
};
}
const styleSlider: SxProps<Theme> = {
color: "#7E2AEA",
height: "12px",
"& .MuiSlider-track": {
border: "none",
},
"& .MuiSlider-rail": {
backgroundColor: "#F2F3F7",
border: `1px solid #9A9AAF`,
},
"& .MuiSlider-thumb": {
height: 26,
width: 26,
border: `6px solid #7E2AEA`,
backgroundColor: "white",
boxShadow: `0px 0px 0px 3px white,
0px 4px 4px 3px #C3C8DD`,
"&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
boxShadow: `0px 0px 0px 3px white,
0px 4px 4px 3px #C3C8DD`,
},
},
};
export default function CropGeneral({imageUrl,
cropAspectRatio,
handleSizeChange,
handleRotateClick,
getInitialCrop,
modalProps,
onDeleteClick,
onClose,
modalStep,
cropImageElementRef}: Props) {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(786));
const [percentCrop, setPercentCrop] = useState<PercentCrop | undefined>(
undefined,
);
const [imageWidth, setImageWidth] = useState<number | null>(null);
const [imageHeight, setImageHeight] = useState<number | null>(null);
const [darken, setDarken] = useState(0);
const step = modalStep + 1
return (
<>
<Box
sx={{
padding: "20px 20px 0",
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "12px"
}}
>
<Typography>{modalProps.name}</Typography>
{modalProps.icon}
</Box>
{onDeleteClick && (
<IconButton
onClick={() => {
onDeleteClick?.();
onClose();
}}
sx={{
height: "48px",
width: "48px",
p: 0,
color: theme.palette.orange.main,
borderRadius: "50%",
}}
>
<DeleteIcon />
</IconButton>
)}
</Box>
<Typography sx={{p: "0 20px 20px", fontSize: "14px", color: "#9A9AAF"}}>
{step + " шаг"}</Typography>
<Box
sx={{
height: "320px",
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "0 20px"
}}
>
{imageUrl && (
<ReactCrop
crop={percentCrop}
onChange={(_, percentCrop) => setPercentCrop(percentCrop)}
minWidth={5}
minHeight={5}
locked
aspect={
cropAspectRatio
? cropAspectRatio.width / cropAspectRatio.height
: undefined
}
>
<img
onLoad={(e) => {
setImageWidth(e.currentTarget.naturalWidth);
setImageHeight(e.currentTarget.naturalHeight);
if (cropImageElementRef.current) {
setPercentCrop(
getInitialCrop(
cropImageElementRef.current.width,
cropImageElementRef.current.height,
cropAspectRatio
? cropAspectRatio.width / cropAspectRatio.height
: 1,
),
);
}
}}
ref={cropImageElementRef}
alt="Crop me"
src={imageUrl}
style={{
filter: `brightness(${100 - darken}%)`,
maxWidth: "100%",
maxHeight: "320px",
display: "block",
objectFit: "contain",
}}
/>
</ReactCrop>
)}
</Box>
<Box
sx={{
mt: "40px",
display: isMobile ? "block" : "flex",
alignItems: "end",
justifyContent: "space-between",
padding: "0 20px"
}}
>
<IconButton onClick={handleRotateClick}>
<ResetIcon />
</IconButton>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
Размер
</Typography>
<Slider
sx={[
styleSlider,
{
width: isMobile ? undefined : "200px",
},
]}
value={percentCrop?.width ?? 1}
min={1}
max={100}
step={0.1}
onChange={(_, newValue) => {
if (typeof newValue === "number") handleSizeChange(newValue);
}}
/>
</Box>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
Затемнение
</Typography>
<Slider
sx={[
styleSlider,
{
width: isMobile ? undefined : "200px",
},
]}
value={darken}
min={0}
max={100}
step={1}
onChange={(_, newValue) => setDarken(newValue as number)}
/>
</Box>
</Box>
</>
)
}