1
- <script setup lang="ts">
2
- import { computed , h , ref } from ' vue'
1
+ <script lang="ts">
2
+ import { computed , h , ref , watchEffect } from ' vue'
3
3
import type { MenuOption } from ' naive-ui'
4
- import { NLayout , NLayoutSider , NMenu } from ' naive-ui'
4
+ import { NButton , NCheckbox , NCheckboxGroup , NFlex , NLayout , NLayoutFooter , NLayoutSider , NMenu } from ' naive-ui'
5
5
import MinusButton from ' ./MinusButton.vue'
6
6
import PlusButton from ' ./PlusButton.vue'
7
7
8
+ const languageName = new Intl .DisplayNames (navigator .language , { type: ' language' })
9
+ </script >
10
+
11
+ <script setup lang="ts">
8
12
const props = defineProps <{
9
13
inputMethod: string
10
14
inputMethods: {
@@ -47,6 +51,73 @@ function labelWithMinus(option: MenuOption) {
47
51
}
48
52
49
53
const collapsed = ref (false )
54
+ const adding = ref (false )
55
+
56
+ const selectedLanguage = ref <string | null >(null )
57
+
58
+ const availableInputMethodOptions = ref <{
59
+ label: string
60
+ key: string
61
+ }[]>([])
62
+
63
+ let map: { [key : string ]: {
64
+ name: string
65
+ displayName: string
66
+ }[] } = {}
67
+
68
+ watchEffect (() => {
69
+ if (! adding .value ) {
70
+ return
71
+ }
72
+ map = {}
73
+ for (const im of window .fcitx .getAllInputMethods ()) {
74
+ const code = im .languageCode .replace (' _' , ' -' );
75
+ (map [code ] = map [code ] || []).push ({
76
+ name: im .name ,
77
+ displayName: im .displayName ,
78
+ })
79
+ }
80
+ availableInputMethodOptions .value = []
81
+ const sortedLanguageCodes = Object .keys (map ).sort ((a : string , b : string ) => {
82
+ if (! a ) {
83
+ return 1
84
+ }
85
+ if (! b ) {
86
+ return - 1
87
+ }
88
+ const la = languageName .of (a ) ?? a
89
+ const lb = languageName .of (b ) ?? b
90
+ if (a === la && b !== lb ) {
91
+ return 1
92
+ }
93
+ if (a !== la && b === lb ) {
94
+ return - 1
95
+ }
96
+ return la .localeCompare (lb )
97
+ })
98
+ for (const languageCode of sortedLanguageCodes ) {
99
+ availableInputMethodOptions .value .push ({
100
+ label: languageCode ? (languageName .of (languageCode ) ?? languageCode ) : languageCode ,
101
+ key: languageCode ,
102
+ })
103
+ }
104
+ })
105
+
106
+ const inputMethodsForLanguage = computed (() => {
107
+ if (! selectedLanguage .value ) {
108
+ return []
109
+ }
110
+ const enabledIMs = props .inputMethods .map (({ name }) => name )
111
+ return map [selectedLanguage .value ].filter (({ name }) => ! enabledIMs .includes (name ))
112
+ })
113
+
114
+ const imsToAdd = ref <string []>([])
115
+
116
+ function add() {
117
+ window .fcitx .setInputMethods (props .inputMethods .map (({ name }) => name ).concat (imsToAdd .value ))
118
+ window .fcitx .updateStatusArea ()
119
+ imsToAdd .value = []
120
+ }
50
121
</script >
51
122
52
123
<template >
@@ -56,22 +127,69 @@ const collapsed = ref(false)
56
127
collapse-mode =" width"
57
128
:collapsed =" collapsed"
58
129
show-trigger
130
+ style =" max-height : calc (100vh - 100px )"
59
131
@collapse =" collapsed = true"
60
132
@expand =" collapsed = false"
61
133
>
62
- <div style =" display : flex ; flex-direction : column ; justify-content : space-between ; height : 100% " >
134
+ <div v-if =" adding" >
135
+ <NMenu
136
+ v-model:value =" selectedLanguage"
137
+ :options =" availableInputMethodOptions"
138
+ />
139
+ </div >
140
+ <div
141
+ v-else
142
+ style =" display : flex ; flex-direction : column ; justify-content : space-between ; height : 100% "
143
+ >
63
144
<NMenu
64
145
v-model:value =" selectedInputMethod"
65
146
:collapsed =" collapsed"
66
147
:collapsed-width =" 0"
67
148
:options =" options"
68
149
:render-label =" labelWithMinus"
69
150
/>
70
- <PlusButton style =" align-self : flex-end " />
151
+ <PlusButton
152
+ style =" align-self : flex-end "
153
+ @click =" adding = true"
154
+ />
71
155
</div >
72
156
</NLayoutSider >
73
- <NLayout style =" min-height : 480px " >
74
- {{ selectedInputMethod }}
157
+ <NLayout style =" min-height : 480px ; max-height : calc (100vh - 100px )" >
158
+ <template v-if =" adding " >
159
+ <NLayout position =" absolute" style =" bottom : 50px ; padding : 16px 0 16px 16px " >
160
+ <NCheckboxGroup v-model:value =" imsToAdd" >
161
+ <NFlex vertical >
162
+ <NCheckbox
163
+ v-for =" im of inputMethodsForLanguage"
164
+ :key =" im.name"
165
+ :value =" im.name"
166
+ :label =" im.displayName"
167
+ />
168
+ </NFlex >
169
+ </NCheckboxGroup >
170
+ </NLayout >
171
+ <NLayoutFooter position =" absolute" >
172
+ <NFlex
173
+ justify =" end"
174
+ style =" padding : 8px "
175
+ >
176
+ <NButton secondary @click =" adding = false" >
177
+ Cancel
178
+ </NButton >
179
+ <NButton
180
+ secondary
181
+ type =" info"
182
+ :disabled =" imsToAdd.length === 0"
183
+ @click =" add"
184
+ >
185
+ Add
186
+ </NButton >
187
+ </NFlex >
188
+ </NLayoutFooter >
189
+ </template >
190
+ <div v-else >
191
+ {{ selectedInputMethod }}
192
+ </div >
75
193
</NLayout >
76
194
</NLayout >
77
195
</template >
0 commit comments