mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-06 03:49:56 +08:00
@@ -10,7 +10,10 @@ import {
|
|||||||
DesktopApiService,
|
DesktopApiService,
|
||||||
} from '@affine/core/modules/desktop-api';
|
} from '@affine/core/modules/desktop-api';
|
||||||
import { GlobalDialogService } from '@affine/core/modules/dialogs';
|
import { GlobalDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { EditorSettingService } from '@affine/core/modules/editor-setting';
|
import {
|
||||||
|
configureSpellCheckSettingModule,
|
||||||
|
EditorSettingService,
|
||||||
|
} from '@affine/core/modules/editor-setting';
|
||||||
import { configureFindInPageModule } from '@affine/core/modules/find-in-page';
|
import { configureFindInPageModule } from '@affine/core/modules/find-in-page';
|
||||||
import { I18nProvider } from '@affine/core/modules/i18n';
|
import { I18nProvider } from '@affine/core/modules/i18n';
|
||||||
import { configureElectronStateStorageImpls } from '@affine/core/modules/storage';
|
import { configureElectronStateStorageImpls } from '@affine/core/modules/storage';
|
||||||
@@ -78,6 +81,7 @@ configureDesktopWorkbenchModule(framework);
|
|||||||
configureAppTabsHeaderModule(framework);
|
configureAppTabsHeaderModule(framework);
|
||||||
configureFindInPageModule(framework);
|
configureFindInPageModule(framework);
|
||||||
configureDesktopApiModule(framework);
|
configureDesktopApiModule(framework);
|
||||||
|
configureSpellCheckSettingModule(framework);
|
||||||
|
|
||||||
framework.impl(PopupWindowProvider, p => {
|
framework.impl(PopupWindowProvider, p => {
|
||||||
const apis = p.get(DesktopApiService).api;
|
const apis = p.get(DesktopApiService).api;
|
||||||
|
|||||||
+8
@@ -43,3 +43,11 @@ export type TabViewsMetaSchema = z.infer<typeof tabViewsMetaSchema>;
|
|||||||
export type WorkbenchMeta = z.infer<typeof workbenchMetaSchema>;
|
export type WorkbenchMeta = z.infer<typeof workbenchMetaSchema>;
|
||||||
export type WorkbenchViewMeta = z.infer<typeof workbenchViewMetaSchema>;
|
export type WorkbenchViewMeta = z.infer<typeof workbenchViewMetaSchema>;
|
||||||
export type WorkbenchViewModule = z.infer<typeof workbenchViewIconNameSchema>;
|
export type WorkbenchViewModule = z.infer<typeof workbenchViewIconNameSchema>;
|
||||||
|
|
||||||
|
export const SpellCheckStateSchema = z.object({
|
||||||
|
enabled: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SpellCheckStateKey = 'spellCheckState';
|
||||||
|
export type SpellCheckStateKey = typeof SpellCheckStateKey;
|
||||||
|
export type SpellCheckStateSchema = z.infer<typeof SpellCheckStateSchema>;
|
||||||
@@ -3,6 +3,7 @@ import { getLinkPreview } from 'link-preview-js';
|
|||||||
|
|
||||||
import { persistentConfig } from '../config-storage/persist';
|
import { persistentConfig } from '../config-storage/persist';
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
|
import type { WorkbenchViewMeta } from '../shared-state-schema';
|
||||||
import type { NamespaceHandlers } from '../type';
|
import type { NamespaceHandlers } from '../type';
|
||||||
import {
|
import {
|
||||||
activateView,
|
activateView,
|
||||||
@@ -27,7 +28,6 @@ import {
|
|||||||
} from '../windows-manager';
|
} from '../windows-manager';
|
||||||
import { showTabContextMenu } from '../windows-manager/context-menu';
|
import { showTabContextMenu } from '../windows-manager/context-menu';
|
||||||
import { getOrCreateCustomThemeWindow } from '../windows-manager/custom-theme-window';
|
import { getOrCreateCustomThemeWindow } from '../windows-manager/custom-theme-window';
|
||||||
import type { WorkbenchViewMeta } from '../windows-manager/tab-views-meta-schema';
|
|
||||||
import { getChallengeResponse } from './challenge';
|
import { getChallengeResponse } from './challenge';
|
||||||
import { uiSubjects } from './subject';
|
import { uiSubjects } from './subject';
|
||||||
|
|
||||||
@@ -216,4 +216,8 @@ export const uiHandlers = {
|
|||||||
win.show();
|
win.show();
|
||||||
win.focus();
|
win.focus();
|
||||||
},
|
},
|
||||||
|
restartApp: async () => {
|
||||||
|
app.relaunch();
|
||||||
|
app.quit();
|
||||||
|
},
|
||||||
} satisfies NamespaceHandlers;
|
} satisfies NamespaceHandlers;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { join } from 'node:path';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
app,
|
app,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
session,
|
session,
|
||||||
type View,
|
type View,
|
||||||
type WebContents,
|
type WebContents,
|
||||||
@@ -26,16 +28,18 @@ import { CLOUD_BASE_URL, isDev } from '../config';
|
|||||||
import { mainWindowOrigin, shellViewUrl } from '../constants';
|
import { mainWindowOrigin, shellViewUrl } from '../constants';
|
||||||
import { ensureHelperProcess } from '../helper-process';
|
import { ensureHelperProcess } from '../helper-process';
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { globalStateStorage } from '../shared-storage/storage';
|
|
||||||
import { getCustomThemeWindow } from './custom-theme-window';
|
|
||||||
import { getMainWindow, MainWindowManager } from './main-window';
|
|
||||||
import {
|
import {
|
||||||
|
SpellCheckStateKey,
|
||||||
|
SpellCheckStateSchema,
|
||||||
TabViewsMetaKey,
|
TabViewsMetaKey,
|
||||||
type TabViewsMetaSchema,
|
type TabViewsMetaSchema,
|
||||||
tabViewsMetaSchema,
|
tabViewsMetaSchema,
|
||||||
type WorkbenchMeta,
|
type WorkbenchMeta,
|
||||||
type WorkbenchViewMeta,
|
type WorkbenchViewMeta,
|
||||||
} from './tab-views-meta-schema';
|
} from '../shared-state-schema';
|
||||||
|
import { globalStateStorage } from '../shared-storage/storage';
|
||||||
|
import { getCustomThemeWindow } from './custom-theme-window';
|
||||||
|
import { getMainWindow, MainWindowManager } from './main-window';
|
||||||
|
|
||||||
async function getAdditionalArguments() {
|
async function getAdditionalArguments() {
|
||||||
const { getExposedMeta } = await import('../exposed');
|
const { getExposedMeta } = await import('../exposed');
|
||||||
@@ -74,6 +78,10 @@ const TabViewsMetaState = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const spellCheckSettings = SpellCheckStateSchema.parse(
|
||||||
|
globalStateStorage.get(SpellCheckStateKey) ?? {}
|
||||||
|
);
|
||||||
|
|
||||||
type AddTabAction = {
|
type AddTabAction = {
|
||||||
type: 'add-tab';
|
type: 'add-tab';
|
||||||
payload: WorkbenchMeta;
|
payload: WorkbenchMeta;
|
||||||
@@ -816,13 +824,44 @@ export class WebContentViewsManager {
|
|||||||
transparent: true,
|
transparent: true,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
spellcheck: false, // TODO(@pengx17): enable?
|
spellcheck: spellCheckSettings.enabled,
|
||||||
preload: join(__dirname, './preload.js'), // this points to the bundled preload module
|
preload: join(__dirname, './preload.js'), // this points to the bundled preload module
|
||||||
// serialize exposed meta that to be used in preload
|
// serialize exposed meta that to be used in preload
|
||||||
additionalArguments: additionalArguments,
|
additionalArguments: additionalArguments,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (spellCheckSettings.enabled) {
|
||||||
|
view.webContents.on('context-menu', (_event, params) => {
|
||||||
|
const menu = new Menu();
|
||||||
|
|
||||||
|
// Add each spelling suggestion
|
||||||
|
for (const suggestion of params.dictionarySuggestions) {
|
||||||
|
menu.append(
|
||||||
|
new MenuItem({
|
||||||
|
label: suggestion,
|
||||||
|
click: () => view.webContents.replaceMisspelling(suggestion),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow users to add the misspelled word to the dictionary
|
||||||
|
if (params.misspelledWord) {
|
||||||
|
menu.append(
|
||||||
|
new MenuItem({
|
||||||
|
label: 'Add to dictionary', // TODO: i18n
|
||||||
|
click: () =>
|
||||||
|
view.webContents.session.addWordToSpellCheckerDictionary(
|
||||||
|
params.misspelledWord
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.popup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.webViewsMap$.next(this.tabViewsMap.set(viewId, view));
|
this.webViewsMap$.next(this.tabViewsMap.set(viewId, view));
|
||||||
let unsub = () => {};
|
let unsub = () => {};
|
||||||
|
|
||||||
|
|||||||
+59
-53
@@ -15,22 +15,26 @@ import {
|
|||||||
SettingRow,
|
SettingRow,
|
||||||
SettingWrapper,
|
SettingWrapper,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
|
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||||
import { ServerConfigService } from '@affine/core/modules/cloud';
|
import { ServerConfigService } from '@affine/core/modules/cloud';
|
||||||
|
import { DesktopApiService } from '@affine/core/modules/desktop-api';
|
||||||
import {
|
import {
|
||||||
EditorSettingService,
|
EditorSettingService,
|
||||||
type FontFamily,
|
type FontFamily,
|
||||||
fontStyleOptions,
|
fontStyleOptions,
|
||||||
} from '@affine/core/modules/editor-setting';
|
} from '@affine/core/modules/editor-setting';
|
||||||
|
import { SpellCheckSettingService } from '@affine/core/modules/editor-setting/services/spell-check-setting';
|
||||||
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 { Trans, useI18n } from '@affine/i18n';
|
||||||
import type { DocMode } from '@blocksuite/affine/blocks';
|
import type { DocMode } from '@blocksuite/affine/blocks';
|
||||||
import { DoneIcon, SearchIcon } from '@blocksuite/icons/rc';
|
import { DoneIcon, SearchIcon } from '@blocksuite/icons/rc';
|
||||||
import {
|
import {
|
||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
useLiveData,
|
useLiveData,
|
||||||
|
useService,
|
||||||
useServices,
|
useServices,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
@@ -41,10 +45,10 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
|
|
||||||
import { DropdownMenu } from './menu';
|
|
||||||
import * as styles from './style.css';
|
import * as styles from './style.css';
|
||||||
|
|
||||||
const getLabel = (fontKey: FontFamily, t: ReturnType<typeof useI18n>) => {
|
const getLabel = (fontKey: FontFamily, t: ReturnType<typeof useI18n>) => {
|
||||||
@@ -351,55 +355,6 @@ const NewDocDefaultModeSettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DeFaultCodeBlockSettings = () => {
|
|
||||||
const t = useI18n();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<SettingRow
|
|
||||||
name={t[
|
|
||||||
'com.affine.settings.editorSettings.general.default-code-block.language.title'
|
|
||||||
]()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.settings.editorSettings.general.default-code-block.language.description'
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<DropdownMenu
|
|
||||||
items={<MenuItem>Plain Text</MenuItem>}
|
|
||||||
trigger={
|
|
||||||
<MenuTrigger className={styles.menuTrigger} disabled>
|
|
||||||
Plain Text
|
|
||||||
</MenuTrigger>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingRow>
|
|
||||||
<SettingRow
|
|
||||||
name={t[
|
|
||||||
'com.affine.settings.editorSettings.general.default-code-block.wrap.title'
|
|
||||||
]()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.settings.editorSettings.general.default-code-block.wrap.description'
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</SettingRow>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SpellCheckSettings = () => {
|
|
||||||
const t = useI18n();
|
|
||||||
return (
|
|
||||||
<SettingRow
|
|
||||||
name={t['com.affine.settings.editorSettings.general.spell-check.title']()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.settings.editorSettings.general.spell-check.description'
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</SettingRow>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const AISettings = () => {
|
const AISettings = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
@@ -460,6 +415,56 @@ const AISettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SpellCheckSettings = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
const spellCheckSetting = useService(SpellCheckSettingService);
|
||||||
|
|
||||||
|
const desktopApiService = useService(DesktopApiService);
|
||||||
|
|
||||||
|
const enabled = useLiveData(spellCheckSetting.enabled$)?.enabled;
|
||||||
|
|
||||||
|
const [requireRestart, setRequireRestart] = useState(false);
|
||||||
|
|
||||||
|
const onToggleSpellCheck = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
spellCheckSetting.setEnabled(checked);
|
||||||
|
setRequireRestart(true);
|
||||||
|
},
|
||||||
|
[spellCheckSetting]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onRestart = useAsyncCallback(async () => {
|
||||||
|
await desktopApiService.handler.ui.restartApp();
|
||||||
|
}, [desktopApiService]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingRow
|
||||||
|
name={t['com.affine.settings.editorSettings.general.spell-check.title']()}
|
||||||
|
desc={
|
||||||
|
requireRestart ? (
|
||||||
|
<div className={styles.spellCheckSettingDescription}>
|
||||||
|
<Trans i18nKey="com.affine.settings.editorSettings.general.spell-check.restart-hint">
|
||||||
|
Settings changed; please restart the app.
|
||||||
|
<button
|
||||||
|
onClick={onRestart}
|
||||||
|
className={styles.spellCheckSettingDescriptionButton}
|
||||||
|
>
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
</Trans>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
t[
|
||||||
|
'com.affine.settings.editorSettings.general.spell-check.description'
|
||||||
|
]()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Switch checked={enabled} onChange={onToggleSpellCheck} />
|
||||||
|
</SettingRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const General = () => {
|
export const General = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
@@ -469,9 +474,10 @@ export const General = () => {
|
|||||||
<FontFamilySettings />
|
<FontFamilySettings />
|
||||||
<CustomFontFamilySettings />
|
<CustomFontFamilySettings />
|
||||||
<NewDocDefaultModeSettings />
|
<NewDocDefaultModeSettings />
|
||||||
|
{BUILD_CONFIG.isElectron && <SpellCheckSettings />}
|
||||||
{/* // TODO(@akumatus): implement these settings
|
{/* // TODO(@akumatus): implement these settings
|
||||||
<DeFaultCodeBlockSettings />
|
<DeFaultCodeBlockSettings />
|
||||||
<SpellCheckSettings /> */}
|
*/}
|
||||||
</SettingWrapper>
|
</SettingWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -154,3 +154,12 @@ export const notFound = style({
|
|||||||
fontSize: cssVar('fontXs'),
|
fontSize: cssVar('fontXs'),
|
||||||
padding: '4px',
|
padding: '4px',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const spellCheckSettingDescription = style({
|
||||||
|
color: cssVarV2('toast/iconState/error'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const spellCheckSettingDescriptionButton = style({
|
||||||
|
color: cssVarV2('text/link'),
|
||||||
|
fontSize: 'inherit',
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type SettingItem<T> = {
|
|||||||
readonly value: T;
|
readonly value: T;
|
||||||
set: (value: T) => void;
|
set: (value: T) => void;
|
||||||
// eslint-disable-next-line rxjs/finnish
|
// eslint-disable-next-line rxjs/finnish
|
||||||
$: T;
|
$: LiveData<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class EditorSetting extends Entity {
|
export class EditorSetting extends Entity {
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import { type Framework, GlobalState } from '@toeverything/infra';
|
import {
|
||||||
|
type Framework,
|
||||||
|
GlobalState,
|
||||||
|
GlobalStateService,
|
||||||
|
} from '@toeverything/infra';
|
||||||
|
|
||||||
import { UserDBService } from '../userspace';
|
import { UserDBService } from '../userspace';
|
||||||
import { EditorSetting } from './entities/editor-setting';
|
import { EditorSetting } from './entities/editor-setting';
|
||||||
import { CurrentUserDBEditorSettingProvider } from './impls/user-db';
|
import { CurrentUserDBEditorSettingProvider } from './impls/user-db';
|
||||||
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';
|
||||||
|
import { SpellCheckSettingService } from './services/spell-check-setting';
|
||||||
export type { FontFamily } from './schema';
|
export type { FontFamily } from './schema';
|
||||||
export { EditorSettingSchema, fontStyleOptions } from './schema';
|
export { EditorSettingSchema, fontStyleOptions } from './schema';
|
||||||
export { EditorSettingService } from './services/editor-setting';
|
export { EditorSettingService } from './services/editor-setting';
|
||||||
@@ -18,3 +23,7 @@ export function configureEditorSettingModule(framework: Framework) {
|
|||||||
GlobalState,
|
GlobalState,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function configureSpellCheckSettingModule(framework: Framework) {
|
||||||
|
framework.service(SpellCheckSettingService, [GlobalStateService]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ 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(''),
|
customFontFamily: z.string().default(''),
|
||||||
newDocDefaultMode: z.enum(['edgeless', 'page']).default('page'),
|
newDocDefaultMode: z.enum(['edgeless', 'page']).default('page'),
|
||||||
spellCheck: z.boolean().default(false),
|
|
||||||
fullWidthLayout: z.boolean().default(false),
|
fullWidthLayout: z.boolean().default(false),
|
||||||
displayDocInfo: z.boolean().default(true),
|
displayDocInfo: z.boolean().default(true),
|
||||||
displayBiDirectionalLink: z.boolean().default(true),
|
displayBiDirectionalLink: z.boolean().default(true),
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import type {
|
||||||
|
SpellCheckStateKey,
|
||||||
|
SpellCheckStateSchema,
|
||||||
|
} from '@affine/electron/main/shared-state-schema';
|
||||||
|
import type { GlobalStateService } from '@toeverything/infra';
|
||||||
|
import { LiveData, Service } from '@toeverything/infra';
|
||||||
|
|
||||||
|
const SPELL_CHECK_SETTING_KEY: SpellCheckStateKey = 'spellCheckState';
|
||||||
|
|
||||||
|
export class SpellCheckSettingService extends Service {
|
||||||
|
constructor(private readonly globalStateService: GlobalStateService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled$ = LiveData.from(
|
||||||
|
this.globalStateService.globalState.watch<
|
||||||
|
SpellCheckStateSchema | undefined
|
||||||
|
>(SPELL_CHECK_SETTING_KEY),
|
||||||
|
{ enabled: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
setEnabled(enabled: boolean) {
|
||||||
|
this.globalStateService.globalState.set(SPELL_CHECK_SETTING_KEY, {
|
||||||
|
enabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,10 +41,11 @@ export const sharedStorage = (globalThis as any).__sharedStorage as
|
|||||||
|
|
||||||
export type { SharedStorage };
|
export type { SharedStorage };
|
||||||
|
|
||||||
export type { UpdateMeta } from '@affine/electron/main/updater/event';
|
|
||||||
export {
|
export {
|
||||||
|
type SpellCheckStateSchema,
|
||||||
type TabViewsMetaSchema,
|
type TabViewsMetaSchema,
|
||||||
type WorkbenchMeta,
|
type WorkbenchMeta,
|
||||||
type WorkbenchViewMeta,
|
type WorkbenchViewMeta,
|
||||||
type WorkbenchViewModule,
|
type WorkbenchViewModule,
|
||||||
} from '@affine/electron/main/windows-manager/tab-views-meta-schema';
|
} from '@affine/electron/main/shared-state-schema';
|
||||||
|
export type { UpdateMeta } from '@affine/electron/main/updater/event';
|
||||||
|
|||||||
@@ -1123,6 +1123,7 @@
|
|||||||
"com.affine.settings.editorSettings.general.font-family.title": "Font family",
|
"com.affine.settings.editorSettings.general.font-family.title": "Font family",
|
||||||
"com.affine.settings.editorSettings.general.spell-check.description": "Automatically detect and correct spelling errors.",
|
"com.affine.settings.editorSettings.general.spell-check.description": "Automatically detect and correct spelling errors.",
|
||||||
"com.affine.settings.editorSettings.general.spell-check.title": "Spell check",
|
"com.affine.settings.editorSettings.general.spell-check.title": "Spell check",
|
||||||
|
"com.affine.settings.editorSettings.general.spell-check.restart-hint": "Settings changed; please restart the app. <1>Restart</1>",
|
||||||
"com.affine.settings.editorSettings.page": "Page",
|
"com.affine.settings.editorSettings.page": "Page",
|
||||||
"com.affine.settings.editorSettings.page.display-bi-link.description": "Display bi-directional links on the doc.",
|
"com.affine.settings.editorSettings.page.display-bi-link.description": "Display bi-directional links on the doc.",
|
||||||
"com.affine.settings.editorSettings.page.display-bi-link.title": "Display bi-directional links",
|
"com.affine.settings.editorSettings.page.display-bi-link.title": "Display bi-directional links",
|
||||||
|
|||||||
Reference in New Issue
Block a user