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:
parent
d8c379de6a
commit
868d1f948a
9 changed files with 117 additions and 21 deletions
17
src/containers/editors/NewEditorBetweenBlocks/index.tsx
Normal file
17
src/containers/editors/NewEditorBetweenBlocks/index.tsx
Normal 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 };
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
.buttons {
|
||||
height: 0;
|
||||
position: relative;
|
||||
|
||||
&_content {
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
42
src/containers/editors/NewEditorBlock/index.tsx
Normal file
42
src/containers/editors/NewEditorBlock/index.tsx
Normal 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 };
|
8
src/containers/editors/NewEditorBlock/styles.module.scss
Normal file
8
src/containers/editors/NewEditorBlock/styles.module.scss
Normal file
|
@ -0,0 +1,8 @@
|
|||
@import "~/styles/variables.scss";
|
||||
|
||||
.block {
|
||||
}
|
||||
|
||||
.pad {
|
||||
margin-bottom: $gap;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
import { BlockType, IBlockComponentProps } from '~/redux/types';
|
||||
import { InputText } from '~/components/input/InputText';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
const NewEditorBlockText: FC<IBlockComponentProps> = ({ block, handler }) => {
|
||||
const onChange = useCallback((text: string) => handler({ type: BlockType.text, text }), [
|
||||
|
@ -8,7 +9,7 @@ const NewEditorBlockText: FC<IBlockComponentProps> = ({ block, handler }) => {
|
|||
]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.wrap}>
|
||||
<InputText handler={onChange} value={block.text} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@import "~/styles/variables.scss";
|
||||
|
||||
.wrap {
|
||||
padding: $gap;
|
||||
background-color: transparentize($content_bg, 0.9);
|
||||
}
|
|
@ -1,32 +1,31 @@
|
|||
import React, { createElement, FC, useCallback, useMemo } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
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 { Group } from '~/components/containers/Group';
|
||||
import { NewEditorBlock } from '~/containers/editors/NewEditorBlock';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
import { IBlock } from '~/redux/types';
|
||||
|
||||
interface IProps {}
|
||||
|
||||
const NewEditorContent: FC<IProps> = () => {
|
||||
const { values, setFieldValue } = useNodeFormContext();
|
||||
const SortableItem = SortableElement(({ value, index }: { value: IBlock; index: number }) => (
|
||||
<NewEditorBlock index={index} block={value} />
|
||||
));
|
||||
|
||||
const onChange = useCallback(
|
||||
(index: number) => (val: IBlock) =>
|
||||
setFieldValue(
|
||||
'blocks',
|
||||
values.blocks.map((el, i) => (i === index ? val : el))
|
||||
),
|
||||
[setFieldValue, values.blocks]
|
||||
);
|
||||
const SortableList = SortableContainer(({ items }: { items: IBlock[] }) => (
|
||||
<div>
|
||||
{items.map((block, i) => (
|
||||
<SortableItem key={i} index={i} value={block} />
|
||||
))}
|
||||
</div>
|
||||
));
|
||||
|
||||
const NewEditorContent: FC<IProps> = () => {
|
||||
const { values } = useNodeFormContext();
|
||||
|
||||
return (
|
||||
<Group className={styles.wrap}>
|
||||
{values.blocks.map((block, i) =>
|
||||
prop(block.type, NODE_EDITOR_BLOCKS)
|
||||
? createElement(prop(block.type, NODE_EDITOR_BLOCKS), { block, handler: onChange(i) })
|
||||
: null
|
||||
)}
|
||||
<SortableList items={values.blocks} />
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
@import "~/styles/variables.scss";
|
||||
|
||||
.wrap {
|
||||
padding: $gap;
|
||||
}
|
||||
|
|
|
@ -134,11 +134,23 @@ export interface NodeEditorBlockConfig {
|
|||
initial?: boolean;
|
||||
}
|
||||
|
||||
export const NODE_EDITOR_BLOCKS: Record<BlockType, FC<IBlockComponentProps>> = {
|
||||
export const EDITOR_BLOCKS: Record<BlockType, FC<IBlockComponentProps>> = {
|
||||
[BlockType.video]: NewEditorBlockVideo,
|
||||
[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>[]> = {
|
||||
[NODE_TYPES.TEXT]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch],
|
||||
[NODE_TYPES.VIDEO]: [EditorFiller, EditorUploadCoverButton, EditorPublicSwitch],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue