fix: use react-resizable-panels (#2679)

This commit is contained in:
Himself65
2023-06-04 23:33:36 +08:00
committed by GitHub
parent acda594cba
commit 1716e7a397
6 changed files with 88 additions and 165 deletions

View File

@@ -47,7 +47,7 @@
"react": "18.3.0-canary-16d053d59-20230506",
"react-dom": "18.3.0-canary-16d053d59-20230506",
"react-is": "^18.2.0",
"react-mosaic-component": "^6.0.1",
"react-resizable-panels": "^0.0.48",
"rxjs": "^7.8.1",
"swr": "^2.1.5",
"y-protocols": "^1.0.5",

View File

@@ -1,6 +1,6 @@
import './page-detail-editor.css';
import { PageNotFoundError, Unreachable } from '@affine/env/constant';
import { PageNotFoundError } from '@affine/env/constant';
import { rootCurrentEditorAtom } from '@affine/workspace/atom';
import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store';
@@ -9,33 +9,29 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-
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 { PluginUIAdapter } from '@toeverything/plugin-infra/type';
import type { ExpectedLayout } from '@toeverything/plugin-infra/type';
import type {
AffinePlugin,
LayoutNode,
PluginUIAdapter,
} from '@toeverything/plugin-infra/type';
import type { PluginBlockSuiteAdapter } from '@toeverything/plugin-infra/type';
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import { useAtomValue, useSetAtom } from 'jotai';
import Head from 'next/head';
import type { FC } from 'react';
import type { FC, ReactElement } from 'react';
import React, {
lazy,
memo,
startTransition,
Suspense,
useCallback,
useMemo,
} from 'react';
import type { MosaicNode } from 'react-mosaic-component';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { workspacePreferredModeAtom } from '../atoms';
import { contentLayoutAtom } from '../atoms/layout';
import type { AffineOfficialWorkspace } from '../shared';
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
const Mosaic = lazy(() =>
import('react-mosaic-component').then(({ Mosaic }) => ({
default: Mosaic,
}))
);
export type PageDetailEditorProps = {
isPublic?: boolean;
workspace: AffineOfficialWorkspace;
@@ -127,6 +123,54 @@ const PluginContentAdapter = memo<{
);
});
type LayoutPanelProps = {
node: LayoutNode;
editorProps: PageDetailEditorProps;
plugins: AffinePlugin<string>[];
};
const LayoutPanel = memo(function LayoutPanel(
props: LayoutPanelProps
): ReactElement {
const node = props.node;
if (typeof node === 'string') {
if (node === 'editor') {
return <EditorWrapper {...props.editorProps} />;
} else {
const plugin = props.plugins.find(
plugin => plugin.definition.id === node
);
const Content = plugin?.uiAdapter.detailContent;
assertExists(Content);
return <PluginContentAdapter detailContent={Content} />;
}
} else {
return (
<PanelGroup direction={node.direction}>
<Panel defaultSize={node.splitPercentage}>
<Suspense>
<LayoutPanel
node={node.first}
editorProps={props.editorProps}
plugins={props.plugins}
/>
</Suspense>
</Panel>
<PanelResizeHandle />
<Panel defaultSize={100 - node.splitPercentage}>
<Suspense>
<LayoutPanel
node={node.second}
editorProps={props.editorProps}
plugins={props.plugins}
/>
</Suspense>
</Panel>
</PanelGroup>
);
}
});
export const PageDetailEditor: FC<PageDetailEditorProps> = props => {
const { workspace, pageId } = props;
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
@@ -135,66 +179,22 @@ export const PageDetailEditor: FC<PageDetailEditorProps> = props => {
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]
);
const [layout, setLayout] = useAtom(contentLayoutAtom);
const onChange = useCallback(
(_: MosaicNode<string | number> | null) => {
// type cast
const node = _ as MosaicNode<string> | null;
if (node) {
if (typeof node === 'string') {
console.error('unexpected layout');
} else {
if (node.splitPercentage && node.splitPercentage < 70) {
return;
} else if (node.first !== 'editor') {
return;
}
setLayout(node as ExpectedLayout);
}
}
},
[setLayout]
);
return (
<>
<Head>
<title>{title}</title>
</Head>
{layout === 'editor' ? (
<EditorWrapper {...props} />
) : (
<Mosaic
onChange={onChange}
renderTile={id => {
if (id === 'editor') {
return <EditorWrapper {...props} />;
} else {
const plugin = plugins.find(
plugin => plugin.definition.id === id
);
if (plugin && plugin.uiAdapter.detailContent) {
return (
<Suspense>
<PluginContentAdapter
detailContent={plugin.uiAdapter.detailContent}
/>
</Suspense>
);
}
}
throw new Unreachable();
}}
value={layout}
/>
)}
<Suspense>
<LayoutPanel node={layout} editorProps={props} plugins={plugins} />
</Suspense>
</>
);
};

View File

@@ -1,6 +1,5 @@
import '@affine/component/theme/global.css';
import '@affine/component/theme/theme.css';
import 'react-mosaic-component/react-mosaic-component.css';
// bootstrap code before everything
import '../bootstrap';