From 8612cc5ce7d1b54c173faa7f757a42bac81b218a Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Sat, 19 Oct 2019 19:42:39 +0700 Subject: [PATCH] video node editor --- src/components/bars/SubmitBar/index.tsx | 7 +++- src/components/editors/VideoEditor/index.tsx | 40 +++++++++++++++++++ .../editors/VideoEditor/styles.scss | 30 ++++++++++++++ .../editors/EditorDialogVideo/index.tsx | 10 +++++ .../editors/EditorDialogVideo/styles.scss | 0 src/redux/flow/sagas.ts | 6 +-- src/redux/modal/constants.ts | 4 ++ src/redux/node/constants.ts | 2 + src/redux/types.ts | 2 +- src/sprites/Sprites.tsx | 10 +++++ 10 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 src/components/editors/VideoEditor/index.tsx create mode 100644 src/components/editors/VideoEditor/styles.scss create mode 100644 src/containers/editors/EditorDialogVideo/index.tsx create mode 100644 src/containers/editors/EditorDialogVideo/styles.scss diff --git a/src/components/bars/SubmitBar/index.tsx b/src/components/bars/SubmitBar/index.tsx index d5952c43..d9ae30f1 100644 --- a/src/components/bars/SubmitBar/index.tsx +++ b/src/components/bars/SubmitBar/index.tsx @@ -18,6 +18,7 @@ type IProps = typeof mapDispatchToProps & {}; const SubmitBarUnconnected: FC = ({ nodeCreate }) => { const onOpenImageEditor = useCallback(() => nodeCreate(NODE_TYPES.IMAGE), [nodeCreate]); const onOpenTextEditor = useCallback(() => nodeCreate(NODE_TYPES.TEXT), [nodeCreate]); + const onOpenVideoEditor = useCallback(() => nodeCreate(NODE_TYPES.VIDEO), [nodeCreate]); return (
@@ -27,7 +28,11 @@ const SubmitBarUnconnected: FC = ({ nodeCreate }) => {
- + +
+ +
+
diff --git a/src/components/editors/VideoEditor/index.tsx b/src/components/editors/VideoEditor/index.tsx new file mode 100644 index 00000000..7409b1d9 --- /dev/null +++ b/src/components/editors/VideoEditor/index.tsx @@ -0,0 +1,40 @@ +import React, { FC, useCallback, useMemo } from 'react'; +import { INode } from '~/redux/types'; +import * as styles from './styles.scss'; +import path from 'ramda/es/path'; +import { InputText } from '~/components/input/InputText'; + +interface IProps { + data: INode; + setData: (val: INode) => void; +} + +const VideoEditor: FC = ({ data, setData }) => { + const setUrl = useCallback( + (url: string) => setData({ ...data, blocks: [{ type: 'video', url }] }), + [data, setData] + ); + + const url = (path(['blocks', 0, 'url'], data) as string) || ''; + const preview = useMemo(() => { + const match = + url && + url.match( + /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?/ + ); + + return match && match[1] ? `http://img.youtube.com/vi/${match[1]}/maxresdefault.jpg` : null; + }, [url]); + + return ( +
+
+
+ +
+
+
+ ); +}; + +export { VideoEditor }; diff --git a/src/components/editors/VideoEditor/styles.scss b/src/components/editors/VideoEditor/styles.scss new file mode 100644 index 00000000..ce800aa2 --- /dev/null +++ b/src/components/editors/VideoEditor/styles.scss @@ -0,0 +1,30 @@ +.preview { + padding-top: 56.25%; + position: relative; + // background: darken($color: $content_bg, $amount: 2%); +} + +.input_wrap { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.input { + // @include outer_shadow(); + + flex: 1 0 50%; + padding: $gap * 2 $gap $gap * 2 $gap; + // border-radius: $radius; + background: $content_bg; + // margin: 20px; + + input { + text-align: center; + } +} diff --git a/src/containers/editors/EditorDialogVideo/index.tsx b/src/containers/editors/EditorDialogVideo/index.tsx new file mode 100644 index 00000000..092c688f --- /dev/null +++ b/src/containers/editors/EditorDialogVideo/index.tsx @@ -0,0 +1,10 @@ +import React, { FC } from 'react'; +import { EditorDialog } from '~/containers/dialogs/EditorDialog'; +import { IDialogProps } from '~/redux/types'; +import { NODE_TYPES } from '~/redux/node/constants'; + +type IProps = IDialogProps & {}; + +const EditorDialogVideo: FC = props => ; + +export { EditorDialogVideo }; diff --git a/src/containers/editors/EditorDialogVideo/styles.scss b/src/containers/editors/EditorDialogVideo/styles.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/redux/flow/sagas.ts b/src/redux/flow/sagas.ts index cb621c23..a52cb975 100644 --- a/src/redux/flow/sagas.ts +++ b/src/redux/flow/sagas.ts @@ -13,13 +13,11 @@ function* onGetFlow() { }: IResultWithStatus<{ nodes: INode[] }> = yield call(getNodes, {}); if (!nodes || !nodes.length) { - // todo: set error empty response + yield put(flowSetNodes([])); + return; } - // todo: write nodes yield put(flowSetNodes(nodes)); - - // console.log('flow', { nodes, error }); } export default function* nodeSaga() { diff --git a/src/redux/modal/constants.ts b/src/redux/modal/constants.ts index 2bde90a2..fa3b53c5 100644 --- a/src/redux/modal/constants.ts +++ b/src/redux/modal/constants.ts @@ -2,6 +2,7 @@ import { ValueOf } from '~/redux/types'; import { LoginDialog } from '~/containers/dialogs/LoginDialog'; import { EditorDialogImage } from '~/containers/editors/EditorDialogImage'; import { EditorDialogText } from '~/containers/editors/EditorDialogText'; +import { EditorDialogVideo } from '~/containers/editors/EditorDialogVideo'; import { NODE_TYPES } from '../node/constants'; export const MODAL_ACTIONS = { @@ -13,18 +14,21 @@ export const MODAL_ACTIONS = { export const DIALOGS = { EDITOR_IMAGE: 'EDITOR_IMAGE', EDITOR_TEXT: 'EDITOR_TEXT', + EDITOR_VIDEO: 'EDITOR_VIDEO', LOGIN: 'LOGIN', }; export const DIALOG_CONTENT = { [DIALOGS.EDITOR_IMAGE]: EditorDialogImage, [DIALOGS.EDITOR_TEXT]: EditorDialogText, + [DIALOGS.EDITOR_VIDEO]: EditorDialogVideo, [DIALOGS.LOGIN]: LoginDialog, }; export const NODE_EDITOR_DIALOGS = { [NODE_TYPES.IMAGE]: DIALOGS.EDITOR_IMAGE, [NODE_TYPES.TEXT]: DIALOGS.EDITOR_TEXT, + [NODE_TYPES.VIDEO]: DIALOGS.EDITOR_VIDEO, }; export interface IDialogProps { diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts index 8f08cce4..4278f0a2 100644 --- a/src/redux/node/constants.ts +++ b/src/redux/node/constants.ts @@ -4,6 +4,7 @@ import { NodeImageSlideBlock } from '~/components/node/NodeImageSlideBlock'; import { NodeTextBlock } from '~/components/node/NodeTextBlock'; import { ImageEditor } from '~/components/editors/ImageEditor'; import { TextEditor } from '~/components/editors/TextEditor'; +import { VideoEditor } from '~/components/editors/VideoEditor'; const prefix = 'NODE.'; export const NODE_ACTIONS = { @@ -82,6 +83,7 @@ export const EMPTY_COMMENT: IComment = { export const NODE_EDITORS = { [NODE_TYPES.IMAGE]: ImageEditor, [NODE_TYPES.TEXT]: TextEditor, + [NODE_TYPES.VIDEO]: VideoEditor, }; export const NODE_EDITOR_DATA: Record< diff --git a/src/redux/types.ts b/src/redux/types.ts index 7c05e93d..65cc711f 100644 --- a/src/redux/types.ts +++ b/src/redux/types.ts @@ -100,7 +100,7 @@ export interface IBlockText { } export interface IBlockEmbed { - type: 'embed'; + type: 'video'; url: string; } diff --git a/src/sprites/Sprites.tsx b/src/sprites/Sprites.tsx index bba02120..6c97ebdd 100644 --- a/src/sprites/Sprites.tsx +++ b/src/sprites/Sprites.tsx @@ -98,6 +98,16 @@ const Sprites: FC<{}> = () => ( + + + + + + + + + + );