diff --git a/src/components/editors/AudioEditor/styles.scss b/src/components/editors/AudioEditor/styles.scss index 4909ae19..c32787d8 100644 --- a/src/components/editors/AudioEditor/styles.scss +++ b/src/components/editors/AudioEditor/styles.scss @@ -1,4 +1,4 @@ .wrap { - padding-bottom: 64px; + padding-bottom: $upload_button_height + $gap; min-height: 200px; } diff --git a/src/components/editors/EditorUploadButton/index.tsx b/src/components/editors/EditorUploadButton/index.tsx index c69dc3cf..c25acf68 100644 --- a/src/components/editors/EditorUploadButton/index.tsx +++ b/src/components/editors/EditorUploadButton/index.tsx @@ -54,8 +54,6 @@ const EditorUploadButtonUnconnected: FC = ({ if (current >= NODE_SETTINGS.MAX_FILES) return; - console.log({ type }); - const items: IFileWithUUID[] = Array.from(uploads).map( (file: File): IFileWithUUID => ({ file, diff --git a/src/components/editors/EditorUploadButton/styles.scss b/src/components/editors/EditorUploadButton/styles.scss index 629c551b..c793e1c6 100644 --- a/src/components/editors/EditorUploadButton/styles.scss +++ b/src/components/editors/EditorUploadButton/styles.scss @@ -1,14 +1,16 @@ .wrap { - width: 52px; - height: 52px; - border-radius: 32px !important; + @include outer_shadow(); + + width: $upload_button_height; + height: $upload_button_height; + border-radius: ($upload_button_height / 2) !important; position: relative; border-radius: $radius; cursor: pointer; // opacity: 0.7; transition: opacity 0.5s; background: $red_gradient; - box-shadow: $content_bg 0 0 5px 10px; + // box-shadow: $content_bg 0 0 5px 10px; &:hover { opacity: 1; @@ -35,4 +37,4 @@ display: flex; align-items: center; justify-content: center; -} \ No newline at end of file +} diff --git a/src/components/editors/EditorUploadCoverButton/index.tsx b/src/components/editors/EditorUploadCoverButton/index.tsx new file mode 100644 index 00000000..dc8fc43c --- /dev/null +++ b/src/components/editors/EditorUploadCoverButton/index.tsx @@ -0,0 +1,111 @@ +import React, { FC, useState, useCallback, useEffect } from 'react'; +import { INode, IFileWithUUID } from '~/redux/types'; +import uuid from 'uuid4'; +import * as styles from './styles.scss'; +import { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from '~/redux/uploads/constants'; +import path from 'ramda/es/path'; +import { connect } from 'react-redux'; +import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; +import { selectUploads } from '~/redux/uploads/selectors'; +import { getURL } from '~/utils/dom'; +import { Icon } from '~/components/input/Icon'; + +const mapStateToProps = state => { + const { statuses, files } = selectUploads(state); + + return { statuses, files }; +}; + +const mapDispatchToProps = { + uploadUploadFiles: UPLOAD_ACTIONS.uploadUploadFiles, +}; + +type IProps = ReturnType & + typeof mapDispatchToProps & { + data: INode; + setData: (data: INode) => void; + temp: string[]; + setTemp: (val: string[]) => void; + }; + +const EditorUploadCoverButtonUnconnected: FC = ({ + data, + setData, + files, + statuses, + uploadUploadFiles, +}) => { + const [cover_temp, setCoverTemp] = useState(null); + + useEffect(() => { + Object.entries(statuses).forEach(([id, status]) => { + if (cover_temp === id && !!status.uuid && files[status.uuid]) { + setData({ ...data, cover: files[status.uuid] }); + setCoverTemp(null); + } + }); + }, [statuses, files, cover_temp, setData, data]); + + const onUpload = useCallback( + (uploads: File[]) => { + const items: IFileWithUUID[] = Array.from(uploads).map( + (file: File): IFileWithUUID => ({ + file, + temp_id: uuid(), + subject: UPLOAD_SUBJECTS.EDITOR, + target: UPLOAD_TARGETS.NODES, + type: UPLOAD_TYPES.IMAGE, + }) + ); + + setCoverTemp(path([0, 'temp_id'], items)); + uploadUploadFiles(items); + }, + [uploadUploadFiles, setCoverTemp] + ); + + const onInputChange = useCallback( + event => { + event.preventDefault(); + + if (!event.target.files || !event.target.files.length) return; + + onUpload(Array.from(event.target.files)); + }, + [onUpload] + ); + const onDropCover = useCallback(() => { + setData({ ...data, cover: null }); + }, [setData, data]); + + const background = data.cover ? getURL(data.cover) : null; + const status = cover_temp && path([cover_temp], statuses); + const preview = status && path(['preview'], status); + + return ( +
+
+
+ {!data.cover && ОБЛОЖКА} + +
+ + {data.cover && ( +
+ +
+ )} +
+
+ ); +}; + +const EditorUploadCoverButton = connect( + mapStateToProps, + mapDispatchToProps +)(EditorUploadCoverButtonUnconnected); + +export { EditorUploadCoverButton }; diff --git a/src/components/editors/EditorUploadCoverButton/styles.scss b/src/components/editors/EditorUploadCoverButton/styles.scss new file mode 100644 index 00000000..ccb396ec --- /dev/null +++ b/src/components/editors/EditorUploadCoverButton/styles.scss @@ -0,0 +1,80 @@ +.wrap { + @include outer_shadow(); + + height: $upload_button_height; + border-radius: ($upload_button_height / 2) !important; + position: relative; + border-radius: $radius; + cursor: pointer; + transition: opacity 0.5s; + background: lighten($content_bg, 4%); + flex: 0 1 $upload_button_height * 4; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + opacity: 1; + } + + input { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + opacity: 0; + z-index: 2; + cursor: pointer; + } +} + +.input { + position: relative; + height: 100%; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + font: $font_16_medium; + text-shadow: rgba(0, 0, 0, 0.5) 0 1px; +} + +.preview { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 1; + border-radius: ($upload_button_height / 2) !important; + background: 50% 50% no-repeat; + background-size: cover; + display: flex; + align-items: center; + flex-direction: row; + justify-content: flex-end; +} + +.button { + width: $upload_button_height; + flex: 0 0 $upload_button_height; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + box-shadow: inset rgba(255, 255, 255, 0.05) 1px 1px, rgba(0, 0, 0, 0.3) -1px 0; + border-radius: $upload_button_height; + background: transparentize($color: lighten($content_bg, 4%), $amount: 0); + + &:hover { + svg { + fill: $red; + } + } + + svg { + width: 32px; + height: 32px; + } +} diff --git a/src/components/editors/ImageEditor/styles.scss b/src/components/editors/ImageEditor/styles.scss index 6ca09dc5..e5bcef09 100644 --- a/src/components/editors/ImageEditor/styles.scss +++ b/src/components/editors/ImageEditor/styles.scss @@ -1,4 +1,4 @@ .wrap { min-height: 200px; - padding-bottom: 60px; + padding-bottom: $upload_button_height + $gap; } diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts index c5900ebb..e5c79811 100644 --- a/src/redux/node/constants.ts +++ b/src/redux/node/constants.ts @@ -11,6 +11,7 @@ import { VideoEditor } from '~/components/editors/VideoEditor'; import { AudioEditor } from '~/components/editors/AudioEditor'; import { EditorImageUploadButton } from '~/components/editors/EditorImageUploadButton'; import { EditorAudioUploadButton } from '~/components/editors/EditorAudioUploadButton'; +import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton'; const prefix = 'NODE.'; export const NODE_ACTIONS = { @@ -98,7 +99,7 @@ export const NODE_EDITORS = { }; export const NODE_PANEL_COMPONENTS = { - [NODE_TYPES.IMAGE]: [EditorImageUploadButton], + [NODE_TYPES.IMAGE]: [EditorImageUploadButton, EditorUploadCoverButton], [NODE_TYPES.AUDIO]: [EditorAudioUploadButton, EditorImageUploadButton], }; diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 66e8f78a..6af3bd4e 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -26,6 +26,8 @@ $medium: 500; $light: 300; $extra_light: 200; +$upload_button_height: 52px; + $font: Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';