mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-14 23:21:37 +03:00
feat(core): enhance share page with selector (#8319)
Closes [BS-1346](https://linear.app/affine-design/issue/BS-1346/白板上的-link-to-block-在只读模式下打开无法跳转和高亮) <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/8ypiIKZXudF5a0tIgIzf/84bb27a9-608f-4cfc-a4c8-58de8aa5d791.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/8ypiIKZXudF5a0tIgIzf/84bb27a9-608f-4cfc-a4c8-58de8aa5d791.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/8ypiIKZXudF5a0tIgIzf/84bb27a9-608f-4cfc-a4c8-58de8aa5d791.mov">Screen Recording 2024-09-20 at 06.21.45.mov</video>
This commit is contained in:
parent
e3e15c6134
commit
661594aec8
@ -377,7 +377,6 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
|
|||||||
(item.name === 'Linked Doc' || item.name === 'Link')
|
(item.name === 'Linked Doc' || item.name === 'Link')
|
||||||
) {
|
) {
|
||||||
item.action = async ({ rootComponent }) => {
|
item.action = async ({ rootComponent }) => {
|
||||||
// TODO(@Mirone): fix the type
|
|
||||||
// @ts-expect-error fixme
|
// @ts-expect-error fixme
|
||||||
const { success, insertedLinkType } =
|
const { success, insertedLinkType } =
|
||||||
// @ts-expect-error fixme
|
// @ts-expect-error fixme
|
||||||
@ -385,7 +384,6 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
|
|||||||
|
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
|
|
||||||
// TODO(@Mirone): fix the type
|
|
||||||
insertedLinkType
|
insertedLinkType
|
||||||
?.then(
|
?.then(
|
||||||
(type: {
|
(type: {
|
||||||
@ -394,17 +392,17 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
|
|||||||
const flavour = type?.flavour;
|
const flavour = type?.flavour;
|
||||||
if (!flavour) return;
|
if (!flavour) return;
|
||||||
|
|
||||||
|
if (flavour === 'affine:bookmark') {
|
||||||
|
track.doc.editor.slashMenu.bookmark();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (flavour === 'affine:embed-linked-doc') {
|
if (flavour === 'affine:embed-linked-doc') {
|
||||||
track.doc.editor.slashMenu.linkDoc({
|
track.doc.editor.slashMenu.linkDoc({
|
||||||
control: 'linkDoc',
|
control: 'linkDoc',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flavour === 'affine:bookmark') {
|
|
||||||
track.doc.editor.slashMenu.bookmark();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { toURLSearchParams } from '@affine/core/utils';
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import { createContext, useCallback, useContext, useMemo } from 'react';
|
import { createContext, useCallback, useContext, useMemo } from 'react';
|
||||||
import type { NavigateFunction, NavigateOptions } from 'react-router-dom';
|
import type { NavigateFunction, NavigateOptions } from 'react-router-dom';
|
||||||
@ -45,11 +46,8 @@ export function useNavigateHelper() {
|
|||||||
elementIds?: string[],
|
elementIds?: string[],
|
||||||
logic: RouteLogic = RouteLogic.PUSH
|
logic: RouteLogic = RouteLogic.PUSH
|
||||||
) => {
|
) => {
|
||||||
const search = new URLSearchParams();
|
const search = toURLSearchParams({ mode, blockIds, elementIds });
|
||||||
if (mode) search.append('mode', mode);
|
const query = search?.size ? `?${search.toString()}` : '';
|
||||||
if (blockIds?.length) search.append('blockIds', blockIds.join(','));
|
|
||||||
if (elementIds?.length) search.append('elementIds', elementIds.join(','));
|
|
||||||
const query = search.size > 0 ? `?${search.toString()}` : '';
|
|
||||||
return navigate(`/workspace/${workspaceId}/${pageId}${query}`, {
|
return navigate(`/workspace/${workspaceId}/${pageId}${query}`, {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
|
@ -3,12 +3,14 @@ import { AppFallback } from '@affine/core/components/affine/app-container';
|
|||||||
import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline-viewer';
|
import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline-viewer';
|
||||||
import { useActiveBlocksuiteEditor } from '@affine/core/components/hooks/use-block-suite-editor';
|
import { useActiveBlocksuiteEditor } from '@affine/core/components/hooks/use-block-suite-editor';
|
||||||
import { usePageDocumentTitle } from '@affine/core/components/hooks/use-global-state';
|
import { usePageDocumentTitle } from '@affine/core/components/hooks/use-global-state';
|
||||||
|
import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper';
|
||||||
import { PageDetailEditor } from '@affine/core/components/page-detail-editor';
|
import { PageDetailEditor } from '@affine/core/components/page-detail-editor';
|
||||||
import { SharePageNotFoundError } from '@affine/core/components/share-page-not-found-error';
|
import { SharePageNotFoundError } from '@affine/core/components/share-page-not-found-error';
|
||||||
import { AppContainer, MainContainer } from '@affine/core/components/workspace';
|
import { AppContainer, MainContainer } from '@affine/core/components/workspace';
|
||||||
import { AuthService } from '@affine/core/modules/cloud';
|
import { AuthService } from '@affine/core/modules/cloud';
|
||||||
import {
|
import {
|
||||||
type Editor,
|
type Editor,
|
||||||
|
type EditorSelector,
|
||||||
EditorService,
|
EditorService,
|
||||||
EditorsService,
|
EditorsService,
|
||||||
} from '@affine/core/modules/editor';
|
} from '@affine/core/modules/editor';
|
||||||
@ -17,7 +19,12 @@ import { ShareReaderService } from '@affine/core/modules/share-doc';
|
|||||||
import { CloudBlobStorage } from '@affine/core/modules/workspace-engine';
|
import { CloudBlobStorage } from '@affine/core/modules/workspace-engine';
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { type DocMode, DocModes } from '@blocksuite/blocks';
|
import {
|
||||||
|
type DocMode,
|
||||||
|
DocModes,
|
||||||
|
RefNodeSlotsProvider,
|
||||||
|
} from '@blocksuite/blocks';
|
||||||
|
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||||
import { Logo1Icon } from '@blocksuite/icons/rc';
|
import { Logo1Icon } from '@blocksuite/icons/rc';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||||
import type { Doc, Workspace } from '@toeverything/infra';
|
import type { Doc, Workspace } from '@toeverything/infra';
|
||||||
@ -57,16 +64,29 @@ export const SharePage = ({
|
|||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const { mode, isTemplate, templateName, templateSnapshotUrl } =
|
const { mode, selector, isTemplate, templateName, templateSnapshotUrl } =
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
const searchParams = new URLSearchParams(location.search);
|
const searchParams = new URLSearchParams(location.search);
|
||||||
const queryStringMode = searchParams.get('mode') as DocMode | null;
|
const queryStringMode = searchParams.get('mode') as DocMode | null;
|
||||||
|
const blockIds = searchParams
|
||||||
|
.get('blockIds')
|
||||||
|
?.split(',')
|
||||||
|
.filter(v => v.length);
|
||||||
|
const elementIds = searchParams
|
||||||
|
.get('elementIds')
|
||||||
|
?.split(',')
|
||||||
|
.filter(v => v.length);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mode:
|
mode:
|
||||||
queryStringMode && DocModes.includes(queryStringMode)
|
queryStringMode && DocModes.includes(queryStringMode)
|
||||||
? queryStringMode
|
? queryStringMode
|
||||||
: null,
|
: null,
|
||||||
|
selector: {
|
||||||
|
blockIds,
|
||||||
|
elementIds,
|
||||||
|
refreshKey: searchParams.get('refreshKey') || undefined,
|
||||||
|
},
|
||||||
isTemplate: searchParams.has('isTemplate'),
|
isTemplate: searchParams.has('isTemplate'),
|
||||||
templateName: searchParams.get('templateName') || '',
|
templateName: searchParams.get('templateName') || '',
|
||||||
templateSnapshotUrl: searchParams.get('snapshotUrl') || '',
|
templateSnapshotUrl: searchParams.get('snapshotUrl') || '',
|
||||||
@ -94,6 +114,7 @@ export const SharePage = ({
|
|||||||
workspaceBinary={data.workspaceBinary}
|
workspaceBinary={data.workspaceBinary}
|
||||||
docBinary={data.docBinary}
|
docBinary={data.docBinary}
|
||||||
publishMode={mode || data.publishMode}
|
publishMode={mode || data.publishMode}
|
||||||
|
selector={selector}
|
||||||
isTemplate={isTemplate}
|
isTemplate={isTemplate}
|
||||||
templateName={templateName}
|
templateName={templateName}
|
||||||
templateSnapshotUrl={templateSnapshotUrl}
|
templateSnapshotUrl={templateSnapshotUrl}
|
||||||
@ -110,6 +131,7 @@ const SharePageInner = ({
|
|||||||
workspaceBinary,
|
workspaceBinary,
|
||||||
docBinary,
|
docBinary,
|
||||||
publishMode = 'page' as DocMode,
|
publishMode = 'page' as DocMode,
|
||||||
|
selector,
|
||||||
isTemplate,
|
isTemplate,
|
||||||
templateName,
|
templateName,
|
||||||
templateSnapshotUrl,
|
templateSnapshotUrl,
|
||||||
@ -119,6 +141,7 @@ const SharePageInner = ({
|
|||||||
workspaceBinary: Uint8Array;
|
workspaceBinary: Uint8Array;
|
||||||
docBinary: Uint8Array;
|
docBinary: Uint8Array;
|
||||||
publishMode?: DocMode;
|
publishMode?: DocMode;
|
||||||
|
selector?: EditorSelector;
|
||||||
isTemplate?: boolean;
|
isTemplate?: boolean;
|
||||||
templateName?: string;
|
templateName?: string;
|
||||||
templateSnapshotUrl?: string;
|
templateSnapshotUrl?: string;
|
||||||
@ -180,6 +203,10 @@ const SharePageInner = ({
|
|||||||
const editor = doc.scope.get(EditorsService).createEditor();
|
const editor = doc.scope.get(EditorsService).createEditor();
|
||||||
editor.setMode(publishMode);
|
editor.setMode(publishMode);
|
||||||
|
|
||||||
|
if (selector) {
|
||||||
|
editor.setSelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@ -190,11 +217,13 @@ const SharePageInner = ({
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
workspacesService,
|
workspacesService,
|
||||||
publishMode,
|
publishMode,
|
||||||
|
selector,
|
||||||
workspaceBinary,
|
workspaceBinary,
|
||||||
docBinary,
|
docBinary,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const pageTitle = useLiveData(page?.title$);
|
const pageTitle = useLiveData(page?.title$);
|
||||||
|
const { jumpToPageBlock, openPage } = useNavigateHelper();
|
||||||
|
|
||||||
usePageDocumentTitle(pageTitle);
|
usePageDocumentTitle(pageTitle);
|
||||||
|
|
||||||
@ -209,12 +238,35 @@ const SharePageInner = ({
|
|||||||
editorContainer,
|
editorContainer,
|
||||||
(editorContainer as any).docTitle
|
(editorContainer as any).docTitle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const disposable = new DisposableGroup();
|
||||||
|
const refNodeSlots =
|
||||||
|
editorContainer.host?.std.getOptional(RefNodeSlotsProvider);
|
||||||
|
if (refNodeSlots) {
|
||||||
|
disposable.add(
|
||||||
|
refNodeSlots.docLinkClicked.on(({ pageId, params }) => {
|
||||||
|
if (params) {
|
||||||
|
const { mode, blockIds, elementIds } = params;
|
||||||
|
return jumpToPageBlock(
|
||||||
|
workspaceId,
|
||||||
|
pageId,
|
||||||
|
mode,
|
||||||
|
blockIds,
|
||||||
|
elementIds
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return openPage(workspaceId, pageId);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unbind();
|
unbind();
|
||||||
editor.setEditorContainer(null);
|
editor.setEditorContainer(null);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[editor, setActiveBlocksuiteEditor]
|
[editor, setActiveBlocksuiteEditor, jumpToPageBlock, openPage, workspaceId]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!workspace || !page || !editor) {
|
if (!workspace || !page || !editor) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import { toURLSearchParams } from '@affine/core/utils';
|
||||||
import { Unreachable } from '@affine/env/constant';
|
import { Unreachable } from '@affine/env/constant';
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { ReferenceParams } from '@blocksuite/blocks';
|
||||||
import { Entity, LiveData } from '@toeverything/infra';
|
import { Entity, LiveData } from '@toeverything/infra';
|
||||||
import { type To } from 'history';
|
import { type To } from 'history';
|
||||||
|
import { omit } from 'lodash-es';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
import type { WorkbenchNewTabHandler } from '../services/workbench-new-tab-handler';
|
import type { WorkbenchNewTabHandler } from '../services/workbench-new-tab-handler';
|
||||||
@ -122,14 +124,7 @@ export class Workbench extends Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openDoc(
|
openDoc(
|
||||||
id:
|
id: string | ({ docId: string } & ReferenceParams),
|
||||||
| string
|
|
||||||
| {
|
|
||||||
docId: string;
|
|
||||||
mode?: DocMode;
|
|
||||||
blockIds?: string[];
|
|
||||||
elementIds?: string[];
|
|
||||||
},
|
|
||||||
options?: WorkbenchOpenOptions
|
options?: WorkbenchOpenOptions
|
||||||
) {
|
) {
|
||||||
const isString = typeof id === 'string';
|
const isString = typeof id === 'string';
|
||||||
@ -137,12 +132,10 @@ export class Workbench extends Entity {
|
|||||||
|
|
||||||
let query = '';
|
let query = '';
|
||||||
if (!isString) {
|
if (!isString) {
|
||||||
const { mode, blockIds, elementIds } = id;
|
const search = toURLSearchParams(omit(id, ['docId']));
|
||||||
const search = new URLSearchParams();
|
if (search?.size) {
|
||||||
if (mode) search.set('mode', mode);
|
query = `?${search.toString()}`;
|
||||||
if (blockIds?.length) search.set('blockIds', blockIds.join(','));
|
}
|
||||||
if (elementIds?.length) search.set('elementIds', elementIds.join(','));
|
|
||||||
if (search.size > 0) query = `?${search.toString()}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.open(`/${docId}${query}`, options);
|
this.open(`/${docId}${query}`, options);
|
||||||
|
Loading…
Reference in New Issue
Block a user