Complete the custom editor theme

This commit is contained in:
2025-07-11 23:02:25 +08:00
parent b5510d605c
commit a720a4cfb8
26 changed files with 1838 additions and 369 deletions

View File

@@ -73,7 +73,8 @@ const EDITING_CONFIG_KEY_MAP: EditingConfigKeyMap = {
const APPEARANCE_CONFIG_KEY_MAP: AppearanceConfigKeyMap = {
language: 'appearance.language',
systemTheme: 'appearance.systemTheme'
systemTheme: 'appearance.systemTheme',
customTheme: 'appearance.customTheme'
} as const;
const UPDATES_CONFIG_KEY_MAP: UpdatesConfigKeyMap = {
@@ -171,7 +172,77 @@ const DEFAULT_CONFIG: AppConfig = {
},
appearance: {
language: LanguageType.LangZhCN,
systemTheme: SystemThemeType.SystemThemeAuto
systemTheme: SystemThemeType.SystemThemeAuto,
customTheme: {
darkTheme: {
// 基础色调
background: '#252B37',
backgroundSecondary: '#213644',
surface: '#474747',
foreground: '#9BB586',
foregroundSecondary: '#9c9c9c',
// 语法高亮
comment: '#6272a4',
keyword: '#ff79c6',
string: '#f1fa8c',
function: '#50fa7b',
number: '#bd93f9',
operator: '#ff79c6',
variable: '#8fbcbb',
type: '#8be9fd',
// 界面元素
cursor: '#fff',
selection: '#0865a9aa',
selectionBlur: '#225377aa',
activeLine: 'rgba(255,255,255,0.04)',
lineNumber: 'rgba(255,255,255, 0.15)',
activeLineNumber: 'rgba(255,255,255, 0.6)',
// 边框分割线
borderColor: '#1e222a',
borderLight: 'rgba(255,255,255, 0.1)',
// 搜索匹配
searchMatch: '#8fbcbb',
matchingBracket: 'rgba(255,255,255,0.1)'
},
lightTheme: {
// 基础色调
background: '#ffffff',
backgroundSecondary: '#f1faf1',
surface: '#f5f5f5',
foreground: '#444d56',
foregroundSecondary: '#6a737d',
// 语法高亮
comment: '#6a737d',
keyword: '#d73a49',
string: '#032f62',
function: '#005cc5',
number: '#005cc5',
operator: '#d73a49',
variable: '#24292e',
type: '#6f42c1',
// 界面元素
cursor: '#000',
selection: '#77baff8c',
selectionBlur: '#b2c2ca85',
activeLine: '#000000',
lineNumber: '#000000',
activeLineNumber: '#000000',
// 边框分割线
borderColor: '#dfdfdf',
borderLight: '#0000000C',
// 搜索匹配
searchMatch: '#005cc5',
matchingBracket: 'rgba(0,0,0,0.1)'
}
}
},
updates: {
version: "1.0.0",
@@ -363,6 +434,51 @@ export const useConfigStore = defineStore('config', () => {
await updateAppearanceConfig('systemTheme', systemTheme);
};
// 更新自定义主题方法
const updateCustomTheme = async (themeType: 'darkTheme' | 'lightTheme', colorKey: string, colorValue: string): Promise<void> => {
// 确保配置已加载
if (!state.configLoaded && !state.isLoading) {
await initConfig();
}
try {
// 深拷贝当前配置
const customTheme = JSON.parse(JSON.stringify(state.config.appearance.customTheme));
// 更新对应主题的颜色值
customTheme[themeType][colorKey] = colorValue;
// 更新整个自定义主题配置到后端
await ConfigService.Set(APPEARANCE_CONFIG_KEY_MAP.customTheme, customTheme);
// 更新前端状态
state.config.appearance.customTheme = customTheme;
} catch (error) {
throw error;
}
};
// 设置整个自定义主题配置
const setCustomTheme = async (customTheme: any): Promise<void> => {
// 确保配置已加载
if (!state.configLoaded && !state.isLoading) {
await initConfig();
}
try {
// 更新整个自定义主题配置到后端
await ConfigService.Set(APPEARANCE_CONFIG_KEY_MAP.customTheme, customTheme);
// 更新前端状态
state.config.appearance.customTheme = customTheme;
// 确保Vue能检测到变化
state.config.appearance = { ...state.config.appearance };
} catch (error) {
throw error;
}
};
// 初始化语言设置
const initializeLanguage = async (): Promise<void> => {
try {
@@ -426,6 +542,8 @@ export const useConfigStore = defineStore('config', () => {
// 主题相关方法
setSystemTheme,
updateCustomTheme,
setCustomTheme,
// 字体大小操作
...adjusters.fontSize,

View File

@@ -65,6 +65,9 @@ export const useEditorStore = defineStore('editor', () => {
characters: 0,
selectedCharacters: 0
});
// 编辑器加载状态
const isLoading = ref(false);
// 异步操作竞态条件控制
const operationSequence = ref(0);
@@ -434,10 +437,12 @@ export const useEditorStore = defineStore('editor', () => {
// 加载编辑器
const loadEditor = async (documentId: number, content: string) => {
// 设置加载状态
isLoading.value = true;
// 生成新的操作ID
const operationId = getNextOperationId();
const abortController = new AbortController();
try {
// 验证参数
if (!documentId) {
@@ -500,15 +505,20 @@ export const useEditorStore = defineStore('editor', () => {
} catch (error) {
if (error instanceof Error && error.message === 'Operation cancelled') {
console.log(`Editor loading cancelled for document ${documentId}`);
return;
} else {
console.error('Failed to load editor:', error);
}
console.error('Failed to load editor:', error);
} finally {
// 清理操作记录
pendingOperations.value.delete(operationId);
if (currentLoadingDocumentId.value === documentId) {
currentLoadingDocumentId.value = null;
}
// 延迟一段时间后再取消加载状态
setTimeout(() => {
isLoading.value = false;
}, 800);
}
};
@@ -684,6 +694,7 @@ export const useEditorStore = defineStore('editor', () => {
// 状态
currentEditor,
documentStats,
isLoading,
// 方法
setEditorContainer,

View File

@@ -1,19 +1,41 @@
import { defineStore } from 'pinia';
import { computed } from 'vue';
import { SystemThemeType } from '@/../bindings/voidraft/internal/models/models';
import { useConfigStore } from './configStore';
import {defineStore} from 'pinia';
import {computed, reactive} from 'vue';
import {SystemThemeType} from '@/../bindings/voidraft/internal/models/models';
import {useConfigStore} from './configStore';
import {useEditorStore} from './editorStore';
import {defaultDarkColors} from '@/views/editor/theme/dark';
import {defaultLightColors} from '@/views/editor/theme/light';
/**
* 主题管理 Store
* 职责:
* 职责:管理主题状态和颜色配置
*/
export const useThemeStore = defineStore('theme', () => {
const configStore = useConfigStore();
// 响应式状态 - 存储当前使用的主题颜色
const themeColors = reactive({
darkTheme: { ...defaultDarkColors },
lightTheme: { ...defaultLightColors }
});
// 计算属性 - 当前选择的主题类型
const currentTheme = computed(() =>
configStore.config?.appearance?.systemTheme || SystemThemeType.SystemThemeAuto
);
// 初始化主题颜色 - 从配置加载
const initializeThemeColors = () => {
const customTheme = configStore.config?.appearance?.customTheme;
if (customTheme) {
if (customTheme.darkTheme) {
Object.assign(themeColors.darkTheme, customTheme.darkTheme);
}
if (customTheme.lightTheme) {
Object.assign(themeColors.lightTheme, customTheme.lightTheme);
}
}
};
// 应用主题到 DOM
const applyThemeToDOM = (theme: SystemThemeType) => {
@@ -27,18 +49,97 @@ export const useThemeStore = defineStore('theme', () => {
const initializeTheme = () => {
const theme = configStore.config?.appearance?.systemTheme || SystemThemeType.SystemThemeAuto;
applyThemeToDOM(theme);
initializeThemeColors();
};
// 设置主题
const setTheme = async (theme: SystemThemeType) => {
await configStore.setSystemTheme(theme);
applyThemeToDOM(theme);
refreshEditorTheme();
};
// 更新主题颜色
const updateThemeColors = (darkColors: any = null, lightColors: any = null): boolean => {
let hasChanges = false;
if (darkColors) {
Object.entries(darkColors).forEach(([key, value]) => {
if (value !== undefined && themeColors.darkTheme[key] !== value) {
themeColors.darkTheme[key] = value;
hasChanges = true;
}
});
}
if (lightColors) {
Object.entries(lightColors).forEach(([key, value]) => {
if (value !== undefined && themeColors.lightTheme[key] !== value) {
themeColors.lightTheme[key] = value;
hasChanges = true;
}
});
}
return hasChanges;
};
// 保存主题颜色到配置
const saveThemeColors = async () => {
const customTheme = {
darkTheme: { ...themeColors.darkTheme },
lightTheme: { ...themeColors.lightTheme }
};
await configStore.setCustomTheme(customTheme);
};
// 重置主题颜色
const resetThemeColors = async (themeType: 'darkTheme' | 'lightTheme') => {
try {
// 1. 更新内存中的颜色状态
if (themeType === 'darkTheme') {
Object.assign(themeColors.darkTheme, defaultDarkColors);
}
if (themeType === 'lightTheme') {
Object.assign(themeColors.lightTheme, defaultLightColors);
}
// 2. 保存到配置
await saveThemeColors();
// 3. 刷新编辑器主题
refreshEditorTheme();
return true;
} catch (error) {
console.error('Failed to reset theme colors:', error);
return false;
}
};
// 刷新编辑器主题(在主题颜色更改后调用)
const refreshEditorTheme = () => {
// 使用当前主题重新应用DOM主题
const theme = currentTheme.value;
applyThemeToDOM(theme);
const editorStore = useEditorStore();
if (editorStore) {
editorStore.applyThemeSettings();
}
};
return {
currentTheme,
themeColors,
setTheme,
initializeTheme,
applyThemeToDOM,
updateThemeColors,
saveThemeColors,
resetThemeColors,
refreshEditorTheme
};
});
});