feat(core): page info ui (#5729)

this PR includes the main table view in the page detail page
This commit is contained in:
Peng Xiao
2024-02-22 05:58:14 +00:00
parent 46cc0810e9
commit d97304e9eb
26 changed files with 2068 additions and 83 deletions
@@ -1,20 +1,27 @@
import type { Workspace } from '@toeverything/infra';
import { useService } from '@toeverything/infra/di';
import { useEffect, useState } from 'react';
import { use } from 'foxact/use';
import { useEffect, useMemo, useState } from 'react';
import { WorkspacePropertiesAdapter } from '../modules/workspace/properties';
import { useBlockSuitePageMeta } from './use-block-suite-page-meta';
function getProxy<T extends object>(obj: T) {
return new Proxy(obj, {});
}
const useReactiveAdapter = (adapter: WorkspacePropertiesAdapter) => {
use(adapter.workspace.blockSuiteWorkspace.doc.whenSynced);
const [proxy, setProxy] = useState(adapter);
// fixme: this is a hack to force re-render when default meta changed
useBlockSuitePageMeta(adapter.workspace.blockSuiteWorkspace);
useEffect(() => {
// todo: track which properties are used and then filter by property path change
// using Y.YEvent.path
function observe() {
setProxy(getProxy(adapter));
requestAnimationFrame(() => {
setProxy(getProxy(adapter));
});
}
adapter.properties.observeDeep(observe);
return () => {
@@ -29,3 +36,11 @@ export function useCurrentWorkspacePropertiesAdapter() {
const adapter = useService(WorkspacePropertiesAdapter);
return useReactiveAdapter(adapter);
}
export function useWorkspacePropertiesAdapter(workspace: Workspace) {
const adapter = useMemo(
() => new WorkspacePropertiesAdapter(workspace),
[workspace]
);
return useReactiveAdapter(adapter);
}
@@ -0,0 +1,46 @@
import type { Page, Workspace } from '@blocksuite/store';
import { type Atom, atom, useAtomValue } from 'jotai';
import { useBlockSuiteWorkspacePage } from './use-block-suite-workspace-page';
const weakMap = new WeakMap<Page, Atom<string[]>>();
function getPageBacklinks(page: Page): string[] {
return page.workspace.indexer.backlink
.getBacklink(page.id)
.map(linkNode => linkNode.pageId)
.filter(id => id !== page.id);
}
const getPageBacklinksAtom = (page: Page | null) => {
if (!page) {
return atom([]);
}
if (!weakMap.has(page)) {
const baseAtom = atom<string[]>([]);
baseAtom.onMount = set => {
const disposables = [
page.slots.ready.on(() => {
set(getPageBacklinks(page));
}),
page.workspace.indexer.backlink.slots.indexUpdated.on(() => {
set(getPageBacklinks(page));
}),
];
set(getPageBacklinks(page));
return () => {
disposables.forEach(disposable => disposable.dispose());
};
};
weakMap.set(page, baseAtom);
}
return weakMap.get(page) as Atom<string[]>;
};
export function useBlockSuitePageBacklinks(
blockSuiteWorkspace: Workspace,
pageId: string
): string[] {
const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId);
return useAtomValue(getPageBacklinksAtom(page));
}
@@ -25,9 +25,11 @@ export function useWorkspaceStatus<
setStatus(
cachedSelector ? cachedSelector(workspace.status) : workspace.status
);
return workspace.onStatusChange.on(status =>
setStatus(cachedSelector ? cachedSelector(status) : status)
).dispose;
return workspace.onStatusChange.on(status => {
requestAnimationFrame(() => {
setStatus(cachedSelector ? cachedSelector(status) : status);
});
}).dispose;
}, [cachedSelector, workspace]);
return status;