11<script setup lang="ts">
22import AuthSetup from ' ../authForms/AuthSetup.vue' ;
33import LanguageSwitcher from ' @/components/shared/LanguageSwitcher.vue' ;
4- import { onMounted , ref } from ' vue' ;
4+ import { computed , onMounted , ref } from ' vue' ;
55import { useAuthStore } from ' @/stores/auth' ;
66import { useRouter } from ' vue-router' ;
77import { useCustomizerStore } from ' @/stores/customizer' ;
@@ -15,12 +15,23 @@ const customizer = useCustomizerStore();
1515const { tm : t } = useModuleI18n (' features/auth' );
1616const theme = useTheme ();
1717
18- function toggleTheme() {
19- const newTheme = customizer .uiTheme === ' PurpleThemeDark' ? ' PurpleTheme' : ' PurpleThemeDark' ;
20- customizer .SET_UI_THEME (newTheme );
21- theme .global .name .value = newTheme ;
18+ const themeOptions = [
19+ { mode: ' light' as const , icon: ' mdi-white-balance-sunny' , labelKey: ' theme.light' },
20+ { mode: ' dark' as const , icon: ' mdi-weather-night' , labelKey: ' theme.dark' },
21+ { mode: ' system' as const , icon: ' mdi-sync' , labelKey: ' theme.system' },
22+ ] as const ;
23+
24+ function setThemeMode(mode : ' light' | ' dark' | ' system' ) {
25+ customizer .SET_THEME_MODE (mode );
26+ theme .global .name .value = customizer .uiTheme ;
2227}
2328
29+ const currentThemeIcon = computed (() => {
30+ if (customizer .themeMode === ' dark' ) return ' mdi-weather-night' ;
31+ if (customizer .themeMode === ' system' ) return ' mdi-sync' ;
32+ return ' mdi-white-balance-sunny' ;
33+ });
34+
2435onMounted (async () => {
2536 const hasToken = authStore .has_token ();
2637
@@ -52,14 +63,55 @@ onMounted(async () => {
5263 <LanguageSwitcher />
5364 <v-divider vertical class =" mx-1"
5465 style =" height : 24px !important ; opacity : 0.9 !important ; align-self : center !important ; border-color : rgba (var (--v-theme-primary ), 0.45 ) !important ;" ></v-divider >
55- <v-btn @click =" toggleTheme" class =" theme-toggle-btn" icon variant =" text" size =" small" >
56- <v-icon size =" 18" :color =" 'rgb(var(--v-theme-primary))'" >
57- {{ customizer.uiTheme === 'PurpleThemeDark' ? 'mdi-white-balance-sunny' : 'mdi-weather-night' }}
58- </v-icon >
59- <v-tooltip activator =" parent" location =" top" >
60- {{ customizer.uiTheme === 'PurpleThemeDark' ? t('theme.switchToLight') : t('theme.switchToDark') }}
61- </v-tooltip >
62- </v-btn >
66+
67+ <!-- 主题切换下拉菜单 -->
68+ <v-menu
69+ open-on-click
70+ location =" bottom center"
71+ offset =" 6"
72+ >
73+ <template v-slot :activator =" { props: themeMenuProps } " >
74+ <v-btn
75+ v-bind =" themeMenuProps"
76+ class =" theme-toggle-btn"
77+ icon
78+ variant =" text"
79+ size =" small"
80+ >
81+ <v-icon size =" 18" :color =" 'rgb(var(--v-theme-primary))'" >
82+ {{ currentThemeIcon }}
83+ </v-icon >
84+ <v-tooltip activator =" parent" location =" top" >
85+ {{ t('theme.title') }}
86+ </v-tooltip >
87+ </v-btn >
88+ </template >
89+
90+ <v-card
91+ class =" styled-menu-card"
92+ style =" min-width : 150px "
93+ elevation =" 8"
94+ rounded =" lg"
95+ >
96+ <v-list density =" compact" class =" styled-menu-list pa-1" >
97+ <v-list-item
98+ v-for =" option in themeOptions"
99+ :key =" option.mode"
100+ @click =" setThemeMode(option.mode)"
101+ :class =" {
102+ 'styled-menu-item-active': customizer.themeMode === option.mode,
103+ }"
104+ class =" styled-menu-item"
105+ rounded =" md"
106+ >
107+ <template v-slot :prepend >
108+ <v-icon size =" 16" style =" margin-right : 8px ; opacity : 0.85 ;" >{{ option.icon }}</v-icon >
109+ </template >
110+ <v-list-item-title >{{ t(option.labelKey) }}</v-list-item-title >
111+ </v-list-item >
112+ </v-list >
113+ </v-card >
114+ </v-menu >
63115 </div >
64116 </div >
65117 <div class =" setup-title" >{{ t('setup.title') }}</div >
0 commit comments