feat(theme): implement comprehensive theme management system
Add full theme support with light, dark, and system modes, including: - Theme store using Pinia for state management - useTheme composable for reactive theme handling - Theme setting UI in settings page - Enhanced CSS variable system with Tailwind integration - IPC communication for theme persistence - Internationalization support for theme texts - System theme detection and auto-switching The implementation follows ClawX's architecture while adapting to Vue 3 and zn-ai's existing infrastructure.
This commit is contained in:
@@ -1,18 +1,58 @@
|
||||
<template>
|
||||
<div class="flex-1 h-full p-[20px] select-none">
|
||||
<TitleSection title="账号设置" desc="请关联PMS和渠道房型名称,可使用智能对标" />
|
||||
<TitleSection title="通用设置" desc="配置应用程序的外观、语言和版本信息" />
|
||||
|
||||
<!-- 主题设置 -->
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE]">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] mr-[24px]">当前版本</div>
|
||||
<div class="value text-[16px] font-medium text-[#171717]">1.0.0</div>
|
||||
<el-button type="text" class="ml-auto">检查更新</el-button>
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE] dark:border-gray-700">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px]">主题设置</div>
|
||||
<div class="value flex-1">
|
||||
<div class="space-y-4">
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<!-- 浅色主题 -->
|
||||
<button
|
||||
class="theme-button px-5 py-2.5 rounded-full border text-[14px] font-medium transition-all duration-200 flex items-center gap-2"
|
||||
:class="[
|
||||
currentTheme === 'light'
|
||||
? 'bg-primary-50 dark:bg-primary-900/20 border-primary-500 dark:border-primary-400 text-primary-700 dark:text-primary-300'
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('light')">
|
||||
<RiSunLine class="w-4 h-4" />
|
||||
浅色
|
||||
</button>
|
||||
|
||||
<!-- 深色主题 -->
|
||||
<button
|
||||
class="theme-button px-5 py-2.5 rounded-full border text-[14px] font-medium transition-all duration-200 flex items-center gap-2"
|
||||
:class="[
|
||||
currentTheme === 'dark'
|
||||
? 'bg-primary-50 dark:bg-primary-900/20 border-primary-500 dark:border-primary-400 text-primary-700 dark:text-primary-300'
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('dark')">
|
||||
<RiMoonLine class="w-4 h-4" />
|
||||
深色
|
||||
</button>
|
||||
|
||||
<!-- 跟随系统 -->
|
||||
<button
|
||||
class="theme-button px-5 py-2.5 rounded-full border text-[14px] font-medium transition-all duration-200 flex items-center gap-2"
|
||||
:class="[
|
||||
currentTheme === 'system'
|
||||
? 'bg-primary-50 dark:bg-primary-900/20 border-primary-500 dark:border-primary-400 text-primary-700 dark:text-primary-300'
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('system')">
|
||||
<RiComputerLine class="w-4 h-4" />
|
||||
跟随系统
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 语言设置 -->
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE]">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] mr-[24px]">语言设置</div>
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE] dark:border-gray-700">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px]">语言设置</div>
|
||||
<div class="value flex gap-2">
|
||||
<el-button v-for="lang in supportedLanguages" :key="lang.code"
|
||||
:type="currentLanguage === lang.code ? 'primary' : 'text'" @click="handleLanguageChange(lang.code)"
|
||||
@@ -21,14 +61,40 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 版本信息 -->
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE] dark:border-gray-700">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px]">当前版本</div>
|
||||
<div class="value text-[16px] font-medium text-[#171717] dark:text-gray-100">1.0.0</div>
|
||||
<el-button type="text" class="ml-auto">检查更新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import TitleSection from '@src/components/TitleSection/index.vue'
|
||||
import { setLanguage, getLanguage, type LanguageType } from '@src/i18n'
|
||||
import { useThemeStore } from '@src/stores/theme'
|
||||
import { RiSunLine, RiMoonLine, RiComputerLine } from '@remixicon/vue'
|
||||
|
||||
// 主题状态管理
|
||||
const themeStore = useThemeStore()
|
||||
const currentTheme = computed(() => themeStore.theme)
|
||||
|
||||
// 主题切换处理
|
||||
const handleThemeChange = async (theme: 'light' | 'dark' | 'system') => {
|
||||
try {
|
||||
console.log('切换主题到:', theme)
|
||||
await themeStore.setTheme(theme)
|
||||
console.log('主题切换成功:', theme)
|
||||
} catch (error) {
|
||||
console.error('主题切换失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 语言设置
|
||||
const supportedLanguages = [
|
||||
{ code: 'zh', label: '中文' },
|
||||
{ code: 'en', label: 'English' },
|
||||
@@ -46,4 +112,19 @@ const handleLanguageChange = async (langCode: LanguageType) => {
|
||||
await setLanguage(langCode)
|
||||
currentLanguage.value = langCode
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.theme-button {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition-property: background-color, border-color, color, transform;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.theme-button:focus-visible {
|
||||
outline: 2px solid var(--primary-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user