Skip to content

Commit f452414

Browse files
committed
fix(core): hide the footer that blocks the toolbar in shared page (#8091)
close PD-1405 CLOUD-64 https://github.com/user-attachments/assets/f6ed2dfc-d238-41d8-abaf-684193a080ff
1 parent 03c2051 commit f452414

File tree

11 files changed

+278
-403
lines changed

11 files changed

+278
-403
lines changed

packages/frontend/core/src/components/blocksuite/block-suite-editor/blocksuite-editor-container.tsx

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { EditorService } from '@affine/core/modules/editor';
21
import type { ReferenceInfo } from '@blocksuite/affine-model';
32
import type { DocMode } from '@blocksuite/blocks';
43
import type {
@@ -8,13 +7,12 @@ import type {
87
PageEditor,
98
} from '@blocksuite/presets';
109
import { type Doc, Slot } from '@blocksuite/store';
11-
import { useService } from '@toeverything/infra';
1210
import clsx from 'clsx';
1311
import type React from 'react';
1412
import {
1513
forwardRef,
1614
useCallback,
17-
useEffect,
15+
useImperativeHandle,
1816
useLayoutEffect,
1917
useMemo,
2018
useRef,
@@ -60,7 +58,6 @@ export const BlocksuiteEditorContainer = forwardRef<
6058
{ page, mode, className, style, shared },
6159
ref
6260
) {
63-
const editorService = useService(EditorService);
6461
const rootRef = useRef<HTMLDivElement>(null);
6562
const docRef = useRef<PageEditor>(null);
6663
const docTitleRef = useRef<DocTitle>(null);
@@ -112,6 +109,9 @@ export const BlocksuiteEditorContainer = forwardRef<
112109
get doc() {
113110
return page;
114111
},
112+
get docTitle() {
113+
return docTitleRef.current;
114+
},
115115
get host() {
116116
return mode === 'page'
117117
? docRef.current?.host
@@ -159,35 +159,9 @@ export const BlocksuiteEditorContainer = forwardRef<
159159
return proxy;
160160
}, [mode, page, slots]);
161161

162-
useEffect(() => {
163-
if (ref) {
164-
if (typeof ref === 'function') {
165-
ref(affineEditorContainerProxy);
166-
} else {
167-
ref.current = affineEditorContainerProxy;
168-
}
169-
}
170-
}, [affineEditorContainerProxy, ref]);
171-
172-
useEffect(() => {
173-
let canceled = false;
174-
let unsubscribe: () => void = () => {};
175-
176-
affineEditorContainerProxy.updateComplete
177-
.then(() => {
178-
if (!canceled) {
179-
unsubscribe = editorService.editor.bindEditorContainer(
180-
affineEditorContainerProxy,
181-
docTitleRef.current as DocTitle
182-
);
183-
}
184-
})
185-
.catch(console.error);
186-
return () => {
187-
canceled = true;
188-
unsubscribe();
189-
};
190-
}, [affineEditorContainerProxy, mode, editorService]);
162+
useImperativeHandle(ref, () => affineEditorContainerProxy, [
163+
affineEditorContainerProxy,
164+
]);
191165

192166
const handleClickPageModeBlank = useCallback(() => {
193167
affineEditorContainerProxy.host?.std.command.exec(
Lines changed: 105 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
1+
import { useRefEffect } from '@affine/component';
12
import { EditorLoading } from '@affine/component/page-detail-skeleton';
2-
import type { DocMode } from '@blocksuite/blocks';
3-
import { assertExists } from '@blocksuite/global/utils';
3+
import {
4+
BookmarkBlockService,
5+
customImageProxyMiddleware,
6+
type DocMode,
7+
EmbedGithubBlockService,
8+
EmbedLoomBlockService,
9+
EmbedYoutubeBlockService,
10+
ImageBlockService,
11+
} from '@blocksuite/blocks';
12+
import { DisposableGroup } from '@blocksuite/global/utils';
413
import type { AffineEditorContainer } from '@blocksuite/presets';
514
import type { Doc } from '@blocksuite/store';
615
import { use } from 'foxact/use';
7-
import type { CSSProperties, ReactElement } from 'react';
8-
import {
9-
forwardRef,
10-
memo,
11-
Suspense,
12-
useCallback,
13-
useEffect,
14-
useRef,
15-
} from 'react';
16+
import type { CSSProperties } from 'react';
17+
import { Suspense, useEffect } from 'react';
1618

1719
import { BlocksuiteEditorContainer } from './blocksuite-editor-container';
1820
import { NoPageRootError } from './no-page-error';
1921

20-
export type ErrorBoundaryProps = {
21-
onReset?: () => void;
22-
};
23-
2422
export type EditorProps = {
2523
page: Doc;
2624
mode: DocMode;
2725
shared?: boolean;
28-
// on Editor instance instantiated
29-
onLoadEditor?: (editor: AffineEditorContainer) => () => void;
26+
// on Editor ready
27+
onEditorReady?: (editor: AffineEditorContainer) => (() => void) | void;
3028
style?: CSSProperties;
3129
className?: string;
3230
};
@@ -53,73 +51,100 @@ function usePageRoot(page: Doc) {
5351
return page.root;
5452
}
5553

56-
const BlockSuiteEditorImpl = forwardRef<AffineEditorContainer, EditorProps>(
57-
function BlockSuiteEditorImpl(
58-
{ mode, page, className, onLoadEditor, shared, style },
59-
ref
60-
) {
61-
usePageRoot(page);
62-
assertExists(page, 'page should not be null');
63-
const editorDisposeRef = useRef<() => void>(() => {});
64-
const editorRef = useRef<AffineEditorContainer | null>(null);
65-
66-
const onRefChange = useCallback(
67-
(editor: AffineEditorContainer | null) => {
68-
editorRef.current = editor;
69-
if (ref) {
70-
if (typeof ref === 'function') {
71-
ref(editor);
72-
} else {
73-
ref.current = editor;
74-
}
75-
}
76-
if (editor && onLoadEditor) {
77-
editorDisposeRef.current = onLoadEditor(editor);
78-
}
79-
},
80-
[onLoadEditor, ref]
81-
);
54+
const BlockSuiteEditorImpl = ({
55+
mode,
56+
page,
57+
className,
58+
shared,
59+
style,
60+
onEditorReady,
61+
}: EditorProps) => {
62+
usePageRoot(page);
8263

83-
useEffect(() => {
84-
const disposable = page.slots.blockUpdated.once(() => {
85-
page.collection.setDocMeta(page.id, {
86-
updatedDate: Date.now(),
87-
});
64+
useEffect(() => {
65+
const disposable = page.slots.blockUpdated.once(() => {
66+
page.collection.setDocMeta(page.id, {
67+
updatedDate: Date.now(),
8868
});
89-
return () => {
90-
disposable.dispose();
91-
};
92-
}, [page]);
69+
});
70+
return () => {
71+
disposable.dispose();
72+
};
73+
}, [page]);
74+
75+
const editorRef = useRefEffect(
76+
(editor: AffineEditorContainer) => {
77+
globalThis.currentEditor = editor;
78+
let canceled = false;
79+
const disposableGroup = new DisposableGroup();
80+
81+
if (onEditorReady) {
82+
// Invoke onLoad once the editor has been mounted to the DOM.
83+
editor.updateComplete
84+
.then(() => {
85+
if (canceled) {
86+
return;
87+
}
88+
// host should be ready
89+
90+
// provide image proxy endpoint to blocksuite
91+
editor.host?.std.clipboard.use(
92+
customImageProxyMiddleware(runtimeConfig.imageProxyUrl)
93+
);
94+
ImageBlockService.setImageProxyURL(runtimeConfig.imageProxyUrl);
95+
96+
// provide link preview endpoint to blocksuite
97+
BookmarkBlockService.setLinkPreviewEndpoint(
98+
runtimeConfig.linkPreviewUrl
99+
);
100+
EmbedGithubBlockService.setLinkPreviewEndpoint(
101+
runtimeConfig.linkPreviewUrl
102+
);
103+
EmbedYoutubeBlockService.setLinkPreviewEndpoint(
104+
runtimeConfig.linkPreviewUrl
105+
);
106+
EmbedLoomBlockService.setLinkPreviewEndpoint(
107+
runtimeConfig.linkPreviewUrl
108+
);
109+
110+
return editor.host?.updateComplete;
111+
})
112+
.then(() => {
113+
if (canceled) {
114+
return;
115+
}
116+
const dispose = onEditorReady(editor);
117+
if (dispose) {
118+
disposableGroup.add(dispose);
119+
}
120+
})
121+
.catch(console.error);
122+
}
93123

94-
useEffect(() => {
95124
return () => {
96-
editorDisposeRef.current();
125+
canceled = true;
126+
disposableGroup.dispose();
97127
};
98-
}, []);
128+
},
129+
[onEditorReady, page]
130+
);
99131

100-
return (
101-
<BlocksuiteEditorContainer
102-
mode={mode}
103-
page={page}
104-
shared={shared}
105-
ref={onRefChange}
106-
className={className}
107-
style={style}
108-
/>
109-
);
110-
}
111-
);
112-
113-
export const BlockSuiteEditor = memo(
114-
forwardRef<AffineEditorContainer, EditorProps>(
115-
function BlockSuiteEditor(props, ref): ReactElement {
116-
return (
117-
<Suspense fallback={<EditorLoading />}>
118-
<BlockSuiteEditorImpl key={props.page.id} ref={ref} {...props} />
119-
</Suspense>
120-
);
121-
}
122-
)
123-
);
132+
return (
133+
<BlocksuiteEditorContainer
134+
mode={mode}
135+
page={page}
136+
shared={shared}
137+
ref={editorRef}
138+
className={className}
139+
style={style}
140+
/>
141+
);
142+
};
124143

125-
BlockSuiteEditor.displayName = 'BlockSuiteEditor';
144+
export const BlockSuiteEditor = (props: EditorProps) => {
145+
return (
146+
<Suspense fallback={<EditorLoading />}>
147+
<BlockSuiteEditorImpl key={props.page.id} {...props} />
148+
</Suspense>
149+
);
150+
};

packages/frontend/core/src/components/blocksuite/block-suite-header/present/detail-header-present-button.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { IconButton } from '@affine/component';
2+
import { EditorService } from '@affine/core/modules/editor';
23
import { PresentationIcon } from '@blocksuite/icons/rc';
3-
4-
import { usePresent } from './use-present';
4+
import { useService } from '@toeverything/infra';
55

66
export const DetailPageHeaderPresentButton = () => {
7-
const { isPresent, handlePresent } = usePresent();
7+
const editorService = useService(EditorService);
88

99
return (
1010
<IconButton
1111
style={{ flexShrink: 0 }}
1212
size="24"
13-
onClick={() => handlePresent(!isPresent)}
13+
onClick={() => editorService.editor.togglePresentation()}
1414
>
1515
<PresentationIcon />
1616
</IconButton>

packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts

Lines changed: 0 additions & 59 deletions
This file was deleted.

packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import { Button } from '@affine/component/ui/button';
2+
import { EditorService } from '@affine/core/modules/editor';
23
import { useI18n } from '@affine/i18n';
34
import { PresentationIcon } from '@blocksuite/icons/rc';
5+
import { useLiveData, useService } from '@toeverything/infra';
46

5-
import { usePresent } from '../../blocksuite/block-suite-header/present/use-present';
67
import * as styles from './styles.css';
78

89
export const PresentButton = () => {
910
const t = useI18n();
10-
const { isPresent, handlePresent } = usePresent();
11+
const editorService = useService(EditorService);
12+
const isPresent = useLiveData(editorService.editor.isPresenting$);
1113

1214
return (
1315
<Button
1416
prefix={<PresentationIcon />}
1517
className={styles.presentButton}
16-
onClick={() => handlePresent()}
18+
onClick={() => editorService.editor.togglePresentation()}
1719
disabled={isPresent}
1820
>
1921
{t['com.affine.share-page.header.present']()}

0 commit comments

Comments
 (0)