22import type { DropdownMenuItem } from " @nuxt/ui" ;
33import type { UnlistenFn } from " @tauri-apps/api/event" ;
44import type { WebviewWindow } from " @tauri-apps/api/webviewWindow" ;
5- import type { PermissionOrgs , PermOrgItem , UserData , UserIntiInfo , LangType } from " ~/types/index" ;
5+ import type { PermissionOrgs , PermOrgItem , UserData , UserIntiInfo , LangType , ThemeType } from " ~/types/index" ;
66
77import { resolveLanguageFromCookies } from " ~/utils" ;
88import { LogicalPosition } from " @tauri-apps/api/dpi" ;
99import { useUserInfoStore } from " ~/store/modules/userInfo" ;
10+ import { useSettingManager } from " ~/composables/useSettingManager" ;
1011
1112const props = defineProps <{ collapse: boolean }>();
1213
@@ -15,10 +16,14 @@ const appConfig = useAppConfig();
1516const userInfoStore = useUserInfoStore ();
1617
1718const { isMacOS } = usePlatform ();
18- const { t, setLocale } = useI18n ();
19+ const { t, setLocale, locales } = useI18n ();
1920// prettier-ignore
2021const { loggedIn, currentSite, userMap, currentUser, currentLanguage } = storeToRefs (userInfoStore );
2122
23+ const { setLang, theme, primaryColorLight, primaryColorDark } = useSettingManager ();
24+ const { manualSetTheme, enableFollowSystem, followSystem, userTheme } = useThemeAdapter ();
25+ const { applyPrimaryColor } = useColor ();
26+
2227const inputSite = ref (" " );
2328const errorMessage = ref (" " );
2429const openModal = ref (false );
@@ -33,8 +38,89 @@ const inputRef = ref<ComponentPublicInstance | null>(null);
3338useEventBus ().on (" login" , openLoginPage );
3439
3540const normalizedInputSite = computed (() => normalizeSite (inputSite .value ));
41+ const selectedLanguage = ref <LangType >(currentLanguage .value );
42+
43+ // TODO 后续逻辑统一到一个位置
44+ const languageItems = computed (() => {
45+ const arr = (locales .value as any []) || [];
46+ return arr .map ((l : any ) => ({
47+ id: l .code || l ,
48+ label: l .name || l
49+ }));
50+ });
51+
52+ const languageChildren = computed (() => [
53+ languageItems .value .map ((item ) => ({
54+ label: item .label ,
55+ type: " checkbox" ,
56+ checked: selectedLanguage .value === (item .id as LangType ),
57+ onUpdateChecked : (checked : boolean ) => {
58+ if (! checked ) return ;
59+ handleLanguageChange (item .id as LangType );
60+ }
61+ }))
62+ ]);
63+
64+ const appearanceOptions = computed (() => [
65+ { id: " withSystem" , label: t (" Common.WithSystem" ) },
66+ { id: " light" , label: t (" Common.Light" ) },
67+ { id: " dark" , label: t (" Common.Dark" ) }
68+ ]);
69+
70+ const selectedAppearance = computed <ThemeType >({
71+ get : () => {
72+ if (followSystem .value ) return " withSystem" ;
73+
74+ const saved = (theme .value || " " ) as ThemeType ;
75+ if (saved === " dark" || saved === " light" ) return saved ;
76+
77+ const current = (userTheme .value || " " ) as ThemeType ;
78+ if (current === " dark" || current === " light" ) return current ;
79+
80+ return " light" ;
81+ },
82+ set : (id : ThemeType ) => {
83+ if (id === " withSystem" ) {
84+ void enableFollowSystem ().then (() => {
85+ useTauriEventEmit (" theme-changed" , { mode: " withSystem" });
86+ nextTick ().then (() => applyCurrentThemeColor (true ));
87+ });
88+ return ;
89+ }
90+
91+ manualSetTheme (id as any );
92+ useTauriEventEmit (" theme-changed" , { mode: id });
93+ nextTick ().then (() => applyCurrentThemeColor (true ));
94+ }
95+ });
96+
97+ const appearanceChildren = computed (() => [
98+ appearanceOptions .value .map ((opt ) => ({
99+ label: opt .label ,
100+ type: " checkbox" ,
101+ checked: selectedAppearance .value === (opt .id as ThemeType ),
102+ onUpdateChecked : (checked : boolean ) => {
103+ if (! checked ) return ;
104+ if (selectedAppearance .value !== (opt .id as ThemeType )) {
105+ selectedAppearance .value = opt .id as ThemeType ;
106+ }
107+ }
108+ }))
109+ ]);
36110
37111const profileMenuItems = computed <DropdownMenuItem [][]>(() => [
112+ [
113+ {
114+ label: t (" Common.Appearance" ),
115+ icon: " solar:palette-linear" ,
116+ children: appearanceChildren .value
117+ },
118+ {
119+ label: t (" Common.Language" ),
120+ icon: " solar:global-outline" ,
121+ children: languageChildren .value
122+ }
123+ ],
38124 [
39125 {
40126 label: t (" Login.AddAccount" ),
@@ -68,10 +154,41 @@ watch(
68154 async (lang : LangType ) => {
69155 const target = lang === " zh" ? " zh" : " en" ;
70156 await setLocale (target );
157+ if (lang && lang !== selectedLanguage .value ) {
158+ selectedLanguage .value = lang ;
159+ }
71160 },
72161 { immediate: true }
73162);
74163
164+ watch (
165+ () => userTheme .value ,
166+ () => {
167+ applyCurrentThemeColor ();
168+ }
169+ );
170+
171+ const applyCurrentThemeColor = (broadcast = false ) => {
172+ const modeNow = (userTheme .value as string ) || (selectedAppearance .value as string );
173+ const hexNow = modeNow === " dark" ? primaryColorDark .value : primaryColorLight .value ;
174+
175+ if (hexNow ) {
176+ applyPrimaryColor (hexNow );
177+ if (broadcast ) {
178+ useTauriEventEmit (" primary-color-changed" , { hex: hexNow , mode: modeNow });
179+ }
180+ }
181+ };
182+
183+ const handleLanguageChange = (code : LangType ) => {
184+ if (! code || code === selectedLanguage .value ) return ;
185+
186+ selectedLanguage .value = code ;
187+ setLang (code );
188+ userInfoStore .applyLanguageToAll (code );
189+ useTauriEventEmit (" language-changed" , { code });
190+ };
191+
75192/**
76193 * @description 标准化站点输入:去除首尾空格 + 去除末尾斜杠
77194 * @param value 站点输入
@@ -140,8 +257,12 @@ function switchAccountChildren() {
140257
141258 return {
142259 label ,
143- icon: isCurrent ? " i-lucide-check" : " i-lucide-user" ,
144- onClick : () => handleSwitchAccount (u .site )
260+ type: " checkbox" ,
261+ checked: isCurrent ,
262+ onUpdateChecked : (checked : boolean ) => {
263+ if (! checked || isCurrent ) return ;
264+ handleSwitchAccount (u .site );
265+ }
145266 } as DropdownMenuItem ;
146267 });
147268
@@ -305,6 +426,8 @@ const handleVersions = (version: string[] | string, appVersion: string) => {
305426};
306427
307428onMounted (async () => {
429+ applyCurrentThemeColor ();
430+
308431 unlistenErrorPageRef .value = await useTauriEventListen (" error-page" , (event ) => {
309432 const { status, reason } = event .payload as {
310433 status: string ;
@@ -380,7 +503,7 @@ onMounted(async () => {
380503 userInfoStore .setCurrentOrg (currentOrgData );
381504 userInfoStore .setUserLoggedIn (true );
382505
383- await setLocale (language )
506+ await setLocale (language );
384507
385508 nextTick (() => {
386509 toast .add ({
0 commit comments