From aff08f4d3defaaa100ffeeb67a0d49408bcde8d5 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Mon, 9 Jun 2025 02:29:15 +0800 Subject: [PATCH] :sparkles: Added dark theme and white theme switching --- .../voidraft/internal/models/models.ts | 33 ++++ frontend/src/App.vue | 4 +- frontend/src/assets/styles/index.css | 3 +- frontend/src/assets/styles/scrollbar.css | 108 +++++++++++ frontend/src/assets/styles/variables.css | 181 +++++++++++++++++- .../components/titlebar/WindowTitleBar.vue | 19 +- frontend/src/components/toolbar/Toolbar.vue | 20 +- frontend/src/composables/useSystemTheme.ts | 35 ++++ frontend/src/i18n/locales/en-US.ts | 11 +- frontend/src/i18n/locales/zh-CN.ts | 11 +- frontend/src/stores/configStore.ts | 15 +- frontend/src/types/index.ts | 2 +- frontend/src/views/settings/Settings.vue | 76 ++------ .../views/settings/components/SettingItem.vue | 9 +- .../settings/components/SettingSection.vue | 9 +- .../settings/components/ToggleSwitch.vue | 4 +- .../views/settings/pages/AppearancePage.vue | 43 ++++- .../src/views/settings/pages/EditingPage.vue | 87 ++++----- .../src/views/settings/pages/GeneralPage.vue | 98 ++++++---- .../views/settings/pages/KeyBindingsPage.vue | 31 +-- .../src/views/settings/pages/UpdatesPage.vue | 25 +-- internal/models/config.go | 22 ++- internal/services/config_service.go | 2 + 23 files changed, 630 insertions(+), 218 deletions(-) create mode 100644 frontend/src/assets/styles/scrollbar.css create mode 100644 frontend/src/composables/useSystemTheme.ts diff --git a/frontend/bindings/voidraft/internal/models/models.ts b/frontend/bindings/voidraft/internal/models/models.ts index 3f75f47..6b1ebe5 100644 --- a/frontend/bindings/voidraft/internal/models/models.ts +++ b/frontend/bindings/voidraft/internal/models/models.ts @@ -114,6 +114,11 @@ export class AppearanceConfig { */ "theme": ThemeType; + /** + * 系统界面主题 + */ + "systemTheme": SystemThemeType; + /** Creates a new AppearanceConfig instance. */ constructor($$source: Partial = {}) { if (!("language" in $$source)) { @@ -122,6 +127,9 @@ export class AppearanceConfig { if (!("theme" in $$source)) { this["theme"] = ("" as ThemeType); } + if (!("systemTheme" in $$source)) { + this["systemTheme"] = ("" as SystemThemeType); + } Object.assign(this, $$source); } @@ -509,6 +517,31 @@ export enum LanguageType { LangEnUS = "en-US", }; +/** + * SystemThemeType 系统主题类型定义 + */ +export enum SystemThemeType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * SystemThemeDark 深色系统主题 + */ + SystemThemeDark = "dark", + + /** + * SystemThemeLight 浅色系统主题 + */ + SystemThemeLight = "light", + + /** + * SystemThemeAuto 跟随系统主题 + */ + SystemThemeAuto = "auto", +}; + /** * TabType 定义了制表符类型 */ diff --git a/frontend/src/App.vue b/frontend/src/App.vue index ef7bd63..7f65515 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,15 +1,17 @@ diff --git a/frontend/src/assets/styles/index.css b/frontend/src/assets/styles/index.css index 9b40cb2..b87d428 100644 --- a/frontend/src/assets/styles/index.css +++ b/frontend/src/assets/styles/index.css @@ -1,4 +1,5 @@ /* 导入所有CSS文件 */ @import 'normalize.css'; @import 'variables.css'; -@import "fonts.css"; \ No newline at end of file +@import "fonts.css"; +@import 'scrollbar.css'; \ No newline at end of file diff --git a/frontend/src/assets/styles/scrollbar.css b/frontend/src/assets/styles/scrollbar.css new file mode 100644 index 0000000..53617f7 --- /dev/null +++ b/frontend/src/assets/styles/scrollbar.css @@ -0,0 +1,108 @@ +/* 滚动条样式 - 支持主题切换 */ + +/* Webkit 浏览器滚动条样式 */ +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +::-webkit-scrollbar-track { + background: var(--scrollbar-track); + border-radius: 6px; +} + +::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 6px; + border: 2px solid var(--scrollbar-track); + transition: background-color 0.2s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover); +} + +::-webkit-scrollbar-thumb:active { + background: var(--scrollbar-thumb-hover); +} + +::-webkit-scrollbar-corner { + background: var(--scrollbar-track); +} + +/* 细滚动条变体(用于特定区域) */ +.thin-scrollbar::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.thin-scrollbar::-webkit-scrollbar-track { + background: var(--scrollbar-track); + border-radius: 4px; +} + +.thin-scrollbar::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 4px; + border: 1px solid var(--scrollbar-track); +} + +.thin-scrollbar::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover); +} + +/* Firefox 滚动条样式 */ +* { + scrollbar-width: auto; + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); +} + +/* 细滚动条的Firefox样式 */ +.thin-scrollbar { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); +} + +/* 隐藏滚动条但保持功能的工具类 */ +.hide-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.hide-scrollbar::-webkit-scrollbar { + display: none; +} + +/* 自定义悬浮显示滚动条 */ +.hover-scrollbar { + scrollbar-width: none; + -ms-overflow-style: none; +} + +.hover-scrollbar::-webkit-scrollbar { + display: none; +} + +.hover-scrollbar:hover { + scrollbar-width: auto; +} + +.hover-scrollbar:hover::-webkit-scrollbar { + display: block; + width: 8px; + height: 8px; +} + +.hover-scrollbar:hover::-webkit-scrollbar-track { + background: var(--scrollbar-track); + border-radius: 4px; +} + +.hover-scrollbar:hover::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 4px; +} + +.hover-scrollbar:hover::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover); +} \ No newline at end of file diff --git a/frontend/src/assets/styles/variables.css b/frontend/src/assets/styles/variables.css index 3f3ec4b..e996367 100644 --- a/frontend/src/assets/styles/variables.css +++ b/frontend/src/assets/styles/variables.css @@ -1,12 +1,177 @@ :root { - /* 主题颜色 */ - --bg-secondary: #0E1217; /* 工具栏背景 */ - - /* 文本颜色 */ + /* 编辑器区域 */ --text-primary: #9BB586; /* 内容区域字体颜色 */ - --text-secondary: #a0aec0; - --text-muted: #666; + + /* 深色主题颜色变量 */ + --dark-toolbar-bg: #2d2d2d; + --dark-toolbar-border: #404040; + --dark-toolbar-text: #ffffff; + --dark-toolbar-text-secondary: #cccccc; + --dark-toolbar-button-hover: #404040; + --dark-bg-secondary: #0E1217; + --dark-text-secondary: #a0aec0; + --dark-text-muted: #666; + --dark-border-color: #2d3748; + --dark-settings-bg: #2a2a2a; + --dark-settings-card-bg: #333333; + --dark-settings-text: #ffffff; + --dark-settings-text-secondary: #cccccc; + --dark-settings-border: #444444; + --dark-settings-input-bg: #3a3a3a; + --dark-settings-input-border: #555555; + --dark-settings-hover: #404040; + --dark-scrollbar-track: #2a2a2a; + --dark-scrollbar-thumb: #555555; + --dark-scrollbar-thumb-hover: #666666; + + /* 浅色主题颜色变量 */ + --light-toolbar-bg: #f8f9fa; + --light-toolbar-border: #e9ecef; + --light-toolbar-text: #212529; + --light-toolbar-text-secondary: #495057; + --light-toolbar-button-hover: #e9ecef; + --light-bg-secondary: #f7fef7; + --light-text-secondary: #374151; + --light-text-muted: #6b7280; + --light-border-color: #e5e7eb; + --light-settings-bg: #ffffff; + --light-settings-card-bg: #f8f9fa; + --light-settings-text: #212529; + --light-settings-text-secondary: #6c757d; + --light-settings-border: #dee2e6; + --light-settings-input-bg: #ffffff; + --light-settings-input-border: #ced4da; + --light-settings-hover: #e9ecef; + --light-scrollbar-track: #f1f3f4; + --light-scrollbar-thumb: #c1c1c1; + --light-scrollbar-thumb-hover: #a8a8a8; + + /* 默认使用深色主题 */ + --toolbar-bg: var(--dark-toolbar-bg); + --toolbar-border: var(--dark-toolbar-border); + --toolbar-text: var(--dark-toolbar-text); + --toolbar-text-secondary: var(--dark-toolbar-text-secondary); + --toolbar-button-hover: var(--dark-toolbar-button-hover); + --toolbar-separator: var(--dark-toolbar-button-hover); + --bg-secondary: var(--dark-bg-secondary); + --text-secondary: var(--dark-text-secondary); + --text-muted: var(--dark-text-muted); + --border-color: var(--dark-border-color); + --settings-bg: var(--dark-settings-bg); + --settings-card-bg: var(--dark-settings-card-bg); + --settings-text: var(--dark-settings-text); + --settings-text-secondary: var(--dark-settings-text-secondary); + --settings-border: var(--dark-settings-border); + --settings-input-bg: var(--dark-settings-input-bg); + --settings-input-border: var(--dark-settings-input-border); + --settings-hover: var(--dark-settings-hover); + --scrollbar-track: var(--dark-scrollbar-track); + --scrollbar-thumb: var(--dark-scrollbar-thumb); + --scrollbar-thumb-hover: var(--dark-scrollbar-thumb-hover); + + color-scheme: light dark; +} - /* 边框颜色 */ - --border-color: #2d3748; +/* 监听系统深色主题 */ +@media (prefers-color-scheme: dark) { + :root[data-theme="auto"] { + --toolbar-bg: var(--dark-toolbar-bg); + --toolbar-border: var(--dark-toolbar-border); + --toolbar-text: var(--dark-toolbar-text); + --toolbar-text-secondary: var(--dark-toolbar-text-secondary); + --toolbar-button-hover: var(--dark-toolbar-button-hover); + --toolbar-separator: var(--dark-toolbar-button-hover); + --bg-secondary: var(--dark-bg-secondary); + --text-secondary: var(--dark-text-secondary); + --text-muted: var(--dark-text-muted); + --border-color: var(--dark-border-color); + --settings-bg: var(--dark-settings-bg); + --settings-card-bg: var(--dark-settings-card-bg); + --settings-text: var(--dark-settings-text); + --settings-text-secondary: var(--dark-settings-text-secondary); + --settings-border: var(--dark-settings-border); + --settings-input-bg: var(--dark-settings-input-bg); + --settings-input-border: var(--dark-settings-input-border); + --settings-hover: var(--dark-settings-hover); + --scrollbar-track: var(--dark-scrollbar-track); + --scrollbar-thumb: var(--dark-scrollbar-thumb); + --scrollbar-thumb-hover: var(--dark-scrollbar-thumb-hover); + } +} + +/* 监听系统浅色主题 */ +@media (prefers-color-scheme: light) { + :root[data-theme="auto"] { + --toolbar-bg: var(--light-toolbar-bg); + --toolbar-border: var(--light-toolbar-border); + --toolbar-text: var(--light-toolbar-text); + --toolbar-text-secondary: var(--light-toolbar-text-secondary); + --toolbar-button-hover: var(--light-toolbar-button-hover); + --toolbar-separator: var(--light-toolbar-button-hover); + --bg-secondary: var(--light-bg-secondary); + --text-secondary: var(--light-text-secondary); + --text-muted: var(--light-text-muted); + --border-color: var(--light-border-color); + --settings-bg: var(--light-settings-bg); + --settings-card-bg: var(--light-settings-card-bg); + --settings-text: var(--light-settings-text); + --settings-text-secondary: var(--light-settings-text-secondary); + --settings-border: var(--light-settings-border); + --settings-input-bg: var(--light-settings-input-bg); + --settings-input-border: var(--light-settings-input-border); + --settings-hover: var(--light-settings-hover); + --scrollbar-track: var(--light-scrollbar-track); + --scrollbar-thumb: var(--light-scrollbar-thumb); + --scrollbar-thumb-hover: var(--light-scrollbar-thumb-hover); + } +} + +/* 手动选择浅色主题 */ +:root[data-theme="light"] { + --toolbar-bg: var(--light-toolbar-bg); + --toolbar-border: var(--light-toolbar-border); + --toolbar-text: var(--light-toolbar-text); + --toolbar-text-secondary: var(--light-toolbar-text-secondary); + --toolbar-button-hover: var(--light-toolbar-button-hover); + --toolbar-separator: var(--light-toolbar-button-hover); + --bg-secondary: var(--light-bg-secondary); + --text-secondary: var(--light-text-secondary); + --text-muted: var(--light-text-muted); + --border-color: var(--light-border-color); + --settings-bg: var(--light-settings-bg); + --settings-card-bg: var(--light-settings-card-bg); + --settings-text: var(--light-settings-text); + --settings-text-secondary: var(--light-settings-text-secondary); + --settings-border: var(--light-settings-border); + --settings-input-bg: var(--light-settings-input-bg); + --settings-input-border: var(--light-settings-input-border); + --settings-hover: var(--light-settings-hover); + --scrollbar-track: var(--light-scrollbar-track); + --scrollbar-thumb: var(--light-scrollbar-thumb); + --scrollbar-thumb-hover: var(--light-scrollbar-thumb-hover); +} + +/* 手动选择深色主题 */ +:root[data-theme="dark"] { + --toolbar-bg: var(--dark-toolbar-bg); + --toolbar-border: var(--dark-toolbar-border); + --toolbar-text: var(--dark-toolbar-text); + --toolbar-text-secondary: var(--dark-toolbar-text-secondary); + --toolbar-button-hover: var(--dark-toolbar-button-hover); + --toolbar-separator: var(--dark-toolbar-button-hover); + --bg-secondary: var(--dark-bg-secondary); + --text-secondary: var(--dark-text-secondary); + --text-muted: var(--dark-text-muted); + --border-color: var(--dark-border-color); + --settings-bg: var(--dark-settings-bg); + --settings-card-bg: var(--dark-settings-card-bg); + --settings-text: var(--dark-settings-text); + --settings-text-secondary: var(--dark-settings-text-secondary); + --settings-border: var(--dark-settings-border); + --settings-input-bg: var(--dark-settings-input-bg); + --settings-input-border: var(--dark-settings-input-border); + --settings-hover: var(--dark-settings-hover); + --scrollbar-track: var(--dark-scrollbar-track); + --scrollbar-thumb: var(--dark-scrollbar-thumb); + --scrollbar-thumb-hover: var(--dark-scrollbar-thumb-hover); } \ No newline at end of file diff --git a/frontend/src/components/titlebar/WindowTitleBar.vue b/frontend/src/components/titlebar/WindowTitleBar.vue index 046f089..cf1a417 100644 --- a/frontend/src/components/titlebar/WindowTitleBar.vue +++ b/frontend/src/components/titlebar/WindowTitleBar.vue @@ -123,7 +123,8 @@ onMounted(async () => { .windows-titlebar { display: flex; height: 32px; - background: #202020; + background: var(--toolbar-bg); + border-bottom: 1px solid var(--toolbar-border); user-select: none; -webkit-user-select: none; position: fixed; @@ -145,7 +146,7 @@ onMounted(async () => { flex: 1; padding-left: 8px; gap: 8px; - color: #ffffff; + color: var(--toolbar-text); font-size: 12px; font-weight: 400; cursor: default; @@ -169,7 +170,7 @@ onMounted(async () => { .titlebar-title { font-size: 12px; - color: #ffffff; + color: var(--toolbar-text); } .titlebar-controls { @@ -187,7 +188,7 @@ onMounted(async () => { height: 32px; border: none; background: transparent; - color: #ffffff; + color: var(--toolbar-text); cursor: pointer; display: flex; align-items: center; @@ -197,11 +198,12 @@ onMounted(async () => { margin: 0; &:hover { - background: rgba(255, 255, 255, 0.0605); + background: var(--toolbar-button-hover); } &:active { - background: rgba(255, 255, 255, 0.0837); + background: var(--toolbar-button-hover); + opacity: 0.8; } } @@ -220,12 +222,13 @@ onMounted(async () => { .minimize-button:hover, .maximize-button:hover { - background: rgba(255, 255, 255, 0.0605); + background: var(--toolbar-button-hover); } .minimize-button:active, .maximize-button:active { - background: rgba(255, 255, 255, 0.0837); + background: var(--toolbar-button-hover); + opacity: 0.8; } .close-button:hover { diff --git a/frontend/src/components/toolbar/Toolbar.vue b/frontend/src/components/toolbar/Toolbar.vue index eedd0cc..e49b46b 100644 --- a/frontend/src/components/toolbar/Toolbar.vue +++ b/frontend/src/components/toolbar/Toolbar.vue @@ -174,7 +174,8 @@ watch(isLoaded, async (newLoaded) => { color: var(--text-muted); .stat-value { - color: #e0e0e0; + color: var(--text-secondary); + font-weight: 500; } } } @@ -212,10 +213,12 @@ watch(isLoaded, async (newLoaded) => { cursor: pointer; padding: 0 3px; border-radius: 3px; - background-color: rgba(255, 255, 255, 0.05); + background-color: var(--border-color); + opacity: 0.6; &:hover { - background-color: rgba(255, 255, 255, 0.1); + opacity: 1; + background-color: var(--border-color); } } @@ -255,7 +258,8 @@ watch(isLoaded, async (newLoaded) => { transition: all 0.2s ease; &:hover { - background-color: rgba(255, 255, 255, 0.1); + background-color: var(--border-color); + opacity: 0.8; } &.active { @@ -291,7 +295,8 @@ watch(isLoaded, async (newLoaded) => { border-radius: 3px; &:hover { - background-color: rgba(255, 255, 255, 0.05); + background-color: var(--border-color); + opacity: 0.8; } .arrow { @@ -321,7 +326,8 @@ watch(isLoaded, async (newLoaded) => { white-space: nowrap; &:hover { - background-color: var(--bg-hover); + background-color: var(--border-color); + opacity: 0.8; } &.active { @@ -342,7 +348,7 @@ watch(isLoaded, async (newLoaded) => { padding: 2px; &:hover { - color: var(--text-primary); + color: var(--text-secondary); } } } diff --git a/frontend/src/composables/useSystemTheme.ts b/frontend/src/composables/useSystemTheme.ts new file mode 100644 index 0000000..686986e --- /dev/null +++ b/frontend/src/composables/useSystemTheme.ts @@ -0,0 +1,35 @@ +import { ref, watch, onMounted, onUnmounted } from 'vue'; +import { useConfigStore } from '@/stores/configStore'; + +export function useSystemTheme() { + const configStore = useConfigStore(); + const currentSystemTheme = ref<'dark' | 'light'>('dark'); + + // 设置主题 - 简化版本 + const setTheme = (theme: string) => { + const root = document.documentElement; + root.setAttribute('data-theme', theme); + }; + + // 监听配置变化 + watch( + () => configStore.config.appearance.systemTheme, + (newTheme) => { + // 直接根据配置设置主题,不需要检测系统主题 + const root = document.documentElement; + root.setAttribute('data-theme', newTheme); + }, + { immediate: true } + ); + + onMounted(() => { + const root = document.documentElement; + const systemTheme = configStore.config.appearance.systemTheme; + root.setAttribute('data-theme', systemTheme); + }); + + return { + currentSystemTheme, + setTheme + }; +} \ No newline at end of file diff --git a/frontend/src/i18n/locales/en-US.ts b/frontend/src/i18n/locales/en-US.ts index 0c68889..3ea1024 100644 --- a/frontend/src/i18n/locales/en-US.ts +++ b/frontend/src/i18n/locales/en-US.ts @@ -37,12 +37,19 @@ export default { languageChanged: 'Language setting updated', languageChangeFailed: 'Failed to update language setting', themeChanged: 'Theme setting updated', - themeChangeFailed: 'Failed to update theme setting' + themeChangeFailed: 'Failed to update theme setting', + systemThemeChanged: 'System theme setting updated', + systemThemeChangeFailed: 'Failed to update system theme setting' }, languages: { 'zh-CN': '简体中文', 'en-US': 'English' }, + systemTheme: { + dark: 'Dark', + light: 'Light', + auto: 'Follow System' + }, document: { loadSuccess: 'Document loaded successfully', loadFailed: 'Failed to load document', @@ -76,7 +83,6 @@ export default { cancel: 'Cancel', dangerZone: 'Danger Zone', resetAllSettings: 'Reset All Settings', - resetDescription: 'This will restore all settings to their default values. This action cannot be undone.', confirmReset: 'Click again to confirm reset', globalHotkey: 'Global Keyboard Shortcuts', enableGlobalHotkey: 'Enable Global Hotkeys', @@ -106,6 +112,7 @@ export default { tabs: 'Tabs', enableTabIndent: 'Enable Tab Indent', language: 'Interface Language', + systemTheme: 'System Theme', theme: 'Editor Theme', themeDescription: 'Choose editor theme', restartRequired: '(Restart required)', diff --git a/frontend/src/i18n/locales/zh-CN.ts b/frontend/src/i18n/locales/zh-CN.ts index e5f7546..79cd336 100644 --- a/frontend/src/i18n/locales/zh-CN.ts +++ b/frontend/src/i18n/locales/zh-CN.ts @@ -37,12 +37,19 @@ export default { languageChanged: '语言设置已更新', languageChangeFailed: '语言设置更新失败', themeChanged: '主题设置已更新', - themeChangeFailed: '主题设置更新失败' + themeChangeFailed: '主题设置更新失败', + systemThemeChanged: '系统主题设置已更新', + systemThemeChangeFailed: '系统主题设置更新失败' }, languages: { 'zh-CN': '简体中文', 'en-US': 'English' }, + systemTheme: { + dark: '深色', + light: '浅色', + auto: '跟随系统' + }, document: { loadSuccess: '文档加载成功', loadFailed: '文档加载失败', @@ -76,7 +83,6 @@ export default { cancel: '取消', dangerZone: '危险操作', resetAllSettings: '重置所有设置', - resetDescription: '这将恢复所有设置为默认值,此操作无法撤销', confirmReset: '再次点击确认重置', globalHotkey: '全局键盘快捷键', enableGlobalHotkey: '启用全局热键', @@ -106,6 +112,7 @@ export default { tabs: '制表符', enableTabIndent: '启用 Tab 缩进', language: '界面语言', + systemTheme: '系统主题', theme: '编辑器主题', themeDescription: '选择编辑器主题', restartRequired: '(需要重启)', diff --git a/frontend/src/stores/configStore.ts b/frontend/src/stores/configStore.ts index aff54d0..f0a144a 100644 --- a/frontend/src/stores/configStore.ts +++ b/frontend/src/stores/configStore.ts @@ -7,6 +7,7 @@ import { EditingConfig, GeneralConfig, LanguageType, + SystemThemeType, TabType, ThemeType } from '@/../bindings/voidraft/internal/models'; @@ -67,7 +68,8 @@ const EDITING_CONFIG_KEY_MAP: EditingConfigKeyMap = { const APPEARANCE_CONFIG_KEY_MAP: AppearanceConfigKeyMap = { language: 'appearance.language', - theme: 'appearance.theme' + theme: 'appearance.theme', + systemTheme: 'appearance.system_theme' } as const; // 配置限制 @@ -139,7 +141,8 @@ const DEFAULT_CONFIG: AppConfig = { }, appearance: { language: LanguageType.LangZhCN, - theme: 'default-dark' as ThemeType + theme: 'default-dark' as ThemeType, + systemTheme: 'dark' as SystemThemeType }, keyBindings: {}, updates: {}, @@ -308,6 +311,13 @@ export const useConfigStore = defineStore('config', () => { }, 'config.themeChangeFailed', 'config.themeChanged'); }; + // 系统主题设置方法 + const setSystemTheme = async (systemTheme: SystemThemeType): Promise => { + await safeCall(async () => { + await updateAppearanceConfig('systemTheme', systemTheme); + }, 'config.systemThemeChangeFailed', 'config.systemThemeChanged'); + }; + // 初始化语言设置 const initializeLanguage = async (): Promise => { try { @@ -372,6 +382,7 @@ export const useConfigStore = defineStore('config', () => { // 主题相关方法 setTheme, + setSystemTheme, // 字体大小操作 ...adjusters.fontSize, diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index e7e6d96..da5b333 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1,4 +1,4 @@ // 统一类型导出 -export type { ThemeType, LanguageType } from '@/../bindings/voidraft/internal/models'; +export type { ThemeType, LanguageType, SystemThemeType } from '@/../bindings/voidraft/internal/models'; export * from './theme'; export * from './editor'; \ No newline at end of file diff --git a/frontend/src/views/settings/Settings.vue b/frontend/src/views/settings/Settings.vue index c4fbdea..0813df1 100644 --- a/frontend/src/views/settings/Settings.vue +++ b/frontend/src/views/settings/Settings.vue @@ -45,7 +45,7 @@ const goBackToEditor = async () => {

{{ t('settings.title') }}

-
+
{ height: 100vh; margin: 0; padding: 0; - background-color: #2a2a2a; - color: #e0e0e0; + background-color: var(--settings-bg); + color: var(--settings-text); display: flex; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; @@ -85,16 +85,16 @@ const goBackToEditor = async () => { .settings-sidebar { width: 200px; height: 100%; - background-color: #333333; - border-right: 1px solid #444444; + background-color: var(--settings-card-bg); + border-right: 1px solid var(--settings-border); display: flex; flex-direction: column; box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); .settings-header { padding: 20px 16px; - border-bottom: 1px solid #444444; - background-color: #2d2d2d; + border-bottom: 1px solid var(--settings-border); + background-color: var(--settings-card-bg); .header-content { display: flex; @@ -104,7 +104,7 @@ const goBackToEditor = async () => { .back-button { background: none; border: none; - color: #a0a0a0; + color: var(--settings-text-secondary); cursor: pointer; padding: 6px; border-radius: 4px; @@ -114,8 +114,8 @@ const goBackToEditor = async () => { transition: all 0.2s ease; &:hover { - color: #e0e0e0; - background-color: #3a3a3a; + color: var(--settings-text); + background-color: var(--settings-hover); } svg { @@ -128,7 +128,7 @@ const goBackToEditor = async () => { font-size: 18px; font-weight: 600; margin: 0; - color: #ffffff; + color: var(--settings-text); } } } @@ -138,19 +138,6 @@ const goBackToEditor = async () => { padding: 10px 0; overflow-y: auto; - &::-webkit-scrollbar { - width: 8px; - } - - &::-webkit-scrollbar-track { - background: #333333; - } - - &::-webkit-scrollbar-thumb { - background-color: #555555; - border-radius: 4px; - } - .nav-item { display: flex; align-items: center; @@ -160,11 +147,11 @@ const goBackToEditor = async () => { border-left: 3px solid transparent; &:hover { - background-color: #3a3a3a; + background-color: var(--settings-hover); } &.active { - background-color: #3c3c3c; + background-color: var(--settings-hover); border-left-color: #4a9eff; font-weight: 500; } @@ -183,8 +170,8 @@ const goBackToEditor = async () => { .settings-footer { padding: 12px 16px 16px 16px; - border-top: 1px solid #444444; - background-color: #2d2d2d; + border-top: 1px solid var(--settings-border); + background-color: var(--settings-card-bg); .memory-info-section { display: flex; @@ -193,7 +180,7 @@ const goBackToEditor = async () => { .section-title { font-size: 10px; - color: #777777; + color: var(--settings-text-secondary); font-weight: 500; margin-bottom: 0; text-transform: uppercase; @@ -206,36 +193,11 @@ const goBackToEditor = async () => { .settings-content { flex: 1; height: 100%; - padding: 24px; + padding: 24px 24px 48px 24px; overflow-y: auto; - background-color: #2a2a2a; - - &::-webkit-scrollbar { - width: 10px; - } - - &::-webkit-scrollbar-track { - background: #2a2a2a; - } - - &::-webkit-scrollbar-thumb { - background-color: #555555; - border-radius: 5px; - border: 2px solid #2a2a2a; - } + background-color: var(--settings-bg); } } -// 自定义变量 -:root { - --border-color: #444444; - --hover-color: #3a3a3a; - --active-bg: #3c3c3c; - --accent-color: #4a9eff; - --bg-primary: #2a2a2a; - --bg-secondary: #333333; - --text-primary: #e0e0e0; - --text-secondary: #a0a0a0; - --text-muted: #777777; -} + \ No newline at end of file diff --git a/frontend/src/views/settings/components/SettingItem.vue b/frontend/src/views/settings/components/SettingItem.vue index 7dbca22..0564e86 100644 --- a/frontend/src/views/settings/components/SettingItem.vue +++ b/frontend/src/views/settings/components/SettingItem.vue @@ -21,11 +21,12 @@ defineProps<{ .setting-item { display: flex; padding: 14px 0; - border-bottom: 1px solid #444444; + border-bottom: 1px solid var(--settings-border); transition: background-color 0.15s ease; &:hover { - background-color: rgba(255, 255, 255, 0.03); + background-color: var(--settings-hover); + opacity: 0.8; } &:last-child { @@ -40,12 +41,12 @@ defineProps<{ font-size: 14px; font-weight: 500; margin-bottom: 6px; - color: #e0e0e0; + color: var(--settings-text); } .setting-description { font-size: 12px; - color: #a0a0a0; + color: var(--settings-text-secondary); line-height: 1.5; } } diff --git a/frontend/src/views/settings/components/SettingSection.vue b/frontend/src/views/settings/components/SettingSection.vue index ac96e65..5b948b1 100644 --- a/frontend/src/views/settings/components/SettingSection.vue +++ b/frontend/src/views/settings/components/SettingSection.vue @@ -16,19 +16,20 @@ defineProps<{