✨ Add font settings
This commit is contained in:
@@ -253,6 +253,21 @@ export class EditorConfig {
|
||||
*/
|
||||
"fontSize": number;
|
||||
|
||||
/**
|
||||
* 字体族
|
||||
*/
|
||||
"fontFamily": string;
|
||||
|
||||
/**
|
||||
* 字体粗细
|
||||
*/
|
||||
"fontWeight": string;
|
||||
|
||||
/**
|
||||
* 行高
|
||||
*/
|
||||
"lineHeight": number;
|
||||
|
||||
/**
|
||||
* 是否启用Tab缩进
|
||||
*/
|
||||
@@ -283,6 +298,15 @@ export class EditorConfig {
|
||||
if (!("fontSize" in $$source)) {
|
||||
this["fontSize"] = 0;
|
||||
}
|
||||
if (!("fontFamily" in $$source)) {
|
||||
this["fontFamily"] = "";
|
||||
}
|
||||
if (!("fontWeight" in $$source)) {
|
||||
this["fontWeight"] = "";
|
||||
}
|
||||
if (!("lineHeight" in $$source)) {
|
||||
this["lineHeight"] = 0;
|
||||
}
|
||||
if (!("enableTabIndent" in $$source)) {
|
||||
this["enableTabIndent"] = false;
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
146
frontend/src/assets/styles/fonts.css
Normal file
146
frontend/src/assets/styles/fonts.css
Normal file
@@ -0,0 +1,146 @@
|
||||
/* HarmonyOS Sans 字体定义 */
|
||||
|
||||
/* HarmonyOS Sans Regular */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Light */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Light.ttf') format('truetype');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Medium */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Medium.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Semibold */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Bold */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Black */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Black.ttf') format('truetype');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans Thin */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Thin.ttf') format('truetype');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC 简体中文字体 */
|
||||
|
||||
/* HarmonyOS Sans SC Regular */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Light */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Light.ttf') format('truetype');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Medium */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Medium.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Semibold */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Bold */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Black */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Black.ttf') format('truetype');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* HarmonyOS Sans SC Thin */
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS Sans SC';
|
||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Thin.ttf') format('truetype');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* 字体加载优化 */
|
||||
.font-loading {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
.font-loaded {
|
||||
font-family: 'HarmonyOS Sans SC', 'HarmonyOS Sans', 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* CodeMirror 专用字体类 */
|
||||
.cm-harmonyos-font {
|
||||
font-family: 'HarmonyOS Sans SC', 'HarmonyOS Sans', 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif !important;
|
||||
font-feature-settings: 'liga' 1, 'calt' 1;
|
||||
font-variant-ligatures: contextual;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
/* 导入所有CSS文件 */
|
||||
@import 'normalize.css';
|
||||
@import 'variables.css';
|
||||
@import 'variables.css';
|
||||
@import "fonts.css";
|
@@ -15,6 +15,8 @@ import {
|
||||
updateTabConfig,
|
||||
createAutoSavePlugin,
|
||||
createSaveShortcutPlugin,
|
||||
createFontExtensionFromBackend,
|
||||
updateFontConfig,
|
||||
} from './extensions';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { DocumentService } from '@/../bindings/voidraft/internal/services';
|
||||
@@ -56,6 +58,14 @@ const createEditor = async () => {
|
||||
configStore.config.tabType
|
||||
);
|
||||
|
||||
// 创建字体扩展
|
||||
const fontExtension = createFontExtensionFromBackend({
|
||||
fontFamily: configStore.config.fontFamily,
|
||||
fontSize: configStore.config.fontSize,
|
||||
lineHeight: configStore.config.lineHeight,
|
||||
fontWeight: configStore.config.fontWeight
|
||||
});
|
||||
|
||||
// 创建统计信息更新扩展
|
||||
const statsExtension = createStatsUpdateExtension(
|
||||
editorStore.updateDocumentStats
|
||||
@@ -82,6 +92,7 @@ const createEditor = async () => {
|
||||
const extensions: Extension[] = [
|
||||
...basicExtensions,
|
||||
...tabExtensions,
|
||||
fontExtension,
|
||||
statsExtension,
|
||||
saveShortcutPlugin,
|
||||
autoSavePlugin
|
||||
@@ -143,6 +154,17 @@ const reconfigureTabSettings = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// 重新配置字体设置
|
||||
const reconfigureFontSettings = () => {
|
||||
if (!editorStore.editorView) return;
|
||||
updateFontConfig(editorStore.editorView as EditorView, {
|
||||
fontFamily: configStore.config.fontFamily,
|
||||
fontSize: configStore.config.fontSize,
|
||||
lineHeight: configStore.config.lineHeight,
|
||||
fontWeight: configStore.config.fontWeight
|
||||
});
|
||||
};
|
||||
|
||||
// 监听Tab设置变化
|
||||
watch(() => configStore.config.tabSize, reconfigureTabSettings);
|
||||
watch(() => configStore.config.enableTabIndent, reconfigureTabSettings);
|
||||
@@ -150,9 +172,19 @@ watch(() => configStore.config.tabType, reconfigureTabSettings);
|
||||
|
||||
// 监听字体大小变化
|
||||
watch(() => configStore.config.fontSize, () => {
|
||||
reconfigureFontSettings();
|
||||
editorStore.applyFontSize();
|
||||
});
|
||||
|
||||
// 监听字体族变化
|
||||
watch(() => configStore.config.fontFamily, reconfigureFontSettings);
|
||||
|
||||
// 监听字体粗细变化
|
||||
watch(() => configStore.config.fontWeight, reconfigureFontSettings);
|
||||
|
||||
// 监听行高变化
|
||||
watch(() => configStore.config.lineHeight, reconfigureFontSettings);
|
||||
|
||||
onMounted(() => {
|
||||
// 创建编辑器
|
||||
createEditor();
|
||||
|
219
frontend/src/editor/extensions/fontExtension.ts
Normal file
219
frontend/src/editor/extensions/fontExtension.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { Extension, Compartment } from '@codemirror/state';
|
||||
|
||||
// 字体配置接口
|
||||
export interface FontConfig {
|
||||
fontFamily: string;
|
||||
fontSize?: number;
|
||||
lineHeight?: number;
|
||||
fontWeight?: string;
|
||||
}
|
||||
|
||||
// 创建字体配置compartment
|
||||
export const fontCompartment = new Compartment();
|
||||
|
||||
// 默认鸿蒙字体配置
|
||||
export const HARMONYOS_FONT_CONFIG: FontConfig = {
|
||||
fontFamily: '"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
};
|
||||
|
||||
// 从后端配置创建字体配置
|
||||
export function createFontConfigFromBackend(backendConfig: {
|
||||
fontFamily?: string;
|
||||
fontSize?: number;
|
||||
lineHeight?: number;
|
||||
fontWeight?: string;
|
||||
}): FontConfig {
|
||||
return {
|
||||
fontFamily: backendConfig.fontFamily || HARMONYOS_FONT_CONFIG.fontFamily,
|
||||
fontSize: backendConfig.fontSize || HARMONYOS_FONT_CONFIG.fontSize,
|
||||
lineHeight: backendConfig.lineHeight || HARMONYOS_FONT_CONFIG.lineHeight,
|
||||
fontWeight: backendConfig.fontWeight || HARMONYOS_FONT_CONFIG.fontWeight,
|
||||
};
|
||||
}
|
||||
|
||||
// 创建字体样式扩展
|
||||
export function createFontExtension(config: Partial<FontConfig> = {}): Extension {
|
||||
const fontConfig = { ...HARMONYOS_FONT_CONFIG, ...config };
|
||||
|
||||
const styles: Record<string, any> = {
|
||||
'&': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
...(fontConfig.fontSize && { fontSize: `${fontConfig.fontSize}px` }),
|
||||
...(fontConfig.lineHeight && { lineHeight: fontConfig.lineHeight.toString() }),
|
||||
...(fontConfig.fontWeight && { fontWeight: fontConfig.fontWeight }),
|
||||
},
|
||||
'.cm-content': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
...(fontConfig.fontSize && { fontSize: `${fontConfig.fontSize}px` }),
|
||||
...(fontConfig.lineHeight && { lineHeight: fontConfig.lineHeight.toString() }),
|
||||
...(fontConfig.fontWeight && { fontWeight: fontConfig.fontWeight }),
|
||||
},
|
||||
'.cm-editor': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
},
|
||||
'.cm-scroller': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
},
|
||||
'.cm-gutters': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
...(fontConfig.fontSize && { fontSize: `${fontConfig.fontSize}px` }),
|
||||
},
|
||||
'.cm-lineNumbers': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
...(fontConfig.fontSize && { fontSize: `${Math.max(10, fontConfig.fontSize - 1)}px` }),
|
||||
},
|
||||
'.cm-tooltip': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
...(fontConfig.fontSize && { fontSize: `${Math.max(12, fontConfig.fontSize - 1)}px` }),
|
||||
},
|
||||
'.cm-completionLabel': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
},
|
||||
'.cm-completionDetail': {
|
||||
fontFamily: fontConfig.fontFamily,
|
||||
}
|
||||
};
|
||||
|
||||
return EditorView.theme(styles);
|
||||
}
|
||||
|
||||
// 创建响应式字体大小扩展
|
||||
export function createResponsiveFontExtension(baseFontSize: number = 14): Extension {
|
||||
return fontCompartment.of(createFontExtension({
|
||||
fontSize: baseFontSize,
|
||||
lineHeight: 1.5
|
||||
}));
|
||||
}
|
||||
|
||||
// 从后端配置创建字体扩展
|
||||
export function createFontExtensionFromBackend(backendConfig: {
|
||||
fontFamily?: string;
|
||||
fontSize?: number;
|
||||
lineHeight?: number;
|
||||
fontWeight?: string;
|
||||
}): Extension {
|
||||
const fontConfig = createFontConfigFromBackend(backendConfig);
|
||||
return fontCompartment.of(createFontExtension(fontConfig));
|
||||
}
|
||||
|
||||
// 动态更新字体配置
|
||||
export function updateFontConfig(view: EditorView, config: Partial<FontConfig>): void {
|
||||
const newFontExtension = createFontExtension(config);
|
||||
|
||||
// 使用compartment重新配置字体扩展
|
||||
view.dispatch({
|
||||
effects: fontCompartment.reconfigure(newFontExtension)
|
||||
});
|
||||
}
|
||||
|
||||
// 预设字体配置
|
||||
export const FONT_PRESETS = {
|
||||
// 鸿蒙字体系列
|
||||
harmonyos: {
|
||||
name: '鸿蒙字体',
|
||||
fontFamily: '"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
harmonyosCondensed: {
|
||||
name: '鸿蒙紧凑字体',
|
||||
fontFamily: '"HarmonyOS Sans Condensed", "HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.4,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
|
||||
// 编程专用字体
|
||||
jetbrainsMono: {
|
||||
name: 'JetBrains Mono',
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
firaCode: {
|
||||
name: 'Fira Code',
|
||||
fontFamily: '"Fira Code", "JetBrains Mono", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
sourceCodePro: {
|
||||
name: 'Source Code Pro',
|
||||
fontFamily: '"Source Code Pro", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
|
||||
// 系统字体
|
||||
systemMono: {
|
||||
name: '系统等宽字体',
|
||||
fontFamily: '"SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
cascadiaCode: {
|
||||
name: 'Cascadia Code',
|
||||
fontFamily: '"Cascadia Code", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
|
||||
// 中文友好字体
|
||||
microsoftYaHei: {
|
||||
name: '微软雅黑',
|
||||
fontFamily: '"Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
pingFang: {
|
||||
name: '苹方字体',
|
||||
fontFamily: '"PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
|
||||
// 经典字体
|
||||
arial: {
|
||||
name: 'Arial',
|
||||
fontFamily: 'Arial, "Helvetica Neue", Helvetica, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
},
|
||||
helvetica: {
|
||||
name: 'Helvetica',
|
||||
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
} as const;
|
||||
|
||||
// 字体预设类型
|
||||
export type FontPresetKey = keyof typeof FONT_PRESETS;
|
||||
|
||||
// 获取所有字体预设选项
|
||||
export function getFontPresetOptions() {
|
||||
return Object.entries(FONT_PRESETS).map(([key, preset]) => ({
|
||||
value: key as FontPresetKey,
|
||||
label: preset.name,
|
||||
fontFamily: preset.fontFamily
|
||||
}));
|
||||
}
|
||||
|
||||
// 根据预设创建字体扩展
|
||||
export function createPresetFontExtension(preset: keyof typeof FONT_PRESETS, overrides: Partial<FontConfig> = {}): Extension {
|
||||
const config = { ...FONT_PRESETS[preset], ...overrides };
|
||||
return createFontExtension(config);
|
||||
}
|
@@ -2,4 +2,5 @@
|
||||
export * from './tabExtension';
|
||||
export * from './wheelZoomExtension';
|
||||
export * from './statsExtension';
|
||||
export * from './autoSaveExtension';
|
||||
export * from './autoSaveExtension';
|
||||
export * from './fontExtension';
|
@@ -66,6 +66,13 @@ export default {
|
||||
selectDirectory: 'Select Directory',
|
||||
fontSize: 'Font Size',
|
||||
fontSizeDescription: 'Editor font size',
|
||||
fontSettings: 'Font Settings',
|
||||
fontPreset: 'Font Preset',
|
||||
fontPresetDescription: 'Choose a predefined font combination',
|
||||
fontWeight: 'Font Weight',
|
||||
fontWeightDescription: 'Set the thickness of the font',
|
||||
lineHeight: 'Line Height',
|
||||
lineHeightDescription: 'Set the spacing between text lines',
|
||||
tabSettings: 'Tab Settings',
|
||||
tabSize: 'Tab Size',
|
||||
tabType: 'Tab Type',
|
||||
|
@@ -66,6 +66,13 @@ export default {
|
||||
selectDirectory: '选择目录',
|
||||
fontSize: '字体大小',
|
||||
fontSizeDescription: '编辑器字体大小',
|
||||
fontSettings: '字体设置',
|
||||
fontPreset: '字体预设',
|
||||
fontPresetDescription: '选择预设的字体组合',
|
||||
fontWeight: '字体粗细',
|
||||
fontWeightDescription: '设置字体的粗细程度',
|
||||
lineHeight: '行高',
|
||||
lineHeightDescription: '设置文本行之间的间距',
|
||||
tabSettings: 'Tab 设置',
|
||||
tabSize: 'Tab 大小',
|
||||
tabType: 'Tab 类型',
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router';
|
||||
import {createRouter, createWebHashHistory, createWebHistory, RouteRecordRaw} from 'vue-router';
|
||||
import Editor from '@/editor/Editor.vue';
|
||||
import Settings from '@/settings/Settings.vue';
|
||||
import GeneralPage from '@/settings/pages/GeneralPage.vue';
|
||||
@@ -49,7 +49,7 @@ const routes: RouteRecordRaw[] = [
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes: routes
|
||||
});
|
||||
|
||||
|
@@ -6,10 +6,54 @@ import SettingSection from '../components/SettingSection.vue';
|
||||
import SettingItem from '../components/SettingItem.vue';
|
||||
import ToggleSwitch from '../components/ToggleSwitch.vue';
|
||||
import { TabType } from '@/../bindings/voidraft/internal/models/models';
|
||||
import { getFontPresetOptions, type FontPresetKey } from '@/editor/extensions/fontExtension';
|
||||
|
||||
const { t } = useI18n();
|
||||
const configStore = useConfigStore();
|
||||
|
||||
// 字体预设选项
|
||||
const fontPresetOptions = getFontPresetOptions();
|
||||
const currentFontPreset = computed(() => configStore.getCurrentFontPreset());
|
||||
|
||||
// 字体预设选择
|
||||
const handleFontPresetChange = (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
const presetKey = target.value;
|
||||
if (presetKey && presetKey !== 'custom') {
|
||||
configStore.setFontPreset(presetKey as FontPresetKey);
|
||||
}
|
||||
};
|
||||
|
||||
// 字体粗细选项
|
||||
const fontWeightOptions = [
|
||||
{ value: '100', label: '极细 (100)' },
|
||||
{ value: '200', label: '超细 (200)' },
|
||||
{ value: '300', label: '细 (300)' },
|
||||
{ value: 'normal', label: '正常 (400)' },
|
||||
{ value: '500', label: '中等 (500)' },
|
||||
{ value: '600', label: '半粗 (600)' },
|
||||
{ value: 'bold', label: '粗体 (700)' },
|
||||
{ value: '800', label: '超粗 (800)' },
|
||||
{ value: '900', label: '极粗 (900)' }
|
||||
];
|
||||
|
||||
// 字体粗细选择
|
||||
const handleFontWeightChange = (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
configStore.setFontWeight(target.value);
|
||||
};
|
||||
|
||||
// 行高控制
|
||||
const increaseLineHeight = () => {
|
||||
const newLineHeight = Math.min(3.0, configStore.config.lineHeight + 0.1);
|
||||
configStore.setLineHeight(Math.round(newLineHeight * 10) / 10);
|
||||
};
|
||||
|
||||
const decreaseLineHeight = () => {
|
||||
const newLineHeight = Math.max(1.0, configStore.config.lineHeight - 0.1);
|
||||
configStore.setLineHeight(Math.round(newLineHeight * 10) / 10);
|
||||
};
|
||||
|
||||
// 字体大小控制
|
||||
const increaseFontSize = () => {
|
||||
configStore.increaseFontSize();
|
||||
@@ -38,7 +82,27 @@ const decreaseTabSize = () => {
|
||||
|
||||
<template>
|
||||
<div class="settings-page">
|
||||
<SettingSection :title="t('settings.fontSize')">
|
||||
<SettingSection :title="t('settings.fontSettings')">
|
||||
<SettingItem
|
||||
:title="t('settings.fontPreset')"
|
||||
:description="t('settings.fontPresetDescription')"
|
||||
>
|
||||
<select
|
||||
class="font-preset-select"
|
||||
:value="currentFontPreset || 'custom'"
|
||||
@change="handleFontPresetChange"
|
||||
>
|
||||
<option value="custom">自定义</option>
|
||||
<option
|
||||
v-for="option in fontPresetOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
:title="t('settings.fontSize')"
|
||||
:description="t('settings.fontSizeDescription')"
|
||||
@@ -49,11 +113,48 @@ const decreaseTabSize = () => {
|
||||
<button @click="increaseFontSize" class="control-button">+</button>
|
||||
</div>
|
||||
</SettingItem>
|
||||
<div class="font-size-preview" :style="{ fontSize: `${configStore.config.fontSize}px` }">
|
||||
<div class="preview-label">预览</div>
|
||||
|
||||
<SettingItem
|
||||
:title="t('settings.fontWeight')"
|
||||
:description="t('settings.fontWeightDescription')"
|
||||
>
|
||||
<select
|
||||
class="font-weight-select"
|
||||
:value="configStore.config.fontWeight"
|
||||
@change="handleFontWeightChange"
|
||||
>
|
||||
<option
|
||||
v-for="option in fontWeightOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
:title="t('settings.lineHeight')"
|
||||
:description="t('settings.lineHeightDescription')"
|
||||
>
|
||||
<div class="number-control">
|
||||
<button @click="decreaseLineHeight" class="control-button">-</button>
|
||||
<span>{{ configStore.config.lineHeight.toFixed(1) }}</span>
|
||||
<button @click="increaseLineHeight" class="control-button">+</button>
|
||||
</div>
|
||||
</SettingItem>
|
||||
|
||||
<div class="font-preview" :style="{
|
||||
fontSize: `${configStore.config.fontSize}px`,
|
||||
fontFamily: configStore.config.fontFamily,
|
||||
fontWeight: configStore.config.fontWeight,
|
||||
lineHeight: configStore.config.lineHeight
|
||||
}">
|
||||
<div class="preview-label">字体预览</div>
|
||||
<div class="preview-text">
|
||||
<span>function example() {</span>
|
||||
<span class="indent">console.log("Hello, World!");</span>
|
||||
<span class="indent">console.log("Hello, 世界!");</span>
|
||||
<span class="indent">const message = "鸿蒙字体测试";</span>
|
||||
<span>}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -195,6 +296,62 @@ const decreaseTabSize = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.font-preview {
|
||||
margin: 15px 0 5px 20px;
|
||||
padding: 15px;
|
||||
background-color: #252525;
|
||||
border: 1px solid #444444;
|
||||
border-radius: 4px;
|
||||
|
||||
.preview-label {
|
||||
font-size: 12px;
|
||||
color: #888888;
|
||||
margin-bottom: 8px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.preview-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
span {
|
||||
color: #d0d0d0;
|
||||
}
|
||||
|
||||
.indent {
|
||||
padding-left: 20px;
|
||||
color: #4a9eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.font-preset-select,
|
||||
.font-weight-select {
|
||||
min-width: 180px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
background-color: #3a3a3a;
|
||||
color: #e0e0e0;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #4a9eff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #666666;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: #3a3a3a;
|
||||
color: #e0e0e0;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-type-toggle {
|
||||
min-width: 100px;
|
||||
padding: 8px 15px;
|
||||
|
@@ -7,10 +7,14 @@ import {EditorConfig, TabType, LanguageType} from '@/../bindings/voidraft/intern
|
||||
import {useLogStore} from './logStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ConfigUtils } from '@/utils/configUtils';
|
||||
import { FONT_PRESETS, getFontPresetOptions, type FontPresetKey } from '@/editor/extensions/fontExtension';
|
||||
|
||||
// 配置键映射 - 前端字段到后端配置键的映射
|
||||
const CONFIG_KEY_MAP = {
|
||||
fontSize: 'editor.font_size',
|
||||
fontFamily: 'editor.font_family',
|
||||
fontWeight: 'editor.font_weight',
|
||||
lineHeight: 'editor.line_height',
|
||||
enableTabIndent: 'editor.enable_tab_indent',
|
||||
tabSize: 'editor.tab_size',
|
||||
tabType: 'editor.tab_type',
|
||||
@@ -33,6 +37,9 @@ export const useConfigStore = defineStore('config', () => {
|
||||
// 配置状态
|
||||
const config = ref<EditorConfig>(new EditorConfig({
|
||||
fontSize: CONFIG_LIMITS.fontSize.default,
|
||||
fontFamily: '"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
||||
fontWeight: 'normal',
|
||||
lineHeight: 1.5,
|
||||
enableTabIndent: true,
|
||||
tabSize: CONFIG_LIMITS.tabSize.default,
|
||||
tabType: CONFIG_LIMITS.tabType.default,
|
||||
@@ -77,7 +84,11 @@ export const useConfigStore = defineStore('config', () => {
|
||||
if (!configLoaded.value) return;
|
||||
|
||||
try {
|
||||
const backendKey = CONFIG_KEY_MAP[key];
|
||||
const backendKey = CONFIG_KEY_MAP[key as keyof typeof CONFIG_KEY_MAP];
|
||||
if (!backendKey) {
|
||||
throw new Error(`No backend key mapping found for ${String(key)}`);
|
||||
}
|
||||
|
||||
await ConfigService.Set(backendKey, value);
|
||||
|
||||
// 更新本地状态
|
||||
@@ -85,7 +96,7 @@ export const useConfigStore = defineStore('config', () => {
|
||||
|
||||
logStore.info(t('config.saveSuccess'));
|
||||
} catch (error) {
|
||||
console.error(`Failed to update config ${key}:`, error);
|
||||
console.error(`Failed to update config ${String(key)}:`, error);
|
||||
logStore.error(t('config.saveFailed'));
|
||||
throw error;
|
||||
}
|
||||
@@ -156,6 +167,55 @@ export const useConfigStore = defineStore('config', () => {
|
||||
async function setTabSize(size: number): Promise<void> {
|
||||
await updateConfig('tabSize', size);
|
||||
}
|
||||
|
||||
// 字体预设相关方法
|
||||
async function setFontPreset(presetKey: FontPresetKey): Promise<void> {
|
||||
const preset = FONT_PRESETS[presetKey];
|
||||
if (!preset) {
|
||||
throw new Error(`Unknown font preset: ${presetKey}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// 批量更新字体相关配置
|
||||
await updateConfig('fontFamily', preset.fontFamily);
|
||||
await updateConfig('fontWeight', preset.fontWeight);
|
||||
await updateConfig('lineHeight', preset.lineHeight);
|
||||
// 可选择是否同时更新字体大小
|
||||
// await updateConfig('fontSize', preset.fontSize);
|
||||
|
||||
logStore.info(`字体预设已切换为: ${preset.name}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to set font preset:', error);
|
||||
logStore.error('字体预设设置失败');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前字体预设(如果匹配的话)
|
||||
function getCurrentFontPreset(): FontPresetKey | null {
|
||||
const currentFamily = config.value.fontFamily;
|
||||
for (const [key, preset] of Object.entries(FONT_PRESETS)) {
|
||||
if (preset.fontFamily === currentFamily) {
|
||||
return key as FontPresetKey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 设置字体族
|
||||
async function setFontFamily(fontFamily: string): Promise<void> {
|
||||
await updateConfig('fontFamily', fontFamily);
|
||||
}
|
||||
|
||||
// 设置字体粗细
|
||||
async function setFontWeight(fontWeight: string): Promise<void> {
|
||||
await updateConfig('fontWeight', fontWeight);
|
||||
}
|
||||
|
||||
// 设置行高
|
||||
async function setLineHeight(lineHeight: number): Promise<void> {
|
||||
await updateConfig('lineHeight', lineHeight);
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
@@ -189,6 +249,13 @@ export const useConfigStore = defineStore('config', () => {
|
||||
setTabSize,
|
||||
|
||||
// 窗口操作
|
||||
toggleAlwaysOnTop
|
||||
toggleAlwaysOnTop,
|
||||
|
||||
// 字体预设相关方法
|
||||
setFontPreset,
|
||||
getCurrentFontPreset,
|
||||
setFontFamily,
|
||||
setFontWeight,
|
||||
setLineHeight
|
||||
};
|
||||
});
|
Reference in New Issue
Block a user