From 49bfcf917ab0c5be711a567a8635961218dbd5e3 Mon Sep 17 00:00:00 2001 From: Akmal Isomadinov Date: Wed, 4 Jan 2023 15:28:52 +0500 Subject: [PATCH 1/3] Web: Combining avatar Editor and IconEditor components into one component and removing avatarEditor and IconEditor components --- .../editor/avatar-cropper.js | 210 ---------------- .../AvatarEditorDialog/editor/index.js | 56 ----- .../dialogs/AvatarEditorDialog/index.js | 39 ++- .../sub-components/IconEditor/Dropzone.js | 118 --------- .../sub-components/IconEditor/IconCropper.js | 227 ------------------ .../sub-components/IconEditor/index.js | 67 ------ .../sub-components/SetRoomParams.js | 39 ++- .../ImageEditor/AvatarPreview/index.js} | 6 +- .../ImageEditor/Dropzone}/StyledDropzone.js | 8 +- .../ImageEditor/Dropzone/index.js} | 34 +-- .../ImageCropper/StyledImageCropper.js | 94 ++++++++ .../ImageEditor/ImageCropper/index.js | 136 +++++++++++ .../ImageEditor/PreviewTile/index.js} | 10 +- packages/components/ImageEditor/index.js | 47 ++++ 14 files changed, 369 insertions(+), 722 deletions(-) delete mode 100644 packages/client/src/components/dialogs/AvatarEditorDialog/editor/avatar-cropper.js delete mode 100644 packages/client/src/components/dialogs/AvatarEditorDialog/editor/index.js delete mode 100644 packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/Dropzone.js delete mode 100644 packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/IconCropper.js delete mode 100644 packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/index.js rename packages/{client/src/components/dialogs/AvatarEditorDialog/editor/preview.js => components/ImageEditor/AvatarPreview/index.js} (87%) rename packages/{client/src/components/dialogs/AvatarEditorDialog/editor => components/ImageEditor/Dropzone}/StyledDropzone.js (87%) rename packages/{client/src/components/dialogs/AvatarEditorDialog/editor/dropzone.js => components/ImageEditor/Dropzone/index.js} (81%) create mode 100644 packages/components/ImageEditor/ImageCropper/StyledImageCropper.js create mode 100644 packages/components/ImageEditor/ImageCropper/index.js rename packages/{client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/PreviewTile.js => components/ImageEditor/PreviewTile/index.js} (90%) create mode 100644 packages/components/ImageEditor/index.js diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/avatar-cropper.js b/packages/client/src/components/dialogs/AvatarEditorDialog/editor/avatar-cropper.js deleted file mode 100644 index d8993a6907..0000000000 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/avatar-cropper.js +++ /dev/null @@ -1,210 +0,0 @@ -import React, { useEffect } from "react"; -import styled from "styled-components"; -import { ReactSVG } from "react-svg"; -import throttle from "lodash/throttle"; -import AvatarEditor from "react-avatar-editor"; - -import Slider from "@docspace/components/slider"; -import IconButton from "@docspace/components/icon-button"; -import { Base } from "@docspace/components/themes"; - -const StyledAvatarCropper = styled.div` - max-width: 216px; - - .icon_cropper-crop_area { - width: 216px; - height: 216px; - margin-bottom: 4px; - position: relative; - .icon_cropper-grid { - pointer-events: none; - position: absolute; - width: 216px; - height: 216px; - top: 0; - bottom: 0; - left: 0; - right: 0; - svg { - opacity: 0.2; - path { - fill: ${(props) => - props.theme.createEditRoomDialog.iconCropper.gridColor}; - } - } - } - } - - .icon_cropper-delete_button { - cursor: pointer; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 8px; - width: 100%; - padding: 6px 0; - background: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.background}; - border: 1px solid - ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.borderColor}; - border-radius: 3px; - margin-bottom: 12px; - - transition: all 0.2s ease; - &:hover { - background: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton - .hoverBackground}; - border: 1px solid - ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton - .hoverBorderColor}; - } - - &-text { - user-select: none; - font-weight: 600; - line-height: 20px; - color: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.color}; - } - - svg { - path { - fill: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.iconColor}; - } - } - } - - .icon_cropper-zoom-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 12px; - margin-bottom: 20px; - - &-slider { - margin: 0; - } - - &-button { - user-select: none; - } - } -`; - -StyledAvatarCropper.defaultProps = { theme: Base }; - -const AvatarCropper = ({ - t, - avatar, - onChangeAvatar, - uploadedFile, - setUploadedFile, - setPreviewAvatar, -}) => { - let editorRef = null; - const setEditorRef = (editor) => (editorRef = editor); - - const handlePositionChange = (position) => - onChangeAvatar({ ...avatar, x: position.x, y: position.y }); - - const handleSliderChange = (e, newZoom = null) => - onChangeAvatar({ ...avatar, zoom: newZoom ? newZoom : +e.target.value }); - - const handleZoomInClick = () => - handleSliderChange({}, avatar.zoom <= 4.5 ? avatar.zoom + 0.5 : 5); - - const handleZoomOutClick = () => - handleSliderChange({}, avatar.zoom >= 1.5 ? avatar.zoom - 0.5 : 1); - - const handleDeleteImage = () => setUploadedFile(null); - - const handleImageChange = throttle(() => { - try { - if (!editorRef) return; - const newPreveiwImage = editorRef.getImageScaledToCanvas()?.toDataURL(); - setPreviewAvatar(newPreveiwImage); - } catch (e) { - console.error(e); - } - }, 300); - - useEffect(() => { - handleImageChange(); - return () => { - setPreviewAvatar(""); - }; - }, [avatar]); - - return ( - -
- - -
- -
- -
- {t("Common:Delete")} -
-
- -
- - - -
-
- ); -}; - -export default AvatarCropper; diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/index.js b/packages/client/src/components/dialogs/AvatarEditorDialog/editor/index.js deleted file mode 100644 index d56e168f0b..0000000000 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/index.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useState } from "react"; -import styled from "styled-components"; - -import AvatarCropper from "./avatar-cropper"; -import AvatarPreview from "./preview"; -import Dropzone from "./dropzone"; - -const StyledWrapper = styled.div` - width: 100%; - display: flex; - flex-direction: column; - gap: 24px; - - .avatar-editor { - display: flex; - gap: 16px; - align-items: center; - } -`; - -const AvatarEditor = ({ - t, - profile, - avatar, - onChangeAvatar, - preview, - setPreview, -}) => { - const setUploadedFile = (file) => - onChangeAvatar({ ...avatar, uploadedFile: file }); - - const isDefaultAvatar = - typeof avatar.uploadedFile === "string" && - avatar.uploadedFile.includes("default_user_photo"); - - return ( - - {avatar.uploadedFile && !isDefaultAvatar && ( -
- - -
- )} - -
- ); -}; - -export default AvatarEditor; diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/index.js b/packages/client/src/components/dialogs/AvatarEditorDialog/index.js index f8c6a03129..cf68eb729b 100644 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/index.js +++ b/packages/client/src/components/dialogs/AvatarEditorDialog/index.js @@ -13,12 +13,32 @@ import { deleteAvatar, } from "@docspace/common/api/people"; import { dataUrlToFile } from "@docspace/common/utils/dataUrlToFile"; -import AvatarEditor from "./editor"; +import ImageEditor from "@docspace/components/ImageEditor"; +import AvatarPreview from "@docspace/components/ImageEditor/AvatarPreview"; -const StyledModalDialog = styled(ModalDialog)``; +const StyledModalDialog = styled(ModalDialog)` + .wrapper-image-editor { + width: 100%; + display: flex; + flex-direction: column; + gap: 24px; + .avatar-editor { + display: flex; + gap: 16px; + align-items: center; + } + } +`; const AvatarEditorDialog = (props) => { - const { t } = useTranslation(["Profile", "PeopleTranslations", "ProfileAction", "Common"]); + const { t } = useTranslation([ + "Profile", + "PeopleTranslations", + "ProfileAction", + "Common", + "CreateEditRoomDialog", + ]); + const { visible, onClose, @@ -89,13 +109,16 @@ const AvatarEditorDialog = (props) => { - + } /> diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/Dropzone.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/Dropzone.js deleted file mode 100644 index 143f61bbe9..0000000000 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/Dropzone.js +++ /dev/null @@ -1,118 +0,0 @@ -import React, { useEffect } from "react"; -import styled from "styled-components"; -import { useDropzone } from "react-dropzone"; -import resizeImage from "resize-image"; -import { Base } from "@docspace/components/themes"; -import { ColorTheme, ThemeType } from "@docspace/common/components/ColorTheme"; - -const StyledDropzone = styled.div` - cursor: pointer; - box-sizing: border-box; - width: 100%; - height: 150px; - border: 2px dashed - ${(props) => props.theme.createEditRoomDialog.dropzone.borderColor}; - border-radius: 6px; - - .dropzone { - height: 100%; - width: 100%; - - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 4px; - - user-select: none; - - &-link { - display: flex; - flex-direction: row; - gap: 4px; - - font-size: 13px; - line-height: 20px; - &-main { - font-weight: 600; - text-decoration: underline; - text-decoration-style: dashed; - text-underline-offset: 1px; - } - &-secondary { - font-weight: 400; - color: ${(props) => - props.theme.createEditRoomDialog.dropzone.linkSecondaryColor}; - } - } - - &-exsts { - font-weight: 600; - font-size: 12px; - line-height: 16px; - color: ${(props) => props.theme.createEditRoomDialog.dropzone.exstsColor}; - } - } -`; - -StyledDropzone.defaultProps = { theme: Base }; - -const Dropzone = ({ t, setUploadedFile, isDisabled }) => { - const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ - maxFiles: 1, - noClick: isDisabled, - noKeyboard: isDisabled, - // maxSize: 1000000, - accept: ["image/png", "image/jpeg"], - }); - - useEffect(() => { - if (acceptedFiles.length) { - const fr = new FileReader(); - fr.readAsDataURL(acceptedFiles[0]); - - fr.onload = () => { - const img = new Image(); - img.onload = () => { - const canvas = resizeImage.resize2Canvas(img, img.width, img.height); - - const data = resizeImage.resize( - canvas, - img.width / 4, - img.height / 4, - resizeImage.JPEG - ); - - fetch(data) - .then((res) => res.blob()) - .then((blob) => { - const file = new File([blob], "File name", { - type: "image/jpg", - }); - setUploadedFile(file); - }); - }; - img.src = fr.result; - }; - } - }, [acceptedFiles]); - - return ( - -
- -
- - {t("DropzoneTitleLink")} - - - {t("DropzoneTitleSecondary")} - -
-
{t("DropzoneTitleExsts")}
-
-
- ); -}; - -export default Dropzone; diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/IconCropper.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/IconCropper.js deleted file mode 100644 index 8a61dd0e9c..0000000000 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/IconCropper.js +++ /dev/null @@ -1,227 +0,0 @@ -import React, { useState, useEffect } from "react"; -import styled from "styled-components"; -import { ReactSVG } from "react-svg"; -import throttle from "lodash/throttle"; -import AvatarEditor from "react-avatar-editor"; - -import Slider from "@docspace/components/slider"; -import IconButton from "@docspace/components/icon-button"; -import { Base } from "@docspace/components/themes"; - -const StyledIconCropper = styled.div` - max-width: 216px; - - .icon_cropper-crop_area { - width: 216px; - height: 216px; - margin-bottom: 4px; - position: relative; - .icon_cropper-grid { - pointer-events: none; - position: absolute; - width: 216px; - height: 216px; - top: 0; - bottom: 0; - left: 0; - right: 0; - svg { - opacity: 0.2; - path { - fill: ${(props) => - props.theme.createEditRoomDialog.iconCropper.gridColor}; - } - } - } - } - - .icon_cropper-delete_button { - cursor: pointer; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 8px; - width: 100%; - padding: 6px 0; - background: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.background}; - border: 1px solid - ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.borderColor}; - border-radius: 3px; - margin-bottom: 12px; - - transition: all 0.2s ease; - &:hover { - background: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton - .hoverBackground}; - border: 1px solid - ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton - .hoverBorderColor}; - } - - &-text { - user-select: none; - font-weight: 600; - line-height: 20px; - color: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.color}; - } - - svg { - path { - fill: ${(props) => - props.theme.createEditRoomDialog.iconCropper.deleteButton.iconColor}; - } - } - } - - .icon_cropper-zoom-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 12px; - margin-bottom: 20px; - - &-slider { - margin: 0; - } - - &-button { - user-select: none; - } - } -`; - -StyledIconCropper.defaultProps = { theme: Base }; - -const IconCropper = ({ - t, - icon, - onChangeIcon, - uploadedFile, - setUploadedFile, - setPreviewIcon, - isDisabled, -}) => { - let editorRef = null; - const setEditorRef = (editor) => (editorRef = editor); - - const handlePositionChange = (position) => { - if (isDisabled) return; - - onChangeIcon({ ...icon, x: position.x, y: position.y }); - }; - - const handleSliderChange = (e, newZoom = null) => { - if (isDisabled) return; - - onChangeIcon({ ...icon, zoom: newZoom ? newZoom : +e.target.value }); - }; - - const handleZoomInClick = () => { - if (isDisabled) return; - - handleSliderChange({}, icon.zoom <= 4.5 ? icon.zoom + 0.5 : 5); - }; - const handleZoomOutClick = () => { - if (isDisabled) return; - - handleSliderChange({}, icon.zoom >= 1.5 ? icon.zoom - 0.5 : 1); - }; - const handleDeleteImage = () => { - if (isDisabled) return; - setUploadedFile(null); - }; - - const handleImageChange = throttle(() => { - try { - if (!editorRef) return; - const newPreveiwImage = editorRef.getImageScaledToCanvas()?.toDataURL(); - setPreviewIcon(newPreveiwImage); - } catch (e) { - console.error(e); - } - }, 300); - - useEffect(() => { - handleImageChange(); - return () => { - setPreviewIcon(""); - }; - }, [icon]); - - return ( - -
- - -
- -
- -
- {t("Common:Delete")} -
-
- -
- - - -
-
- ); -}; - -export default IconCropper; diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/index.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/index.js deleted file mode 100644 index 3e2f24470f..0000000000 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/index.js +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useState } from "react"; -import styled from "styled-components"; - -import Dropzone from "./Dropzone"; - -const StyledIconEditor = styled.div` - .icon-editor { - display: flex; - flex-direction: row; - align-items: flex-start; - justify-content: start; - gap: 16px; - } -`; - -import IconCropper from "./IconCropper"; -import PreviewTile from "./PreviewTile"; - -const IconEditor = ({ - t, - isEdit, - title, - tags, - defaultTagLabel, - icon, - onChangeIcon, - isDisabled, -}) => { - const [previewIcon, setPreviewIcon] = useState(null); - - const setUploadedFile = (uploadedFile) => - onChangeIcon({ ...icon, uploadedFile }); - - return ( - - {icon.uploadedFile && ( -
- - - tag.name)} - defaultTagLabel={defaultTagLabel} - isDisabled={isDisabled} - /> -
- )} - -
- ); -}; - -export default IconEditor; diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/SetRoomParams.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/SetRoomParams.js index 8d5fe5b665..7881f25701 100644 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/SetRoomParams.js +++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/SetRoomParams.js @@ -6,7 +6,7 @@ import RoomTypeDropdown from "./RoomTypeDropdown"; import ThirdPartyStorage from "./ThirdPartyStorage"; import TagInput from "./TagInput"; import RoomType from "./RoomType"; -import IconEditor from "./IconEditor"; + import PermanentSettings from "./PermanentSettings"; import InputParam from "./Params/InputParam"; import IsPrivateParam from "./IsPrivateParam"; @@ -15,11 +15,22 @@ import withLoader from "@docspace/client/src/HOCs/withLoader"; import Loaders from "@docspace/common/components/Loaders"; import { getRoomTypeDefaultTagTranslation } from "../data"; +import ImageEditor from "@docspace/components/ImageEditor"; +import PreviewTile from "@docspace/components/ImageEditor/PreviewTile"; + const StyledSetRoomParams = styled.div` display: flex; flex-direction: column; width: 100%; gap: 22px; + + .icon-editor { + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: start; + gap: 16px; + } `; const SetRoomParams = ({ @@ -35,6 +46,8 @@ const SetRoomParams = ({ isValidTitle, setIsValidTitle, }) => { + const [previewIcon, setPreviewIcon] = React.useState(null); + const onChangeName = (e) => { setIsValidTitle(true); setRoomParams({ ...roomParams, title: e.target.value }); @@ -111,14 +124,26 @@ const SetRoomParams = ({ /> )} - tag.name)} + isDisabled={isDisabled} + defaultTagLabel={getRoomTypeDefaultTagTranslation( + roomParams.type, + t + )} + /> + } /> ); diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/preview.js b/packages/components/ImageEditor/AvatarPreview/index.js similarity index 87% rename from packages/client/src/components/dialogs/AvatarEditorDialog/editor/preview.js rename to packages/components/ImageEditor/AvatarPreview/index.js index 5c3243a0b5..417b8851a9 100644 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/preview.js +++ b/packages/components/ImageEditor/AvatarPreview/index.js @@ -1,10 +1,10 @@ import React from "react"; import styled from "styled-components"; -import Avatar from "@docspace/components/avatar"; -import Text from "@docspace/components/text"; +import Avatar from "../../avatar"; +import Text from "../../text"; -import { hugeMobile } from "@docspace/components/utils/device"; +import { hugeMobile } from "../../utils/device"; const StyledWrapper = styled.div` width: 100%; diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/StyledDropzone.js b/packages/components/ImageEditor/Dropzone/StyledDropzone.js similarity index 87% rename from packages/client/src/components/dialogs/AvatarEditorDialog/editor/StyledDropzone.js rename to packages/components/ImageEditor/Dropzone/StyledDropzone.js index ff108d2bdb..38ef2dd3e4 100644 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/StyledDropzone.js +++ b/packages/components/ImageEditor/Dropzone/StyledDropzone.js @@ -1,7 +1,7 @@ import styled from "styled-components"; -import { hugeMobile } from "@docspace/components/utils/device"; +import { hugeMobile } from "../../utils/device"; -import { Base } from "@docspace/components/themes"; +import { Base } from "../../themes"; const StyledDropzone = styled.div` cursor: pointer; @@ -16,10 +16,8 @@ const StyledDropzone = styled.div` .dropzone_loader { position: absolute; - top: 50%; left: 50%; - transform: translate(-50%, -50%); } @@ -43,8 +41,6 @@ const StyledDropzone = styled.div` font-size: 13px; line-height: 20px; &-main { - color: ${(props) => - props.theme.createEditRoomDialog.dropzone.linkMainColor}; font-weight: 600; text-decoration: underline; text-decoration-style: dashed; diff --git a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/dropzone.js b/packages/components/ImageEditor/Dropzone/index.js similarity index 81% rename from packages/client/src/components/dialogs/AvatarEditorDialog/editor/dropzone.js rename to packages/components/ImageEditor/Dropzone/index.js index 05afd65776..266866768b 100644 --- a/packages/client/src/components/dialogs/AvatarEditorDialog/editor/dropzone.js +++ b/packages/components/ImageEditor/Dropzone/index.js @@ -1,24 +1,22 @@ -import React, { useState, useRef, useMemo, useEffect } from "react"; +import React, { useState, useRef, useEffect } from "react"; -import { useTranslation } from "react-i18next"; import { useDropzone } from "react-dropzone"; - -import StyledDropzone from "./StyledDropzone"; -import Loader from "@docspace/components/loader"; - -import { toastr } from "@docspace/components"; import resizeImage from "resize-image"; +import Loader from "../../loader"; + +import { toastr } from "../../"; + +import { ColorTheme, ThemeType } from "@docspace/common/components/ColorTheme"; +import StyledDropzone from "./StyledDropzone"; + const ONE_MEGABYTE = 1024 * 1024; const COMPRESSION_RATIO = 2; const NO_COMPRESSION_RATIO = 1; -const Dropzone = ({ setUploadedFile }) => { +const Dropzone = ({ t, setUploadedFile, isDisabled }) => { const [loadingFile, setLoadingFile] = useState(false); - const { t } = useTranslation("CreateEditRoomDialog"); - const mount = useRef(false); - const timer = useRef(null); useEffect(() => { @@ -99,7 +97,7 @@ const Dropzone = ({ setUploadedFile }) => { error instanceof Error && error.message === "recursion depth exceeded" ) { - toastr.error(t("SizeImageLarge")); + toastr.error(t("CreateEditRoomDialog:SizeImageLarge")); } console.error(error); }) @@ -113,6 +111,8 @@ const Dropzone = ({ setUploadedFile }) => { const { getRootProps, getInputProps } = useDropzone({ maxFiles: 1, + noClick: isDisabled, + noKeyboard: isDisabled, // maxSize: 1000000, accept: ["image/png", "image/jpeg"], onDrop, @@ -126,12 +126,16 @@ const Dropzone = ({ setUploadedFile }) => {
- {t("DropzoneTitleLink")} + + {t("CreateEditRoomDialog:DropzoneTitleLink")} + - {t("DropzoneTitleSecondary")} + {t("CreateEditRoomDialog:DropzoneTitleSecondary")}
-
{t("DropzoneTitleExsts")}
+
+ {t("CreateEditRoomDialog:DropzoneTitleExsts")} +
); diff --git a/packages/components/ImageEditor/ImageCropper/StyledImageCropper.js b/packages/components/ImageEditor/ImageCropper/StyledImageCropper.js new file mode 100644 index 0000000000..0f71dd9cab --- /dev/null +++ b/packages/components/ImageEditor/ImageCropper/StyledImageCropper.js @@ -0,0 +1,94 @@ +import styled from "styled-components"; +import { Base } from "../../themes"; + +const StyledImageCropper = styled.div` + max-width: 216px; + + .icon_cropper-crop_area { + width: 216px; + height: 216px; + margin-bottom: 4px; + position: relative; + .icon_cropper-grid { + pointer-events: none; + position: absolute; + width: 216px; + height: 216px; + top: 0; + bottom: 0; + left: 0; + right: 0; + svg { + opacity: 0.2; + path { + fill: ${(props) => + props.theme.createEditRoomDialog.iconCropper.gridColor}; + } + } + } + } + + .icon_cropper-delete_button { + cursor: pointer; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 8px; + width: 100%; + padding: 6px 0; + background: ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton.background}; + border: 1px solid + ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton.borderColor}; + border-radius: 3px; + margin-bottom: 12px; + + transition: all 0.2s ease; + &:hover { + background: ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton + .hoverBackground}; + border: 1px solid + ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton + .hoverBorderColor}; + } + + &-text { + user-select: none; + font-weight: 600; + line-height: 20px; + color: ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton.color}; + } + + svg { + path { + fill: ${(props) => + props.theme.createEditRoomDialog.iconCropper.deleteButton.iconColor}; + } + } + } + + .icon_cropper-zoom-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 12px; + margin-bottom: 20px; + + &-slider { + margin: 0; + } + + &-button { + user-select: none; + } + } +`; + +StyledImageCropper.defaultProps = { theme: Base }; +export default StyledImageCropper; diff --git a/packages/components/ImageEditor/ImageCropper/index.js b/packages/components/ImageEditor/ImageCropper/index.js new file mode 100644 index 0000000000..073def3861 --- /dev/null +++ b/packages/components/ImageEditor/ImageCropper/index.js @@ -0,0 +1,136 @@ +import React, { useEffect } from "react"; +import { ReactSVG } from "react-svg"; +import throttle from "lodash/throttle"; +import AvatarEditor from "react-avatar-editor"; + +import Slider from "../../slider"; +import IconButton from "../../icon-button"; +import StyledImageCropper from "./StyledImageCropper"; + +const ImageCropper = ({ + t, + image, + onChangeImage, + uploadedFile, + setUploadedFile, + setPreviewImage, + isDisabled, +}) => { + let editorRef = null; + const setEditorRef = (editor) => (editorRef = editor); + + const handlePositionChange = (position) => { + if (isDisabled) return; + + onChangeImage({ ...image, x: position.x, y: position.y }); + }; + + const handleSliderChange = (e, newZoom = null) => { + if (isDisabled) return; + + onChangeImage({ ...image, zoom: newZoom ? newZoom : +e.target.value }); + }; + + const handleZoomInClick = () => { + if (isDisabled) return; + + handleSliderChange({}, image.zoom <= 4.5 ? image.zoom + 0.5 : 5); + }; + + const handleZoomOutClick = () => { + if (isDisabled) return; + + handleSliderChange({}, image.zoom >= 1.5 ? image.zoom - 0.5 : 1); + }; + + const handleDeleteImage = () => { + if (isDisabled) return; + setUploadedFile(null); + }; + + const handleImageChange = throttle(() => { + try { + if (!editorRef) return; + const newPreveiwImage = editorRef.getImageScaledToCanvas()?.toDataURL(); + setPreviewImage(newPreveiwImage); + } catch (e) { + console.error(e); + } + }, 300); + + useEffect(() => { + handleImageChange(); + return () => { + setPreviewImage(""); + }; + }, [image]); + + return ( + +
+ + +
+
+ +
+ {t("Common:Delete")} +
+
+ +
+ + + +
+
+ ); +}; + +export default ImageCropper; diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/PreviewTile.js b/packages/components/ImageEditor/PreviewTile/index.js similarity index 90% rename from packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/PreviewTile.js rename to packages/components/ImageEditor/PreviewTile/index.js index 490ab96b50..5d749c768a 100644 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/IconEditor/PreviewTile.js +++ b/packages/components/ImageEditor/PreviewTile/index.js @@ -1,11 +1,11 @@ import React from "react"; import styled from "styled-components"; -import { smallTablet } from "@docspace/components/utils/device"; - import Tags from "@docspace/common/components/Tags"; -import Tag from "@docspace/components/tag"; -import { Base } from "@docspace/components/themes"; + +import { smallTablet } from "../../utils/device"; +import Tag from "../../tag"; +import { Base } from "../../themes"; const StyledPreviewTile = styled.div` background: ${(props) => @@ -73,7 +73,7 @@ const StyledPreviewTile = styled.div` `; StyledPreviewTile.defaultProps = { theme: Base }; -const PreviewTile = ({ t, title, previewIcon, tags, defaultTagLabel }) => { +const PreviewTile = ({ title, previewIcon, tags, defaultTagLabel }) => { return (
diff --git a/packages/components/ImageEditor/index.js b/packages/components/ImageEditor/index.js new file mode 100644 index 0000000000..465b45ed21 --- /dev/null +++ b/packages/components/ImageEditor/index.js @@ -0,0 +1,47 @@ +import React from "react"; +import Dropzone from "./Dropzone"; +import ImageCropper from "./ImageCropper"; + +const ImageEditor = ({ + t, + image, + onChangeImage, + Preview, + setPreview, + isDisabled, + classNameWrapperImageCropper, + className, +}) => { + const setUploadedFile = (uploadedFile) => + onChangeImage({ ...image, uploadedFile }); + + const isDefaultAvatar = + typeof image.uploadedFile === "string" && + image.uploadedFile.includes("default_user_photo"); + + return ( +
+ {image.uploadedFile && !isDefaultAvatar && ( +
+ + {Preview} +
+ )} + +
+ ); +}; + +export default ImageEditor; From c9c523261f29c89d36194697db7de3131db88a2f Mon Sep 17 00:00:00 2001 From: Timofey Boyko <55255132+TimofeyBoyko@users.noreply.github.com> Date: Mon, 9 Jan 2023 10:09:37 +0300 Subject: [PATCH 2/3] Fixed Bug 60407 - Files. The button for calling the sort menu settings does not work when opening the information panel. --- .../table-container/StyledTableContainer.js | 17 +++++++++++++++++ .../components/table-container/TableSettings.js | 9 ++++++--- packages/components/themes/base.js | 6 ++++-- packages/components/themes/dark.js | 6 ++++-- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/components/table-container/StyledTableContainer.js b/packages/components/table-container/StyledTableContainer.js index 78eec7fce5..919c8970aa 100644 --- a/packages/components/table-container/StyledTableContainer.js +++ b/packages/components/table-container/StyledTableContainer.js @@ -1,6 +1,7 @@ import styled, { css } from "styled-components"; import Base from "../themes/base"; import { mobile, tablet, hugeMobile } from "../utils/device"; +import IconButton from "../icon-button"; import Scrollbar from "../scrollbar"; import { isMobile, isMobileOnly } from "react-device-detect"; @@ -412,6 +413,21 @@ const StyledScrollbar = styled(Scrollbar)` StyledTableRow.defaultProps = { theme: Base }; +const StyledSettingsIcon = styled(IconButton)` + ${(props) => + props.isDisabled && + css` + svg { + path { + fill: ${props.theme.tableContainer.header + .settingsIconDisableColor} !important; + } + } + `} +`; + +StyledSettingsIcon.defaultProps = { theme: Base }; + export { StyledTableContainer, StyledTableRow, @@ -424,4 +440,5 @@ export { StyledInfoPanelToggleWrapper, StyledEmptyTableContainer, StyledScrollbar, + StyledSettingsIcon, }; diff --git a/packages/components/table-container/TableSettings.js b/packages/components/table-container/TableSettings.js index b0c07d3c04..6879994cc1 100644 --- a/packages/components/table-container/TableSettings.js +++ b/packages/components/table-container/TableSettings.js @@ -1,8 +1,11 @@ import React, { useRef, useState } from "react"; import PropTypes from "prop-types"; -import IconButton from "../icon-button"; +// import IconButton from "../icon-button"; import DropDown from "../drop-down"; -import { StyledTableSettings } from "./StyledTableContainer"; +import { + StyledTableSettings, + StyledSettingsIcon, +} from "./StyledTableContainer"; import Checkbox from "../checkbox"; const TableSettings = ({ columns, infoPanelVisible }) => { @@ -27,7 +30,7 @@ const TableSettings = ({ columns, infoPanelVisible }) => { className="table-container_header-settings-icon" ref={ref} > - Date: Mon, 9 Jan 2023 10:46:54 +0300 Subject: [PATCH 3/3] Fixed Bug 60176 - Rooms. The menu of rooms/subfolders on the panel and in the header does not match the layouts. --- .../src/pages/Home/InfoPanel/Body/helpers/ContextHelper.js | 6 +++++- packages/client/src/store/ContextOptionsStore.js | 4 ++-- packages/client/src/store/TreeFoldersStore.js | 5 ++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/client/src/pages/Home/InfoPanel/Body/helpers/ContextHelper.js b/packages/client/src/pages/Home/InfoPanel/Body/helpers/ContextHelper.js index e1cb9dba43..1babbe1744 100644 --- a/packages/client/src/pages/Home/InfoPanel/Body/helpers/ContextHelper.js +++ b/packages/client/src/pages/Home/InfoPanel/Body/helpers/ContextHelper.js @@ -87,7 +87,11 @@ class ContextHelper { this.selection.options || [], this.selection ) - : this.getContextOptionActions(this.selection, this.t); + : this.getContextOptionActions( + this.selection, + this.t, + this.selection.isSelectedFolder + ); }; } diff --git a/packages/client/src/store/ContextOptionsStore.js b/packages/client/src/store/ContextOptionsStore.js index c994fce4ff..141af9e371 100644 --- a/packages/client/src/store/ContextOptionsStore.js +++ b/packages/client/src/store/ContextOptionsStore.js @@ -493,7 +493,7 @@ class ContextOptionsStore { onSelectItem({ id: item.id, isFolder: item.isFolder }, true, false); }; - getFilesContextOptions = (item, t) => { + getFilesContextOptions = (item, t, isInfoPanel) => { const { contextOptions } = item; const { id, rootFolderId } = this.selectedFolderStore; const { enablePlugins } = this.authStore.settingsStore; @@ -582,7 +582,7 @@ class ContextOptionsStore { }, ]; const moveActions = - !isMobile && !isMobileUtils() && !isTabletUtils() + !isMobile && !isMobileUtils() && !isTabletUtils() && !isInfoPanel ? [ { id: "option_move-or-copy", diff --git a/packages/client/src/store/TreeFoldersStore.js b/packages/client/src/store/TreeFoldersStore.js index 6cbb92702c..fe982eae73 100644 --- a/packages/client/src/store/TreeFoldersStore.js +++ b/packages/client/src/store/TreeFoldersStore.js @@ -136,7 +136,10 @@ class TreeFoldersStore { } get isPersonalRoom() { - return this.myFolder && this.myFolder.id === this.selectedFolderStore.id; + return ( + this.myFolder && + this.myFolder.rootFolderType === this.selectedFolderStore.rootFolderType + ); } get isShareFolder() {