mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(core): observe editor settings change and update edgeless editor (#8105)
<div class='graphite__hidden'>
<div>🎥 Video uploaded on Graphite:</div>
<a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/cfdd0578-274c-42e3-9ef5-5528e8b25306.mov">
<img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/cfdd0578-274c-42e3-9ef5-5528e8b25306.mov">
</a>
</div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/cfdd0578-274c-42e3-9ef5-5528e8b25306.mov">录屏2024-09-05 14.32.41.mov</video>
This commit is contained in:
@@ -191,6 +191,8 @@ export const ConnectorSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.connecter']()}
|
||||
docName="connector"
|
||||
keyName="connector"
|
||||
flavour="connector"
|
||||
/>
|
||||
<SettingRow
|
||||
name={t[
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,8 @@ export const MindMapSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.mind-map']()}
|
||||
docName="mindmap"
|
||||
keyName={'mindmap' as any}
|
||||
flavour="mindmap"
|
||||
height={320}
|
||||
/>
|
||||
<SettingRow
|
||||
|
||||
@@ -170,6 +170,8 @@ export const NoteSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.note']()}
|
||||
docName="note"
|
||||
keyName="affine:note"
|
||||
flavour="affine:note"
|
||||
/>
|
||||
<SettingRow
|
||||
name={t[
|
||||
|
||||
@@ -45,6 +45,8 @@ export const PenSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.pen']()}
|
||||
docName="pen"
|
||||
keyName="brush"
|
||||
flavour="brush"
|
||||
/>
|
||||
<SettingRow
|
||||
name={t['com.affine.settings.editorSettings.edgeless.pen.color']()}
|
||||
|
||||
@@ -132,6 +132,8 @@ export const ShapeSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.shape']()}
|
||||
docName="shape"
|
||||
keyName="shape"
|
||||
flavour="shape"
|
||||
/>
|
||||
|
||||
<RadioGroup
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import type { EditorSettingSchema } from '@affine/core/modules/editor-settting';
|
||||
import { EditorSettingService } from '@affine/core/modules/editor-settting';
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import { BlockStdScope } from '@blocksuite/block-std';
|
||||
import type { SurfaceBlockModel } from '@blocksuite/block-std/gfx';
|
||||
import type { EdgelessRootService, FrameBlockModel } from '@blocksuite/blocks';
|
||||
import { SpecProvider } from '@blocksuite/blocks';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import { useFramework } from '@toeverything/infra';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { map, pairwise } from 'rxjs';
|
||||
|
||||
import { snapshotContainer, snapshotTitle } from '../style.css';
|
||||
import { type DocName, getDocByName } from './docs';
|
||||
@@ -11,9 +18,16 @@ import { type DocName, getDocByName } from './docs';
|
||||
interface Props {
|
||||
title: string;
|
||||
docName: DocName;
|
||||
flavour: BlockSuite.EdgelessModelKeys;
|
||||
keyName: keyof EditorSettingSchema;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
export function getSurfaceBlock(doc: Doc) {
|
||||
const blocks = doc.getBlocksByFlavour('affine:surface');
|
||||
return blocks.length !== 0 ? (blocks[0].model as SurfaceBlockModel) : null;
|
||||
}
|
||||
|
||||
function getFrameBlock(doc: Doc) {
|
||||
const blocks = doc.getBlocksByFlavour('affine:frame');
|
||||
return blocks.length !== 0 ? (blocks[0].model as FrameBlockModel) : null;
|
||||
@@ -22,8 +36,30 @@ function getFrameBlock(doc: Doc) {
|
||||
const boundMap = new Map<DocName, Bound>();
|
||||
|
||||
export const EdgelessSnapshot = (props: Props) => {
|
||||
const { title, docName, height = 180 } = props;
|
||||
const { title, docName, flavour, keyName, height = 180 } = props;
|
||||
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
||||
const docRef = useRef<Doc | null>(null);
|
||||
const editorHostRef = useRef<EditorHost | null>(null);
|
||||
const framework = useFramework();
|
||||
const { editorSetting } = framework.get(EditorSettingService);
|
||||
|
||||
const updateElement = useCallback(
|
||||
(props: Record<string, unknown>) => {
|
||||
const editorHost = editorHostRef.current;
|
||||
const doc = docRef.current;
|
||||
if (!editorHost || !doc) return;
|
||||
const edgelessService = editorHost.std.getService(
|
||||
'affine:page'
|
||||
) as EdgelessRootService;
|
||||
const blocks = doc.getBlocksByFlavour(flavour);
|
||||
const surface = getSurfaceBlock(doc);
|
||||
const elements = surface?.getElementsByType(flavour) || [];
|
||||
[...blocks, ...elements].forEach(ele => {
|
||||
edgelessService.updateElement(ele.id, props);
|
||||
});
|
||||
},
|
||||
[flavour]
|
||||
);
|
||||
|
||||
const renderEditor = useCallback(async () => {
|
||||
if (!wrapperRef.current) return;
|
||||
@@ -34,12 +70,15 @@ export const EdgelessSnapshot = (props: Props) => {
|
||||
doc,
|
||||
extensions: SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
||||
}).render();
|
||||
docRef.current = doc;
|
||||
editorHostRef.current = editorHost;
|
||||
const settings = editorSetting.get(keyName);
|
||||
updateElement(settings as any);
|
||||
|
||||
// refresh viewport
|
||||
const edgelessService = editorHost.std.getService(
|
||||
'affine:page'
|
||||
) as EdgelessRootService;
|
||||
|
||||
// refresh viewport
|
||||
edgelessService.specSlots.viewConnected.once(({ component }) => {
|
||||
const edgelessBlock = component as any;
|
||||
edgelessBlock.editorViewportSelector = 'ref-viewport';
|
||||
@@ -54,14 +93,36 @@ export const EdgelessSnapshot = (props: Props) => {
|
||||
});
|
||||
});
|
||||
|
||||
// append to dom node
|
||||
wrapperRef.current.append(editorHost);
|
||||
}, [docName]);
|
||||
}, [docName, editorSetting, keyName, updateElement]);
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
renderEditor();
|
||||
}, [renderEditor]);
|
||||
|
||||
// observe editor settings change
|
||||
useEffect(() => {
|
||||
const sub = editorSetting.provider
|
||||
.watchAll()
|
||||
.pipe(
|
||||
map(settings => {
|
||||
if (typeof settings[keyName] === 'string') {
|
||||
return JSON.parse(settings[keyName]);
|
||||
}
|
||||
return keyName;
|
||||
}),
|
||||
pairwise()
|
||||
)
|
||||
.subscribe(([prev, current]) => {
|
||||
if (!isEqual(prev, current)) {
|
||||
updateElement(current);
|
||||
}
|
||||
});
|
||||
return () => sub.unsubscribe();
|
||||
}, [editorSetting.provider, flavour, keyName, updateElement]);
|
||||
|
||||
return (
|
||||
<div className={snapshotContainer}>
|
||||
<div className={snapshotTitle}>{title}</div>
|
||||
|
||||
@@ -141,6 +141,8 @@ export const TextSettings = () => {
|
||||
<EdgelessSnapshot
|
||||
title={t['com.affine.settings.editorSettings.edgeless.text']()}
|
||||
docName="text"
|
||||
keyName="affine:edgeless-text"
|
||||
flavour="affine:edgeless-text"
|
||||
/>
|
||||
<SettingRow
|
||||
name={t['com.affine.settings.editorSettings.edgeless.text.color']()}
|
||||
|
||||
Reference in New Issue
Block a user