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:
akumatus
2024-09-05 07:30:20 +00:00
parent f452414952
commit 19a7d1eb92
8 changed files with 1890 additions and 1730 deletions

View File

@@ -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[

View File

@@ -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

View File

@@ -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[

View File

@@ -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']()}

View File

@@ -132,6 +132,8 @@ export const ShapeSettings = () => {
<EdgelessSnapshot
title={t['com.affine.settings.editorSettings.edgeless.shape']()}
docName="shape"
keyName="shape"
flavour="shape"
/>
<RadioGroup

View File

@@ -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>

View File

@@ -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']()}