mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor(core): move fontFamily and fullWidthLayout to editor settings (#7988)
This commit is contained in:
@@ -19,10 +19,7 @@ export type DateFormats =
|
|||||||
|
|
||||||
export type AppSetting = {
|
export type AppSetting = {
|
||||||
clientBorder: boolean;
|
clientBorder: boolean;
|
||||||
fullWidthLayout: boolean;
|
|
||||||
windowFrameStyle: 'frameless' | 'NativeTitleBar';
|
windowFrameStyle: 'frameless' | 'NativeTitleBar';
|
||||||
fontStyle: FontFamily;
|
|
||||||
customFontFamily: string;
|
|
||||||
dateFormat: DateFormats;
|
dateFormat: DateFormats;
|
||||||
startWeekOnMonday: boolean;
|
startWeekOnMonday: boolean;
|
||||||
enableBlurBackground: boolean;
|
enableBlurBackground: boolean;
|
||||||
@@ -46,24 +43,9 @@ export const dateFormatOptions: DateFormats[] = [
|
|||||||
'dd MMMM YYYY',
|
'dd MMMM YYYY',
|
||||||
];
|
];
|
||||||
|
|
||||||
export type FontFamily = 'Sans' | 'Serif' | 'Mono' | 'Custom';
|
|
||||||
|
|
||||||
export const fontStyleOptions = [
|
|
||||||
{ key: 'Sans', value: 'var(--affine-font-sans-family)' },
|
|
||||||
{ key: 'Serif', value: 'var(--affine-font-serif-family)' },
|
|
||||||
{ key: 'Mono', value: 'var(--affine-font-mono-family)' },
|
|
||||||
{ key: 'Custom', value: 'var(--affine-font-sans-family)' },
|
|
||||||
] satisfies {
|
|
||||||
key: FontFamily;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
|
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
|
||||||
clientBorder: environment.isDesktop && !environment.isWindows,
|
clientBorder: environment.isDesktop && !environment.isWindows,
|
||||||
fullWidthLayout: false,
|
|
||||||
windowFrameStyle: 'frameless',
|
windowFrameStyle: 'frameless',
|
||||||
fontStyle: 'Sans',
|
|
||||||
customFontFamily: '',
|
|
||||||
dateFormat: dateFormatOptions[0],
|
dateFormat: dateFormatOptions[0],
|
||||||
startWeekOnMonday: false,
|
startWeekOnMonday: false,
|
||||||
enableBlurBackground: true,
|
enableBlurBackground: true,
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export const AFFINE_FLAGS = {
|
|||||||
displayName: 'Editor Settings',
|
displayName: 'Editor Settings',
|
||||||
description: 'Enables editor settings.',
|
description: 'Enables editor settings.',
|
||||||
configurable: isCanaryBuild,
|
configurable: isCanaryBuild,
|
||||||
defaultState: false,
|
defaultState: isCanaryBuild,
|
||||||
},
|
},
|
||||||
} satisfies { [key in string]: FlagInfo };
|
} satisfies { [key in string]: FlagInfo };
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import type { useI18n } from '@affine/i18n';
|
import type { useI18n } from '@affine/i18n';
|
||||||
import { SettingsIcon } from '@blocksuite/icons/rc';
|
import { SettingsIcon } from '@blocksuite/icons/rc';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
|
||||||
import { appSettingAtom } from '@toeverything/infra';
|
import { appSettingAtom } from '@toeverything/infra';
|
||||||
import type { createStore } from 'jotai';
|
import type { createStore } from 'jotai';
|
||||||
import type { useTheme } from 'next-themes';
|
import type { useTheme } from 'next-themes';
|
||||||
|
|
||||||
import type { useLanguageHelper } from '../hooks/affine/use-language-helper';
|
import type { useLanguageHelper } from '../hooks/affine/use-language-helper';
|
||||||
import { track } from '../mixpanel';
|
import { track } from '../mixpanel';
|
||||||
|
import type { EditorSettingService } from '../modules/editor-settting';
|
||||||
import { registerAffineCommand } from './registry';
|
import { registerAffineCommand } from './registry';
|
||||||
|
|
||||||
export function registerAffineSettingsCommands({
|
export function registerAffineSettingsCommands({
|
||||||
@@ -14,15 +14,20 @@ export function registerAffineSettingsCommands({
|
|||||||
store,
|
store,
|
||||||
theme,
|
theme,
|
||||||
languageHelper,
|
languageHelper,
|
||||||
|
editorSettingService,
|
||||||
}: {
|
}: {
|
||||||
t: ReturnType<typeof useI18n>;
|
t: ReturnType<typeof useI18n>;
|
||||||
store: ReturnType<typeof createStore>;
|
store: ReturnType<typeof createStore>;
|
||||||
theme: ReturnType<typeof useTheme>;
|
theme: ReturnType<typeof useTheme>;
|
||||||
languageHelper: ReturnType<typeof useLanguageHelper>;
|
languageHelper: ReturnType<typeof useLanguageHelper>;
|
||||||
editor: AffineEditorContainer | null;
|
editorSettingService: EditorSettingService;
|
||||||
}) {
|
}) {
|
||||||
const unsubs: Array<() => void> = [];
|
const unsubs: Array<() => void> = [];
|
||||||
const { onLanguageChange, languagesList, currentLanguage } = languageHelper;
|
const { onLanguageChange, languagesList, currentLanguage } = languageHelper;
|
||||||
|
const updateSettings = editorSettingService.editorSetting.set.bind(
|
||||||
|
editorSettingService.editorSetting
|
||||||
|
);
|
||||||
|
const settings$ = editorSettingService.editorSetting.settings$;
|
||||||
|
|
||||||
// color modes
|
// color modes
|
||||||
unsubs.push(
|
unsubs.push(
|
||||||
@@ -91,18 +96,14 @@ export function registerAffineSettingsCommands({
|
|||||||
]()}`,
|
]()}`,
|
||||||
category: 'affine:settings',
|
category: 'affine:settings',
|
||||||
icon: <SettingsIcon />,
|
icon: <SettingsIcon />,
|
||||||
preconditionStrategy: () =>
|
preconditionStrategy: () => settings$.value.fontFamily !== 'Sans',
|
||||||
store.get(appSettingAtom).fontStyle !== 'Sans',
|
|
||||||
run() {
|
run() {
|
||||||
track.$.cmdk.settings.changeAppSetting({
|
track.$.cmdk.settings.changeAppSetting({
|
||||||
key: 'fontStyle',
|
key: 'fontStyle',
|
||||||
value: 'Sans',
|
value: 'Sans',
|
||||||
});
|
});
|
||||||
|
|
||||||
store.set(appSettingAtom, prev => ({
|
updateSettings('fontFamily', 'Sans');
|
||||||
...prev,
|
|
||||||
fontStyle: 'Sans',
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -115,18 +116,14 @@ export function registerAffineSettingsCommands({
|
|||||||
]()}`,
|
]()}`,
|
||||||
category: 'affine:settings',
|
category: 'affine:settings',
|
||||||
icon: <SettingsIcon />,
|
icon: <SettingsIcon />,
|
||||||
preconditionStrategy: () =>
|
preconditionStrategy: () => settings$.value.fontFamily !== 'Serif',
|
||||||
store.get(appSettingAtom).fontStyle !== 'Serif',
|
|
||||||
run() {
|
run() {
|
||||||
track.$.cmdk.settings.changeAppSetting({
|
track.$.cmdk.settings.changeAppSetting({
|
||||||
key: 'fontStyle',
|
key: 'fontStyle',
|
||||||
value: 'Serif',
|
value: 'Serif',
|
||||||
});
|
});
|
||||||
|
|
||||||
store.set(appSettingAtom, prev => ({
|
updateSettings('fontFamily', 'Serif');
|
||||||
...prev,
|
|
||||||
fontStyle: 'Serif',
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -139,18 +136,14 @@ export function registerAffineSettingsCommands({
|
|||||||
]()}`,
|
]()}`,
|
||||||
category: 'affine:settings',
|
category: 'affine:settings',
|
||||||
icon: <SettingsIcon />,
|
icon: <SettingsIcon />,
|
||||||
preconditionStrategy: () =>
|
preconditionStrategy: () => settings$.value.fontFamily !== 'Mono',
|
||||||
store.get(appSettingAtom).fontStyle !== 'Mono',
|
|
||||||
run() {
|
run() {
|
||||||
track.$.cmdk.settings.changeAppSetting({
|
track.$.cmdk.settings.changeAppSetting({
|
||||||
key: 'fontStyle',
|
key: 'fontStyle',
|
||||||
value: 'Mono',
|
value: 'Mono',
|
||||||
});
|
});
|
||||||
|
|
||||||
store.set(appSettingAtom, prev => ({
|
updateSettings('fontFamily', 'Mono');
|
||||||
...prev,
|
|
||||||
fontStyle: 'Mono',
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -209,7 +202,7 @@ export function registerAffineSettingsCommands({
|
|||||||
id: `affine:change-full-width-layout`,
|
id: `affine:change-full-width-layout`,
|
||||||
label: () =>
|
label: () =>
|
||||||
`${t['com.affine.cmdk.affine.full-width-layout.to']()} ${t[
|
`${t['com.affine.cmdk.affine.full-width-layout.to']()} ${t[
|
||||||
store.get(appSettingAtom).fullWidthLayout
|
settings$.value.fullWidthLayout
|
||||||
? 'com.affine.cmdk.affine.switch-state.off'
|
? 'com.affine.cmdk.affine.switch-state.off'
|
||||||
: 'com.affine.cmdk.affine.switch-state.on'
|
: 'com.affine.cmdk.affine.switch-state.on'
|
||||||
]()}`,
|
]()}`,
|
||||||
@@ -218,13 +211,9 @@ export function registerAffineSettingsCommands({
|
|||||||
run() {
|
run() {
|
||||||
track.$.cmdk.settings.changeAppSetting({
|
track.$.cmdk.settings.changeAppSetting({
|
||||||
key: 'fullWidthLayout',
|
key: 'fullWidthLayout',
|
||||||
value: store.get(appSettingAtom).fullWidthLayout ? 'off' : 'on',
|
value: settings$.value.fullWidthLayout ? 'off' : 'on',
|
||||||
});
|
});
|
||||||
|
updateSettings('fullWidthLayout', !settings$.value.fullWidthLayout);
|
||||||
store.set(appSettingAtom, prev => ({
|
|
||||||
...prev,
|
|
||||||
fullWidthLayout: !prev.fullWidthLayout,
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -97,17 +97,6 @@ export const AppearanceSettings = () => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<SettingRow
|
|
||||||
name={t['com.affine.appearanceSettings.fullWidth.title']()}
|
|
||||||
desc={t['com.affine.appearanceSettings.fullWidth.description']()}
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
data-testid="full-width-layout-trigger"
|
|
||||||
checked={appSettings.fullWidthLayout}
|
|
||||||
onChange={checked => updateSettings('fullWidthLayout', checked)}
|
|
||||||
/>
|
|
||||||
</SettingRow>
|
|
||||||
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
||||||
<SettingRow
|
<SettingRow
|
||||||
name={t['com.affine.appearanceSettings.windowFrame.title']()}
|
name={t['com.affine.appearanceSettings.windowFrame.title']()}
|
||||||
|
|||||||
@@ -13,19 +13,21 @@ import {
|
|||||||
SettingRow,
|
SettingRow,
|
||||||
SettingWrapper,
|
SettingWrapper,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
import {
|
||||||
|
EditorSettingService,
|
||||||
|
type FontFamily,
|
||||||
|
fontStyleOptions,
|
||||||
|
} from '@affine/core/modules/editor-settting';
|
||||||
import {
|
import {
|
||||||
type FontData,
|
type FontData,
|
||||||
SystemFontFamilyService,
|
SystemFontFamilyService,
|
||||||
} from '@affine/core/modules/system-font-family';
|
} from '@affine/core/modules/system-font-family';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import {
|
import {
|
||||||
type AppSetting,
|
|
||||||
type DocMode,
|
type DocMode,
|
||||||
type FontFamily,
|
|
||||||
fontStyleOptions,
|
|
||||||
useLiveData,
|
useLiveData,
|
||||||
useService,
|
useService,
|
||||||
|
useServices,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import {
|
import {
|
||||||
type ChangeEvent,
|
type ChangeEvent,
|
||||||
@@ -43,7 +45,9 @@ import { menu, menuTrigger, searchInput, settingWrapper } from './style.css';
|
|||||||
|
|
||||||
const FontFamilySettings = () => {
|
const FontFamilySettings = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
const { editorSettingService } = useServices({ EditorSettingService });
|
||||||
|
const settings = useLiveData(editorSettingService.editorSetting.settings$);
|
||||||
|
|
||||||
const getLabel = useCallback(
|
const getLabel = useCallback(
|
||||||
(fontKey: FontFamily) => {
|
(fontKey: FontFamily) => {
|
||||||
switch (fontKey) {
|
switch (fontKey) {
|
||||||
@@ -70,8 +74,8 @@ const FontFamilySettings = () => {
|
|||||||
}
|
}
|
||||||
const label = getLabel(key);
|
const label = getLabel(key);
|
||||||
let fontFamily = value;
|
let fontFamily = value;
|
||||||
if (key === 'Custom' && appSettings.customFontFamily) {
|
if (key === 'Custom' && settings.customFontFamily) {
|
||||||
fontFamily = `${appSettings.customFontFamily}, ${value}`;
|
fontFamily = `${settings.customFontFamily}, ${value}`;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
value: key,
|
value: key,
|
||||||
@@ -83,20 +87,22 @@ const FontFamilySettings = () => {
|
|||||||
} satisfies RadioItem;
|
} satisfies RadioItem;
|
||||||
})
|
})
|
||||||
.filter(item => item !== null);
|
.filter(item => item !== null);
|
||||||
}, [appSettings.customFontFamily, getLabel]);
|
}, [getLabel, settings.customFontFamily]);
|
||||||
|
|
||||||
|
const handleFontFamilyChange = useCallback(
|
||||||
|
(value: FontFamily) => {
|
||||||
|
editorSettingService.editorSetting.set('fontFamily', value);
|
||||||
|
},
|
||||||
|
[editorSettingService.editorSetting]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
items={radioItems}
|
items={radioItems}
|
||||||
value={appSettings.fontStyle}
|
value={settings.fontFamily}
|
||||||
width={250}
|
width={250}
|
||||||
className={settingWrapper}
|
className={settingWrapper}
|
||||||
onChange={useCallback(
|
onChange={handleFontFamilyChange}
|
||||||
(value: AppSetting['fontStyle']) => {
|
|
||||||
updateSettings('fontStyle', value);
|
|
||||||
},
|
|
||||||
[updateSettings]
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -211,15 +217,17 @@ const FontMenuItem = ({
|
|||||||
|
|
||||||
const CustomFontFamilySettings = () => {
|
const CustomFontFamilySettings = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
const { editorSettingService } = useServices({ EditorSettingService });
|
||||||
const fontFamily = getFontFamily(appSettings.customFontFamily);
|
const settings = useLiveData(editorSettingService.editorSetting.settings$);
|
||||||
|
|
||||||
|
const fontFamily = getFontFamily(settings.customFontFamily);
|
||||||
const onCustomFontFamilyChange = useCallback(
|
const onCustomFontFamilyChange = useCallback(
|
||||||
(fontFamily: string) => {
|
(fontFamily: string) => {
|
||||||
updateSettings('customFontFamily', fontFamily);
|
editorSettingService.editorSetting.set('customFontFamily', fontFamily);
|
||||||
},
|
},
|
||||||
[updateSettings]
|
[editorSettingService.editorSetting]
|
||||||
);
|
);
|
||||||
if (appSettings.fontStyle !== 'Custom' || !environment.isDesktop) {
|
if (settings.fontFamily !== 'Custom' || !environment.isDesktop) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -239,7 +247,7 @@ const CustomFontFamilySettings = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuTrigger className={menuTrigger} style={{ fontFamily }}>
|
<MenuTrigger className={menuTrigger} style={{ fontFamily }}>
|
||||||
{appSettings.customFontFamily || 'Select a font'}
|
{settings.customFontFamily || 'Select a font'}
|
||||||
</MenuTrigger>
|
</MenuTrigger>
|
||||||
</Menu>
|
</Menu>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
@@ -291,37 +299,6 @@ export const General = () => {
|
|||||||
<FontFamilySettings />
|
<FontFamilySettings />
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<CustomFontFamilySettings />
|
<CustomFontFamilySettings />
|
||||||
<SettingRow
|
|
||||||
name={t[
|
|
||||||
'com.affine.settings.editorSettings.general.font-family.title'
|
|
||||||
]()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.settings.editorSettings.general.font-family.description'
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<Menu items={<MenuItem>inter</MenuItem>}>
|
|
||||||
<MenuTrigger className={menuTrigger} disabled>
|
|
||||||
inter
|
|
||||||
</MenuTrigger>
|
|
||||||
</Menu>
|
|
||||||
</SettingRow>
|
|
||||||
<SettingRow
|
|
||||||
name={t['com.affine.settings.editorSettings.general.font-size.title']()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.settings.editorSettings.general.font-size.description'
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<Menu
|
|
||||||
contentOptions={{
|
|
||||||
className: menu,
|
|
||||||
}}
|
|
||||||
items={<MenuItem>15</MenuItem>}
|
|
||||||
>
|
|
||||||
<MenuTrigger className={menuTrigger} disabled>
|
|
||||||
15
|
|
||||||
</MenuTrigger>
|
|
||||||
</Menu>
|
|
||||||
</SettingRow>
|
|
||||||
<SettingRow
|
<SettingRow
|
||||||
name={t[
|
name={t[
|
||||||
'com.affine.settings.editorSettings.general.default-new-doc.title'
|
'com.affine.settings.editorSettings.general.default-new-doc.title'
|
||||||
|
|||||||
@@ -3,12 +3,35 @@ import {
|
|||||||
SettingRow,
|
SettingRow,
|
||||||
SettingWrapper,
|
SettingWrapper,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
import { EditorSettingService } from '@affine/core/modules/editor-settting';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
export const Page = () => {
|
export const Page = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
const editorSetting = useService(EditorSettingService).editorSetting;
|
||||||
|
const settings = useLiveData(editorSetting.settings$);
|
||||||
|
|
||||||
|
const handleFullWidthLayoutChange = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
editorSetting.set('fullWidthLayout', checked);
|
||||||
|
},
|
||||||
|
[editorSetting]
|
||||||
|
);
|
||||||
|
const handleDisplayDocInfoChange = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
editorSetting.set('displayDocInfo', checked);
|
||||||
|
},
|
||||||
|
[editorSetting]
|
||||||
|
);
|
||||||
|
const handleDisplayBiDirectionalLinkChange = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
editorSetting.set('displayBiDirectionalLink', checked);
|
||||||
|
},
|
||||||
|
[editorSetting]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingWrapper title={t['com.affine.settings.editorSettings.page']()}>
|
<SettingWrapper title={t['com.affine.settings.editorSettings.page']()}>
|
||||||
<SettingRow
|
<SettingRow
|
||||||
@@ -19,8 +42,8 @@ export const Page = () => {
|
|||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
data-testid="full-width-layout-trigger"
|
data-testid="full-width-layout-trigger"
|
||||||
checked={appSettings.fullWidthLayout}
|
checked={settings.fullWidthLayout}
|
||||||
onChange={checked => updateSettings('fullWidthLayout', checked)}
|
onChange={handleFullWidthLayoutChange}
|
||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingRow
|
<SettingRow
|
||||||
@@ -31,7 +54,11 @@ export const Page = () => {
|
|||||||
'com.affine.settings.editorSettings.page.display-doc-info.description'
|
'com.affine.settings.editorSettings.page.display-doc-info.description'
|
||||||
]()}
|
]()}
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch
|
||||||
|
data-testid="display-doc-info-trigger"
|
||||||
|
checked={settings.displayDocInfo}
|
||||||
|
onChange={handleDisplayDocInfoChange}
|
||||||
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingRow
|
<SettingRow
|
||||||
name={t[
|
name={t[
|
||||||
@@ -41,7 +68,11 @@ export const Page = () => {
|
|||||||
'com.affine.settings.editorSettings.page.display-bi-link.description'
|
'com.affine.settings.editorSettings.page.display-bi-link.description'
|
||||||
]()}
|
]()}
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch
|
||||||
|
data-testid="display-bi-link-trigger"
|
||||||
|
checked={settings.displayBiDirectionalLink}
|
||||||
|
onChange={handleDisplayBiDirectionalLinkChange}
|
||||||
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
</SettingWrapper>
|
</SettingWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,20 +4,18 @@ import { useDocCollectionPage } from '@affine/core/hooks/use-block-suite-workspa
|
|||||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||||
import type { Doc as BlockSuiteDoc, DocCollection } from '@blocksuite/store';
|
import type { Doc as BlockSuiteDoc, DocCollection } from '@blocksuite/store';
|
||||||
import {
|
import { type DocMode, useLiveData, useService } from '@toeverything/infra';
|
||||||
type DocMode,
|
|
||||||
fontStyleOptions,
|
|
||||||
useLiveData,
|
|
||||||
useService,
|
|
||||||
} from '@toeverything/infra';
|
|
||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import { memo, Suspense, useCallback, useMemo } from 'react';
|
import { memo, Suspense, useCallback, useMemo } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { useAppSettingHelper } from '../hooks/affine/use-app-setting-helper';
|
|
||||||
import { EditorService } from '../modules/editor';
|
import { EditorService } from '../modules/editor';
|
||||||
|
import {
|
||||||
|
EditorSettingService,
|
||||||
|
fontStyleOptions,
|
||||||
|
} from '../modules/editor-settting';
|
||||||
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
||||||
import * as styles from './page-detail-editor.css';
|
import * as styles from './page-detail-editor.css';
|
||||||
|
|
||||||
@@ -51,21 +49,22 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
|||||||
const mode = useLiveData(editor.mode$);
|
const mode = useLiveData(editor.mode$);
|
||||||
|
|
||||||
const isSharedMode = editor.isSharedMode;
|
const isSharedMode = editor.isSharedMode;
|
||||||
const { appSettings } = useAppSettingHelper();
|
const editorSetting = useService(EditorSettingService).editorSetting;
|
||||||
|
const settings = useLiveData(editorSetting.settings$);
|
||||||
|
|
||||||
const value = useMemo(() => {
|
const value = useMemo(() => {
|
||||||
const fontStyle = fontStyleOptions.find(
|
const fontStyle = fontStyleOptions.find(
|
||||||
option => option.key === appSettings.fontStyle
|
option => option.key === settings.fontFamily
|
||||||
);
|
);
|
||||||
if (!fontStyle) {
|
if (!fontStyle) {
|
||||||
return cssVar('fontSansFamily');
|
return cssVar('fontSansFamily');
|
||||||
}
|
}
|
||||||
const customFontFamily = appSettings.customFontFamily;
|
const customFontFamily = settings.customFontFamily;
|
||||||
|
|
||||||
return customFontFamily && fontStyle.key === 'Custom'
|
return customFontFamily && fontStyle.key === 'Custom'
|
||||||
? `${customFontFamily}, ${fontStyle.value}`
|
? `${customFontFamily}, ${fontStyle.value}`
|
||||||
: fontStyle.value;
|
: fontStyle.value;
|
||||||
}, [appSettings.customFontFamily, appSettings.fontStyle]);
|
}, [settings.customFontFamily, settings.fontFamily]);
|
||||||
|
|
||||||
const blockId = useRouterHash();
|
const blockId = useRouterHash();
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
|||||||
return (
|
return (
|
||||||
<Editor
|
<Editor
|
||||||
className={clsx(styles.editor, {
|
className={clsx(styles.editor, {
|
||||||
'full-screen': !isSharedMode && appSettings.fullWidthLayout,
|
'full-screen': !isSharedMode && settings.fullWidthLayout,
|
||||||
'is-public': isSharedMode,
|
'is-public': isSharedMode,
|
||||||
})}
|
})}
|
||||||
style={
|
style={
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
registerAffineUpdatesCommands,
|
registerAffineUpdatesCommands,
|
||||||
} from '../commands';
|
} from '../commands';
|
||||||
import { usePageHelper } from '../components/blocksuite/block-suite-page-list/utils';
|
import { usePageHelper } from '../components/blocksuite/block-suite-page-list/utils';
|
||||||
|
import { EditorSettingService } from '../modules/editor-settting';
|
||||||
import { CMDKQuickSearchService } from '../modules/quicksearch/services/cmdk';
|
import { CMDKQuickSearchService } from '../modules/quicksearch/services/cmdk';
|
||||||
import { useLanguageHelper } from './affine/use-language-helper';
|
import { useLanguageHelper } from './affine/use-language-helper';
|
||||||
import { useActiveBlocksuiteEditor } from './use-block-suite-editor';
|
import { useActiveBlocksuiteEditor } from './use-block-suite-editor';
|
||||||
@@ -67,6 +68,7 @@ export function useRegisterWorkspaceCommands() {
|
|||||||
const navigationHelper = useNavigateHelper();
|
const navigationHelper = useNavigateHelper();
|
||||||
const [editor] = useActiveBlocksuiteEditor();
|
const [editor] = useActiveBlocksuiteEditor();
|
||||||
const cmdkQuickSearchService = useService(CMDKQuickSearchService);
|
const cmdkQuickSearchService = useService(CMDKQuickSearchService);
|
||||||
|
const editorSettingService = useService(EditorSettingService);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsub = registerCMDKCommand(cmdkQuickSearchService, editor);
|
const unsub = registerCMDKCommand(cmdkQuickSearchService, editor);
|
||||||
@@ -109,13 +111,13 @@ export function useRegisterWorkspaceCommands() {
|
|||||||
t,
|
t,
|
||||||
theme,
|
theme,
|
||||||
languageHelper,
|
languageHelper,
|
||||||
editor,
|
editorSettingService,
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsub();
|
unsub();
|
||||||
};
|
};
|
||||||
}, [store, t, theme, languageHelper, editor]);
|
}, [editorSettingService, languageHelper, store, t, theme]);
|
||||||
|
|
||||||
// register AffineLayoutCommands
|
// register AffineLayoutCommands
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import { EditorSetting } from './entities/editor-setting';
|
|||||||
import { GlobalStateEditorSettingProvider } from './impls/global-state';
|
import { GlobalStateEditorSettingProvider } from './impls/global-state';
|
||||||
import { EditorSettingProvider } from './provider/editor-setting-provider';
|
import { EditorSettingProvider } from './provider/editor-setting-provider';
|
||||||
import { EditorSettingService } from './services/editor-setting';
|
import { EditorSettingService } from './services/editor-setting';
|
||||||
|
export type { FontFamily } from './schema';
|
||||||
|
export { EditorSettingSchema, fontStyleOptions } from './schema';
|
||||||
|
export { EditorSettingService } from './services/editor-setting';
|
||||||
|
|
||||||
export function configureEditorSettingModule(framework: Framework) {
|
export function configureEditorSettingModule(framework: Framework) {
|
||||||
framework
|
framework
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export type FontFamily = 'Sans' | 'Serif' | 'Mono' | 'Custom';
|
||||||
|
|
||||||
|
export const fontStyleOptions = [
|
||||||
|
{ key: 'Sans', value: 'var(--affine-font-sans-family)' },
|
||||||
|
{ key: 'Serif', value: 'var(--affine-font-serif-family)' },
|
||||||
|
{ key: 'Mono', value: 'var(--affine-font-mono-family)' },
|
||||||
|
{ key: 'Custom', value: 'var(--affine-font-sans-family)' },
|
||||||
|
] satisfies {
|
||||||
|
key: FontFamily;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
|
||||||
const BSEditorSettingSchema = z.object({
|
const BSEditorSettingSchema = z.object({
|
||||||
// TODO: import from bs
|
// TODO: import from bs
|
||||||
connector: z.object({
|
connector: z.object({
|
||||||
@@ -14,9 +26,14 @@ const BSEditorSettingSchema = z.object({
|
|||||||
.default('#000000'),
|
.default('#000000'),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const AffineEditorSettingSchema = z.object({
|
const AffineEditorSettingSchema = z.object({
|
||||||
fontFamily: z.enum(['Sans', 'Serif', 'Mono', 'Custom']).default('Sans'),
|
fontFamily: z.enum(['Sans', 'Serif', 'Mono', 'Custom']).default('Sans'),
|
||||||
|
customFontFamily: z.string().default(''),
|
||||||
|
newDocDefaultMode: z.enum(['edgeless', 'page']).default('page'),
|
||||||
|
spellCheck: z.boolean().default(false),
|
||||||
|
fullWidthLayout: z.boolean().default(false),
|
||||||
|
displayDocInfo: z.boolean().default(true),
|
||||||
|
displayBiDirectionalLink: z.boolean().default(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (
|
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
|
||||||
import * as Dialog from '@radix-ui/react-dialog';
|
import * as Dialog from '@radix-ui/react-dialog';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import anime, { type AnimeInstance, type AnimeParams } from 'animejs';
|
import anime, { type AnimeInstance, type AnimeParams } from 'animejs';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
|
import { EditorSettingService } from '../../editor-settting';
|
||||||
import type { PeekViewAnimation } from '../entities/peek-view';
|
import type { PeekViewAnimation } from '../entities/peek-view';
|
||||||
import * as styles from './modal-container.css';
|
import * as styles from './modal-container.css';
|
||||||
|
|
||||||
@@ -90,7 +91,8 @@ export const PeekViewModalContainer = forwardRef<
|
|||||||
const overlayRef = useRef<HTMLDivElement>(null);
|
const overlayRef = useRef<HTMLDivElement>(null);
|
||||||
const controlsRef = useRef<HTMLDivElement>(null);
|
const controlsRef = useRef<HTMLDivElement>(null);
|
||||||
const prevAnimeMap = useRef<Record<string, AnimeInstance | undefined>>({});
|
const prevAnimeMap = useRef<Record<string, AnimeInstance | undefined>>({});
|
||||||
const { appSettings } = useAppSettingHelper();
|
const editorSettings = useService(EditorSettingService).editorSetting;
|
||||||
|
const settings = useLiveData(editorSettings.settings$);
|
||||||
|
|
||||||
const animateControls = useCallback((animateIn = false) => {
|
const animateControls = useCallback((animateIn = false) => {
|
||||||
const controls = controlsRef.current;
|
const controls = controlsRef.current;
|
||||||
@@ -320,7 +322,7 @@ export const PeekViewModalContainer = forwardRef<
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-anime-state={animeState}
|
data-anime-state={animeState}
|
||||||
data-full-width-layout={appSettings.fullWidthLayout}
|
data-full-width-layout={settings.fullWidthLayout}
|
||||||
ref={contentClipRef}
|
ref={contentClipRef}
|
||||||
className={styles.modalContentContainer}
|
className={styles.modalContentContainer}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
confirmExperimentalPrompt,
|
confirmExperimentalPrompt,
|
||||||
openAboutPanel,
|
openAboutPanel,
|
||||||
openAppearancePanel,
|
openAppearancePanel,
|
||||||
|
openEditorSetting,
|
||||||
openExperimentalFeaturesPanel,
|
openExperimentalFeaturesPanel,
|
||||||
openSettingModal,
|
openSettingModal,
|
||||||
openShortcutsPanel,
|
openShortcutsPanel,
|
||||||
@@ -61,8 +62,7 @@ test('Change theme', async ({ page }) => {
|
|||||||
test('Change layout width', async ({ page }) => {
|
test('Change layout width', async ({ page }) => {
|
||||||
await openHomePage(page);
|
await openHomePage(page);
|
||||||
await waitForEditorLoad(page);
|
await waitForEditorLoad(page);
|
||||||
await openSettingModal(page);
|
await openEditorSetting(page);
|
||||||
await openAppearancePanel(page);
|
|
||||||
|
|
||||||
await page.getByTestId('full-width-layout-trigger').click();
|
await page.getByTestId('full-width-layout-trigger').click();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ export async function openAppearancePanel(page: Page) {
|
|||||||
await page.getByTestId('appearance-panel-trigger').click();
|
await page.getByTestId('appearance-panel-trigger').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function openEditorSetting(page: Page) {
|
||||||
|
await page.getByTestId('settings-modal-trigger').click();
|
||||||
|
await page.getByTestId('editor-panel-trigger').click();
|
||||||
|
}
|
||||||
|
|
||||||
export async function openShortcutsPanel(page: Page) {
|
export async function openShortcutsPanel(page: Page) {
|
||||||
await page.getByTestId('shortcuts-panel-trigger').click();
|
await page.getByTestId('shortcuts-panel-trigger').click();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user