diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/BulletedListBlock/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/BulletedListBlock/index.tsx new file mode 100644 index 0000000000..880fb29337 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/BulletedListBlock/index.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { BlockType, NestedBlock } from '$app/interfaces/document'; +import { Circle } from '@mui/icons-material'; +import TextBlock from '$app/components/document/TextBlock'; +import NodeChildren from '$app/components/document/Node/NodeChildren'; + +function BulletedListBlock({ node, childIds }: { node: NestedBlock; childIds?: string[] }) { + return ( + <> +
+
+ +
+
+ +
+
+ + + ); +} + +export default BulletedListBlock; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnBlock/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/Column.tsx similarity index 82% rename from frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnBlock/index.tsx rename to frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/Column.tsx index cd12b16f06..f88031e64f 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnBlock/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/Column.tsx @@ -1,7 +1,7 @@ +import NodeComponent from '$app/components/document/Node'; import React from 'react'; -import NodeComponent from '../Node'; -export default function ColumnBlock({ id, index, width }: { id: string; index: number; width: string }) { +export function ColumnBlock({ id, index, width }: { id: string; index: number; width: string }) { const renderResizer = () => { return (
diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/ColumnListBlock.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/index.tsx similarity index 94% rename from frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/ColumnListBlock.tsx rename to frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/index.tsx index b39905545d..b0c406908b 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/ColumnListBlock.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/ColumnListBlock/index.tsx @@ -1,7 +1,6 @@ import React, { useMemo } from 'react'; -import ColumnBlock from '../ColumnBlock'; - import { Node } from '$app/interfaces/document'; +import { ColumnBlock } from './Column'; export default function ColumnListBlock({ node, diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/BulletedListBlock.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/BulletedListBlock.tsx deleted file mode 100644 index 0555d1f116..0000000000 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/BulletedListBlock.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Circle } from '@mui/icons-material'; -import NodeComponent from '../Node'; -import { Node } from '$app/interfaces/document'; - -export default function BulletedListBlock({ - title, - node, - childIds, -}: { - title: JSX.Element; - node: Node; - childIds?: string[]; -}) { - return ( -
-
-
- -
- {title} -
- -
- {childIds?.map((item) => ( - - ))} -
-
- ); -} diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/NumberedListBlock.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/NumberedListBlock.tsx deleted file mode 100644 index 774397c8dc..0000000000 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/NumberedListBlock.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import NodeComponent from '../Node'; -import { Node } from '$app/interfaces/document'; - -export default function NumberedListBlock({ - title, - node, - childIds, -}: { - title: JSX.Element; - node: Node; - childIds?: string[]; -}) { - const index = 1; - return ( -
-
-
{`${index} .`}
- {title} -
- -
- {childIds?.map((item) => ( - - ))} -
-
- ); -} diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/index.tsx deleted file mode 100644 index 37af080afe..0000000000 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/ListBlock/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, { useMemo } from 'react'; -import TextBlock from '../TextBlock'; -import NumberedListBlock from './NumberedListBlock'; -import BulletedListBlock from './BulletedListBlock'; -import ColumnListBlock from './ColumnListBlock'; -import { Node, TextDelta } from '@/appflowy_app/interfaces/document'; - -export default function ListBlock({ node }: { node: Node }) { - const title = useMemo(() => { - // if (node.data.style?.type === 'column') return <>; - return
{/**/}
; - }, [node]); - - // if (node.data.type === 'numbered') { - // return ; - // } - // - // if (node.data.type === 'bulleted') { - // return ; - // } - // - // if (node.data.type === 'column') { - // return ; - // } - - return null; -} diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx index 0c4adaa14a..d6fde477f1 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/Node/index.tsx @@ -8,6 +8,9 @@ import { BlockType } from '$app/interfaces/document'; import HeadingBlock from '$app/components/document/HeadingBlock'; import TodoListBlock from '$app/components/document/TodoListBlock'; import QuoteBlock from '$app/components/document/QuoteBlock'; +import BulletedListBlock from '$app/components/document/BulletedListBlock'; +import NumberedListBlock from '$app/components/document/NumberedListBlock'; +import { Alert } from '@mui/material'; function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes) { const { node, childIds, isSelected, ref } = useNode(id); @@ -26,8 +29,18 @@ function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes; } + case BlockType.BulletedListBlock: { + return ; + } + case BlockType.NumberedListBlock: { + return ; + } default: - return null; + return ( + +

The current version does not support this Block.

+
+ ); } }, [node, childIds]); diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/NumberedListBlock.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/NumberedListBlock.hooks.ts new file mode 100644 index 0000000000..39bf073c35 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/NumberedListBlock.hooks.ts @@ -0,0 +1,26 @@ +import { useAppSelector } from '$app/stores/store'; +import { BlockType, NestedBlock } from '$app/interfaces/document'; + +export function useNumberedListBlock(node: NestedBlock) { + // Find the last index of the previous blocks + const prevNumberedIndex = useAppSelector((state) => { + const nodes = state['document'].nodes; + const children = state['document'].children; + // The parent must be existed + const parent = nodes[node.parent!]; + const siblings = children[parent.children]; + const index = siblings.indexOf(node.id); + if (index === 0) return 0; + const prevNodeIds = siblings.slice(0, index); + // The index is distance from last block to the last non-numbered-list block + const lastIndex = prevNodeIds.reverse().findIndex((id) => { + return nodes[id].type !== BlockType.NumberedListBlock; + }); + if (lastIndex === -1) return prevNodeIds.length; + return lastIndex; + }); + + return { + index: prevNumberedIndex + 1, + }; +} diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/index.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/index.tsx new file mode 100644 index 0000000000..28c9028c8f --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/NumberedListBlock/index.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { BlockType, NestedBlock } from '$app/interfaces/document'; +import TextBlock from '$app/components/document/TextBlock'; +import NodeChildren from '$app/components/document/Node/NodeChildren'; +import { useNumberedListBlock } from '$app/components/document/NumberedListBlock/NumberedListBlock.hooks'; + +function NumberedListBlock({ node, childIds }: { node: NestedBlock; childIds?: string[] }) { + const { index } = useNumberedListBlock(node); + + return ( + <> +
+
+ {index}. +
+
+ +
+
+ + + ); +} + +export default NumberedListBlock; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/events/TurnIntoEvents.hooks.ts b/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/events/TurnIntoEvents.hooks.ts index 50d34cfddd..4983a1dc70 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/events/TurnIntoEvents.hooks.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/components/document/TextBlock/events/TurnIntoEvents.hooks.ts @@ -7,12 +7,20 @@ import { turnToBlockThunk } from '$app_reducers/document/async-actions'; import { blockConfig } from '$app/constants/document/config'; import { Editor } from 'slate'; import { getBeforeRangeAt } from '$app/utils/document/slate/text'; -import { getHeadingDataFromEditor, getQuoteDataFromEditor, getTodoListDataFromEditor } from '$app/utils/document/blocks'; +import { + getHeadingDataFromEditor, + getQuoteDataFromEditor, + getTodoListDataFromEditor, + getBulletedDataFromEditor, + getNumberedListDataFromEditor, +} from '$app/utils/document/blocks'; const blockDataFactoryMap: Record BlockData | undefined> = { [BlockType.HeadingBlock]: getHeadingDataFromEditor, [BlockType.TodoListBlock]: getTodoListDataFromEditor, [BlockType.QuoteBlock]: getQuoteDataFromEditor, + [BlockType.BulletedListBlock]: getBulletedDataFromEditor, + [BlockType.NumberedListBlock]: getNumberedListDataFromEditor }; export function useTurnIntoBlock(id: string) { diff --git a/frontend/appflowy_tauri/src/appflowy_app/constants/document/config.ts b/frontend/appflowy_tauri/src/appflowy_app/constants/document/config.ts index 0155eb4eb9..421abc2af0 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/constants/document/config.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/constants/document/config.ts @@ -53,8 +53,9 @@ export const blockConfig: Record< splitType: BlockType.NumberedListBlock, /** * 1. or 2. or 3. + * a. or b. or c. */ - markdownRegexps: [/^(\s*\d+\.)$/], + markdownRegexps: [/^(\s*[\d|a-zA-Z]+\.)$/], }, [BlockType.QuoteBlock]: { canAddChild: true, diff --git a/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts b/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts index 620072bd10..42ef40808f 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/interfaces/document.ts @@ -25,6 +25,14 @@ export interface TodoListBlockData extends TextBlockData { checked: boolean; } +export interface BulletListBlockData extends TextBlockData { + format: 'default' | 'circle' | 'square' | 'disc'; +} + +export interface NumberedListBlockData extends TextBlockData { + format: 'default' | 'numbers' | 'letters' | 'roman_numerals'; +} + export interface QuoteBlockData extends TextBlockData { size: 'default' | 'large'; } @@ -43,6 +51,10 @@ export type BlockData = Type extends BlockType.HeadingBlock ? TodoListBlockData : Type extends BlockType.QuoteBlock ? QuoteBlockData + : Type extends BlockType.BulletedListBlock + ? BulletListBlockData + : Type extends BlockType.NumberedListBlock + ? NumberedListBlockData : TextBlockData; export interface NestedBlock { diff --git a/frontend/appflowy_tauri/src/appflowy_app/utils/document/blocks/index.ts b/frontend/appflowy_tauri/src/appflowy_app/utils/document/blocks/index.ts index 8e373f7feb..7b37f560c1 100644 --- a/frontend/appflowy_tauri/src/appflowy_app/utils/document/blocks/index.ts +++ b/frontend/appflowy_tauri/src/appflowy_app/utils/document/blocks/index.ts @@ -1,7 +1,12 @@ import { Editor } from 'slate'; -import { HeadingBlockData, TodoListBlockData } from '$app/interfaces/document'; -import { getAfterRangeAt, getBeforeRangeAt } from '$app/utils/document/slate/text'; -import { getDeltaAfterSelection, getDeltaFromSlateNodes } from '$app/utils/document/blocks/common'; +import { + BulletListBlockData, + HeadingBlockData, + NumberedListBlockData, + TodoListBlockData, +} from '$app/interfaces/document'; +import { getBeforeRangeAt } from '$app/utils/document/slate/text'; +import { getDeltaAfterSelection } from '$app/utils/document/blocks/common'; /** * get heading data from editor, only support markdown @@ -43,10 +48,36 @@ export function getTodoListDataFromEditor(editor: Editor): TodoListBlockData | u if (!selection) return; const hashTags = Editor.string(editor, getBeforeRangeAt(editor, selection)); const checked = hashTags.match(/x/g)?.length; - const slateNodes = Editor.fragment(editor, getAfterRangeAt(editor, selection)); - const delta = getDeltaFromSlateNodes(slateNodes); + const delta = getDeltaAfterSelection(editor); + if (!delta) return; return { delta, checked: !!checked, }; } + +/** + * get bulleted_list data from editor, only support markdown + * @param editor + */ +export function getBulletedDataFromEditor(editor: Editor): BulletListBlockData | undefined { + const delta = getDeltaAfterSelection(editor); + if (!delta) return; + return { + delta, + format: 'default', + }; +} + +/** + * get numbered_list data from editor, only support markdown + * @param editor + */ +export function getNumberedListDataFromEditor(editor: Editor): NumberedListBlockData | undefined { + const delta = getDeltaAfterSelection(editor); + if (!delta) return; + return { + delta, + format: 'default', + }; +}