feat(editor): store real color values in edgeless (#9254)

### What's Changed!

* adds theme type: `ThemeSchema`
* adds default theme: `DefaultTheme`
* stores real color values
This commit is contained in:
fundon
2024-12-30 03:36:35 +00:00
parent a5641ae608
commit b9f2650369
287 changed files with 2219 additions and 1520 deletions
@@ -10,23 +10,23 @@ import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
ConnectorMode,
DefaultTheme,
FontFamily,
FontFamilyMap,
FontStyle,
FontWeightMap,
PointStyle,
StrokeColor,
StrokeColorMap,
StrokeStyle,
TextAlign,
} from '@blocksuite/affine/blocks';
import type { Doc } 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, settingWrapper } from '../style.css';
import { sortedFontWeightEntries, useColor } from '../utils';
import { sortedFontWeightEntries, usePalettes } from '../utils';
import { Point } from './point';
import { EdgelessSnapshot } from './snapshot';
import { getSurfaceBlock } from './utils';
@@ -50,7 +50,15 @@ export const ConnectorSettings = () => {
const framework = useFramework();
const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const getColorFromMap = useColor();
const {
palettes: strokeColorPalettes,
getCurrentColor: getCurrentStrokeColor,
} = usePalettes(
DefaultTheme.StrokeColorPalettes,
DefaultTheme.connectorColor
);
const { palettes: textColorPalettes, getCurrentColor: getCurrentTextColor } =
usePalettes(DefaultTheme.StrokeColorPalettes, DefaultTheme.black);
const connecterStyleItems = useMemo<RadioItem[]>(
() => [
@@ -152,28 +160,28 @@ export const ConnectorSettings = () => {
const currentColor = useMemo(() => {
const color = settings.connector.stroke;
return getColorFromMap(color, StrokeColorMap);
}, [getColorFromMap, settings.connector.stroke]);
return getCurrentStrokeColor(color);
}, [getCurrentStrokeColor, settings.connector.stroke]);
const colorItems = useMemo(() => {
const { stroke } = settings.connector;
return Object.entries(StrokeColor).map(([name, value]) => {
return strokeColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set('connector', { stroke: value });
};
const isSelected = stroke === value;
const isSelected = isEqual(stroke, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings]);
}, [editorSetting, settings, strokeColorPalettes]);
const startEndPointItems = useMemo(() => {
const { frontEndpointStyle } = settings.connector;
@@ -322,7 +330,7 @@ export const ConnectorSettings = () => {
const textColorItems = useMemo(() => {
const { color } = settings.connector.labelStyle;
return Object.entries(StrokeColor).map(([name, value]) => {
return textColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set('connector', {
labelStyle: {
@@ -330,24 +338,24 @@ export const ConnectorSettings = () => {
},
});
};
const isSelected = color === value;
const isSelected = isEqual(color, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings]);
}, [editorSetting, settings, textColorPalettes]);
const textColor = useMemo(() => {
const { color } = settings.connector.labelStyle;
return getColorFromMap(color, StrokeColorMap);
}, [getColorFromMap, settings]);
return getCurrentTextColor(color);
}, [getCurrentTextColor, settings]);
const getElements = useCallback((doc: Doc) => {
const surface = getSurfaceBlock(doc);
@@ -374,7 +382,7 @@ export const ConnectorSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={currentColor.value} />}
prefix={<Point color={currentColor.resolvedValue} />}
>
{currentColor.key}
</MenuTrigger>
@@ -479,7 +487,7 @@ export const ConnectorSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={textColor.value} />}
prefix={<Point color={textColor.resolvedValue} />}
>
{textColor.key}
</MenuTrigger>
@@ -34,7 +34,10 @@
"anchor": "center"
},
"labelStyle": {
"color": "--affine-palette-line-black",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fontSize": 16,
"fontFamily": "blocksuite:surface:Inter",
"fontWeight": "400",
@@ -49,7 +52,7 @@
"source": {
"position": [120.8515625, 146.44921875]
},
"stroke": "--affine-palette-line-grey",
"stroke": "#929292",
"strokeStyle": "solid",
"strokeWidth": 2,
"target": {
@@ -83,7 +86,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-12.04296875,-49.66796875,542.9765625,248.3984375]",
"index": "Zz",
"childElementIds": {
@@ -456,7 +456,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-131.27862548828125,-112.8125,880.65234375,645.11328125]",
"index": "aEV",
"childElementIds": {}
@@ -60,8 +60,14 @@
"BvanBL7O38": {
"index": "a0",
"seed": 819595867,
"color": "--affine-black",
"fillColor": "--affine-white",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": {
"dark": "#000000",
"light": "#ffffff"
},
"filled": true,
"fontFamily": "blocksuite:surface:Poppins",
"fontSize": 20,
@@ -79,7 +85,7 @@
},
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "#84CFFF",
"strokeColor": "#84cfff",
"strokeStyle": "solid",
"strokeWidth": 4,
"text": {
@@ -98,8 +104,14 @@
"QkmFfps45U": {
"index": "a0",
"seed": 557026939,
"color": "--affine-black",
"fillColor": "--affine-white",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": {
"dark": "#000000",
"light": "#ffffff"
},
"filled": true,
"fontFamily": "blocksuite:surface:Poppins",
"fontSize": 16,
@@ -117,7 +129,7 @@
},
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "--affine-palette-line-purple",
"strokeColor": "#6e52df",
"strokeStyle": "solid",
"strokeWidth": 3,
"text": {
@@ -136,8 +148,14 @@
"1IN8YOdsCP": {
"index": "a0",
"seed": 205695803,
"color": "--affine-black",
"fillColor": "--affine-white",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": {
"dark": "#000000",
"light": "#ffffff"
},
"filled": true,
"fontFamily": "blocksuite:surface:Poppins",
"fontSize": 16,
@@ -155,7 +173,7 @@
},
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "--affine-palette-line-magenta",
"strokeColor": "#e96cab",
"strokeStyle": "solid",
"strokeWidth": 3,
"text": {
@@ -174,8 +192,14 @@
"iFQ9oVR0KN": {
"index": "a0",
"seed": 585656351,
"color": "--affine-black",
"fillColor": "--affine-white",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": {
"dark": "#000000",
"light": "#ffffff"
},
"filled": true,
"fontFamily": "blocksuite:surface:Poppins",
"fontSize": 16,
@@ -193,7 +217,7 @@
},
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "--affine-palette-line-orange",
"strokeColor": "#ffebd5",
"strokeStyle": "solid",
"strokeWidth": 3,
"text": {
@@ -226,7 +250,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-542.4695816040039,-292.0061340332031,798.42578125,414.50390625]",
"index": "Zz",
"childElementIds": {
@@ -45,7 +45,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[361.3046875,-9.600906372070312,803.04296875,291.26953125]",
"index": "a0",
"childElementIds": {
@@ -63,7 +63,10 @@
"version": 1,
"props": {
"xywh": "[538.826171875,46.71159362792969,448,180]",
"background": "--affine-note-background-blue",
"background": {
"dark": "#000000",
"light": "#ffffff"
},
"index": "a3",
"hidden": false,
"displayMode": "edgeless",
@@ -33,8 +33,8 @@
"index": "aT",
"seed": 930141788,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -61,8 +61,8 @@
"index": "aU",
"seed": 1175065049,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -87,8 +87,8 @@
"index": "aV",
"seed": 225475485,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -111,8 +111,8 @@
"index": "aW",
"seed": 140962525,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -157,8 +157,8 @@
"index": "aX",
"seed": 2003216140,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -228,8 +228,8 @@
"index": "aY",
"seed": 1302768834,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -310,8 +310,8 @@
"index": "aZ",
"seed": 2123783898,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -412,8 +412,8 @@
"index": "aa",
"seed": 706133801,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -542,8 +542,8 @@
"index": "ab",
"seed": 1404216526,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -661,8 +661,8 @@
"index": "ac",
"seed": 1570152044,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -753,8 +753,8 @@
"index": "ad",
"seed": 2117166361,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -837,8 +837,8 @@
"index": "ae",
"seed": 1268192592,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -929,8 +929,8 @@
"index": "af",
"seed": 2028387099,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1056,8 +1056,8 @@
"index": "ag",
"seed": 1730436869,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1142,8 +1142,8 @@
"index": "ah",
"seed": 377436171,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1176,8 +1176,8 @@
"index": "ai",
"seed": 778156917,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1230,8 +1230,8 @@
"index": "aj",
"seed": 1095606790,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1266,8 +1266,8 @@
"index": "ak",
"seed": 667632025,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1333,8 +1333,8 @@
"index": "al",
"seed": 1331977937,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1420,8 +1420,8 @@
"index": "am",
"seed": 368164521,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1542,8 +1542,8 @@
"index": "an",
"seed": 649801494,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1679,8 +1679,8 @@
"index": "ao",
"seed": 1487715532,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1792,8 +1792,8 @@
"index": "ap",
"seed": 781297555,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1874,8 +1874,8 @@
"index": "aq",
"seed": 950769071,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1937,8 +1937,8 @@
"index": "ar",
"seed": 1741156016,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -1963,8 +1963,8 @@
"index": "as",
"seed": 1573145582,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -2027,8 +2027,8 @@
"index": "at",
"seed": 94123324,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -2062,8 +2062,8 @@
"index": "au",
"seed": 823278468,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -2101,8 +2101,8 @@
"index": "av",
"seed": 48765550,
"color": {
"light": "--affine-palette-line-black",
"dark": "--affine-palette-line-white"
"dark": "#ffffff",
"light": "#000000"
},
"lineWidth": 4,
"points": [
@@ -2148,7 +2148,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-99.986,288.226,963.308,237.136]",
"index": "a0",
"childElementIds": {
@@ -32,8 +32,11 @@
"e6t9tKz8Sy": {
"index": "a5",
"seed": 338503204,
"color": "--affine-palette-line-black",
"fillColor": "--affine-palette-shape-yellow",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": "#fffbd5",
"filled": true,
"fontFamily": "blocksuite:surface:Inter",
"fontSize": 12,
@@ -45,7 +48,7 @@
"shadow": null,
"shapeStyle": "General",
"shapeType": "ellipse",
"strokeColor": "--affine-palette-line-yellow",
"strokeColor": "#fcd34d",
"strokeStyle": "solid",
"strokeWidth": 2,
"textResizing": 1,
@@ -56,8 +59,11 @@
"F8qB_zDC5Q": {
"index": "a6",
"seed": 1896265661,
"color": "--affine-palette-line-black",
"fillColor": "--affine-palette-shape-yellow",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": "#fffbd5",
"filled": true,
"fontFamily": "blocksuite:surface:Inter",
"fontSize": 12,
@@ -69,7 +75,7 @@
"shadow": null,
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "--affine-palette-line-yellow",
"strokeColor": "#fcd34d",
"strokeStyle": "solid",
"strokeWidth": 2,
"textResizing": 1,
@@ -80,8 +86,11 @@
"mPR44JBpcd": {
"index": "a7",
"seed": 2073974140,
"color": "--affine-palette-line-black",
"fillColor": "--affine-palette-shape-yellow",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": "#fffbd5",
"filled": true,
"fontFamily": "blocksuite:surface:Inter",
"fontSize": 12,
@@ -93,7 +102,7 @@
"shadow": null,
"shapeStyle": "General",
"shapeType": "diamond",
"strokeColor": "--affine-palette-line-yellow",
"strokeColor": "#fcd34d",
"strokeStyle": "solid",
"strokeWidth": 2,
"textResizing": 1,
@@ -104,8 +113,11 @@
"cmtluc3FWR": {
"index": "a8",
"seed": 1457248130,
"color": "--affine-palette-line-black",
"fillColor": "--affine-palette-shape-yellow",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": "#fffbd5",
"filled": true,
"fontFamily": "blocksuite:surface:Inter",
"fontSize": 12,
@@ -117,7 +129,7 @@
"shadow": null,
"shapeStyle": "General",
"shapeType": "triangle",
"strokeColor": "--affine-palette-line-yellow",
"strokeColor": "#fcd34d",
"strokeStyle": "solid",
"strokeWidth": 2,
"textResizing": 1,
@@ -128,8 +140,11 @@
"knt_TKvACR": {
"index": "a9",
"seed": 1896265661,
"color": "--affine-palette-line-black",
"fillColor": "--affine-palette-shape-yellow",
"color": {
"dark": "#ffffff",
"light": "#000000"
},
"fillColor": "#fffbd5",
"filled": true,
"fontFamily": "blocksuite:surface:Inter",
"fontSize": 12,
@@ -141,7 +156,7 @@
"shadow": null,
"shapeStyle": "General",
"shapeType": "rect",
"strokeColor": "--affine-palette-line-yellow",
"strokeColor": "#fcd34d",
"strokeStyle": "solid",
"strokeWidth": 2,
"textResizing": 1,
@@ -166,7 +181,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-23.859796066464128,332.87664265400565,881.5090292421075,190.55181066780085]",
"index": "a0"
},
@@ -39,7 +39,7 @@
"props": {
"xywh": "[18.221401559354234,201.98389611782602,800.6283921393511,489.15472412109375]",
"index": "a0",
"color": "--affine-palette-line-blue",
"color": "#84cfff",
"fontFamily": "blocksuite:surface:Inter",
"fontStyle": "normal",
"fontWeight": "400",
@@ -101,7 +101,7 @@
}
]
},
"background": "--affine-palette-transparent",
"background": "transparent",
"xywh": "[-21.778598440645766,126.5612581783729,880.6283921393511,640]",
"index": "a1",
"childElementIds": {
@@ -10,19 +10,19 @@ import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
createEnumMap,
NoteBackgroundColor,
NoteBackgroundColorMap,
DefaultTheme,
NoteShadow,
NoteShadowMap,
StrokeStyle,
} from '@blocksuite/affine/blocks';
import type { Doc } 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, settingWrapper } from '../style.css';
import { useColor } from '../utils';
import { usePalettes } from '../utils';
import { Point } from './point';
import { EdgelessSnapshot } from './snapshot';
@@ -49,7 +49,10 @@ export const NoteSettings = () => {
const framework = useFramework();
const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const getColorFromMap = useColor();
const { palettes, getCurrentColor } = usePalettes(
DefaultTheme.NoteBackgroundColorPalettes,
DefaultTheme.noteBackgrounColor
);
const borderStyleItems = useMemo<RadioItem[]>(
() => [
@@ -102,23 +105,23 @@ export const NoteSettings = () => {
const backgroundItems = useMemo(() => {
const { background } = settings['affine:note'];
return Object.entries(NoteBackgroundColor).map(([name, value]) => {
return palettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set('affine:note', { background: value });
};
const isSelected = background === value;
const isSelected = isEqual(background, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings]);
}, [editorSetting, settings, palettes]);
const cornerItems = useMemo(() => {
const { borderRadius } = settings['affine:note'].edgeless.style;
@@ -164,8 +167,8 @@ export const NoteSettings = () => {
const currentColor = useMemo(() => {
const { background } = settings['affine:note'];
return getColorFromMap(background, NoteBackgroundColorMap);
}, [getColorFromMap, settings]);
return getCurrentColor(background);
}, [getCurrentColor, settings]);
const getElements = useCallback((doc: Doc) => {
return doc.getBlocksByFlavour('affine:note') || [];
@@ -192,7 +195,7 @@ export const NoteSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={currentColor.value} />}
prefix={<Point color={currentColor.resolvedValue} />}
>
{currentColor.key}
</MenuTrigger>
@@ -2,14 +2,15 @@ import { MenuItem, MenuTrigger, Slider } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import { StrokeColor, StrokeColorMap } from '@blocksuite/affine/blocks';
import { DefaultTheme } from '@blocksuite/affine/blocks';
import type { Doc } 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 { useColor } from '../utils';
import { usePalettes } from '../utils';
import { Point } from './point';
import { EdgelessSnapshot } from './snapshot';
import { getSurfaceBlock } from './utils';
@@ -19,31 +20,34 @@ export const PenSettings = () => {
const framework = useFramework();
const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const getColorFromMap = useColor();
const { palettes, getCurrentColor } = usePalettes(
DefaultTheme.StrokeColorPalettes,
DefaultTheme.black
);
const currentColor = useMemo(() => {
return getColorFromMap(settings.brush.color, StrokeColorMap);
}, [getColorFromMap, settings.brush.color]);
return getCurrentColor(settings.brush.color);
}, [getCurrentColor, settings.brush.color]);
const colorItems = useMemo(() => {
const { color } = settings.brush;
return Object.entries(StrokeColor).map(([name, value]) => {
return palettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set('brush', { color: value });
};
const isSelected = color === value;
const isSelected = isEqual(color, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings.brush]);
}, [editorSetting, settings.brush, palettes]);
const borderThickness = settings.brush.lineWidth;
const setBorderThickness = useCallback(
@@ -78,7 +82,7 @@ export const PenSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={currentColor.value} />}
prefix={<Point color={currentColor.resolvedValue} />}
>
{currentColor.key}
</MenuTrigger>
@@ -13,7 +13,7 @@ export const Point = ({
width: size,
height: size,
borderRadius: '50%',
backgroundColor: `var(${color})`,
backgroundColor: color,
border: `1px solid ${cssVarV2('layer/insideBorder/blackBorder')}`,
}}
></div>
@@ -15,22 +15,20 @@ import type {
ShapeName,
} from '@blocksuite/affine/blocks';
import {
createEnumMap,
DefaultTheme,
FontFamily,
FontFamilyMap,
FontStyle,
FontWeightMap,
getShapeName,
ShapeFillColor,
ShapeStyle,
ShapeType,
StrokeColor,
StrokeColorMap,
StrokeStyle,
TextAlign,
} from '@blocksuite/affine/blocks';
import type { Doc } from '@blocksuite/affine/store';
import { useFramework, useLiveData } from '@toeverything/infra';
import { isEqual } from 'lodash-es';
import { useCallback, useMemo, useState } from 'react';
import { DropdownMenu } from '../menu';
@@ -40,7 +38,7 @@ import {
settingWrapper,
shapeIndicator,
} from '../style.css';
import { sortedFontWeightEntries, useColor } from '../utils';
import { sortedFontWeightEntries, usePalettes } from '../utils';
import type { DocName } from './docs';
import { Point } from './point';
import { EdgelessSnapshot } from './snapshot';
@@ -55,14 +53,20 @@ enum ShapeTextFontSize {
'64px' = '64',
}
const ShapeFillColorMap = createEnumMap(ShapeFillColor);
export const ShapeSettings = () => {
const t = useI18n();
const framework = useFramework();
const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const getColorFromMap = useColor();
const {
palettes: strokeColorPalettes,
getCurrentColor: getCurrentStrokeColor,
} = usePalettes(
DefaultTheme.StrokeColorPalettes,
DefaultTheme.shapeStrokeColor
);
const { palettes: fillColorPalettes, getCurrentColor: getCurrentFillColor } =
usePalettes(DefaultTheme.FillColorPalettes, DefaultTheme.shapeFillColor);
const [currentShape, setCurrentShape] = useState<ShapeName>(ShapeType.Rect);
@@ -206,43 +210,43 @@ export const ShapeSettings = () => {
const fillColorItems = useMemo(() => {
const { fillColor } = settings[`shape:${currentShape}`];
return Object.entries(ShapeFillColor).map(([name, value]) => {
return fillColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set(`shape:${currentShape}`, { fillColor: value });
};
const isSelected = fillColor === value;
const isSelected = isEqual(fillColor, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings, currentShape]);
}, [editorSetting, settings, currentShape, fillColorPalettes]);
const borderColorItems = useMemo(() => {
const strokeColorItems = useMemo(() => {
const { strokeColor } = settings[`shape:${currentShape}`];
return Object.entries(StrokeColor).map(([name, value]) => {
return strokeColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set(`shape:${currentShape}`, { strokeColor: value });
};
const isSelected = strokeColor === value;
const isSelected = isEqual(strokeColor, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings, currentShape]);
}, [editorSetting, settings, currentShape, strokeColorPalettes]);
const borderThickness = settings[`shape:${currentShape}`].strokeWidth;
const setBorderThickness = useCallback(
@@ -316,23 +320,23 @@ export const ShapeSettings = () => {
const textColorItems = useMemo(() => {
const { color } = settings[`shape:${currentShape}`];
return Object.entries(StrokeColor).map(([name, value]) => {
return strokeColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set(`shape:${currentShape}`, { color: value });
};
const isSelected = color === value;
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings, currentShape]);
}, [editorSetting, settings, currentShape, strokeColorPalettes]);
const getElements = useCallback(
(doc: Doc) => {
@@ -370,18 +374,18 @@ export const ShapeSettings = () => {
const fillColor = useMemo(() => {
const color = settings[`shape:${currentShape}`].fillColor;
return getColorFromMap(color, ShapeFillColorMap);
}, [currentShape, getColorFromMap, settings]);
return getCurrentFillColor(color);
}, [currentShape, getCurrentFillColor, settings]);
const borderColor = useMemo(() => {
const strokeColor = useMemo(() => {
const color = settings[`shape:${currentShape}`].strokeColor;
return getColorFromMap(color, StrokeColorMap);
}, [currentShape, getColorFromMap, settings]);
return getCurrentStrokeColor(color);
}, [currentShape, getCurrentStrokeColor, settings]);
const textColor = useMemo(() => {
const color = settings[`shape:${currentShape}`].color;
return getColorFromMap(color, StrokeColorMap);
}, [currentShape, getColorFromMap, settings]);
return getCurrentStrokeColor(color);
}, [currentShape, getCurrentStrokeColor, settings]);
const height = currentDoc === 'flow' ? 456 : 180;
return (
@@ -443,7 +447,7 @@ export const ShapeSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={fillColor.value} />}
prefix={<Point color={fillColor.resolvedValue} />}
>
{fillColor.key}
</MenuTrigger>
@@ -457,15 +461,15 @@ export const ShapeSettings = () => {
]()}
desc={''}
>
{borderColor ? (
{strokeColor ? (
<DropdownMenu
items={borderColorItems}
items={strokeColorItems}
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={borderColor.value} />}
prefix={<Point color={strokeColor.resolvedValue} />}
>
{borderColor.key}
{strokeColor.key}
</MenuTrigger>
}
/>
@@ -513,7 +517,7 @@ export const ShapeSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={textColor.value} />}
prefix={<Point color={textColor.resolvedValue} />}
>
{textColor.key}
</MenuTrigger>
@@ -8,21 +8,21 @@ import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
DefaultTheme,
FontFamily,
FontFamilyMap,
FontStyle,
FontWeightMap,
StrokeColor,
StrokeColorMap,
TextAlign,
} from '@blocksuite/affine/blocks';
import type { Doc } 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, settingWrapper } from '../style.css';
import { sortedFontWeightEntries, useColor } from '../utils';
import { sortedFontWeightEntries, usePalettes } from '../utils';
import { Point } from './point';
import { EdgelessSnapshot } from './snapshot';
@@ -31,7 +31,10 @@ export const TextSettings = () => {
const framework = useFramework();
const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$);
const getColorFromMap = useColor();
const { palettes, getCurrentColor } = usePalettes(
DefaultTheme.StrokeColorPalettes,
DefaultTheme.textColor
);
const alignItems = useMemo<RadioItem[]>(
() => [
@@ -72,23 +75,23 @@ export const TextSettings = () => {
const colorItems = useMemo(() => {
const { color } = settings['affine:edgeless-text'];
return Object.entries(StrokeColor).map(([name, value]) => {
return palettes.map(({ key, value, resolvedValue }) => {
const handler = () => {
editorSetting.set('affine:edgeless-text', { color: value });
};
const isSelected = color === value;
const isSelected = isEqual(color, value);
return (
<MenuItem
key={name}
key={key}
onSelect={handler}
selected={isSelected}
prefix={<Point color={value} />}
prefix={<Point color={resolvedValue} />}
>
{name}
{key}
</MenuItem>
);
});
}, [editorSetting, settings]);
}, [editorSetting, settings, palettes]);
const fontFamilyItems = useMemo(() => {
const { fontFamily } = settings['affine:edgeless-text'];
@@ -137,8 +140,8 @@ export const TextSettings = () => {
const currentColor = useMemo(() => {
const { color } = settings['affine:edgeless-text'];
return getColorFromMap(color, StrokeColorMap);
}, [getColorFromMap, settings]);
return getCurrentColor(color);
}, [getCurrentColor, settings]);
const getElements = useCallback((doc: Doc) => {
return doc.getBlocksByFlavour('affine:edgeless-text') || [];
@@ -162,7 +165,7 @@ export const TextSettings = () => {
trigger={
<MenuTrigger
className={menuTrigger}
prefix={<Point color={currentColor.value} />}
prefix={<Point color={currentColor.resolvedValue} />}
>
{currentColor.key}
</MenuTrigger>
@@ -1,48 +1,48 @@
import { FontWeight } from '@blocksuite/affine/blocks';
import {
type Color,
ColorScheme,
FontWeight,
type Palette,
resolveColor,
} from '@blocksuite/affine/blocks';
import { isEqual } from 'lodash-es';
import { useTheme } from 'next-themes';
function getColorFromMap(
color: string | { normal: string } | { light: string; dark: string },
colorMap: { [key: string]: string },
theme: 'light' | 'dark' = 'light'
):
| {
value: string;
key: string;
}
| undefined {
if (typeof color === 'string') {
return { value: color, key: colorMap[color] };
}
if ('normal' in color) {
return {
value: color.normal,
key: colorMap[color.normal],
};
}
if ('light' in color && 'dark' in color) {
return {
value: color[theme],
key: colorMap[color[theme]],
};
}
return undefined;
}
export const useColor = () => {
export const useResolvedTheme = () => {
const { resolvedTheme } = useTheme();
return (
color: string | { normal: string } | { light: string; dark: string },
colorMap: { [key: string]: string }
) =>
getColorFromMap(
color,
colorMap,
resolvedTheme as 'light' | 'dark' | undefined
);
return resolvedTheme === ColorScheme.Dark
? ColorScheme.Dark
: ColorScheme.Light;
};
export const usePalettes = (
originalPalettes: Palette[],
defaultColor: Color
) => {
const theme = useResolvedTheme();
const isDark = theme === ColorScheme.Dark;
const palettes = originalPalettes.map(({ key, value }) => {
// Title needs to be inverted.
if (isDark) {
if (key === 'Black') {
key = 'White';
} else if (key === 'White') {
key = 'Black';
}
}
return {
key,
value,
resolvedValue: resolveColor(value, theme),
};
});
return {
palettes,
getCurrentColor: (color: Color) =>
palettes.find(({ value }) => isEqual(value, color)) ||
palettes.find(({ value }) => isEqual(value, defaultColor)),
};
};
export const sortedFontWeightEntries = Object.entries(FontWeight).sort(