import './page-detail-editor.css'; import { DEFAULT_HELLO_WORLD_PAGE_ID, PageNotFoundError, } from '@affine/env/constant'; import { rootCurrentEditorAtom } from '@affine/workspace/atom'; import type { EditorContainer } from '@blocksuite/editor'; import type { Page } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store'; import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta'; import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page'; import { useBlockSuiteWorkspacePageTitle } from '@toeverything/hooks/use-block-suite-workspace-page-title'; import { affinePluginsAtom } from '@toeverything/plugin-infra/manager'; import type { AffinePlugin, LayoutNode, PluginUIAdapter, } from '@toeverything/plugin-infra/type'; import type { PluginBlockSuiteAdapter } from '@toeverything/plugin-infra/type'; import { useAtomValue, useSetAtom } from 'jotai'; import Head from 'next/head'; import type { FC, ReactElement } from 'react'; import React, { memo, startTransition, Suspense, useCallback, useMemo, } from 'react'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { pageSettingFamily } from '../atoms'; import { contentLayoutAtom } from '../atoms/layout'; import type { AffineOfficialWorkspace } from '../shared'; import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor'; export type PageDetailEditorProps = { isPublic?: boolean; workspace: AffineOfficialWorkspace; pageId: string; onInit: (page: Page, editor: Readonly) => void; onLoad?: (page: Page, editor: EditorContainer) => () => void; }; const EditorWrapper = memo(function EditorWrapper({ workspace, pageId, onInit, onLoad, isPublic, }: PageDetailEditorProps) { const affinePluginsMap = useAtomValue(affinePluginsAtom); const plugins = useMemo( () => Object.values(affinePluginsMap), [affinePluginsMap] ); const blockSuiteWorkspace = workspace.blockSuiteWorkspace; const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId); if (!page) { throw new PageNotFoundError(blockSuiteWorkspace, pageId); } const meta = useBlockSuitePageMeta(blockSuiteWorkspace).find( meta => meta.id === pageId ); const pageSettingAtom = pageSettingFamily(pageId); const pageSetting = useAtomValue(pageSettingAtom); const currentMode = pageSetting?.mode ?? DEFAULT_HELLO_WORLD_PAGE_ID === pageId ? 'edgeless' : 'page'; const setEditor = useSetAtom(rootCurrentEditorAtom); assertExists(meta); return ( ) => { startTransition(() => { setEditor(editor); }); onInit(page, editor); }, [onInit, setEditor] )} onLoad={useCallback( (page: Page, editor: EditorContainer) => { startTransition(() => { setEditor(editor); }); page.workspace.setPageMeta(page.id, { updatedDate: Date.now(), }); localStorage.setItem('last_page_id', page.id); let dispose = () => {}; if (onLoad) { dispose = onLoad(page, editor); } const uiDecorators = plugins .map(plugin => plugin.blockSuiteAdapter.uiDecorator) .filter((ui): ui is PluginBlockSuiteAdapter['uiDecorator'] => Boolean(ui) ); const disposes = uiDecorators.map(ui => ui(editor)); return () => { disposes.map(fn => fn()); dispose(); }; }, [plugins, onLoad, setEditor] )} /> ); }); const PluginContentAdapter = memo<{ detailContent: PluginUIAdapter['detailContent']; }>(function PluginContentAdapter({ detailContent }) { return (
{detailContent({ contentLayoutAtom, })}
); }); type LayoutPanelProps = { node: LayoutNode; editorProps: PageDetailEditorProps; plugins: AffinePlugin[]; }; const LayoutPanel = memo(function LayoutPanel( props: LayoutPanelProps ): ReactElement { const node = props.node; if (typeof node === 'string') { if (node === 'editor') { return ; } else { const plugin = props.plugins.find( plugin => plugin.definition.id === node ); const Content = plugin?.uiAdapter.detailContent; assertExists(Content); return ; } } else { return ( ); } }); export const PageDetailEditor: FC = props => { const { workspace, pageId } = props; const blockSuiteWorkspace = workspace.blockSuiteWorkspace; const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId); if (!page) { throw new PageNotFoundError(blockSuiteWorkspace, pageId); } const title = useBlockSuiteWorkspacePageTitle(blockSuiteWorkspace, pageId); const layout = useAtomValue(contentLayoutAtom); const affinePluginsMap = useAtomValue(affinePluginsAtom); const plugins = useMemo( () => Object.values(affinePluginsMap), [affinePluginsMap] ); return ( <> {title} ); };