diff --git a/packages/backend/src/repositories/appearance.repository.ts b/packages/backend/src/repositories/appearance.repository.ts index 1204c55..b64f243 100644 --- a/packages/backend/src/repositories/appearance.repository.ts +++ b/packages/backend/src/repositories/appearance.repository.ts @@ -58,6 +58,9 @@ const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): Appearanc settings.terminalBackgroundOverlayOpacity = parseFloat(row.value); terminalBackgroundOverlayOpacityFound = true; break; + case 'editorFontFamily': + settings.editorFontFamily = row.value || null; // 如果为空字符串,则视为 null + break; } } @@ -69,6 +72,7 @@ const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): Appearanc terminalFontFamily: settings.terminalFontFamily ?? defaults.terminalFontFamily, terminalFontSize: settings.terminalFontSize ?? defaults.terminalFontSize, editorFontSize: settings.editorFontSize ?? defaults.editorFontSize, + editorFontFamily: settings.editorFontFamily ?? defaults.editorFontFamily, terminalBackgroundImage: settings.terminalBackgroundImage ?? defaults.terminalBackgroundImage, pageBackgroundImage: settings.pageBackgroundImage ?? defaults.pageBackgroundImage, // 修改:只有当数据库中未找到记录时才使用默认值 @@ -91,6 +95,7 @@ const getDefaultAppearanceSettings = (): Omit => { terminalFontFamily: 'Consolas, "Courier New", monospace, "Microsoft YaHei", "微软雅黑"', terminalFontSize: 14, editorFontSize: 14, + editorFontFamily: 'Consolas, "Noto Sans SC", "Microsoft YaHei"', terminalBackgroundImage: undefined, pageBackgroundImage: undefined, terminalBackgroundEnabled: true, // 默认启用 @@ -117,6 +122,7 @@ export const ensureDefaultSettingsExist = async (db: sqlite3.Database): Promise< { key: 'terminalFontFamily', value: defaults.terminalFontFamily }, { key: 'terminalFontSize', value: defaults.terminalFontSize }, { key: 'editorFontSize', value: defaults.editorFontSize }, + { key: 'editorFontFamily', value: defaults.editorFontFamily }, { key: 'terminalBackgroundImage', value: defaults.terminalBackgroundImage ?? '' }, // 数据库中使用空字符串 { key: 'pageBackgroundImage', value: defaults.pageBackgroundImage ?? '' }, // 数据库中使用空字符串 { key: 'terminalBackgroundEnabled', value: defaults.terminalBackgroundEnabled }, diff --git a/packages/backend/src/services/appearance.service.ts b/packages/backend/src/services/appearance.service.ts index bfb602f..a56279c 100644 --- a/packages/backend/src/services/appearance.service.ts +++ b/packages/backend/src/services/appearance.service.ts @@ -69,6 +69,28 @@ export const updateSettings = async (settingsDto: UpdateAppearanceDto): Promise< settingsDto.editorFontSize = size; } + // 验证 editorFontFamily (如果提供了) + if (settingsDto.hasOwnProperty('editorFontFamily')) { + if (settingsDto.editorFontFamily === null) { + // 允许用户将字体设置为空 (null),表示重置或使用默认 + // 无需额外操作,仓库层会处理 null + } else if (typeof settingsDto.editorFontFamily === 'string') { + const fontFamily = settingsDto.editorFontFamily; + // 校验字体名称格式和长度 + if (fontFamily.length > 255) { + throw new Error('编辑器字体名称过长,最多允许 255 个字符。'); + } + + if (fontFamily.trim() === '' && fontFamily !== '') { + + } + + } else { + // 如果提供了 editorFontFamily 但不是 string 或 null + throw new Error('无效的编辑器字体名称类型,应为字符串或 null。'); + } + } + // 验证 terminalBackgroundOverlayOpacity (如果提供了) if (settingsDto.terminalBackgroundOverlayOpacity !== undefined && settingsDto.terminalBackgroundOverlayOpacity !== null) { const opacity = Number(settingsDto.terminalBackgroundOverlayOpacity); diff --git a/packages/backend/src/types/appearance.types.ts b/packages/backend/src/types/appearance.types.ts index d568f99..7c42984 100644 --- a/packages/backend/src/types/appearance.types.ts +++ b/packages/backend/src/types/appearance.types.ts @@ -16,6 +16,7 @@ export interface AppearanceSettings { terminalBackgroundImage?: string; // 终端背景图片 URL 或路径 pageBackgroundImage?: string; // 页面背景图片 URL 或路径 editorFontSize?: number; // 编辑器字体大小 (px) + editorFontFamily?: string | null; // Monaco Editor 字体偏好 terminalBackgroundEnabled?: boolean; // 终端背景是否启用 terminalBackgroundOverlayOpacity?: number; // 终端背景蒙版透明度 (0-1) updatedAt?: number; diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 59fb96e..26ba305 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@nexus-terminal/frontend", - "version": "0.7", + "version": "0.7.1", "private": true, "type": "module", "scripts": { diff --git a/packages/frontend/src/components/FileEditorContainer.vue b/packages/frontend/src/components/FileEditorContainer.vue index ab32d1d..5f5f3db 100644 --- a/packages/frontend/src/components/FileEditorContainer.vue +++ b/packages/frontend/src/components/FileEditorContainer.vue @@ -5,18 +5,21 @@ import MonacoEditor from './MonacoEditor.vue'; import FileEditorTabs from './FileEditorTabs.vue'; import type { FileTab } from '../stores/fileEditor.store'; import { useFocusSwitcherStore } from '../stores/focusSwitcher.store'; -import { useSessionStore } from '../stores/session.store'; -import { useSettingsStore } from '../stores/settings.store'; -import { storeToRefs } from 'pinia'; -import { useWorkspaceEventEmitter } from '../composables/workspaceEvents'; +import { useSessionStore } from '../stores/session.store'; +import { useSettingsStore } from '../stores/settings.store'; +import { useAppearanceStore } from '../stores/appearance.store'; // +++ 导入外观 Store +++ +import { storeToRefs } from 'pinia'; +import { useWorkspaceEventEmitter } from '../composables/workspaceEvents'; const { t } = useI18n(); const emitWorkspaceEvent = useWorkspaceEventEmitter(); // +++ 获取事件发射器 +++ const focusSwitcherStore = useFocusSwitcherStore(); // +++ 实例化焦点切换 Store +++ const sessionStore = useSessionStore(); // +++ 实例化会话 Store +++ const settingsStore = useSettingsStore(); // +++ 实例化设置 Store +++ +const appearanceStore = useAppearanceStore(); // +++ 实例化外观 Store +++ const { shareFileEditorTabsBoolean } = storeToRefs(settingsStore); // +++ 获取共享设置 +++ - +const { currentEditorFontFamily } = storeToRefs(appearanceStore); // +++ 获取编辑器字体家族设置 +++ + // --- Props --- const props = defineProps({ tabs: { @@ -344,16 +347,17 @@ const handleKeyDown = (event: KeyboardEvent) => { v-else-if="activeTab" ref="monacoEditorRef" :key="activeTab.id" - v-model="localEditorContent" + v-model="localEditorContent" :language="currentTabLanguage" + :font-family="currentEditorFontFamily" theme="vs-dark" class="editor-instance" @request-save="handleSaveRequest" :initialScrollTop="activeTab?.scrollTop ?? 0" :initialScrollLeft="activeTab?.scrollLeft ?? 0" @update:scrollPosition="handleEditorScroll" - /> -
{{ t('fileManager.selectFileToEdit') }}
+ /> +
{{ t('fileManager.selectFileToEdit') }}
diff --git a/packages/frontend/src/components/MonacoEditor.vue b/packages/frontend/src/components/MonacoEditor.vue index 78fc986..60494d8 100644 --- a/packages/frontend/src/components/MonacoEditor.vue +++ b/packages/frontend/src/components/MonacoEditor.vue @@ -25,17 +25,21 @@ const props = defineProps({ type: Boolean, default: false, }, - initialScrollTop: { // 新增 prop + fontFamily: { + type: String, + default: 'Consolas, "Courier New", monospace', + }, + initialScrollTop: { type: Number, default: 0, }, - initialScrollLeft: { // 新增 prop + initialScrollLeft: { type: Number, default: 0, }, }); -const emit = defineEmits(['update:modelValue', 'request-save', 'update:scrollPosition']); // 新增 emit +const emit = defineEmits(['update:modelValue', 'request-save', 'update:scrollPosition']); const editorContainer = ref(null); let editorInstance: monaco.editor.IStandaloneCodeEditor | null = null; @@ -48,7 +52,8 @@ onMounted(() => { value: props.modelValue, language: props.language, theme: props.theme, - fontSize: localFontSize.value, + fontSize: localFontSize.value, + fontFamily: props.fontFamily, // 使用 prop 的字体家族 automaticLayout: true, readOnly: props.readOnly, minimap: { enabled: true }, @@ -211,6 +216,12 @@ watch(() => props.readOnly, (newReadOnly) => { } }); +watch(() => props.fontFamily, (newFontFamily) => { + if (editorInstance) { + editorInstance.updateOptions({ fontFamily: newFontFamily }); + } +}); + // --- 移除对全局字体大小的监听 --- onBeforeUnmount(() => { diff --git a/packages/frontend/src/components/StyleCustomizer.vue b/packages/frontend/src/components/StyleCustomizer.vue index a0abecb..6bca272 100644 --- a/packages/frontend/src/components/StyleCustomizer.vue +++ b/packages/frontend/src/components/StyleCustomizer.vue @@ -1,7 +1,8 @@