From 6a2030e2351a9c41a1bd25156fc372395e0e8e89 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 2 Oct 2024 11:19:44 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20change=20useHead?= =?UTF-8?q?ing=20to=20useHeadingStore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to get the headings in multiple places. To not have multiple listeners to compute the same thing, we will use a store to store the editor headings. --- .../doc-editor/components/BlockNoteEditor.tsx | 15 +++++- .../docs/doc-editor/components/DocEditor.tsx | 5 +- .../doc-editor/components/PanelEditor.tsx | 7 +-- .../src/features/docs/doc-editor/index.tsx | 1 + .../features/docs/doc-editor/stores/index.ts | 1 + .../doc-editor/stores/useHeadingStore.tsx | 43 +++++++++++++++++ .../src/features/docs/doc-editor/types.tsx | 11 +++++ .../components/TableContent.tsx | 4 +- .../docs/doc-table-content/hooks/index.ts | 1 - .../doc-table-content/hooks/useHeading.tsx | 46 ------------------- .../features/docs/doc-table-content/index.ts | 2 - .../features/docs/doc-table-content/types.ts | 10 ---- 12 files changed, 78 insertions(+), 68 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/stores/useHeadingStore.tsx delete mode 100644 src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/index.ts delete mode 100644 src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/useHeading.tsx delete mode 100644 src/frontend/apps/impress/src/features/docs/doc-table-content/types.ts diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index 8895e41f..5d531a05 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -13,7 +13,7 @@ import { Version } from '@/features/docs/doc-versioning/'; import { useCreateDocAttachment } from '../api/useCreateDocUpload'; import useSaveDoc from '../hook/useSaveDoc'; -import { useDocStore } from '../stores'; +import { useDocStore, useHeadingStore } from '../stores'; import { randomColor } from '../utils'; import { BlockNoteToolbar } from './BlockNoteToolbar'; @@ -78,6 +78,7 @@ export const BlockNoteContent = ({ isError: isErrorAttachment, error: errorAttachment, } = useCreateDocAttachment(); + const { setHeadings, resetHeadings } = useHeadingStore(); const uploadFile = useCallback( async (file: File) => { @@ -116,6 +117,18 @@ export const BlockNoteContent = ({ setStore(storeId, { editor }); }, [setStore, storeId, editor]); + useEffect(() => { + setHeadings(editor); + + editor?.onEditorContentChange(() => { + setHeadings(editor); + }); + + return () => { + resetHeadings(); + }; + }, [editor, resetHeadings, setHeadings]); + return ( {isErrorAttachment && ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index 58342c3c..c1f4198d 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -8,9 +8,10 @@ import { Box, Card, Text, TextErrors } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; import { DocHeader } from '@/features/docs/doc-header'; import { Doc } from '@/features/docs/doc-management'; -import { useHeading } from '@/features/docs/doc-table-content'; import { Versions, useDocVersion } from '@/features/docs/doc-versioning/'; +import { useHeadingStore } from '../stores'; + import { BlockNoteEditor } from './BlockNoteEditor'; import { IconOpenPanelEditor, PanelEditor } from './PanelEditor'; @@ -23,7 +24,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => { query: { versionId }, } = useRouter(); const { t } = useTranslation(); - const headings = useHeading(doc.id); + const { headings } = useHeadingStore(); const isVersion = versionId && typeof versionId === 'string'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx index 56638d61..60ce65b8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx @@ -3,11 +3,12 @@ import { useTranslation } from 'react-i18next'; import { Box, BoxButton, Card, IconBG, Text } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Doc } from '@/features/docs//doc-management'; -import { HeadingBlock, TableContent } from '@/features/docs/doc-table-content'; +import { Doc } from '@/features/docs/doc-management'; +import { TableContent } from '@/features/docs/doc-table-content'; import { VersionList } from '@/features/docs/doc-versioning'; -import { usePanelEditorStore } from '../stores/usePanelEditorStore'; +import { usePanelEditorStore } from '../stores'; +import { HeadingBlock } from '../types'; interface PanelProps { doc: Doc; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx index 24ecfc79..ad4eaebf 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx @@ -1,3 +1,4 @@ export * from './components'; export * from './stores'; +export * from './types'; export * from './utils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/stores/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/index.ts index 8efa0586..52c5b509 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/stores/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/index.ts @@ -1,2 +1,3 @@ export * from './useDocStore'; +export * from './useHeadingStore'; export * from './usePanelEditorStore'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useHeadingStore.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useHeadingStore.tsx new file mode 100644 index 00000000..ac9b8a4b --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useHeadingStore.tsx @@ -0,0 +1,43 @@ +import { BlockNoteEditor } from '@blocknote/core'; +import { create } from 'zustand'; + +import { HeadingBlock } from '../types'; + +const recursiveTextContent = (content: HeadingBlock['content']): string => { + if (!content) { + return ''; + } + + return content.reduce((acc, content) => { + if (content.type === 'text') { + return acc + content.text; + } else if (content.type === 'link') { + return acc + recursiveTextContent(content.content); + } + + return acc; + }, ''); +}; + +export interface UseHeadingStore { + headings: HeadingBlock[]; + setHeadings: (editor: BlockNoteEditor) => void; + resetHeadings: () => void; +} + +export const useHeadingStore = create((set) => ({ + headings: [], + setHeadings: (editor) => { + const headingBlocks = editor?.document + .filter((block) => block.type === 'heading') + .map((block) => ({ + ...block, + contentText: recursiveTextContent( + block.content as unknown as HeadingBlock['content'], + ), + })) as unknown as HeadingBlock[]; + + set(() => ({ headings: headingBlocks })); + }, + resetHeadings: () => set(() => ({ headings: [] })), +})); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx index 4390a173..19094b6c 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx @@ -1,3 +1,14 @@ export interface DocAttachment { file: string; } + +export type HeadingBlock = { + id: string; + type: string; + text: string; + content: HeadingBlock[]; + contentText: string; + props: { + level: number; + }; +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx index b9dde6ea..426058b9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx @@ -2,11 +2,9 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, BoxButton, Text } from '@/components'; -import { useDocStore } from '@/features/docs/doc-editor'; +import { HeadingBlock, useDocStore } from '@/features/docs/doc-editor'; import { Doc } from '@/features/docs/doc-management'; -import { HeadingBlock } from '../types'; - import { Heading } from './Heading'; interface TableContentProps { diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/index.ts deleted file mode 100644 index d9b27305..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useHeading'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/useHeading.tsx b/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/useHeading.tsx deleted file mode 100644 index bccc6d65..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/hooks/useHeading.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useCallback, useState } from 'react'; - -import { useDocStore } from '../../doc-editor'; -import { HeadingBlock } from '../types'; - -const recursiveTextContent = (content: HeadingBlock['content']): string => { - if (!content) { - return ''; - } - - return content.reduce((acc, content) => { - if (content.type === 'text') { - return acc + content.text; - } else if (content.type === 'link') { - return acc + recursiveTextContent(content.content); - } - - return acc; - }, ''); -}; - -export const useHeading = (docId: string) => { - const { docsStore } = useDocStore(); - const editor = docsStore?.[docId]?.editor; - - const headingFiltering = useCallback( - () => - editor?.document - .filter((block) => block.type === 'heading') - .map((block) => ({ - ...block, - contentText: recursiveTextContent( - block.content as unknown as HeadingBlock['content'], - ), - })) as unknown as HeadingBlock[], - [editor?.document], - ); - - const [headings, setHeadings] = useState(headingFiltering()); - - editor?.onEditorContentChange(() => { - setHeadings(headingFiltering()); - }); - - return headings; -}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/index.ts b/src/frontend/apps/impress/src/features/docs/doc-table-content/index.ts index 2103701b..07635cbb 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-table-content/index.ts @@ -1,3 +1 @@ export * from './components'; -export * from './hooks'; -export * from './types'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/types.ts b/src/frontend/apps/impress/src/features/docs/doc-table-content/types.ts deleted file mode 100644 index feeefc2e..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type HeadingBlock = { - id: string; - type: string; - text: string; - content: HeadingBlock[]; - contentText: string; - props: { - level: number; - }; -};