import { CropIcon } from "@icons/CropIcon"; import { ResetIcon } from "@icons/ResetIcon"; import { Box, Button, IconButton, Modal, Slider, SxProps, Theme, Typography, useMediaQuery, useTheme, } from "@mui/material"; import { closeCropModal, resetToOriginalImage, setCropModalImageUrl, useCropModalStore } from "@root/cropModal"; import { FC, useRef, useState } from "react"; import ReactCrop, { Crop, PixelCrop } from "react-image-crop"; import "react-image-crop/dist/ReactCrop.css"; import { canvasPreview } from "./utils/canvasPreview"; import { enqueueSnackbar } from "notistack"; const styleSlider: SxProps = { 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`, }, }, }; interface Props { onSaveImageClick?: (imageUrl: string) => void; } export const CropModal: FC = ({ onSaveImageClick }) => { const theme = useTheme(); const isCropModalOpen = useCropModalStore(state => state.isCropModalOpen); const imageUrl = useCropModalStore(state => state.imageUrl); const [crop, setCrop] = useState(); const [completedCrop, setCompletedCrop] = useState(); const [darken, setDarken] = useState(0); const [rotate, setRotate] = useState(0); const [width, setWidth] = useState(0); const cropImageElementRef = useRef(null); const isMobile = useMediaQuery(theme.breakpoints.down(786)); const handleCropClick = async () => { if (!completedCrop) throw new Error("No completed crop"); if (!cropImageElementRef.current) throw new Error("No image"); const canvasCopy = document.createElement("canvas"); const ctx = canvasCopy.getContext("2d"); if (!ctx) throw new Error("No 2d context"); canvasCopy.width = completedCrop.width; canvasCopy.height = completedCrop.height; ctx.filter = `brightness(${100 - darken}%)`; await canvasPreview(cropImageElementRef.current, canvasCopy, completedCrop, rotate); canvasCopy.toBlob((blob) => { if (!blob) { throw new Error("Failed to create blob"); } const newImageUrl = URL.createObjectURL(blob); setCropModalImageUrl(newImageUrl); setCrop(undefined); setCompletedCrop(undefined); }); }; function handleSaveClick() { if (imageUrl) onSaveImageClick?.(imageUrl); setCrop(undefined); setCompletedCrop(undefined); closeCropModal(); } function handleLoadOriginalImage() { const isSuccess = resetToOriginalImage(); if (!isSuccess) enqueueSnackbar("Не удалось восстановить оригинал. Приносим глубочайшие извинения"); } const getImageSize = () => { if (cropImageElementRef.current) { const imageWidth = cropImageElementRef.current.naturalWidth; const imageHeight = cropImageElementRef.current.naturalHeight; const aspect = imageWidth / imageHeight; if (aspect <= 1.333) { setWidth(240); } if (aspect >= 1.5) { setWidth(580); } if (aspect >= 1.778) { setWidth(580); } } }; return ( {imageUrl && ( setCrop(percentCrop)} onComplete={(c) => setCompletedCrop(c)} maxWidth={500} minWidth={50} maxHeight={320} minHeight={50} > Crop me )} {crop?.width ? Math.round(crop.width) + "px" : ""} {crop?.height ? Math.round(crop.height) + "px" : ""} setRotate(r => (r + 90) % 360)}> Размер { setWidth(newValue as number); }} /> Затемнение setDarken(newValue as number)} /> ); };