feat: add mindmap and connector settings (#8198)

### What changed?
- Add `connector` label settings.
- Add `mindmap` style settings.
- Add skeleton loading placeholder.

<div class='graphite__hidden'>
          <div>🎥 Video uploaded on Graphite:</div>
            <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/31159d74-ef62-4c7f-b1d9-cde73047cf29.mov">
              <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/31159d74-ef62-4c7f-b1d9-cde73047cf29.mov">
            </a>
          </div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/31159d74-ef62-4c7f-b1d9-cde73047cf29.mov">录屏2024-09-11 16.30.17.mov</video>
This commit is contained in:
akumatus
2024-09-11 09:17:11 +00:00
parent 85aa73bcf6
commit f12655655e
8 changed files with 420 additions and 75 deletions

View File

@@ -10,10 +10,15 @@ import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { import {
ConnectorMode, ConnectorMode,
FontFamily,
FontFamilyMap,
FontStyle,
FontWeightMap,
LineColor, LineColor,
LineColorMap, LineColorMap,
PointStyle, PointStyle,
StrokeStyle, StrokeStyle,
TextAlign,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import type { Doc } from '@blocksuite/store'; import type { Doc } from '@blocksuite/store';
import { useFramework, useLiveData } from '@toeverything/infra'; import { useFramework, useLiveData } from '@toeverything/infra';
@@ -21,7 +26,7 @@ import { useCallback, useMemo } from 'react';
import { DropdownMenu } from '../menu'; import { DropdownMenu } from '../menu';
import { menuTrigger, settingWrapper } from '../style.css'; import { menuTrigger, settingWrapper } from '../style.css';
import { useColor } from '../utils'; import { sortedFontWeightEntries, useColor } from '../utils';
import { Point } from './point'; import { Point } from './point';
import { EdgelessSnapshot } from './snapshot'; import { EdgelessSnapshot } from './snapshot';
import { getSurfaceBlock } from './utils'; import { getSurfaceBlock } from './utils';
@@ -31,6 +36,15 @@ enum ConnecterStyle {
Scribbled = 'scribbled', Scribbled = 'scribbled',
} }
enum ConnectorTextFontSize {
'16px' = '16',
'20px' = '20',
'24px' = '24',
'32px' = '32',
'40px' = '40',
'64px' = '64',
}
export const ConnectorSettings = () => { export const ConnectorSettings = () => {
const t = useI18n(); const t = useI18n();
const framework = useFramework(); const framework = useFramework();
@@ -191,6 +205,150 @@ export const ConnectorSettings = () => {
}); });
}, [editorSetting, settings]); }, [editorSetting, settings]);
const alignItems = useMemo<RadioItem[]>(
() => [
{
value: TextAlign.Left,
label:
t[
'com.affine.settings.editorSettings.edgeless.text.alignment.left'
](),
},
{
value: TextAlign.Center,
label:
t[
'com.affine.settings.editorSettings.edgeless.text.alignment.center'
](),
},
{
value: TextAlign.Right,
label:
t[
'com.affine.settings.editorSettings.edgeless.text.alignment.right'
](),
},
],
[t]
);
const textAlignment = settings.connector.labelStyle.textAlign;
const setTextAlignment = useCallback(
(value: TextAlign) => {
editorSetting.set('connector', {
labelStyle: {
textAlign: value,
},
});
},
[editorSetting]
);
const fontFamilyItems = useMemo(() => {
const { fontFamily } = settings.connector.labelStyle;
return Object.entries(FontFamily).map(([name, value]) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
fontFamily: value,
},
});
};
const isSelected = fontFamily === value;
return (
<MenuItem key={name} onSelect={handler} selected={isSelected}>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const fontStyleItems = useMemo(() => {
const { fontStyle } = settings.connector.labelStyle;
return Object.entries(FontStyle).map(([name, value]) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
fontStyle: value,
},
});
};
const isSelected = fontStyle === value;
return (
<MenuItem key={name} onSelect={handler} selected={isSelected}>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const fontWeightItems = useMemo(() => {
const { fontWeight } = settings.connector.labelStyle;
return sortedFontWeightEntries.map(([name, value]) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
fontWeight: value,
},
});
};
const isSelected = fontWeight === value;
return (
<MenuItem key={name} onSelect={handler} selected={isSelected}>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const fontSizeItems = useMemo(() => {
const { fontSize } = settings.connector.labelStyle;
return Object.entries(ConnectorTextFontSize).map(([name, value]) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
fontSize: Number(value),
},
});
};
const isSelected = fontSize === Number(value);
return (
<MenuItem key={name} onSelect={handler} selected={isSelected}>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const textColorItems = useMemo(() => {
const { color } = settings.connector.labelStyle;
return Object.entries(LineColor).map(([name, value]) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
color: value,
},
});
};
const isSelected = color === value;
return (
<MenuItem
key={name}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const textColor = useMemo(() => {
const { color } = settings.connector.labelStyle;
return getColorFromMap(color, LineColorMap);
}, [getColorFromMap, settings]);
const getElements = useCallback((doc: Doc) => { const getElements = useCallback((doc: Doc) => {
const surface = getSurfaceBlock(doc); const surface = getSurfaceBlock(doc);
return surface?.getElementsByType('connector') || []; return surface?.getElementsByType('connector') || [];
@@ -309,6 +467,100 @@ export const ConnectorSettings = () => {
} }
/> />
</SettingRow> </SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.shape.text-color'
]()}
desc={''}
>
{textColor ? (
<DropdownMenu
items={textColorItems}
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={textColor.value} />}
>
{textColor.key}
</MenuTrigger>
}
/>
) : null}
</SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.text.font-family'
]()}
desc={''}
>
<DropdownMenu
items={fontFamilyItems}
trigger={
<MenuTrigger className={menuTrigger}>
{FontFamilyMap[settings.connector.labelStyle.fontFamily]}
</MenuTrigger>
}
/>
</SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.shape.font-size'
]()}
desc={''}
>
<DropdownMenu
items={fontSizeItems}
trigger={
<MenuTrigger className={menuTrigger}>
{settings.connector.labelStyle.fontSize + 'px'}
</MenuTrigger>
}
/>
</SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.text.font-style'
]()}
desc={''}
>
<DropdownMenu
items={fontStyleItems}
trigger={
<MenuTrigger className={menuTrigger}>
{settings.connector.labelStyle.fontStyle}
</MenuTrigger>
}
/>
</SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.text.font-weight'
]()}
desc={''}
>
<DropdownMenu
items={fontWeightItems}
trigger={
<MenuTrigger className={menuTrigger}>
{FontWeightMap[settings.connector.labelStyle.fontWeight]}
</MenuTrigger>
}
/>
</SettingRow>
<SettingRow
name={t[
'com.affine.settings.editorSettings.edgeless.shape.text-alignment'
]()}
desc={''}
>
<RadioGroup
items={alignItems}
value={textAlignment}
width={250}
className={settingWrapper}
onChange={setTextAlignment}
/>
</SettingRow>
</> </>
); );
}; };

View File

@@ -1,14 +1,14 @@
{ {
"type": "page", "type": "page",
"meta": { "meta": {
"id": "v4nxnq2Al2", "id": "gJEFfmo4QJ",
"title": "", "title": "",
"createDate": 1725459565290, "createDate": 1726038448921,
"tags": [] "tags": []
}, },
"blocks": { "blocks": {
"type": "block", "type": "block",
"id": "eDFE5HokPO", "id": "orzKfiHevj",
"flavour": "affine:page", "flavour": "affine:page",
"version": 2, "version": 2,
"props": { "props": {
@@ -20,37 +20,58 @@
"children": [ "children": [
{ {
"type": "block", "type": "block",
"id": "ZksVPLRI0K", "id": "-48EmppaxI",
"flavour": "affine:surface", "flavour": "affine:surface",
"version": 5, "version": 5,
"props": { "props": {
"elements": { "elements": {
"hdqh5vFnzj": { "m_PwyyI76y": {
"index": "a0", "index": "a0",
"seed": 263456687, "seed": 44330892,
"frontEndpointStyle": "None", "frontEndpointStyle": "None",
"labelOffset": {
"distance": 0.5,
"anchor": "center"
},
"labelStyle": {
"color": "--affine-palette-line-black",
"fontSize": 16,
"fontFamily": "blocksuite:surface:Inter",
"fontWeight": "400",
"fontStyle": "normal",
"textAlign": "center"
},
"labelXYWH": [235.6484375, 65.23828125, 200, 20],
"mode": 2, "mode": 2,
"rearEndpointStyle": "Arrow", "rearEndpointStyle": "Arrow",
"rough": false, "rough": false,
"roughness": 1.4, "roughness": 1.4,
"source": { "source": {
"position": [196.0625, 145.84765625] "position": [120.8515625, 146.44921875]
}, },
"stroke": "--affine-palette-line-grey", "stroke": "--affine-palette-line-grey",
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 2, "strokeWidth": 2,
"target": { "target": {
"position": [418.5859375, 52.13671875] "position": [387.4453125, 4.02734375]
},
"text": {
"affine:surface:text": true,
"delta": [
{
"insert": "label"
}
]
}, },
"type": "connector", "type": "connector",
"id": "hdqh5vFnzj" "id": "m_PwyyI76y"
} }
} }
}, },
"children": [ "children": [
{ {
"type": "block", "type": "block",
"id": "TNgzGwq6Ct", "id": "-6UhNH7qhy",
"flavour": "affine:frame", "flavour": "affine:frame",
"version": 1, "version": 1,
"props": { "props": {
@@ -63,10 +84,10 @@
] ]
}, },
"background": "--affine-palette-transparent", "background": "--affine-palette-transparent",
"xywh": "[-13.38671875,-4.5625,739.3828125,192.51171875]", "xywh": "[-12.04296875,-49.66796875,542.9765625,248.3984375]",
"index": "a0", "index": "Zz",
"childElementIds": { "childElementIds": {
"hdqh5vFnzj": true "m_PwyyI76y": true
} }
}, },
"children": [] "children": []

View File

@@ -69,13 +69,14 @@ export async function getDocByName(name: DocName) {
if (docMap.get(name)) { if (docMap.get(name)) {
return docMap.get(name); return docMap.get(name);
} }
const snapshot = (await loaders[name]()) as DocSnapshot;
const promiseDoc = initDocFromSnapshot(snapshot); const promise = initDoc(name);
docMap.set(name, promiseDoc); docMap.set(name, promise);
return promiseDoc; return promise;
} }
async function initDocFromSnapshot(snapshot: DocSnapshot) { async function initDoc(name: DocName) {
const snapshot = (await loaders[name]()) as DocSnapshot;
const collection = await getCollection(); const collection = await getCollection();
const job = new Job({ const job = new Job({
collection, collection,

View File

@@ -1,61 +1,65 @@
{ {
"type": "page", "type": "page",
"meta": { "meta": {
"id": "0P4XpxtY1T", "id": "_JUmoI_F28",
"title": "", "title": "BlockSuite Playground",
"createDate": 1725500529462, "createDate": 1725610677620,
"tags": [] "tags": []
}, },
"blocks": { "blocks": {
"type": "block", "type": "block",
"id": "o_kDMq1Y2z", "id": "FnaWN8Zm2_",
"flavour": "affine:page", "flavour": "affine:page",
"version": 2, "version": 2,
"props": { "props": {
"title": { "title": {
"$blocksuite:internal:text$": true, "$blocksuite:internal:text$": true,
"delta": [] "delta": [
{
"insert": "BlockSuite Playground"
}
]
} }
}, },
"children": [ "children": [
{ {
"type": "block", "type": "block",
"id": "CX3YRdnn7u", "id": "hevWf4ccWc",
"flavour": "affine:surface", "flavour": "affine:surface",
"version": 5, "version": 5,
"props": { "props": {
"elements": { "elements": {
"uXwcJ22j4U": { "MYyOCcLTWN": {
"index": "a1", "index": "a0",
"seed": 521352102, "seed": 739933670,
"children": { "children": {
"affine:surface:ymap": true, "affine:surface:ymap": true,
"json": { "json": {
"5Jk9NbvuPN": { "BvanBL7O38": {
"index": "a0" "index": "a0"
}, },
"DqF847301v": { "QkmFfps45U": {
"index": "a0", "index": "a0",
"parent": "5Jk9NbvuPN" "parent": "BvanBL7O38"
}, },
"3cpFVUO7z_": { "1IN8YOdsCP": {
"index": "a1", "index": "a1",
"parent": "5Jk9NbvuPN" "parent": "BvanBL7O38"
}, },
"cq1V7jb9Nw": { "iFQ9oVR0KN": {
"index": "a2", "index": "a2",
"parent": "5Jk9NbvuPN" "parent": "BvanBL7O38"
} }
} }
}, },
"layoutType": 0, "layoutType": 0,
"style": 1, "style": 1,
"type": "mindmap", "type": "mindmap",
"id": "uXwcJ22j4U" "id": "MYyOCcLTWN"
}, },
"5Jk9NbvuPN": { "BvanBL7O38": {
"index": "a0", "index": "a0",
"seed": 2040865434, "seed": 819595867,
"color": "--affine-black", "color": "--affine-black",
"fillColor": "--affine-white", "fillColor": "--affine-white",
"filled": true, "filled": true,
@@ -87,13 +91,13 @@
] ]
}, },
"textResizing": 0, "textResizing": 0,
"xywh": "[219.1787109375,-137.21072387695312,144.7799530029297,52]", "xywh": "[-214.85955810546875,-113.65847778320312,144.7799530029297,52]",
"type": "shape", "type": "shape",
"id": "5Jk9NbvuPN" "id": "BvanBL7O38"
}, },
"DqF847301v": { "QkmFfps45U": {
"index": "a0", "index": "a0",
"seed": 42391752, "seed": 557026939,
"color": "--affine-black", "color": "--affine-black",
"fillColor": "--affine-white", "fillColor": "--affine-white",
"filled": true, "filled": true,
@@ -125,13 +129,13 @@
] ]
}, },
"textResizing": 0, "textResizing": 0,
"xywh": "[563.9586639404297,-210.21072387695312,76.83197021484375,36]", "xywh": "[129.92039489746094,-186.65847778320312,76.83197021484375,36]",
"type": "shape", "type": "shape",
"id": "DqF847301v" "id": "QkmFfps45U"
}, },
"3cpFVUO7z_": { "1IN8YOdsCP": {
"index": "a0", "index": "a0",
"seed": 1821565231, "seed": 205695803,
"color": "--affine-black", "color": "--affine-black",
"fillColor": "--affine-white", "fillColor": "--affine-white",
"filled": true, "filled": true,
@@ -163,13 +167,13 @@
] ]
}, },
"textResizing": 0, "textResizing": 0,
"xywh": "[563.9586639404297,-129.21072387695312,76.83197021484375,36]", "xywh": "[129.92039489746094,-105.65847778320312,76.83197021484375,36]",
"type": "shape", "type": "shape",
"id": "3cpFVUO7z_" "id": "1IN8YOdsCP"
}, },
"cq1V7jb9Nw": { "iFQ9oVR0KN": {
"index": "a0", "index": "a0",
"seed": 1835053830, "seed": 585656351,
"color": "--affine-black", "color": "--affine-black",
"fillColor": "--affine-white", "fillColor": "--affine-white",
"filled": true, "filled": true,
@@ -201,16 +205,16 @@
] ]
}, },
"textResizing": 0, "textResizing": 0,
"xywh": "[563.9586639404297,-48.210723876953125,76.83197021484375,36]", "xywh": "[129.92039489746094,-24.658477783203125,76.83197021484375,36]",
"type": "shape", "type": "shape",
"id": "cq1V7jb9Nw" "id": "iFQ9oVR0KN"
} }
} }
}, },
"children": [ "children": [
{ {
"type": "block", "type": "block",
"id": "yUWjMW5rEZ", "id": "bVYX1z2q3T",
"flavour": "affine:frame", "flavour": "affine:frame",
"version": 1, "version": 1,
"props": { "props": {
@@ -223,10 +227,10 @@
] ]
}, },
"background": "--affine-palette-transparent", "background": "--affine-palette-transparent",
"xywh": "[138.3125,-266.609375,602.640625,321.26171875]", "xywh": "[-542.4695816040039,-292.0061340332031,798.42578125,414.50390625]",
"index": "a0", "index": "Zz",
"childElementIds": { "childElementIds": {
"uXwcJ22j4U": true "MYyOCcLTWN": true
} }
}, },
"children": [] "children": []

View File

@@ -5,38 +5,70 @@ import {
type RadioItem, type RadioItem,
} from '@affine/component'; } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components'; import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { LayoutType, MindmapStyle } from '@blocksuite/blocks';
import type { Doc } from '@blocksuite/store'; import type { Doc } from '@blocksuite/store';
import { useCallback, useMemo, useState } from 'react'; import { useFramework, useLiveData } from '@toeverything/infra';
import { useCallback, useMemo } from 'react';
import { DropdownMenu } from '../menu'; import { DropdownMenu } from '../menu';
import { menuTrigger, settingWrapper } from '../style.css'; import { menuTrigger, settingWrapper } from '../style.css';
import { EdgelessSnapshot } from './snapshot'; import { EdgelessSnapshot } from './snapshot';
import { getSurfaceBlock } from './utils'; import { getSurfaceBlock } from './utils';
const MINDMAP_STYLES = [
{
value: MindmapStyle.ONE,
name: 'Style 1',
},
{
value: MindmapStyle.TWO,
name: 'Style 2',
},
{
value: MindmapStyle.THREE,
name: 'Style 3',
},
{
value: MindmapStyle.FOUR,
name: 'Style 4',
},
];
export const MindMapSettings = () => { export const MindMapSettings = () => {
const t = useI18n(); const t = useI18n();
const [layoutValue, setLayoutValue] = useState<'left' | 'radial' | 'right'>( const framework = useFramework();
'right' const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const { layoutType } = settings.mindmap;
const setLayoutType = useCallback(
(value: LayoutType) => {
editorSetting.set('mindmap', {
layoutType: value,
});
},
[editorSetting]
); );
const layoutValueItems = useMemo<RadioItem[]>( const layoutTypeItems = useMemo<RadioItem[]>(
() => [ () => [
{ {
value: 'left', value: LayoutType.LEFT as any,
label: label:
t[ t[
'com.affine.settings.editorSettings.edgeless.mind-map.layout.left' 'com.affine.settings.editorSettings.edgeless.mind-map.layout.left'
](), ](),
}, },
{ {
value: 'radial', value: LayoutType.BALANCE as any,
label: label:
t[ t[
'com.affine.settings.editorSettings.edgeless.mind-map.layout.radial' 'com.affine.settings.editorSettings.edgeless.mind-map.layout.radial'
](), ](),
}, },
{ {
value: 'right', value: LayoutType.RIGHT as any,
label: label:
t[ t[
'com.affine.settings.editorSettings.edgeless.mind-map.layout.right' 'com.affine.settings.editorSettings.edgeless.mind-map.layout.right'
@@ -46,6 +78,21 @@ export const MindMapSettings = () => {
[t] [t]
); );
const styleItems = useMemo(() => {
const { style } = settings.mindmap;
return MINDMAP_STYLES.map(({ name, value }) => {
const handler = () => {
editorSetting.set('mindmap', { style: value });
};
const isSelected = style === value;
return (
<MenuItem key={name} onSelect={handler} selected={isSelected}>
{name}
</MenuItem>
);
});
}, [editorSetting, settings]);
const getElements = useCallback((doc: Doc) => { const getElements = useCallback((doc: Doc) => {
const surface = getSurfaceBlock(doc); const surface = getSurfaceBlock(doc);
return surface?.getElementsByType('mindmap') || []; return surface?.getElementsByType('mindmap') || [];
@@ -65,10 +112,10 @@ export const MindMapSettings = () => {
desc={''} desc={''}
> >
<DropdownMenu <DropdownMenu
items={<MenuItem>Style 1</MenuItem>} items={styleItems}
trigger={ trigger={
<MenuTrigger className={menuTrigger} disabled> <MenuTrigger className={menuTrigger}>
Style 1 {`Style ${settings.mindmap.style}`}
</MenuTrigger> </MenuTrigger>
} }
/> />
@@ -80,11 +127,11 @@ export const MindMapSettings = () => {
desc={''} desc={''}
> >
<RadioGroup <RadioGroup
items={layoutValueItems} items={layoutTypeItems}
value={layoutValue} value={layoutType}
width={250} width={250}
className={settingWrapper} className={settingWrapper}
onChange={setLayoutValue} onChange={setLayoutType}
/> />
</SettingRow> </SettingRow>
</> </>

View File

@@ -47,10 +47,12 @@ import { EdgelessSnapshot } from './snapshot';
import { getSurfaceBlock } from './utils'; import { getSurfaceBlock } from './utils';
enum ShapeTextFontSize { enum ShapeTextFontSize {
'12px' = '12', '16px' = '16',
'20px' = '20', '20px' = '20',
'28px' = '28', '24px' = '24',
'36px' = '36', '32px' = '32',
'40px' = '40',
'64px' = '64',
} }
const ShapeFillColorMap = createEnumMap(ShapeFillColor); const ShapeFillColorMap = createEnumMap(ShapeFillColor);
@@ -557,7 +559,7 @@ export const ShapeSettings = () => {
items={fontStyleItems} items={fontStyleItems}
trigger={ trigger={
<MenuTrigger className={menuTrigger}> <MenuTrigger className={menuTrigger}>
{String(settings[`shape:${currentShape}`].fontStyle)} {settings[`shape:${currentShape}`].fontStyle}
</MenuTrigger> </MenuTrigger>
} }
/> />

View File

@@ -1,3 +1,4 @@
import { Skeleton } from '@affine/component';
import type { EditorSettingSchema } from '@affine/core/modules/editor-settting'; import type { EditorSettingSchema } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-settting'; import { EditorSettingService } from '@affine/core/modules/editor-settting';
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
@@ -12,7 +13,12 @@ import { isEqual } from 'lodash-es';
import { useCallback, useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { map, pairwise } from 'rxjs'; import { map, pairwise } from 'rxjs';
import { snapshotContainer, snapshotLabel, snapshotTitle } from '../style.css'; import {
snapshotContainer,
snapshotLabel,
snapshotSkeleton,
snapshotTitle,
} from '../style.css';
import { type DocName, getDocByName } from './docs'; import { type DocName, getDocByName } from './docs';
import { getFrameBlock } from './utils'; import { getFrameBlock } from './utils';
@@ -136,7 +142,13 @@ export const EdgelessSnapshot = (props: Props) => {
overflow: 'hidden', overflow: 'hidden',
height, height,
}} }}
></div> >
<Skeleton
className={snapshotSkeleton}
variant="rounded"
height={'100%'}
/>
</div>
{children} {children}
</div> </div>
); );

View File

@@ -43,6 +43,12 @@ export const snapshotTitle = style({
color: cssVarV2('text/secondary'), color: cssVarV2('text/secondary'),
}); });
export const snapshotSkeleton = style({
position: 'absolute',
top: 0,
left: 0,
});
export const snapshot = style({ export const snapshot = style({
width: '100%', width: '100%',
height: '180px', height: '180px',