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:
@@ -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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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": []
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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": []
|
||||||
|
|||||||
@@ -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>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user