feat(core): auto select block when jump to block (#4858)

Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
JimmFly
2023-11-10 11:02:56 +08:00
committed by GitHub
parent f1e32aab66
commit 1fe5a0fffa
10 changed files with 199 additions and 185 deletions

View File

@@ -3,7 +3,6 @@ import type {
WorkspaceFlavour,
WorkspaceUISchema,
} from '@affine/env/workspace';
import { initEmptyPage } from '@toeverything/infra/blocksuite';
import { lazy, useCallback } from 'react';
import type { OnLoadEditor } from '../../components/page-detail-editor';
@@ -50,7 +49,6 @@ export const UI = {
return (
<PageDetailEditor
pageId={currentPageId}
onInit={useCallback(async page => initEmptyPage(page), [])}
onLoad={onLoad}
workspace={workspace.blockSuiteWorkspace}
/>

View File

@@ -25,7 +25,6 @@ import { initEmptyPage } from '@toeverything/infra/blocksuite';
import { buildShowcaseWorkspace } from '@toeverything/infra/blocksuite';
import { useAtomValue } from 'jotai';
import { nanoid } from 'nanoid';
import { useCallback } from 'react';
import { setPageModeAtom } from '../../atoms';
import {
@@ -94,7 +93,6 @@ export const LocalAdapter: WorkspaceAdapter<WorkspaceFlavour.LOCAL> = {
return (
<PageDetailEditor
pageId={currentPageId}
onInit={useCallback(async page => initEmptyPage(page), [])}
onLoad={onLoadEditor}
workspace={workspace}
/>

View File

@@ -1,8 +1,6 @@
import { PageNotFoundError } from '@affine/env/constant';
import type { WorkspaceFlavour } from '@affine/env/workspace';
import { type WorkspaceUISchema } from '@affine/env/workspace';
import { initEmptyPage } from '@toeverything/infra/blocksuite';
import { useCallback } from 'react';
import { useWorkspace } from '../../hooks/use-workspace';
import { PageDetailEditor, Provider } from '../shared';
@@ -18,7 +16,6 @@ export const UI = {
return (
<PageDetailEditor
pageId={currentPageId}
onInit={useCallback(async page => initEmptyPage(page), [])}
onLoad={onLoadEditor}
workspace={workspace.blockSuiteWorkspace}
/>

View File

@@ -1,8 +1,9 @@
import './page-detail-editor.css';
import { PageNotFoundError } from '@affine/env/constant';
import type { LayoutNode } from '@affine/sdk//entry';
import type { LayoutNode } from '@affine/sdk/entry';
import { rootBlockHubAtom } from '@affine/workspace/atom';
import type { BlockHub } from '@blocksuite/blocks';
import type { EditorContainer } from '@blocksuite/editor';
import { assertExists, DisposableGroup } from '@blocksuite/global/utils';
import type { Page, Workspace } from '@blocksuite/store';
@@ -40,8 +41,9 @@ import * as styles from './page-detail-editor.css';
import { editorContainer, pluginContainer } from './page-detail-editor.css';
import { TrashButtonGroup } from './pure/trash-button-group';
function useRouterHash() {
return useLocation().hash.substring(1);
declare global {
// eslint-disable-next-line no-var
var currentEditor: EditorContainer | undefined;
}
export type OnLoadEditor = (page: Page, editor: EditorContainer) => () => void;
@@ -50,17 +52,43 @@ export interface PageDetailEditorProps {
isPublic?: boolean;
workspace: Workspace;
pageId: string;
onInit: (
page: Page,
editor: Readonly<EditorContainer>
) => Promise<void> | void;
onLoad?: OnLoadEditor;
}
function useRouterHash() {
return useLocation().hash.substring(1);
}
function useCreateAndSetRootBlockHub(
editor?: EditorContainer,
showBlockHub?: boolean
) {
const setBlockHub = useSetAtom(rootBlockHubAtom);
useEffect(() => {
let canceled = false;
let blockHub: BlockHub | undefined;
if (editor && showBlockHub) {
editor
.createBlockHub()
.then(bh => {
if (canceled) {
return;
}
blockHub = bh;
setBlockHub(blockHub);
})
.catch(console.error);
}
return () => {
canceled = true;
blockHub?.remove();
};
}, [editor, showBlockHub, setBlockHub]);
}
const EditorWrapper = memo(function EditorWrapper({
workspace,
pageId,
onInit,
onLoad,
isPublic,
}: PageDetailEditorProps) {
@@ -79,7 +107,6 @@ const EditorWrapper = memo(function EditorWrapper({
const pageSetting = useAtomValue(pageSettingAtom);
const currentMode = pageSetting?.mode ?? 'page';
const setBlockHub = useSetAtom(rootBlockHubAtom);
const { appSettings } = useAppSettingHelper();
assertExists(meta);
@@ -91,29 +118,6 @@ const EditorWrapper = memo(function EditorWrapper({
return fontStyle.value;
}, [appSettings.fontStyle]);
const [loading, setLoading] = useState(true);
const blockId = useRouterHash();
const blockElement = useMemo(() => {
if (!blockId || loading) {
return null;
}
return document.querySelector(`[data-block-id="${blockId}"]`);
}, [blockId, loading]);
useEffect(() => {
if (blockElement) {
setTimeout(
() =>
blockElement.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'center',
}),
0
);
}
}, [blockElement]);
const setEditorMode = useCallback(
(mode: 'page' | 'edgeless') => {
if (mode === 'edgeless') {
@@ -125,6 +129,56 @@ const EditorWrapper = memo(function EditorWrapper({
[switchToEdgelessMode, switchToPageMode, pageId]
);
const [editor, setEditor] = useState<EditorContainer>();
const blockId = useRouterHash();
useCreateAndSetRootBlockHub(editor, !meta.trash);
const onLoadEditor = useCallback(
(editor: EditorContainer) => {
// debug current detail editor
globalThis.currentEditor = editor;
setEditor(editor);
const disposableGroup = new DisposableGroup();
disposableGroup.add(
page.slots.blockUpdated.once(() => {
page.workspace.setPageMeta(page.id, {
updatedDate: Date.now(),
});
})
);
localStorage.setItem('last_page_id', page.id);
if (onLoad) {
disposableGroup.add(onLoad(page, editor));
}
const rootStore = getCurrentStore();
const editorItems = rootStore.get(pluginEditorAtom);
let disposes: (() => void)[] = [];
const renderTimeout = window.setTimeout(() => {
disposes = Object.entries(editorItems).map(([id, editorItem]) => {
const div = document.createElement('div');
div.setAttribute('plugin-id', id);
const cleanup = editorItem(div, editor);
assertExists(parent);
document.body.appendChild(div);
return () => {
cleanup();
document.body.removeChild(div);
};
});
});
return () => {
disposableGroup.dispose();
clearTimeout(renderTimeout);
window.setTimeout(() => {
disposes.forEach(dispose => dispose());
});
};
},
[onLoad, page]
);
return (
<>
<Editor
@@ -140,55 +194,8 @@ const EditorWrapper = memo(function EditorWrapper({
mode={isPublic ? 'page' : currentMode}
page={page}
onModeChange={setEditorMode}
onInit={useCallback(
(page: Page, editor: Readonly<EditorContainer>) => {
onInit(page, editor);
},
[onInit]
)}
setBlockHub={setBlockHub}
onLoad={useCallback(
(page: Page, editor: EditorContainer) => {
const disposableGroup = new DisposableGroup();
disposableGroup.add(
page.slots.blockUpdated.once(() => {
page.workspace.setPageMeta(page.id, {
updatedDate: Date.now(),
});
})
);
localStorage.setItem('last_page_id', page.id);
if (onLoad) {
disposableGroup.add(onLoad(page, editor));
}
const rootStore = getCurrentStore();
const editorItems = rootStore.get(pluginEditorAtom);
let disposes: (() => void)[] = [];
const renderTimeout = window.setTimeout(() => {
disposes = Object.entries(editorItems).map(([id, editorItem]) => {
const div = document.createElement('div');
div.setAttribute('plugin-id', id);
const cleanup = editorItem(div, editor);
assertExists(parent);
document.body.appendChild(div);
return () => {
cleanup();
document.body.removeChild(div);
};
});
});
return () => {
disposableGroup.dispose();
clearTimeout(renderTimeout);
window.setTimeout(() => {
disposes.forEach(dispose => dispose());
});
setLoading(false);
};
},
[onLoad]
)}
defaultSelectedBlockId={blockId}
onLoadEditor={onLoadEditor}
/>
{meta.trash && <TrashButtonGroup />}
<Bookmark page={page} />

View File

@@ -2,7 +2,7 @@ import {
AppSidebarFallback,
appSidebarResizingAtom,
} from '@affine/component/app-sidebar';
import { BlockHubWrapper } from '@affine/component/block-hub';
import { RootBlockHub } from '@affine/component/block-hub';
import {
type DraggableTitleCellData,
PageListDragOverlay,
@@ -13,10 +13,7 @@ import {
WorkspaceFallback,
} from '@affine/component/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import {
rootBlockHubAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { assertExists } from '@blocksuite/global/utils';
import type { Page } from '@blocksuite/store';
import type { DragEndEvent } from '@dnd-kit/core';
@@ -294,7 +291,7 @@ export const WorkspaceLayoutInner = ({
>
{incompatible ? <WorkspaceUpgrade /> : children}
<ToolContainer inTrashPage={inTrashPage}>
<BlockHubWrapper blockHubAtom={rootBlockHubAtom} />
<RootBlockHub />
<HelpIsland showList={pageId ? undefined : showList} />
</ToolContainer>
</MainContainer>

View File

@@ -70,7 +70,6 @@ export const Component = (): ReactElement => {
isPublic
workspace={page.workspace}
pageId={page.id}
onInit={noop}
onLoad={useCallback(() => noop, [])}
/>
</MainContainer>