fix: resolve conflicts

This commit is contained in:
IlyaDoronin 2023-08-14 17:16:01 +03:00
commit f2a9e61452
12 changed files with 557 additions and 158 deletions

@ -18,6 +18,7 @@
"@types/react-dnd": "^3.0.2",
"@types/react-dom": "^18.0.0",
"file-saver": "^2.0.5",
"html-to-image": "^1.11.11",
"jszip": "^3.10.1",
"notistack": "^3.0.1",
"react": "^18.2.0",
@ -25,6 +26,8 @@
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-easy-crop": "^5.0.0",
"react-image-crop": "^10.1.5",
"react-image-file-resizer": "^0.4.8",
"react-router-dom": "^6.6.2",
"react-scripts": "5.0.1",

@ -0,0 +1,10 @@
import { FC } from "react";
export const CropIcon: FC = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
<path d="M6 6H2.25" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M6 2.25V18H21.75" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M18 15V6H9" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M18 21.75V18" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
);

@ -0,0 +1,33 @@
import { CSSProperties, FC } from "react";
interface Iporps {
style?: CSSProperties;
onClick?: () => void;
}
export const ResetIcon: FC<Iporps> = ({ style, onClick }) => (
<svg
onClick={onClick}
style={style}
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
>
<path
d="M22.0254 12.4609H28.0254V6.46094"
stroke="#9A9AAF"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M23.7755 23.775C22.2375 25.3143 20.2775 26.3628 18.1434 26.788C16.0094 27.2132 13.7972 26.9958 11.7867 26.1635C9.77619 25.3312 8.05769 23.9213 6.8486 22.1122C5.63951 20.3031 4.99414 18.176 4.99414 16C4.99414 13.824 5.63951 11.6969 6.8486 9.8878C8.05769 8.07866 9.77619 6.66877 11.7867 5.83647C13.7972 5.00417 16.0094 4.78686 18.1434 5.21202C20.2775 5.63719 22.2375 6.68573 23.7755 8.22501L28.0255 12.4625"
stroke="#9A9AAF"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);

@ -1,35 +1,29 @@
import { Box } from "@mui/material";
import { FC } from "react";
// interface Props {
// color: string;
// }
interface Iprops {
onClick?: () => void;
}
export default function AddImage() {
const AddImage: FC<Iprops> = ({ onClick }) => {
return (
<Box
onClick={onClick}
sx={{
height: "38px",
width: "45px",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
}}
>
<svg
width="60"
height="40"
viewBox="0 0 60 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg width="60" height="40" viewBox="0 0 60 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M40.3333 0H1.66667C0.746192 0 0 0.89543 0 2V38C0 39.1046 0.746192 40 1.66667 40H40.3333V0Z"
fill="#EEE4FC"
/>
<path
d="M58 0H40V40H58C58.4602 40 60 39.1046 60 38V2C60 0.89543 58.4602 0 58 0Z"
fill="#7E2AEA"
/>
<path d="M58 0H40V40H58C58.4602 40 60 39.1046 60 38V2C60 0.89543 58.4602 0 58 0Z" fill="#7E2AEA" />
<path
d="M49.518 24.612C49.398 24.612 49.296 24.576 49.212 24.504C49.14 24.42 49.104 24.318 49.104 24.198V20.454H45.414C45.294 20.454 45.192 20.418 45.108 20.346C45.036 20.262 45 20.16 45 20.04V19.464C45 19.344 45.036 19.248 45.108 19.176C45.192 19.092 45.294 19.05 45.414 19.05H49.104V15.414C49.104 15.294 49.14 15.198 49.212 15.126C49.296 15.042 49.398 15 49.518 15H50.148C50.268 15 50.364 15.042 50.436 15.126C50.52 15.198 50.562 15.294 50.562 15.414V19.05H54.27C54.39 19.05 54.486 19.092 54.558 19.176C54.642 19.248 54.684 19.344 54.684 19.464V20.04C54.684 20.16 54.642 20.262 54.558 20.346C54.486 20.418 54.39 20.454 54.27 20.454H50.562V24.198C50.562 24.318 50.52 24.42 50.436 24.504C50.364 24.576 50.268 24.612 50.148 24.612H49.518Z"
fill="white"
@ -37,16 +31,16 @@ export default function AddImage() {
<path
d="M30.9583 10H8.04167C7.46637 10 7 10.4477 7 11V29C7 29.5523 7.46637 30 8.04167 30H30.9583C31.5336 30 32 29.5523 32 29V11C32 10.4477 31.5336 10 30.9583 10Z"
stroke="#7E2AEA"
strokeWidth="2"
stroke-width="2"
stroke-linecap="round"
strokeLinejoin="round"
stroke-linejoin="round"
/>
<path
d="M7 24.9035L13.5495 18.3127C13.6464 18.2137 13.7619 18.135 13.8894 18.0813C14.0168 18.0276 14.1535 18 14.2917 18C14.4298 18 14.5666 18.0276 14.694 18.0813C14.8214 18.135 14.9369 18.2137 15.0339 18.3127L20.8411 24.1567C20.9381 24.2557 21.0536 24.3343 21.181 24.388C21.3084 24.4417 21.4452 24.4694 21.5833 24.4694C21.7215 24.4694 21.8582 24.4417 21.9856 24.388C22.1131 24.3343 22.2286 24.2557 22.3255 24.1567L25.0078 21.4574C25.1047 21.3584 25.2203 21.2797 25.3477 21.2261C25.4751 21.1724 25.6119 21.1447 25.75 21.1447C25.8881 21.1447 26.0249 21.1724 26.1523 21.2261C26.2797 21.2797 26.3953 21.3584 26.4922 21.4574L32 27"
stroke="#7E2AEA"
strokeWidth="2"
stroke-width="2"
stroke-linecap="round"
strokeLinejoin="round"
stroke-linejoin="round"
/>
<path
d="M22.5 18C23.3284 18 24 17.3284 24 16.5C24 15.6716 23.3284 15 22.5 15C21.6716 15 21 15.6716 21 16.5C21 17.3284 21.6716 18 22.5 18Z"
@ -55,4 +49,6 @@ export default function AddImage() {
</svg>
</Box>
);
}
};
export default AddImage;

@ -18,6 +18,7 @@ import { Result } from "./pages/Result/Result";
import { Setting } from "./pages/Result/Setting";
import MyQuizzes from "./pages/createQuize/MyQuizzes";
import MyQuizzesFull from "./pages/createQuize/MyQuizzesFull";
import ImageCrop from "@ui_kit/Modal/ImageCrop";
const routeslink: {
path: string;
@ -56,6 +57,7 @@ root.render(
/>
))}
<Route path="quize-setting/:quizId" element={<StartPage />} />
<Route path="crop" element={<ImageCrop />} />
</Routes>
</BrowserRouter>
</ThemeProvider>

@ -1,4 +1,4 @@
import {Box, Link, Typography, useTheme} from "@mui/material";
import { Box, Link, Typography, useTheme } from "@mui/material";
import AddImage from "../../../assets/icons/questionsPage/addImage";
import EnterIcon from "../../../assets/icons/questionsPage/enterIcon";
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict";
@ -6,57 +6,58 @@ import SwitchOptionsAndPict from "./switchOptionsAndPict";
import React from "react";
interface Props {
totalIndex: number
totalIndex: number;
}
export default function OptionsAndPicture({totalIndex}: Props) {
const theme = useTheme();
const [switchState, setSwitchState] = React.useState('setting');
const SSHC = (data: string) => {
setSwitchState(data)
}
return (
export default function OptionsAndPicture({ totalIndex }: Props) {
const theme = useTheme();
const [switchState, setSwitchState] = React.useState("setting");
const SSHC = (data: string) => {
setSwitchState(data);
};
return (
<>
<Box sx={{ padding: '20px'}}>
<Box sx={{display: 'flex', alignItems: 'center', paddingBottom: '25px'}}>
<AddImage/>
<Typography
sx={{
padding: '0 0 0 20px',
fontWeight: 400,
fontSize: '18px',
lineHeight: '21.33px',
color: theme.palette.grey2.main
}}
>
Добавьте ответ
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: '10px'}}>
<Link
component="button"
variant="body2"
sx={{color: theme.palette.brightPurple.main}}
// onClick={() => {
// console.info("I'm a button.");
// }}
>
Добавьте ответ
</Link>
<Typography
sx={{
fontWeight: 400,
fontSize: '18px',
lineHeight: '21.33px',
color: theme.palette.grey2.main
}}
>или нажмите Enter</Typography>
<EnterIcon/>
</Box>
<Box sx={{ padding: "20px" }}>
<Box sx={{ display: "flex", alignItems: "center", paddingBottom: "25px" }}>
<AddImage />
<Typography
sx={{
padding: "0 0 0 20px",
fontWeight: 400,
fontSize: "18px",
lineHeight: "21.33px",
color: theme.palette.grey2.main,
}}
>
Добавьте ответ
</Typography>
</Box>
<ButtonsOptionsAndPict switchState={switchState} SSHC={SSHC} totalIndex={totalIndex}/>
<SwitchOptionsAndPict switchState={switchState}/>
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
<Link
component="button"
variant="body2"
sx={{ color: theme.palette.brightPurple.main }}
// onClick={() => {
// console.info("I'm a button.");
// }}
>
Добавьте ответ
</Link>
<Typography
sx={{
fontWeight: 400,
fontSize: "18px",
lineHeight: "21.33px",
color: theme.palette.grey2.main,
}}
>
или нажмите Enter
</Typography>
<EnterIcon />
</Box>
</Box>
<ButtonsOptionsAndPict switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<SwitchOptionsAndPict switchState={switchState} />
</>
)
}
);
}

@ -8,7 +8,7 @@ import SwitchPageOptions from "./switchPageOptions";
type Props = {
disableInput?: boolean;
totalIndex: number
totalIndex: number;
};
export default function PageOptions({ disableInput, totalIndex }: Props) {
@ -59,7 +59,7 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
</Typography>
</Box>
</Box>
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex}/>
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<SwitchPageOptions switchState={switchState} />
</>
);

@ -2,12 +2,18 @@ import { Box, Typography, useTheme } from "@mui/material";
import AddImage from "@icons/questionsPage/addImage";
import AddVideofile from "@icons/questionsPage/addVideofile";
import { useState } from "react";
import { CroppingModal } from "@ui_kit/Modal/CroppingModal";
export default function ImageAndVideoButtons() {
const theme = useTheme();
const [opened, setOpened] = useState<boolean>(false);
return (
<Box sx={{ display: "flex", alignItems: "center", gap: "12px", mt: "20px", mb: "20px" }}>
<AddImage />
<AddImage onClick={() => setOpened(true)} />
<CroppingModal opened={opened} onClose={() => setOpened(false)} />
<Typography
sx={{
fontWeight: 400,

@ -1,101 +1,111 @@
import {Box, SxProps, Theme, Typography, useMediaQuery, useTheme} from "@mui/material";
import { Box, SxProps, Theme, Typography, useMediaQuery, useTheme } from "@mui/material";
import React from "react";
interface Props {
children?: React.ReactNode;
isExpanded?: boolean;
onClick?: () => void;
sx?: SxProps<Theme>;
header: string;
children?: React.ReactNode;
isExpanded?: boolean;
onClick?: () => void;
sx?: SxProps<Theme>;
header: string;
}
export default function AccordMy ({ children, isExpanded = false, onClick, sx, header }: Props) {
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const upSm = useMediaQuery(theme.breakpoints.up("sm"));
return (
<Box
sx={{
width: "100%",
paddingBottom: "15px",
overflow: "hidden",
borderBottom: `1px solid ${theme.palette.grey2.main}`,
boxShadow: `0px 100px 309px rgba(210, 208, 225, 0.24),
export default function AccordMy({ children, isExpanded = false, onClick, sx, header }: Props) {
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const upSm = useMediaQuery(theme.breakpoints.up("sm"));
return (
<Box
sx={{
width: "100%",
paddingBottom: "15px",
overflow: "hidden",
borderBottom: `1px solid ${theme.palette.grey2.main}`,
boxShadow: `0px 100px 309px rgba(210, 208, 225, 0.24),
0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525),
0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066),
0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12),
0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343),
0px 2.76726px 8.55082px rgba(210, 208, 225, 0.067
4749)`,
}}
}}
>
<Box
sx={{
width: "100%",
backgroundColor: "transparent",
}}
>
<Box
onClick={onClick}
sx={{
paddingTop: "15px",
paddingRight: "20px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
userSelect: "none",
}}
>
<Typography
sx={{
fontSize: upMd ? "18px" : "16px",
lineHeight: upMd ? undefined : "19px",
px: 0,
}}
>
{header}
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
height: "100%",
alignItems: "center",
gap: upSm ? "111px" : "17px",
}}
>
<Box
sx={{
width: "100%",
backgroundColor: "transparent",
}}
sx={{
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Box
onClick={onClick}
sx={{
paddingTop: "15px",
paddingRight: "20px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
userSelect: "none",
}}
>
<Typography
sx={{
fontSize: upMd ? "18px" : "16px",
lineHeight: upMd ? undefined : "19px",
px: 0,
}}
>
{header}
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
height: "100%",
alignItems: "center",
gap: upSm ? "111px" : "17px",
}}
>
<Box
sx={{
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<svg style={{ transform: isExpanded ? "rotate(180deg)" : undefined }} xmlns="http://www.w3.org/2000/svg" width="32" height="33" viewBox="0 0 32 33" fill="none">
<path d="M20.5 15.2949L16 20.2949L11.5 15.2949" stroke="#757575" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</Box>
</Box>
</Box>
{isExpanded && (
<Box
sx={{
backgroundColor: "transparent",
gap: "15px",
paddingTop: "15px",
...sx
}}
>
{children}
</Box>
)
}
<svg
style={{ transform: isExpanded ? "rotate(180deg)" : undefined }}
xmlns="http://www.w3.org/2000/svg"
width="32"
height="33"
viewBox="0 0 32 33"
fill="none"
>
<path
d="M20.5 15.2949L16 20.2949L11.5 15.2949"
stroke="#757575"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</Box>
</Box>
</Box>
)
}
{isExpanded && (
<Box
sx={{
backgroundColor: "transparent",
gap: "15px",
paddingTop: "15px",
...sx,
}}
>
{children}
</Box>
)}
</Box>
</Box>
);
}

@ -0,0 +1,293 @@
import React, { FC, useRef, useState } from "react";
import { saveAs } from "file-saver";
import ReactCrop, { Crop } from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { Box, Button, Modal, Slider, Typography, useMediaQuery, useTheme } from "@mui/material";
import quiz from "../../assets/quiz-template-6.png";
import { ResetIcon } from "@icons/ResetIcon";
interface Iprops {
opened: boolean;
onClose: () => void;
}
export const CroppingModal: FC<Iprops> = ({ opened, onClose }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(786));
const style = {
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: isMobile ? "343px" : "620px",
bgcolor: "background.paper",
boxShadow: 24,
padding: "20px",
borderRadius: "8px",
};
const styleSlider = {
width: isMobile ? "350px" : "250px",
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`,
},
},
};
const [src, setSrc] = useState<string | ArrayBuffer | null>(quiz);
const [crop, setCrop] = useState<Crop>({ unit: "px", y: 0, x: 0, width: 100, height: 100 });
const [completedCrop, setCompletedCrop] = useState<Crop | null>(null);
const [imageSize, setImageSize] = useState(580);
const [darken, setDarken] = useState(0);
const fileInputRef = useRef<HTMLInputElement>(null);
console.log(src);
const onCropComplete = (crop: Crop) => {
setCompletedCrop(crop);
};
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
if (event.target && event.target.result) {
setSrc(event.target.result);
}
};
reader.readAsDataURL(file);
}
};
const handleDownloadClick = async () => {
if (completedCrop && src) {
const croppedImageUrl = await getCroppedAndDarkenedImg(src, completedCrop, "cropped.jpeg", darken);
saveAs(croppedImageUrl, "cropped-image.jpeg");
}
};
const getCroppedAndDarkenedImg = (
image: string | ArrayBuffer,
crop: Crop,
fileName: string,
darken: number
): Promise<string> => {
const img = new Image();
img.src = image as string;
let scaleX = 360 / 580;
let scaleY = 219 / 320;
if (img.naturalWidth) {
scaleX = img.naturalWidth / 580;
}
if (img.naturalHeight) {
scaleY = img.naturalHeight / 320;
}
console.log(scaleX);
console.log(scaleY);
const canvas = document.createElement("canvas");
canvas.width = crop.width!;
canvas.height = crop.height!;
const ctx = canvas.getContext("2d");
if (!ctx) {
throw new Error("Canvas context is null");
}
ctx.drawImage(
img,
crop.x! * scaleX,
crop.y! * scaleY,
crop.width! * scaleX,
crop.height! * scaleY,
0,
0,
crop.width!,
crop.height!
);
const imageData = ctx.getImageData(0, 0, crop.width!, crop.height!);
const newImageData = imageData.data.map((value, index) => {
if ((index + 1) % 4 === 0) {
return value;
}
return value * (1 - darken / 100);
});
imageData.data.set(newImageData);
ctx.putImageData(imageData, 0, 0);
return new Promise<string>((resolve, reject) => {
canvas.toBlob((blob) => {
if (!blob) {
reject(new Error("Canvas is empty"));
return;
}
const file = new File([blob], fileName, { type: "image/jpeg" });
const imageUrl = window.URL.createObjectURL(file);
resolve(imageUrl);
}, "image/jpeg");
});
};
return (
<Modal
open={opened}
onClose={onClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Box
sx={{
height: "320px",
padding: "10px",
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<ReactCrop crop={crop} onChange={(newCrop) => setCrop(newCrop)} onComplete={onCropComplete}>
{src && (
<img
src={src as string}
style={{
filter: `brightness(${100 - darken}%)`,
maxWidth: "580px",
}}
width={580 * (imageSize / 200)}
height={320}
alt="Crop"
/>
)}
</ReactCrop>
</Box>
<Box
sx={{
color: "#7E2AEA",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: "16xp",
fontWeight: "600",
marginBottom: "50px",
}}
>
<Typography sx={{ color: "#7E2AEA", lineHeight: "0px" }}>{Math.round(crop.width)}</Typography>x
<Typography sx={{ color: "#7E2AEA", lineHeight: "0px" }}>{Math.round(crop.width)}</Typography>
px
</Box>
<Box sx={{ display: isMobile ? "block" : "flex", alignItems: "end", justifyContent: "space-between" }}>
<ResetIcon
onClick={() => {
setCrop((prevCrop: Crop) => ({
...prevCrop,
unit: "px",
x: 210,
y: 10,
width: 210,
height: 300,
}));
setDarken(0);
setImageSize(580);
}}
style={{ marginBottom: "10px", cursor: "pointer" }}
/>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>Размер</Typography>
<Slider
sx={styleSlider}
value={imageSize}
min={50}
max={200}
step={1}
onChange={(_, newValue) => setImageSize(newValue as number)}
/>
</Box>
<Box>
<Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>Затемнение</Typography>
<Slider
sx={styleSlider}
value={darken}
min={0}
max={100}
step={1}
onChange={(_, newValue) => setDarken(newValue as number)}
/>
</Box>
</Box>
<Box sx={{ marginTop: "40px", width: "100%", display: "flex", justifyContent: "end" }}>
<input
ref={fileInputRef}
type="file"
accept="image/*"
id="fileInput"
style={{ display: "none" }}
onChange={handleFileChange}
/>
<Button
onClick={() => fileInputRef.current?.click()}
disableRipple
sx={{
width: "215px",
height: "48px",
color: "#7E2AEA",
borderRadius: "8px",
border: "1px solid #7E2AEA",
marginRight: "10px",
}}
>
Загрузить оригинал
</Button>
<Button
onClick={handleDownloadClick}
disableRipple
sx={{
width: "149px",
height: "48px",
color: "white",
background: "#7E2AEA",
borderRadius: "8px",
}}
>
Обрезать
</Button>
</Box>
</Box>
</Modal>
);
};

@ -0,0 +1,15 @@
import { Box, Button } from "@mui/material";
import { FC, useState } from "react";
import { CroppingModal } from "./CroppingModal";
const ImageCrop: FC = () => {
const [opened, setOpened] = useState<boolean>(false);
return (
<Box>
<CroppingModal opened={opened} onClose={() => setOpened(false)} />
<Button onClick={() => setOpened(true)}>Открыть модалку</Button>
</Box>
);
};
export default ImageCrop;

@ -5165,6 +5165,11 @@ html-minifier-terser@^6.0.2:
relateurl "^0.2.7"
terser "^5.10.0"
html-to-image@^1.11.11:
version "1.11.11"
resolved "https://registry.yarnpkg.com/html-to-image/-/html-to-image-1.11.11.tgz#c0f8a34dc9e4b97b93ff7ea286eb8562642ebbea"
integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==
html-webpack-plugin@^5.5.0:
version "5.5.0"
resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz"
@ -6692,6 +6697,11 @@ normalize-url@^6.0.1:
resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
normalize-wheel@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
integrity sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==
notistack@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/notistack/-/notistack-3.0.1.tgz"
@ -7831,11 +7841,26 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-easy-crop@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/react-easy-crop/-/react-easy-crop-5.0.0.tgz#8945dccf4d9f578e7d8d06ed71229e93f46d4a43"
integrity sha512-ppYg3E0jxpDW+HdgLa65lCykZSsGMuusBuKD3HeTMs/Aod4xiWyAH5jZn5iHlllLUV2c0PPT6FznvdNeLhO2wA==
dependencies:
normalize-wheel "^1.0.1"
tslib "2.0.1"
react-error-overlay@^6.0.11:
version "6.0.11"
resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
react-image-crop@^10.1.5:
version "10.1.5"
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-10.1.5.tgz#60f9d81405b01b6925629cae235e8406616fc0e5"
integrity sha512-BL8Rd/UHCE4O5GcYQiWDKVh5JOJb0Ic/Gde2W171v5nY7RyQzFLM1cxIzlYfESLO/lNgBVhDHuEV9RHnqALMkA==
dependencies:
clsx "^1.2.1"
react-image-file-resizer@^0.4.8:
version "0.4.8"
resolved "https://registry.npmjs.org/react-image-file-resizer/-/react-image-file-resizer-0.4.8.tgz"
@ -8997,6 +9022,11 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e"
integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"