feat(core): frame editor settings (#9970)
Co-authored-by: L-Sun <zover.v@gmail.com> Co-authored-by: Mirone <Saul-Mirone@outlook.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import type {
|
import type {
|
||||||
GfxBlockElementModel,
|
GfxBlockElementModel,
|
||||||
|
GfxCompatibleProps,
|
||||||
GfxElementGeometry,
|
GfxElementGeometry,
|
||||||
GfxGroupCompatibleInterface,
|
GfxGroupCompatibleInterface,
|
||||||
GfxModel,
|
GfxModel,
|
||||||
@@ -10,7 +11,6 @@ import {
|
|||||||
descendantElementsImpl,
|
descendantElementsImpl,
|
||||||
generateKeyBetweenV2,
|
generateKeyBetweenV2,
|
||||||
GfxCompatible,
|
GfxCompatible,
|
||||||
GfxCompatibleZodSchema,
|
|
||||||
gfxGroupCompatibleSymbol,
|
gfxGroupCompatibleSymbol,
|
||||||
hasDescendantElementImpl,
|
hasDescendantElementImpl,
|
||||||
} from '@blocksuite/block-std/gfx';
|
} from '@blocksuite/block-std/gfx';
|
||||||
@@ -18,33 +18,33 @@ import { Bound } from '@blocksuite/global/utils';
|
|||||||
import { BlockModel, defineBlockSchema, type Text } from '@blocksuite/store';
|
import { BlockModel, defineBlockSchema, type Text } from '@blocksuite/store';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { ColorSchema, DefaultTheme } from '../../themes/index.js';
|
import { type Color, ColorSchema, DefaultTheme } from '../../themes/index.js';
|
||||||
|
|
||||||
|
export type FrameBlockProps = {
|
||||||
|
title: Text;
|
||||||
|
background: Color;
|
||||||
|
childElementIds?: Record<string, boolean>;
|
||||||
|
presentationIndex?: string;
|
||||||
|
} & GfxCompatibleProps;
|
||||||
|
|
||||||
export const FrameZodSchema = z
|
export const FrameZodSchema = z
|
||||||
.object({
|
.object({
|
||||||
background: ColorSchema,
|
background: ColorSchema,
|
||||||
childElementIds: z.record(z.boolean()),
|
|
||||||
presentationIndex: z.string(),
|
|
||||||
})
|
})
|
||||||
.and(GfxCompatibleZodSchema)
|
|
||||||
.default({
|
.default({
|
||||||
background: DefaultTheme.transparent,
|
background: DefaultTheme.transparent,
|
||||||
xywh: `[0,0,100,100]`,
|
|
||||||
index: 'a0',
|
|
||||||
childElementIds: Object.create(null),
|
|
||||||
presentationIndex: generateKeyBetweenV2(null, null),
|
|
||||||
lockedBySelf: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type FrameBlockProps = z.infer<typeof FrameZodSchema> & {
|
|
||||||
title: Text;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FrameBlockSchema = defineBlockSchema({
|
export const FrameBlockSchema = defineBlockSchema({
|
||||||
flavour: 'affine:frame',
|
flavour: 'affine:frame',
|
||||||
props: (internal): FrameBlockProps => ({
|
props: (internal): FrameBlockProps => ({
|
||||||
title: internal.Text(),
|
title: internal.Text(),
|
||||||
...FrameZodSchema.parse(undefined),
|
background: 'transparent',
|
||||||
|
xywh: `[0,0,100,100]`,
|
||||||
|
index: 'a0',
|
||||||
|
childElementIds: Object.create(null),
|
||||||
|
presentationIndex: generateKeyBetweenV2(null, null),
|
||||||
|
lockedBySelf: false,
|
||||||
}),
|
}),
|
||||||
metadata: {
|
metadata: {
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|||||||
@@ -158,15 +158,12 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
|||||||
const { service, surfaceBlockModel } = edgeless;
|
const { service, surfaceBlockModel } = edgeless;
|
||||||
const frameMgr = service.frame;
|
const frameMgr = service.frame;
|
||||||
const frameIndex = service.frames.length + 1;
|
const frameIndex = service.frames.length + 1;
|
||||||
const id = this.crud.addBlock(
|
const props = this.std.get(EditPropsStore).applyLastProps('affine:frame', {
|
||||||
'affine:frame',
|
title: new Y.Text(`Frame ${frameIndex}`),
|
||||||
{
|
xywh: serializeXYWH(...xywh),
|
||||||
title: new Y.Text(`Frame ${frameIndex}`),
|
presentationIndex: frameMgr.generatePresentationIndex(),
|
||||||
xywh: serializeXYWH(...xywh),
|
});
|
||||||
presentationIndex: frameMgr.generatePresentationIndex(),
|
const id = this.crud.addBlock('affine:frame', props, surfaceBlockModel);
|
||||||
},
|
|
||||||
surfaceBlockModel
|
|
||||||
);
|
|
||||||
edgeless.doc.captureSync();
|
edgeless.doc.captureSync();
|
||||||
const frame = this.crud.getElementById(id);
|
const frame = this.crud.getElementById(id);
|
||||||
if (!frame) return;
|
if (!frame) return;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||||
import { Overlay } from '@blocksuite/affine-block-surface';
|
import { Overlay } from '@blocksuite/affine-block-surface';
|
||||||
|
import type { FrameBlockModel, NoteBlockModel } from '@blocksuite/affine-model';
|
||||||
|
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
generateKeyBetweenV2,
|
generateKeyBetweenV2,
|
||||||
getTopElements,
|
getTopElements,
|
||||||
@@ -23,7 +25,6 @@ import type { Store } from '@blocksuite/store';
|
|||||||
import { Text } from '@blocksuite/store';
|
import { Text } from '@blocksuite/store';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
import type { FrameBlockModel, NoteBlockModel } from '../../index.js';
|
|
||||||
import { areSetsEqual } from './utils/misc.js';
|
import { areSetsEqual } from './utils/misc.js';
|
||||||
import { isFrameBlock } from './utils/query.js';
|
import { isFrameBlock } from './utils/query.js';
|
||||||
|
|
||||||
@@ -194,16 +195,16 @@ export class EdgelessFrameManager extends GfxExtension {
|
|||||||
|
|
||||||
private _addFrameBlock(bound: Bound) {
|
private _addFrameBlock(bound: Bound) {
|
||||||
const surfaceModel = this.gfx.surface as SurfaceBlockModel;
|
const surfaceModel = this.gfx.surface as SurfaceBlockModel;
|
||||||
const id = this.gfx.doc.addBlock(
|
const props = this.gfx.std
|
||||||
'affine:frame',
|
.get(EditPropsStore)
|
||||||
{
|
.applyLastProps('affine:frame', {
|
||||||
title: new Text(new Y.Text(`Frame ${this.frames.length + 1}`)),
|
title: new Text(new Y.Text(`Frame ${this.frames.length + 1}`)),
|
||||||
xywh: bound.serialize(),
|
xywh: bound.serialize(),
|
||||||
index: this.gfx.layer.generateIndex(true),
|
index: this.gfx.layer.generateIndex(true),
|
||||||
presentationIndex: this.generatePresentationIndex(),
|
presentationIndex: this.generatePresentationIndex(),
|
||||||
},
|
});
|
||||||
surfaceModel
|
|
||||||
);
|
const id = this.gfx.doc.addBlock('affine:frame', props, surfaceModel);
|
||||||
const frameModel = this.gfx.getElementById(id);
|
const frameModel = this.gfx.getElementById(id);
|
||||||
|
|
||||||
if (!frameModel || !isFrameBlock(frameModel)) {
|
if (!frameModel || !isFrameBlock(frameModel)) {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { OverlayIdentifier } from '@blocksuite/affine-block-surface';
|
import { OverlayIdentifier } from '@blocksuite/affine-block-surface';
|
||||||
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
||||||
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
import {
|
||||||
|
EditPropsStore,
|
||||||
|
TelemetryProvider,
|
||||||
|
} from '@blocksuite/affine-shared/services';
|
||||||
import type { PointerEventState } from '@blocksuite/block-std';
|
import type { PointerEventState } from '@blocksuite/block-std';
|
||||||
import {
|
import {
|
||||||
BaseTool,
|
BaseTool,
|
||||||
@@ -70,16 +73,17 @@ export class FrameTool extends BaseTool {
|
|||||||
const frames = this.gfx.layer.blocks.filter(
|
const frames = this.gfx.layer.blocks.filter(
|
||||||
block => block.flavour === 'affine:frame'
|
block => block.flavour === 'affine:frame'
|
||||||
) as FrameBlockModel[];
|
) as FrameBlockModel[];
|
||||||
const id = this.doc.addBlock(
|
|
||||||
'affine:frame',
|
const props = this.std
|
||||||
{
|
.get(EditPropsStore)
|
||||||
|
.applyLastProps('affine:frame', {
|
||||||
title: new Text(new Y.Text(`Frame ${frames.length + 1}`)),
|
title: new Text(new Y.Text(`Frame ${frames.length + 1}`)),
|
||||||
xywh: Bound.fromPoints([this._startPoint, currentPoint]).serialize(),
|
xywh: Bound.fromPoints([this._startPoint, currentPoint]).serialize(),
|
||||||
index: this.gfx.layer.generateIndex(true),
|
index: this.gfx.layer.generateIndex(true),
|
||||||
presentationIndex: this.frameManager.generatePresentationIndex(),
|
presentationIndex: this.frameManager.generatePresentationIndex(),
|
||||||
},
|
});
|
||||||
this.gfx.surface
|
|
||||||
);
|
const id = this.doc.addBlock('affine:frame', props, this.gfx.surface);
|
||||||
|
|
||||||
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||||
control: 'canvas:draw',
|
control: 'canvas:draw',
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ export {
|
|||||||
export {
|
export {
|
||||||
GfxBlockElementModel,
|
GfxBlockElementModel,
|
||||||
type GfxCommonBlockProps,
|
type GfxCommonBlockProps,
|
||||||
GfxCommonBlockZodSchema,
|
|
||||||
GfxCompatibleBlockModel as GfxCompatible,
|
GfxCompatibleBlockModel as GfxCompatible,
|
||||||
type GfxCompatibleProps,
|
type GfxCompatibleProps,
|
||||||
GfxCompatibleZodSchema,
|
|
||||||
} from './model/gfx-block-model.js';
|
} from './model/gfx-block-model.js';
|
||||||
export { type GfxModel } from './model/model.js';
|
export { type GfxModel } from './model/model.js';
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ import {
|
|||||||
polygonGetPointTangent,
|
polygonGetPointTangent,
|
||||||
polygonNearestPoint,
|
polygonNearestPoint,
|
||||||
rotatePoints,
|
rotatePoints,
|
||||||
SerializedXYWHZodSchema,
|
|
||||||
} from '@blocksuite/global/utils';
|
} from '@blocksuite/global/utils';
|
||||||
import { BlockModel } from '@blocksuite/store';
|
import { BlockModel } from '@blocksuite/store';
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isLockedByAncestorImpl,
|
isLockedByAncestorImpl,
|
||||||
@@ -35,24 +33,20 @@ import type { SurfaceBlockModel } from './surface/surface-model.js';
|
|||||||
/**
|
/**
|
||||||
* The props that a graphics block model should have.
|
* The props that a graphics block model should have.
|
||||||
*/
|
*/
|
||||||
export const GfxCompatibleZodSchema = z.object({
|
export type GfxCompatibleProps = {
|
||||||
xywh: SerializedXYWHZodSchema,
|
xywh: SerializedXYWH;
|
||||||
index: z.string(),
|
index: string;
|
||||||
lockedBySelf: z.boolean().optional(),
|
lockedBySelf?: boolean;
|
||||||
});
|
};
|
||||||
export type GfxCompatibleProps = z.infer<typeof GfxCompatibleZodSchema>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This type include the common props for the graphic block model.
|
* This type include the common props for the graphic block model.
|
||||||
* You can use this type with Omit to define the props of a graphic block model.
|
* You can use this type with Omit to define the props of a graphic block model.
|
||||||
*/
|
*/
|
||||||
export const GfxCommonBlockZodSchema = GfxCompatibleZodSchema.and(
|
export type GfxCommonBlockProps = GfxCompatibleProps & {
|
||||||
z.object({
|
rotate: number;
|
||||||
rotate: z.number(),
|
scale: number;
|
||||||
scale: z.number(),
|
};
|
||||||
})
|
|
||||||
);
|
|
||||||
export type GfxCommonBlockProps = z.infer<typeof GfxCommonBlockZodSchema>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The graphic block model that can be rendered in the graphics mode.
|
* The graphic block model that can be rendered in the graphics mode.
|
||||||
|
|||||||
@@ -16,5 +16,4 @@ export * from './slot.js';
|
|||||||
export * from './types.js';
|
export * from './types.js';
|
||||||
export * from './with-disposable.js';
|
export * from './with-disposable.js';
|
||||||
export type { SerializedXYWH, XYWH } from './xywh.js';
|
export type { SerializedXYWH, XYWH } from './xywh.js';
|
||||||
export { SerializedXYWHZodSchema } from './xywh.js';
|
|
||||||
export { deserializeXYWH, serializeXYWH } from './xywh.js';
|
export { deserializeXYWH, serializeXYWH } from './xywh.js';
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XYWH represents the x, y, width, and height of an element or block.
|
* XYWH represents the x, y, width, and height of an element or block.
|
||||||
*/
|
*/
|
||||||
@@ -10,30 +8,6 @@ export type XYWH = [number, number, number, number];
|
|||||||
*/
|
*/
|
||||||
export type SerializedXYWH = `[${number},${number},${number},${number}]`;
|
export type SerializedXYWH = `[${number},${number},${number},${number}]`;
|
||||||
|
|
||||||
export const SerializedXYWHZodSchema = z.custom<SerializedXYWH>((val: any) => {
|
|
||||||
if (typeof val !== 'string') {
|
|
||||||
throw new Error('SerializedXYWH should be a string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!val.startsWith('[') || !val.endsWith(']')) {
|
|
||||||
throw new Error('SerializedXYWH should be wrapped in square brackets');
|
|
||||||
}
|
|
||||||
|
|
||||||
const parts = val.slice(1, -1).split(',');
|
|
||||||
|
|
||||||
if (parts.length !== 4) {
|
|
||||||
throw new Error('SerializedXYWH should have 4 parts');
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const part of parts) {
|
|
||||||
if (!/^\d+$/.test(part)) {
|
|
||||||
throw new Error('Each part of SerializedXYWH should be a number');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return val as SerializedXYWH;
|
|
||||||
});
|
|
||||||
|
|
||||||
export function serializeXYWH(
|
export function serializeXYWH(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"meta": {
|
||||||
|
"id": "gIUEIHL42k",
|
||||||
|
"title": "FrameDoc",
|
||||||
|
"createDate": 1738858597791,
|
||||||
|
"tags": []
|
||||||
|
},
|
||||||
|
"blocks": {
|
||||||
|
"type": "block",
|
||||||
|
"id": "MCYCDPz_QH",
|
||||||
|
"flavour": "affine:page",
|
||||||
|
"version": 2,
|
||||||
|
"props": {
|
||||||
|
"title": {
|
||||||
|
"$blocksuite:internal:text$": true,
|
||||||
|
"delta": [
|
||||||
|
{
|
||||||
|
"insert": "FrameDoc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "block",
|
||||||
|
"id": "I_s0rS2Pbl",
|
||||||
|
"flavour": "affine:surface",
|
||||||
|
"version": 5,
|
||||||
|
"props": {
|
||||||
|
"elements": {}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "block",
|
||||||
|
"id": "mHE8GI9UWx",
|
||||||
|
"flavour": "affine:frame",
|
||||||
|
"version": 1,
|
||||||
|
"props": {
|
||||||
|
"title": {
|
||||||
|
"$blocksuite:internal:text$": true,
|
||||||
|
"delta": [
|
||||||
|
{
|
||||||
|
"insert": "Frame 1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"background": "transparent",
|
||||||
|
"xywh": "[-186.37939453125,-68.03814697265625,375.8616943359375,114.787109375]",
|
||||||
|
"index": "Zz",
|
||||||
|
"childElementIds": {},
|
||||||
|
"presentationIndex": "a00zHdtY37OLhj7JOhCr9ywYQXy1SbAI6kM",
|
||||||
|
"lockedBySelf": false
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,8 @@ export type DocName =
|
|||||||
| 'flow'
|
| 'flow'
|
||||||
| 'text'
|
| 'text'
|
||||||
| 'connector'
|
| 'connector'
|
||||||
| 'mindmap';
|
| 'mindmap'
|
||||||
|
| 'frame';
|
||||||
|
|
||||||
const docMap = new Map<DocName, Promise<Store | undefined>>();
|
const docMap = new Map<DocName, Promise<Store | undefined>>();
|
||||||
|
|
||||||
@@ -40,6 +41,10 @@ async function loadShape() {
|
|||||||
return (await import('./shape.json')).default;
|
return (await import('./shape.json')).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadFrame() {
|
||||||
|
return (await import('./frame.json')).default;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadFlow() {
|
async function loadFlow() {
|
||||||
return (await import('./flow.json')).default;
|
return (await import('./flow.json')).default;
|
||||||
}
|
}
|
||||||
@@ -60,6 +65,7 @@ const loaders = {
|
|||||||
note: loadNote,
|
note: loadNote,
|
||||||
pen: loadPen,
|
pen: loadPen,
|
||||||
shape: loadShape,
|
shape: loadShape,
|
||||||
|
frame: loadFrame,
|
||||||
flow: loadFlow,
|
flow: loadFlow,
|
||||||
text: loadText,
|
text: loadText,
|
||||||
connector: loadConnector,
|
connector: loadConnector,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { SettingWrapper } from '@affine/component/setting-components';
|
|||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
|
|
||||||
import { ConnectorSettings } from './connector';
|
import { ConnectorSettings } from './connector';
|
||||||
|
import { FrameSettings } from './frame';
|
||||||
import { GeneralEdgelessSetting } from './general';
|
import { GeneralEdgelessSetting } from './general';
|
||||||
import { MindMapSettings } from './mind-map';
|
import { MindMapSettings } from './mind-map';
|
||||||
import { NoteSettings } from './note';
|
import { NoteSettings } from './note';
|
||||||
@@ -17,6 +18,7 @@ export const Edgeless = () => {
|
|||||||
<NoteSettings />
|
<NoteSettings />
|
||||||
<TextSettings />
|
<TextSettings />
|
||||||
<ShapeSettings />
|
<ShapeSettings />
|
||||||
|
<FrameSettings />
|
||||||
<ConnectorSettings />
|
<ConnectorSettings />
|
||||||
<PenSettings />
|
<PenSettings />
|
||||||
<MindMapSettings />
|
<MindMapSettings />
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { MenuItem, MenuTrigger } from '@affine/component';
|
||||||
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
|
import { EditorSettingService } from '@affine/core/modules/editor-setting';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
|
import { DefaultTheme } from '@blocksuite/affine/blocks';
|
||||||
|
import type { Store } from '@blocksuite/affine/store';
|
||||||
|
import { useFramework, useLiveData } from '@toeverything/infra';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { DropdownMenu } from '../menu';
|
||||||
|
import { menuTrigger } from '../style.css';
|
||||||
|
import { usePalettes } from '../utils';
|
||||||
|
import { Point } from './point';
|
||||||
|
import { EdgelessSnapshot } from './snapshot';
|
||||||
|
|
||||||
|
export const FrameSettings = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
const framework = useFramework();
|
||||||
|
const { editorSetting } = framework.get(EditorSettingService);
|
||||||
|
const settings = useLiveData(editorSetting.settings$);
|
||||||
|
const { palettes, getCurrentColor } = usePalettes(
|
||||||
|
[
|
||||||
|
{ key: 'Transparent', value: DefaultTheme.transparent },
|
||||||
|
...DefaultTheme.FillColorPalettes,
|
||||||
|
],
|
||||||
|
DefaultTheme.transparent
|
||||||
|
);
|
||||||
|
|
||||||
|
const { background } = settings['affine:frame'];
|
||||||
|
const currentColor = useMemo(() => {
|
||||||
|
return getCurrentColor(background);
|
||||||
|
}, [getCurrentColor, background]);
|
||||||
|
|
||||||
|
const colorItems = useMemo(() => {
|
||||||
|
return palettes.map(({ key, value, resolvedValue }) => {
|
||||||
|
const handler = () => {
|
||||||
|
editorSetting.set('affine:frame', { background: value });
|
||||||
|
};
|
||||||
|
const isSelected = isEqual(background, value);
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={key}
|
||||||
|
onSelect={handler}
|
||||||
|
selected={isSelected}
|
||||||
|
prefix={<Point color={resolvedValue} />}
|
||||||
|
>
|
||||||
|
{key}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, [editorSetting, background, palettes]);
|
||||||
|
|
||||||
|
const getElements = useCallback((doc: Store) => {
|
||||||
|
return doc.getBlocksByFlavour('affine:frame') || [];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EdgelessSnapshot
|
||||||
|
title={t['com.affine.settings.editorSettings.edgeless.frame']()}
|
||||||
|
docName="frame"
|
||||||
|
keyName="affine:frame"
|
||||||
|
getElements={getElements}
|
||||||
|
/>
|
||||||
|
<SettingRow
|
||||||
|
name={t[
|
||||||
|
'com.affine.settings.editorSettings.edgeless.frame.background'
|
||||||
|
]()}
|
||||||
|
desc={''}
|
||||||
|
>
|
||||||
|
{currentColor ? (
|
||||||
|
<DropdownMenu
|
||||||
|
items={colorItems}
|
||||||
|
trigger={
|
||||||
|
<MenuTrigger
|
||||||
|
className={menuTrigger}
|
||||||
|
prefix={<Point color={currentColor.resolvedValue} />}
|
||||||
|
>
|
||||||
|
{currentColor.key}
|
||||||
|
</MenuTrigger>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</SettingRow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -115,7 +115,8 @@ export const EdgelessSnapshot = (props: Props) => {
|
|||||||
doc.readonly = false;
|
doc.readonly = false;
|
||||||
edgelessBlock.editorViewportSelector = 'ref-viewport';
|
edgelessBlock.editorViewportSelector = 'ref-viewport';
|
||||||
const frame = getFrameBlock(doc);
|
const frame = getFrameBlock(doc);
|
||||||
if (frame) {
|
if (frame && docName !== 'frame') {
|
||||||
|
// docName with value 'frame' shouldn't be deleted, it is a part of frame settings
|
||||||
boundMap.set(docName, Bound.deserialize(frame.xywh));
|
boundMap.set(docName, Bound.deserialize(frame.xywh));
|
||||||
doc.deleteBlock(frame);
|
doc.deleteBlock(frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1212,6 +1212,8 @@
|
|||||||
"com.affine.settings.editorSettings.edgeless.shape.text-alignment": "Text alignment",
|
"com.affine.settings.editorSettings.edgeless.shape.text-alignment": "Text alignment",
|
||||||
"com.affine.settings.editorSettings.edgeless.shape.text-color": "Text color",
|
"com.affine.settings.editorSettings.edgeless.shape.text-color": "Text color",
|
||||||
"com.affine.settings.editorSettings.edgeless.shape.triangle": "Triangle",
|
"com.affine.settings.editorSettings.edgeless.shape.triangle": "Triangle",
|
||||||
|
"com.affine.settings.editorSettings.edgeless.frame": "Frame",
|
||||||
|
"com.affine.settings.editorSettings.edgeless.frame.background": "Background",
|
||||||
"com.affine.settings.editorSettings.edgeless.style": "Style",
|
"com.affine.settings.editorSettings.edgeless.style": "Style",
|
||||||
"com.affine.settings.editorSettings.edgeless.style.general": "General",
|
"com.affine.settings.editorSettings.edgeless.style.general": "General",
|
||||||
"com.affine.settings.editorSettings.edgeless.style.scribbled": "Scribbled",
|
"com.affine.settings.editorSettings.edgeless.style.scribbled": "Scribbled",
|
||||||
|
|||||||
Reference in New Issue
Block a user