1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

#57 added block-based content editor

This commit is contained in:
Fedor Katurov 2021-03-26 16:38:08 +07:00
parent d8c379de6a
commit 868d1f948a
9 changed files with 117 additions and 21 deletions

View file

@ -0,0 +1,17 @@
import React, { FC } from 'react';
import styles from './styles.module.scss';
import { Button } from '~/components/input/Button';
interface IProps {}
const NewEditorBetweenBlocks: FC<IProps> = () => {
return (
<div className={styles.buttons}>
<div className={styles.buttons_content}>
<Button iconLeft="plus" round />
</div>
</div>
);
};
export { NewEditorBetweenBlocks };

View file

@ -0,0 +1,12 @@
.buttons {
height: 0;
position: relative;
&_content {
position: absolute;
bottom: -10px;
right: 0;
z-index: 2;
}
}

View file

@ -0,0 +1,42 @@
import React, { createElement, FC, Fragment, useCallback } from 'react';
import { IBlock } from '~/redux/types';
import { prop } from 'ramda';
import { EDITOR_BLOCKS } from '~/redux/node/constants';
import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik';
import { NewEditorBetweenBlocks } from '~/containers/editors/NewEditorBetweenBlocks';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
interface IProps {
block: IBlock;
index: number;
}
const NewEditorBlock: FC<IProps> = ({ block, index }) => {
const { values, setFieldValue } = useNodeFormContext();
const handler = useCallback(
(val: IBlock) =>
setFieldValue(
'blocks',
values.blocks.map((el, i) => (i === index ? val : el))
),
[setFieldValue, values.blocks]
);
if (!prop(block.type, EDITOR_BLOCKS)) {
return null;
}
return (
<div className={styles.block}>
{prop(block.type, EDITOR_BLOCKS)
? createElement(prop(block.type, EDITOR_BLOCKS), { block, handler })
: null}
<NewEditorBetweenBlocks />
</div>
);
};
export { NewEditorBlock };

View file

@ -0,0 +1,8 @@
@import "~/styles/variables.scss";
.block {
}
.pad {
margin-bottom: $gap;
}

View file

@ -1,6 +1,7 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import { BlockType, IBlockComponentProps } from '~/redux/types'; import { BlockType, IBlockComponentProps } from '~/redux/types';
import { InputText } from '~/components/input/InputText'; import { InputText } from '~/components/input/InputText';
import styles from './styles.module.scss';
const NewEditorBlockText: FC<IBlockComponentProps> = ({ block, handler }) => { const NewEditorBlockText: FC<IBlockComponentProps> = ({ block, handler }) => {
const onChange = useCallback((text: string) => handler({ type: BlockType.text, text }), [ const onChange = useCallback((text: string) => handler({ type: BlockType.text, text }), [
@ -8,7 +9,7 @@ const NewEditorBlockText: FC<IBlockComponentProps> = ({ block, handler }) => {
]); ]);
return ( return (
<div> <div className={styles.wrap}>
<InputText handler={onChange} value={block.text} /> <InputText handler={onChange} value={block.text} />
</div> </div>
); );

View file

@ -0,0 +1,6 @@
@import "~/styles/variables.scss";
.wrap {
padding: $gap;
background-color: transparentize($content_bg, 0.9);
}

View file

@ -1,32 +1,31 @@
import React, { createElement, FC, useCallback, useMemo } from 'react'; import React, { FC } from 'react';
import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik'; import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik';
import { NODE_EDITOR_BLOCKS } from '~/redux/node/constants';
import { has, prop } from 'ramda';
import styles from './styles.module.scss'; import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import { NewEditorBlock } from '~/containers/editors/NewEditorBlock';
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
import { IBlock } from '~/redux/types'; import { IBlock } from '~/redux/types';
interface IProps {} interface IProps {}
const NewEditorContent: FC<IProps> = () => { const SortableItem = SortableElement(({ value, index }: { value: IBlock; index: number }) => (
const { values, setFieldValue } = useNodeFormContext(); <NewEditorBlock index={index} block={value} />
));
const onChange = useCallback( const SortableList = SortableContainer(({ items }: { items: IBlock[] }) => (
(index: number) => (val: IBlock) => <div>
setFieldValue( {items.map((block, i) => (
'blocks', <SortableItem key={i} index={i} value={block} />
values.blocks.map((el, i) => (i === index ? val : el)) ))}
), </div>
[setFieldValue, values.blocks] ));
);
const NewEditorContent: FC<IProps> = () => {
const { values } = useNodeFormContext();
return ( return (
<Group className={styles.wrap}> <Group className={styles.wrap}>
{values.blocks.map((block, i) => <SortableList items={values.blocks} />
prop(block.type, NODE_EDITOR_BLOCKS)
? createElement(prop(block.type, NODE_EDITOR_BLOCKS), { block, handler: onChange(i) })
: null
)}
</Group> </Group>
); );
}; };

View file

@ -1,5 +1,4 @@
@import "~/styles/variables.scss"; @import "~/styles/variables.scss";
.wrap { .wrap {
padding: $gap;
} }

View file

@ -134,11 +134,23 @@ export interface NodeEditorBlockConfig {
initial?: boolean; initial?: boolean;
} }
export const NODE_EDITOR_BLOCKS: Record<BlockType, FC<IBlockComponentProps>> = { export const EDITOR_BLOCKS: Record<BlockType, FC<IBlockComponentProps>> = {
[BlockType.video]: NewEditorBlockVideo, [BlockType.video]: NewEditorBlockVideo,
[BlockType.text]: NewEditorBlockText, [BlockType.text]: NewEditorBlockText,
}; };
export const NODE_BLOCKS: Record<
string,
Partial<Record<BlockType, { limit?: number; initial?: boolean }>>
> = {
[NODE_TYPES.TEXT]: {
[BlockType.text]: {
limit: 1,
initial: true,
},
},
};
export const NODE_PANEL_COMPONENTS: Record<string, FC<IEditorComponentProps>[]> = { export const NODE_PANEL_COMPONENTS: Record<string, FC<IEditorComponentProps>[]> = {
[NODE_TYPES.TEXT]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch], [NODE_TYPES.TEXT]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch],
[NODE_TYPES.VIDEO]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch], [NODE_TYPES.VIDEO]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch],