opti: 1.adjust eventlistener;
This commit is contained in:
@@ -23,7 +23,7 @@ import { useFlag } from '@toeverything/datasource/feature-flags';
|
|||||||
import { CollapsiblePageTree } from './collapsible-page-tree';
|
import { CollapsiblePageTree } from './collapsible-page-tree';
|
||||||
import { Tabs } from './components/tabs';
|
import { Tabs } from './components/tabs';
|
||||||
import { TabMap, TAB_TITLE } from './components/tabs/Tabs';
|
import { TabMap, TAB_TITLE } from './components/tabs/Tabs';
|
||||||
import { TOC } from './components/toc';
|
import { Toc } from './components/toc';
|
||||||
import { WorkspaceName } from './workspace-name';
|
import { WorkspaceName } from './workspace-name';
|
||||||
|
|
||||||
type PageProps = {
|
type PageProps = {
|
||||||
@@ -92,7 +92,7 @@ export function Page(props: PageProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{activeTab === TabMap.get(TAB_TITLE.TOC).value && (
|
{activeTab === TabMap.get(TAB_TITLE.TOC).value && (
|
||||||
<TOC editor={editorRef.current}>TOC</TOC>
|
<Toc editor={editorRef.current}>TOC</Toc>
|
||||||
)}
|
)}
|
||||||
</WorkspaceSidebarContent>
|
</WorkspaceSidebarContent>
|
||||||
</WorkspaceSidebar>
|
</WorkspaceSidebar>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { BlockEditor } from '@toeverything/components/editor-core';
|
import { BlockEditor } from '@toeverything/components/editor-core';
|
||||||
import { styled } from '@toeverything/components/ui';
|
import { styled } from '@toeverything/components/ui';
|
||||||
import { services } from '@toeverything/datasource/db-service';
|
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import {
|
import {
|
||||||
createContext,
|
createContext,
|
||||||
@@ -12,12 +11,9 @@ import {
|
|||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import {
|
import {
|
||||||
BLOCK_TYPES,
|
BLOCK_TYPES,
|
||||||
getPageContentById,
|
getContentByAsyncBlocks,
|
||||||
} from '../../utils/getPageContentById';
|
getPageTOC,
|
||||||
|
} from '../../utils/toc';
|
||||||
const StyledTOC = styled('div')(() => {
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
const StyledTOCItem = styled('a')<{ type?: string; isActive?: boolean }>(
|
const StyledTOCItem = styled('a')<{ type?: string; isActive?: boolean }>(
|
||||||
({ type, isActive }) => {
|
({ type, isActive }) => {
|
||||||
@@ -120,49 +116,42 @@ const renderTOCContent = tocDataSource => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TOC = (props: Props) => {
|
export const Toc = (props: Props) => {
|
||||||
const { editor } = props;
|
const { editor } = props;
|
||||||
const { workspace_id, page_id } = useParams();
|
const { page_id } = useParams();
|
||||||
const [tocDataSource, setTocDataSource] = useState([]);
|
const [tocDataSource, setTocDataSource] = useState([]);
|
||||||
const [activeBlockId, setActiveBlockId] = useState('blockId');
|
const [activeBlockId, setActiveBlockId] = useState('blockId');
|
||||||
|
|
||||||
const updateTocDataSource = useCallback(async () => {
|
const updateTocDataSource = useCallback(async () => {
|
||||||
const tocDataSource = await getPageContentById(editor, page_id);
|
const { children = [] } =
|
||||||
|
(await editor.queryByPageId(page_id))?.[0] || {};
|
||||||
|
const asyncBlocks = (await editor.getBlockByIds(children)) || [];
|
||||||
|
const tocDataSource = getPageTOC(
|
||||||
|
asyncBlocks,
|
||||||
|
await getContentByAsyncBlocks(asyncBlocks, updateTocDataSource)
|
||||||
|
);
|
||||||
|
|
||||||
setTocDataSource(tocDataSource);
|
setTocDataSource(tocDataSource);
|
||||||
}, [editor, page_id]);
|
}, [editor, page_id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => await updateTocDataSource())();
|
(async () => {
|
||||||
|
await updateTocDataSource();
|
||||||
|
})();
|
||||||
}, [updateTocDataSource]);
|
}, [updateTocDataSource]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let unobserve: () => void;
|
|
||||||
const observe = async () => {
|
|
||||||
unobserve = await services.api.tocService.observe(
|
|
||||||
{ workspace: workspace_id, pageId: page_id },
|
|
||||||
updateTocDataSource
|
|
||||||
);
|
|
||||||
};
|
|
||||||
void observe();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unobserve?.();
|
|
||||||
};
|
|
||||||
}, [updateTocDataSource, workspace_id]);
|
|
||||||
|
|
||||||
const onClick = async (blockId?: string) => {
|
const onClick = async (blockId?: string) => {
|
||||||
if (blockId === activeBlockId) {
|
if (blockId === activeBlockId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(blockId);
|
|
||||||
setActiveBlockId(blockId);
|
setActiveBlockId(blockId);
|
||||||
await editor.scrollManager.scrollIntoViewByBlockId(blockId);
|
await editor.scrollManager.scrollIntoViewByBlockId(blockId);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TOCContext.Provider value={{ activeBlockId, onClick }}>
|
<TOCContext.Provider value={{ activeBlockId, onClick }}>
|
||||||
<StyledTOC>{renderTOCContent(tocDataSource)}</StyledTOC>
|
<div>{renderTOCContent(tocDataSource)}</div>
|
||||||
</TOCContext.Provider>
|
</TOCContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { TOC } from './TOC';
|
export { Toc } from './Toc';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { BlockEditor } from '@toeverything/components/editor-core';
|
import { AsyncBlock } from '@toeverything/components/editor-core';
|
||||||
|
|
||||||
export const BLOCK_TYPES = {
|
export const BLOCK_TYPES = {
|
||||||
GROUP: 'group',
|
GROUP: 'group',
|
||||||
@@ -7,23 +7,29 @@ export const BLOCK_TYPES = {
|
|||||||
HEADING3: 'heading3',
|
HEADING3: 'heading3',
|
||||||
};
|
};
|
||||||
|
|
||||||
const getContentByAsyncBlocks = async (asyncBlocks = []) => {
|
/* 😞😞sorry, I don't know how to define unlimited dimensions array */
|
||||||
|
const getContentByAsyncBlocks = async (
|
||||||
|
asyncBlocks: AsyncBlock[] = [],
|
||||||
|
callback: () => void
|
||||||
|
): Promise<any[]> => {
|
||||||
/* maybe should recast it to tail recursion */
|
/* maybe should recast it to tail recursion */
|
||||||
return await Promise.all(
|
return await Promise.all(
|
||||||
asyncBlocks.map(async asyncBlock => {
|
asyncBlocks.map(async (asyncBlock: AsyncBlock) => {
|
||||||
const asyncBlocks = await asyncBlock.children();
|
const asyncBlocks = await asyncBlock.children();
|
||||||
|
|
||||||
if (asyncBlocks?.length) {
|
if (asyncBlocks?.length) {
|
||||||
return getContentByAsyncBlocks(asyncBlocks);
|
return getContentByAsyncBlocks(asyncBlocks, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, type } = asyncBlock;
|
/* get update notice */
|
||||||
|
asyncBlock.onUpdate(callback);
|
||||||
|
|
||||||
|
const { id, type } = asyncBlock;
|
||||||
if (Object.values(BLOCK_TYPES).includes(type)) {
|
if (Object.values(BLOCK_TYPES).includes(type)) {
|
||||||
const properties = await asyncBlock.getProperties();
|
const properties = await asyncBlock.getProperties();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: id,
|
id,
|
||||||
type,
|
type,
|
||||||
text: properties?.text?.value?.[0]?.text || '',
|
text: properties?.text?.value?.[0]?.text || '',
|
||||||
};
|
};
|
||||||
@@ -34,12 +40,7 @@ const getContentByAsyncBlocks = async (asyncBlocks = []) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPageContentById = async (editor: BlockEditor, pageId: string) => {
|
const getPageTOC = (asyncBlocks: AsyncBlock[], tocContents) => {
|
||||||
const { children = [] } = (await editor.queryByPageId(pageId))?.[0] || {};
|
|
||||||
const asyncBlocks = (await editor.getBlockByIds(children)) || [];
|
|
||||||
|
|
||||||
const tocContents = await getContentByAsyncBlocks(asyncBlocks);
|
|
||||||
|
|
||||||
return tocContents
|
return tocContents
|
||||||
.reduce((tocGroupContent, tocContent, index) => {
|
.reduce((tocGroupContent, tocContent, index) => {
|
||||||
const { id, type } = asyncBlocks[index];
|
const { id, type } = asyncBlocks[index];
|
||||||
@@ -61,4 +62,4 @@ const getPageContentById = async (editor: BlockEditor, pageId: string) => {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getPageContentById };
|
export { getPageTOC, getContentByAsyncBlocks };
|
||||||
@@ -5,7 +5,6 @@ import { Database } from './database';
|
|||||||
import { EditorBlock } from './editor-block';
|
import { EditorBlock } from './editor-block';
|
||||||
import { FileService } from './file';
|
import { FileService } from './file';
|
||||||
import { PageTree } from './workspace/page-tree';
|
import { PageTree } from './workspace/page-tree';
|
||||||
import { TOC } from './workspace/toc';
|
|
||||||
import { UserConfig } from './workspace/user-config';
|
import { UserConfig } from './workspace/user-config';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -49,7 +48,6 @@ export interface DbServicesMap {
|
|||||||
userConfig: UserConfig;
|
userConfig: UserConfig;
|
||||||
file: FileService;
|
file: FileService;
|
||||||
commentService: CommentService;
|
commentService: CommentService;
|
||||||
tocService: TOC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RegisterDependencyConfigWithName extends RegisterDependencyConfig {
|
interface RegisterDependencyConfigWithName extends RegisterDependencyConfig {
|
||||||
@@ -78,13 +76,6 @@ const dbServiceConfig: RegisterDependencyConfigWithName[] = [
|
|||||||
value: PageTree,
|
value: PageTree,
|
||||||
dependencies: [{ token: Database }],
|
dependencies: [{ token: Database }],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'class',
|
|
||||||
callName: 'tocService',
|
|
||||||
token: TOC,
|
|
||||||
value: TOC,
|
|
||||||
dependencies: [{ token: Database }],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 'class',
|
type: 'class',
|
||||||
callName: 'userConfig',
|
callName: 'userConfig',
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { ServiceBaseClass } from '../base';
|
|
||||||
import { ReturnUnobserve } from '../database/observer';
|
|
||||||
import { ObserveCallback } from './page-tree';
|
|
||||||
|
|
||||||
export class TOC extends ServiceBaseClass {
|
|
||||||
private onActivePageChange?: () => void;
|
|
||||||
|
|
||||||
async observe(
|
|
||||||
{ workspace, pageId }: { workspace: string; pageId: string },
|
|
||||||
callback: ObserveCallback
|
|
||||||
): Promise<ReturnUnobserve> {
|
|
||||||
// not only use observe, but also addChildrenListener is OK 🎉🎉🎉
|
|
||||||
// const pageBlock = await this.getBlock(workspace, pageId);
|
|
||||||
//
|
|
||||||
// this.onActivePageChange?.();
|
|
||||||
// pageBlock?.addChildrenListener('onPageChildrenChange', () => {
|
|
||||||
// callback();
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// this.onActivePageChange = () => pageBlock?.removeChildrenListener('onPageChildrenChange');
|
|
||||||
|
|
||||||
const unobserve = await this._observe(workspace, pageId, callback);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unobserve();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user