diff --git a/packages/common/infra/src/modules/feature-flag/constant.ts b/packages/common/infra/src/modules/feature-flag/constant.ts index 62a1679c6eba..5b30ea4c69dc 100644 --- a/packages/common/infra/src/modules/feature-flag/constant.ts +++ b/packages/common/infra/src/modules/feature-flag/constant.ts @@ -91,6 +91,13 @@ export const AFFINE_FLAGS = { configurable: true, defaultState: false, }, + enable_editor_settings: { + category: 'affine', + displayName: 'Editor Settings', + description: 'Enables editor settings.', + configurable: isCanaryBuild, + defaultState: false, + }, } satisfies { [key in string]: FlagInfo }; export type AFFINE_FLAGS = typeof AFFINE_FLAGS; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/connecter.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/connecter.tsx new file mode 100644 index 000000000000..6b72c7fce2bd --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/connecter.tsx @@ -0,0 +1,183 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, + Slider, +} from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useMemo, useState } from 'react'; + +import { menuTrigger, settingWrapper } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +export const ConnecterSettings = () => { + const t = useI18n(); + + const [connecterStyle, setConnecterStyle] = useState<'general' | 'scribbled'>( + 'general' + ); + const [connectorShape, setConnectorShape] = useState< + 'elbowed' | 'curve' | 'straight' + >('elbowed'); + const [borderStyle, setBorderStyle] = useState<'solid' | 'dash'>('solid'); + const [borderThickness, setBorderThickness] = useState([3]); + + const connecterStyleItems = useMemo( + () => [ + { + value: 'general', + label: t['com.affine.settings.editorSettings.edgeless.style.general'](), + }, + { + value: 'scribbled', + label: + t['com.affine.settings.editorSettings.edgeless.style.scribbled'](), + }, + ], + [t] + ); + const connecterShapeItems = useMemo( + () => [ + { + value: 'elbowed', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.connecter.connector-shape.elbowed' + ](), + }, + { + value: 'curve', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.connecter.connector-shape.curve' + ](), + }, + { + value: 'straight', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.connecter.connector-shape.straight' + ](), + }, + ], + [t] + ); + const borderStyleItems = useMemo( + () => [ + { + value: 'solid', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.solid'](), + }, + { + value: 'dash', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.dash'](), + }, + ], + [t] + ); + return ( + <> + + + Grey}> + + Grey + + + + + + + + + + + + + + + + + None}> + + None + + + + + Arrow}> + + Arrow + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/edgeless.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/edgeless.tsx new file mode 100644 index 000000000000..a29a5cd97eb9 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/edgeless.tsx @@ -0,0 +1,23 @@ +import { SettingWrapper } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; + +import { ConnecterSettings } from './connecter'; +import { MindMapSettings } from './mind-map'; +import { NoteSettings } from './note'; +import { PenSettings } from './pen'; +import { ShapeSettings } from './shape'; +import { TextSettings } from './text'; + +export const Edgeless = () => { + const t = useI18n(); + return ( + + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/index.ts b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/index.ts new file mode 100644 index 000000000000..40928e7be43b --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/index.ts @@ -0,0 +1 @@ +export * from './edgeless'; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/mind-map.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/mind-map.tsx new file mode 100644 index 000000000000..33d4a5c5844a --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/mind-map.tsx @@ -0,0 +1,79 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, +} from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useMemo, useState } from 'react'; + +import { menuTrigger, settingWrapper } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +export const MindMapSettings = () => { + const t = useI18n(); + const [layoutValue, setLayoutValue] = useState<'left' | 'radial' | 'right'>( + 'right' + ); + const layoutValueItems = useMemo( + () => [ + { + value: 'left', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.mind-map.layout.left' + ](), + }, + { + value: 'radial', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.mind-map.layout.radial' + ](), + }, + { + value: 'right', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.mind-map.layout.right' + ](), + }, + ], + [t] + ); + return ( + <> + + + Style 1}> + + Style 1 + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/note.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/note.tsx new file mode 100644 index 000000000000..d6df662febd1 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/note.tsx @@ -0,0 +1,111 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, + Slider, +} from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useMemo, useState } from 'react'; + +import { menuTrigger, settingWrapper } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +export const NoteSettings = () => { + const t = useI18n(); + const [borderStyle, setBorderStyle] = useState<'solid' | 'dash' | 'none'>( + 'solid' + ); + const [borderThickness, setBorderThickness] = useState([3]); + + const borderStyleItems = useMemo( + () => [ + { + value: 'solid', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.solid'](), + }, + { + value: 'dash', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.dash'](), + }, + { + value: 'none', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.none'](), + }, + ], + [t] + ); + return ( + <> + + + Yellow}> + + Yellow + + + + + Small}> + + Small + + + + + Box shadow}> + + Box shadow + + + + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/pen.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/pen.tsx new file mode 100644 index 000000000000..b6d2795cd8fb --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/pen.tsx @@ -0,0 +1,44 @@ +import { Menu, MenuItem, MenuTrigger, Slider } from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useState } from 'react'; + +import { menuTrigger } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +export const PenSettings = () => { + const t = useI18n(); + const [borderThickness, setBorderThickness] = useState([3]); + return ( + <> + + + Yellow}> + + Yellow + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/shape.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/shape.tsx new file mode 100644 index 000000000000..fdde2abc4852 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/shape.tsx @@ -0,0 +1,276 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, + Slider, +} from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useMemo, useState } from 'react'; + +import { menuTrigger, settingWrapper, shapeIndicator } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +type Shape = + | 'square' + | 'ellipse' + | 'diamond' + | 'triangle' + | 'rounded-rectangle'; + +export const ShapeSettings = () => { + const t = useI18n(); + const [currentShape, setCurrentShape] = useState('square'); + const [shapeStyle, setShapeStyle] = useState<'general' | 'scribbled'>( + 'general' + ); + const [borderStyle, setBorderStyle] = useState<'solid' | 'dash' | 'none'>( + 'solid' + ); + const [borderThickness, setBorderThickness] = useState([3]); + const [textAlignment, setTextAlignment] = useState< + 'left' | 'center' | 'right' + >('left'); + + const shapeStyleItems = useMemo( + () => [ + { + value: 'general', + label: t['com.affine.settings.editorSettings.edgeless.style.general'](), + }, + { + value: 'scribbled', + label: + t['com.affine.settings.editorSettings.edgeless.style.scribbled'](), + }, + ], + [t] + ); + + const borderStyleItems = useMemo( + () => [ + { + value: 'solid', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.solid'](), + }, + { + value: 'dash', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.dash'](), + }, + { + value: 'none', + label: + t['com.affine.settings.editorSettings.edgeless.note.border.none'](), + }, + ], + [t] + ); + + const alignItems = useMemo( + () => [ + { + value: 'left', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.left' + ](), + }, + { + value: 'center', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.center' + ](), + }, + { + value: 'right', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.right' + ](), + }, + ], + [t] + ); + + const shapes = useMemo( + () => [ + { + value: 'square', + label: t['com.affine.settings.editorSettings.edgeless.shape.square'](), + }, + { + value: 'ellipse', + label: t['com.affine.settings.editorSettings.edgeless.shape.ellipse'](), + }, + { + value: 'diamond', + label: t['com.affine.settings.editorSettings.edgeless.shape.diamond'](), + }, + { + value: 'triangle', + label: + t['com.affine.settings.editorSettings.edgeless.shape.triangle'](), + }, + { + value: 'rounded-rectangle', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.shape.rounded-rectangle' + ](), + }, + ], + [t] + ); + + return ( + <> + + + + + + + + Yellow}> + + Yellow + + + + + Yellow}> + + Yellow + + + + + + + + + + + Yellow}> + + Yellow + + + + + Inter}> + + Inter + + + + + 15px}> + + 15px + + + + + Regular}> + + Regular + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/snapshot.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/snapshot.tsx new file mode 100644 index 000000000000..5914351ef3f6 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/snapshot.tsx @@ -0,0 +1,24 @@ +import { snapshot, snapshotContainer, snapshotTitle } from '../style.css'; + +export const EdgelessSnapshot = ({ + title, + option, + type, +}: { + title: string; + option: string[]; + type: string; +}) => { + return ( +
+
{title}
+
+ Mock Preview +
+
+ ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/text.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/text.tsx new file mode 100644 index 000000000000..4ce4cbc00df5 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/edgeless/text.tsx @@ -0,0 +1,112 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, +} from '@affine/component'; +import { SettingRow } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; +import { useMemo, useState } from 'react'; + +import { menuTrigger, settingWrapper } from '../style.css'; +import { EdgelessSnapshot } from './snapshot'; + +export const TextSettings = () => { + const t = useI18n(); + + const [textAlignment, setTextAlignment] = useState< + 'left' | 'center' | 'right' + >('left'); + + const alignItems = useMemo( + () => [ + { + value: 'left', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.left' + ](), + }, + { + value: 'center', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.center' + ](), + }, + { + value: 'right', + label: + t[ + 'com.affine.settings.editorSettings.edgeless.text.alignment.right' + ](), + }, + ], + [t] + ); + + return ( + <> + + + Blue}> + + Blue + + + + + Inter}> + + Inter + + + + + 15px}> + + 15px + + + + + Regular}> + + Regular + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx new file mode 100644 index 000000000000..ae1ebd9a0291 --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx @@ -0,0 +1,199 @@ +import { + Menu, + MenuItem, + MenuTrigger, + RadioGroup, + type RadioItem, + Switch, +} from '@affine/component'; +import { + SettingRow, + SettingWrapper, +} from '@affine/component/setting-components'; +import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; +import { useI18n } from '@affine/i18n'; +import { + type AppSetting, + type DocMode, + fontStyleOptions, +} from '@toeverything/infra'; +import { useCallback, useMemo, useState } from 'react'; + +import { menu, menuTrigger, settingWrapper } from './style.css'; + +const FontFamilySettings = () => { + const t = useI18n(); + const { appSettings, updateSettings } = useAppSettingHelper(); + + const radioItems = useMemo(() => { + return fontStyleOptions.map(({ key, value }) => { + const label = + key === 'Mono' + ? t[`com.affine.appearanceSettings.fontStyle.mono`]() + : key === 'Sans' + ? t['com.affine.appearanceSettings.fontStyle.sans']() + : key === 'Serif' + ? t['com.affine.appearanceSettings.fontStyle.serif']() + : ''; + return { + value: key, + label, + testId: 'system-font-style-trigger', + style: { fontFamily: value }, + } satisfies RadioItem; + }); + }, [t]); + + return ( + { + updateSettings('fontStyle', value); + }, + [updateSettings] + )} + /> + ); +}; +const NewDocDefaultModeSettings = () => { + const t = useI18n(); + const [value, setValue] = useState('page'); + const radioItems = useMemo( + () => [ + { + value: 'page', + label: t['Page'](), + testId: 'page-mode-trigger', + }, + { + value: 'edgeless', + label: t['Edgeless'](), + testId: 'edgeless-mode-trigger', + }, + ], + [t] + ); + return ( + + ); +}; + +export const General = () => { + const t = useI18n(); + return ( + + + + + + + + + + + + inter}> + + inter + + + + + 15} + > + + 15 + + + + + + + + Plain Text} + > + + Plain Text + + + + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/index.tsx new file mode 100644 index 000000000000..54959cfde6ab --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/index.tsx @@ -0,0 +1,24 @@ +import { SettingHeader } from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; + +import { Edgeless } from './edgeless'; +import { General } from './general'; +import { Page } from './page'; +import { Preferences } from './preferences'; + +export const EditorSettings = () => { + const t = useI18n(); + + return ( + <> + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/page.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/page.tsx new file mode 100644 index 000000000000..1ea71372cf9c --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/page.tsx @@ -0,0 +1,38 @@ +import { Switch } from '@affine/component'; +import { + SettingRow, + SettingWrapper, +} from '@affine/component/setting-components'; +import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; +import { useI18n } from '@affine/i18n'; + +export const Page = () => { + const t = useI18n(); + const { appSettings, updateSettings } = useAppSettingHelper(); + return ( + + + updateSettings('fullWidthLayout', checked)} + /> + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/preferences.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/preferences.tsx new file mode 100644 index 000000000000..82001804251a --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/preferences.tsx @@ -0,0 +1,36 @@ +import { Button } from '@affine/component'; +import { + SettingRow, + SettingWrapper, +} from '@affine/component/setting-components'; +import { useI18n } from '@affine/i18n'; + +export const Preferences = () => { + const t = useI18n(); + return ( + + + + + + + + + ); +}; diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/style.css.ts b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/style.css.ts new file mode 100644 index 000000000000..89e5768f768f --- /dev/null +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/style.css.ts @@ -0,0 +1,51 @@ +import { cssVar } from '@toeverything/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; +export const settingWrapper = style({ + flexGrow: 1, + display: 'flex', + justifyContent: 'flex-end', + minWidth: '150px', + maxWidth: '250px', +}); + +export const menu = style({ + background: 'white', + width: '250px', + maxHeight: '30vh', + overflowY: 'auto', +}); + +export const menuTrigger = style({ + textTransform: 'capitalize', + fontWeight: 600, + width: '250px', +}); + +export const snapshotContainer = style({ + display: 'flex', + flexDirection: 'column', + marginBottom: '24px', +}); + +export const snapshotTitle = style({ + marginBottom: '8px', + fontSize: cssVar('fontSm'), + fontWeight: 500, + color: cssVarV2('text/secondary'), +}); + +export const snapshot = style({ + width: '100%', + height: '180px', + border: `1px solid ${cssVarV2('layer/insideBorder/border')}`, + borderRadius: '4px', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const shapeIndicator = style({ + boxShadow: 'none', + backgroundColor: cssVarV2('layer/background/tertiary'), +}); diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx index 7d6d7b03fa43..00d2f18c5806 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx @@ -2,11 +2,16 @@ import { UserFeatureService } from '@affine/core/modules/cloud/services/user-fea import { useI18n } from '@affine/i18n'; import { AppearanceIcon, + BlocksuiteIcon, ExperimentIcon, InformationIcon, KeyboardIcon, } from '@blocksuite/icons/rc'; -import { useLiveData, useServices } from '@toeverything/infra'; +import { + FeatureFlagService, + useLiveData, + useServices, +} from '@toeverything/infra'; import type { ReactElement, SVGProps } from 'react'; import { useEffect } from 'react'; @@ -15,6 +20,7 @@ import type { GeneralSettingKey } from '../types'; import { AboutAffine } from './about'; import { AppearanceSettings } from './appearance'; import { BillingSettings } from './billing'; +import { EditorSettings } from './editor'; import { ExperimentalFeatures } from './experimental-features'; import { PaymentIcon, UpgradeIcon } from './icons'; import { AFFiNEPricingPlans } from './plans'; @@ -31,15 +37,24 @@ export type GeneralSettingList = GeneralSettingListItem[]; export const useGeneralSettingList = (): GeneralSettingList => { const t = useI18n(); - const { authService, serverConfigService, userFeatureService } = useServices({ + const { + authService, + serverConfigService, + userFeatureService, + featureFlagService, + } = useServices({ AuthService, ServerConfigService, UserFeatureService, + FeatureFlagService, }); const status = useLiveData(authService.session.status$); const hasPaymentFeature = useLiveData( serverConfigService.serverConfig.features$.map(f => f?.payment) ); + const enableEditorSettings = useLiveData( + featureFlagService.flags.enable_editor_settings.$ + ); useEffect(() => { userFeatureService.userFeature.revalidate(); @@ -65,6 +80,15 @@ export const useGeneralSettingList = (): GeneralSettingList => { testId: 'about-panel-trigger', }, ]; + if (enableEditorSettings) { + // add editor settings to second position + settings.splice(1, 0, { + key: 'editor', + title: t['com.affine.settings.editorSettings.title'](), + icon: BlocksuiteIcon, + testId: 'editor-panel-trigger', + }); + } if (hasPaymentFeature) { settings.splice(3, 0, { @@ -103,6 +127,8 @@ export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => { switch (generalKey) { case 'shortcuts': return ; + case 'editor': + return ; case 'appearance': return ; case 'about': diff --git a/packages/frontend/core/src/components/affine/setting-modal/types.ts b/packages/frontend/core/src/components/affine/setting-modal/types.ts index 4226fe09e4fa..06f9f8b06da8 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/types.ts +++ b/packages/frontend/core/src/components/affine/setting-modal/types.ts @@ -5,6 +5,7 @@ export const GeneralSettingKeys = [ 'plans', 'billing', 'experimental-features', + 'editor', ] as const; export const WorkspaceSubTabs = ['preference', 'properties'] as const; diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 25ffab4dfff0..ec892557a0cf 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -1217,6 +1217,94 @@ "com.affine.settings.appearance.window-frame-description": "Customise appearance of Windows Client.", "com.affine.settings.auto-check-description": "If enabled, it will automatically check for new versions at regular intervals.", "com.affine.settings.auto-download-description": "If enabled, new versions will be automatically downloaded to the current device.", + "com.affine.settings.editorSettings": "Editor", + "com.affine.settings.editorSettings.title": "Editor Settings", + "com.affine.settings.editorSettings.subtitle": "Configure your own editor.", + "com.affine.settings.editorSettings.general": "General", + "com.affine.settings.editorSettings.general.ai.title": "AFFiNE AI", + "com.affine.settings.editorSettings.general.ai.description": "Enable the powerful AI assistant, AFFiNE AI.", + "com.affine.settings.editorSettings.general.font-style.title": "Font style", + "com.affine.settings.editorSettings.general.font-style.description": "Choose your editor’s font style.", + "com.affine.settings.editorSettings.general.font-family.title": "Font family", + "com.affine.settings.editorSettings.general.font-family.description": "Choose your editor’s font family.", + "com.affine.settings.editorSettings.general.font-family.custom.title": "Custom font family", + "com.affine.settings.editorSettings.general.font-family.custom.description": "Customize your text experience.", + "com.affine.settings.editorSettings.general.font-size.title": "Font size", + "com.affine.settings.editorSettings.general.font-size.description": "Choose your editor’s base font size.", + "com.affine.settings.editorSettings.general.default-new-doc.title": "New doc default mode", + "com.affine.settings.editorSettings.general.default-new-doc.description": "Default mode for new doc.", + "com.affine.settings.editorSettings.general.default-code-block.language.title": "Code blocks default language", + "com.affine.settings.editorSettings.general.default-code-block.language.description": "Set a default programming language.", + "com.affine.settings.editorSettings.general.default-code-block.wrap.title": "Wrap code in code blocks", + "com.affine.settings.editorSettings.general.default-code-block.wrap.description": "Encapsulate code snippets for better readability.", + "com.affine.settings.editorSettings.general.spell-check.title": "Spell check", + "com.affine.settings.editorSettings.general.spell-check.description": "Automatically detect and correct spelling errors.", + "com.affine.settings.editorSettings.page": "Page", + "com.affine.settings.editorSettings.page.full-width.title": "Full width layout", + "com.affine.settings.editorSettings.page.full-width.description": "Maximise display of content within a page.", + "com.affine.settings.editorSettings.page.display-doc-info.title": "Display doc info", + "com.affine.settings.editorSettings.page.display-doc-info.description": "Display document information on the doc.", + "com.affine.settings.editorSettings.edgeless": "Edgeless", + "com.affine.settings.editorSettings.edgeless.style": "Style", + "com.affine.settings.editorSettings.edgeless.style.general": "General", + "com.affine.settings.editorSettings.edgeless.style.scribbled": "Scribbled", + "com.affine.settings.editorSettings.edgeless.custom": "Custom", + "com.affine.settings.editorSettings.edgeless.note": "Note", + "com.affine.settings.editorSettings.edgeless.note.background": "Background", + "com.affine.settings.editorSettings.edgeless.note.corners": "Corners", + "com.affine.settings.editorSettings.edgeless.note.shadow": "Shadow style", + "com.affine.settings.editorSettings.edgeless.note.border": "Border style", + "com.affine.settings.editorSettings.edgeless.note.border.solid": "Solid", + "com.affine.settings.editorSettings.edgeless.note.border.dash": "Dash", + "com.affine.settings.editorSettings.edgeless.note.border.none": "None", + "com.affine.settings.editorSettings.edgeless.note.border-thickness": "Border thickness", + "com.affine.settings.editorSettings.edgeless.text": "Text", + "com.affine.settings.editorSettings.edgeless.text.color": "Text color", + "com.affine.settings.editorSettings.edgeless.text.font": "Font", + "com.affine.settings.editorSettings.edgeless.text.font-size": "Font size", + "com.affine.settings.editorSettings.edgeless.text.font-weight": "Font weight", + "com.affine.settings.editorSettings.edgeless.text.alignment": "Alignment", + "com.affine.settings.editorSettings.edgeless.text.alignment.left": "Left", + "com.affine.settings.editorSettings.edgeless.text.alignment.center": "Center", + "com.affine.settings.editorSettings.edgeless.text.alignment.right": "Right", + "com.affine.settings.editorSettings.edgeless.shape": "Shape", + "com.affine.settings.editorSettings.edgeless.shape.square": "Square", + "com.affine.settings.editorSettings.edgeless.shape.ellipse": "Ellipse", + "com.affine.settings.editorSettings.edgeless.shape.diamond": "Diamond", + "com.affine.settings.editorSettings.edgeless.shape.triangle": "Triangle", + "com.affine.settings.editorSettings.edgeless.shape.rounded-rectangle": "Rounded Rectangle", + "com.affine.settings.editorSettings.edgeless.shape.fill-color": "Fill color", + "com.affine.settings.editorSettings.edgeless.shape.border-color": "Border color", + "com.affine.settings.editorSettings.edgeless.shape.border-style": "Border style", + "com.affine.settings.editorSettings.edgeless.shape.border-thickness": "Border thickness", + "com.affine.settings.editorSettings.edgeless.shape.text-color": "Text color", + "com.affine.settings.editorSettings.edgeless.shape.font": "Font", + "com.affine.settings.editorSettings.edgeless.shape.font-size": "Font size", + "com.affine.settings.editorSettings.edgeless.shape.font-style": "Font style", + "com.affine.settings.editorSettings.edgeless.shape.text-alignment": "Text alignment", + "com.affine.settings.editorSettings.edgeless.connecter": "Connecter", + "com.affine.settings.editorSettings.edgeless.connecter.color": "Color", + "com.affine.settings.editorSettings.edgeless.connecter.connector-shape": "Connector Shape", + "com.affine.settings.editorSettings.edgeless.connecter.connector-shape.elbowed": "Elbowed", + "com.affine.settings.editorSettings.edgeless.connecter.connector-shape.curve": "Curve", + "com.affine.settings.editorSettings.edgeless.connecter.connector-shape.straight": "Straight", + "com.affine.settings.editorSettings.edgeless.connecter.border-style": "Border style", + "com.affine.settings.editorSettings.edgeless.connecter.border-thickness": "Border thickness", + "com.affine.settings.editorSettings.edgeless.connecter.start-endpoint": "Start endpoint", + "com.affine.settings.editorSettings.edgeless.connecter.end-endpoint": "End endpoint", + "com.affine.settings.editorSettings.edgeless.pen": "Pen", + "com.affine.settings.editorSettings.edgeless.pen.color": "Color", + "com.affine.settings.editorSettings.edgeless.pen.thickness": "Thickness", + "com.affine.settings.editorSettings.edgeless.mind-map": "Mind Map", + "com.affine.settings.editorSettings.edgeless.mind-map.layout": "Layout", + "com.affine.settings.editorSettings.edgeless.mind-map.layout.left": "Left", + "com.affine.settings.editorSettings.edgeless.mind-map.layout.radial": "Radial", + "com.affine.settings.editorSettings.edgeless.mind-map.layout.right": "Right", + "com.affine.settings.editorSettings.preferences": "Preferences", + "com.affine.settings.editorSettings.preferences.export.title": "Export Settings", + "com.affine.settings.editorSettings.preferences.export.description": "You can export the entire preferences data for backup, and the exported data can be re-imported.", + "com.affine.settings.editorSettings.preferences.import.title": "Import Settings", + "com.affine.settings.editorSettings.preferences.import.description": "You can import previously exported preferences data for restoration.", "com.affine.settings.email": "Email", "com.affine.settings.email.action": "Change email", "com.affine.settings.email.action.change": "Change email",