1
1
<script setup lang="ts">
2
- import { Button } from ' @/components/ui/button' ;
3
- import { Card , CardContent , CardDescription , CardHeader , CardTitle } from ' @/components/ui/card' ;
4
- import { DropdownMenu , DropdownMenuContent , DropdownMenuItem , DropdownMenuTrigger } from ' @/components/ui/dropdown-menu' ;
5
- import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from ' @/components/ui/select' ;
6
2
import { useLocale } from ' @/composables/useLocale' ;
7
3
import { router , usePage } from ' @inertiajs/vue3' ;
8
- import { Globe } from ' lucide-vue-next' ;
9
- import { computed , watch } from ' vue' ;
4
+ import { computed , defineAsyncComponent , watch } from ' vue' ;
10
5
import { useI18n } from ' vue-i18n' ;
11
6
12
7
interface Props {
13
8
display? : ' dropdown' | ' select' | ' cards' ;
14
9
}
15
10
16
- withDefaults (defineProps <Props >(), {
17
- display: ' dropdown' ,
18
- });
19
-
20
- const { t, locale } = useI18n ();
11
+ const { locale } = useI18n ();
21
12
const page = usePage ();
22
13
const { initializeLocale } = useLocale ();
23
14
24
- const availableLocales = page .props .locale .available ;
15
+ const availableLocales = ( page .props .locale as any ) .available ;
25
16
26
17
const capitalize = (s : string ) => (s ? s .charAt (0 ).toUpperCase () + s .slice (1 ) : s );
27
18
@@ -31,7 +22,7 @@ const languages = availableLocales.map((code: string) => {
31
22
});
32
23
33
24
const currentLanguage = computed (() => {
34
- return languages .find ((lang ) => lang .code === locale .value ) || languages [0 ];
25
+ return languages .find ((lang : any ) => lang .code === locale .value ) || languages [0 ];
35
26
});
36
27
37
28
watch (locale , async (newLocale , oldLocale ) => {
@@ -65,75 +56,23 @@ const syncLocaleWithBackend = async (langCode: string) => {
65
56
const switchLanguage = async (langCode : string ) => {
66
57
locale .value = langCode ;
67
58
};
68
- </script >
69
59
70
- <template >
71
- <!-- Dropdown Display (Default) -->
72
- <DropdownMenu v-if =" display === 'dropdown'" >
73
- <DropdownMenuTrigger as-child >
74
- <Button variant =" ghost" size =" icon" class =" h-8 w-8 p-0" >
75
- <Globe class =" h-4 w-4 text-foreground" />
76
- <span class =" sr-only" >{{ t('common.switchLanguage') }}</span >
77
- </Button >
78
- </DropdownMenuTrigger >
79
- <DropdownMenuContent align =" end" >
80
- <DropdownMenuItem
81
- v-for =" language in languages"
82
- :key =" language.code"
83
- @click =" switchLanguage(language.code)"
84
- :class =" { 'bg-accent': language.code === currentLanguage.code }"
85
- >
86
- {{ language.name }}
87
- </DropdownMenuItem >
88
- </DropdownMenuContent >
89
- </DropdownMenu >
60
+ // Dynamic component mapping
61
+ const componentMap = {
62
+ dropdown: defineAsyncComponent (() => import (' ./LanguageSwitcherDropdown.vue' )),
63
+ select: defineAsyncComponent (() => import (' ./LanguageSwitcherSelect.vue' )),
64
+ cards: defineAsyncComponent (() => import (' ./LanguageSwitcherCards.vue' )),
65
+ };
90
66
91
- <!-- Select Display -->
92
- <Select v-else-if =" display === 'select'" v-model =" locale" >
93
- <SelectTrigger class =" w-[180px]" >
94
- <SelectValue class =" text-foreground" >
95
- <span class =" flex items-center gap-2" >
96
- <span class =" text-foreground" >{{ currentLanguage.name }}</span >
97
- </span >
98
- </SelectValue >
99
- </SelectTrigger >
100
- <SelectContent >
101
- <SelectItem v-for =" language in languages" :key =" language.code" :value =" language.code" >
102
- <span class =" flex items-center gap-2" >
103
- <span >{{ language.name }}</span >
104
- </span >
105
- </SelectItem >
106
- </SelectContent >
107
- </Select >
67
+ const props = withDefaults (defineProps <Props >(), {
68
+ display: ' dropdown' ,
69
+ });
70
+
71
+ const currentComponent = computed (() => {
72
+ return componentMap [props .display as keyof typeof componentMap ] || componentMap .dropdown ;
73
+ });
74
+ </script >
108
75
109
- <!-- Card Display -->
110
- <Card v-else-if =" display === 'cards'" >
111
- <CardHeader >
112
- <CardTitle class =" flex items-center gap-2" >
113
- <Globe class =" h-5 w-5" />
114
- {{ t('settings.language.title') }}
115
- </CardTitle >
116
- <CardDescription >
117
- {{ t('settings.language.description') }}
118
- </CardDescription >
119
- </CardHeader >
120
- <CardContent >
121
- <div class =" grid gap-3" >
122
- <Button
123
- v-for =" language in languages"
124
- :key =" language.code"
125
- @click =" switchLanguage(language.code)"
126
- variant =" outline"
127
- :class =" ['justify-start', language.code === currentLanguage.code ? 'border-primary bg-primary/5' : 'hover:bg-muted']"
128
- >
129
- <div class =" flex w-full items-center justify-between" >
130
- <span class =" font-medium" >{{ language.name }}</span >
131
- <span v-if =" language.code === currentLanguage.code" class =" text-xs text-muted-foreground" >
132
- {{ t('settings.language.currentLanguage') }}
133
- </span >
134
- </div >
135
- </Button >
136
- </div >
137
- </CardContent >
138
- </Card >
76
+ <template >
77
+ <component :is =" currentComponent" :languages =" languages" :current-language =" currentLanguage" :locale =" locale" @switch-language =" switchLanguage" />
139
78
</template >
0 commit comments