♻️(frontend) change useHeading to useHeadingStore

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.
This commit is contained in:
Anthony LC
2024-10-02 11:19:44 +02:00
committed by Anthony LC
parent 4d2a73556a
commit 6a2030e235
12 changed files with 78 additions and 68 deletions

View File

@@ -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 (
<Box $css={cssEditor}>
{isErrorAttachment && (

View File

@@ -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';

View File

@@ -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;

View File

@@ -1,3 +1,4 @@
export * from './components';
export * from './stores';
export * from './types';
export * from './utils';

View File

@@ -1,2 +1,3 @@
export * from './useDocStore';
export * from './useHeadingStore';
export * from './usePanelEditorStore';

View File

@@ -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<UseHeadingStore>((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: [] })),
}));

View File

@@ -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;
};
};

View File

@@ -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 {

View File

@@ -1 +0,0 @@
export * from './useHeading';

View File

@@ -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<HeadingBlock[]>(headingFiltering());
editor?.onEditorContentChange(() => {
setHeadings(headingFiltering());
});
return headings;
};

View File

@@ -1,3 +1 @@
export * from './components';
export * from './hooks';
export * from './types';

View File

@@ -1,10 +0,0 @@
export type HeadingBlock = {
id: string;
type: string;
text: string;
content: HeadingBlock[];
contentText: string;
props: {
level: number;
};
};