Skip to content

Commit 2e5c291

Browse files
authored
feat(web-ui): replace dropdown menus with checkboxes (#3455)
1 parent 65878af commit 2e5c291

File tree

14 files changed

+363
-273
lines changed

14 files changed

+363
-273
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<script setup>
2+
const model = defineModel({ required: true });
3+
const slots = defineSlots();
4+
const props = defineProps({
5+
class: {
6+
type: String,
7+
default: ""
8+
},
9+
desc: {
10+
type: String,
11+
default: null
12+
},
13+
id: {
14+
type: String,
15+
required: true
16+
},
17+
label: {
18+
type: String,
19+
default: null
20+
},
21+
localePrefix: {
22+
type: String,
23+
default: "missing-prefix"
24+
},
25+
default: {
26+
type: undefined,
27+
default: null,
28+
}
29+
});
30+
31+
// Add the mandatory class values
32+
const extendedClassStr = (() => {
33+
let values = props.class.split(" ");
34+
if (!values.includes("form-check")) {
35+
values.push("form-check");
36+
}
37+
return values.join(" ");
38+
})();
39+
40+
// Map the value to boolean representation if possible, otherwise return null.
41+
const mapToBoolRepresentation = (value) => {
42+
// Try literal values first
43+
if (value === true || value === false) {
44+
return { possibleValues: [true, false], value: value };
45+
}
46+
if (value === 1 || value === 0) {
47+
return { possibleValues: [1, 0], value: value };
48+
}
49+
50+
const stringPairs = [
51+
["true", "false"],
52+
["1", "0"],
53+
["enabled", "disabled"],
54+
["enable", "disable"],
55+
["yes", "no"],
56+
["on", "off"]
57+
];
58+
59+
value = `${value}`.toLowerCase().trim();
60+
for (const pair of stringPairs) {
61+
if (value === pair[0] || value === pair[1]) {
62+
return { possibleValues: pair, value: value };
63+
}
64+
}
65+
66+
return null;
67+
}
68+
69+
// Determine the true/false values for the checkbox
70+
const checkboxValues = (() => {
71+
const mappedValues = (() => {
72+
const boolValues = mapToBoolRepresentation(model.value);
73+
if (boolValues !== null) {
74+
return boolValues.possibleValues;
75+
}
76+
77+
// Return fallback if nothing matches
78+
console.error(`Checkbox value ${model.value} did not match any acceptable pattern!`);
79+
return ["true", "false"];
80+
})();
81+
82+
return { truthy: mappedValues[0], falsy: mappedValues[1] };
83+
})();
84+
const parsedDefaultPropValue = (() => {
85+
const boolValues = mapToBoolRepresentation(props.default);
86+
if (boolValues !== null) {
87+
// Convert truthy to true/false.
88+
return boolValues.value === boolValues.possibleValues[0];
89+
}
90+
91+
return null;
92+
})();
93+
94+
const labelField = props.label ?? `${props.localePrefix}.${props.id}`;
95+
const descField = props.desc ?? `${props.localePrefix}.${props.id}_desc`;
96+
const showDesc = props.desc !== "" || Object.entries(slots).length > 0;
97+
const showDefValue = parsedDefaultPropValue !== null;
98+
const defValue = parsedDefaultPropValue ? "_common.enabled_def_cbox" : "_common.disabled_def_cbox";
99+
</script>
100+
101+
<template>
102+
<div :class="extendedClassStr">
103+
<label :for="props.id" :class="`form-check-label${showDesc ? ' mb-2' : ''}`">
104+
{{ $t(labelField) }}
105+
<div class="mt-0 form-text" v-if="showDefValue">
106+
{{ $t(defValue) }}
107+
</div>
108+
</label>
109+
<input type="checkbox"
110+
class="form-check-input"
111+
:id="props.id"
112+
v-model="model"
113+
:true-value="checkboxValues.truthy"
114+
:false-value="checkboxValues.falsy" />
115+
<div class="form-text" v-if="showDesc">
116+
{{ $t(descField) }}
117+
<slot></slot>
118+
</div>
119+
</div>
120+
</template>

src_assets/common/assets/web/apps.html

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,13 @@ <h1>{{ $t('apps.applications_title') }}</h1>
116116
<div id="appOutputHelp" class="form-text">{{ $t('apps.output_desc') }}</div>
117117
</div>
118118
<!-- prep-cmd -->
119-
<div class="mb-3">
120-
<label for="excludeGlobalPrep" class="form-label">{{ $t('apps.global_prep_name') }}</label>
121-
<select id="excludeGlobalPrep" class="form-select" v-model="editForm['exclude-global-prep-cmd']">
122-
<option v-for="val in [false, true]" :value="val">
123-
{{ !val ? $t('_common.enabled') : $t('_common.disabled') }}
124-
</option>
125-
</select>
126-
<div class="form-text">{{ $t('apps.global_prep_desc') }}</div>
127-
</div>
119+
<Checkbox class="mb-3"
120+
id="excludeGlobalPrep"
121+
label="apps.global_prep_name"
122+
desc="apps.global_prep_desc"
123+
v-model="editForm['exclude-global-prep-cmd']"
124+
default="true"
125+
></Checkbox>
128126
<div class="mb-3">
129127
<label for="appName" class="form-label">{{ $t('apps.cmd_prep_name') }}</label>
130128
<div class="form-text">{{ $t('apps.cmd_prep_desc') }}</div>
@@ -152,12 +150,12 @@ <h1>{{ $t('apps.applications_title') }}</h1>
152150
<td>
153151
<input type="text" class="form-control monospace" v-model="c.undo" />
154152
</td>
155-
<td v-if="platform === 'windows'">
156-
<div class="form-check">
157-
<input type="checkbox" class="form-check-input" :id="'prep-cmd-admin-' + i" v-model="c.elevated"
158-
true-value="true" false-value="false" />
159-
<label :for="'prep-cmd-admin-' + i" class="form-check-label">{{ $t('_common.elevated') }}</label>
160-
</div>
153+
<td v-if="platform === 'windows'" class="align-middle">
154+
<Checkbox :id="'prep-cmd-admin-' + i"
155+
label="_common.elevated"
156+
desc=""
157+
v-model="c.elevated"
158+
></Checkbox>
161159
</td>
162160
<td>
163161
<button class="btn btn-danger" @click="editForm['prep-cmd'].splice(i,1)">
@@ -208,26 +206,30 @@ <h1>{{ $t('apps.applications_title') }}</h1>
208206
<div id="appWorkingDirHelp" class="form-text">{{ $t('apps.working_dir_desc') }}</div>
209207
</div>
210208
<!-- elevation -->
211-
<div class="mb-3 form-check" v-if="platform === 'windows'">
212-
<label for="appElevation" class="form-check-label">{{ $t('_common.run_as') }}</label>
213-
<input type="checkbox" class="form-check-input" id="appElevation" v-model="editForm.elevated"
214-
true-value="true" false-value="false" />
215-
<div class="form-text">{{ $t('apps.run_as_desc') }}</div>
216-
</div>
209+
<Checkbox v-if="platform === 'windows'"
210+
class="mb-3"
211+
id="appElevation"
212+
label="_common.run_as"
213+
desc="apps.run_as_desc"
214+
v-model="editForm.elevated"
215+
default="false"
216+
></Checkbox>
217217
<!-- auto-detach -->
218-
<div class="mb-3 form-check">
219-
<label for="autoDetach" class="form-check-label">{{ $t('apps.auto_detach') }}</label>
220-
<input type="checkbox" class="form-check-input" id="autoDetach" v-model="editForm['auto-detach']"
221-
true-value="true" false-value="false" />
222-
<div class="form-text">{{ $t('apps.auto_detach_desc') }}</div>
223-
</div>
218+
<Checkbox class="mb-3"
219+
id="autoDetach"
220+
label="apps.auto_detach"
221+
desc="apps.auto_detach_desc"
222+
v-model="editForm['auto-detach']"
223+
default="true"
224+
></Checkbox>
224225
<!-- wait for all processes -->
225-
<div class="mb-3 form-check">
226-
<label for="waitAll" class="form-check-label">{{ $t('apps.wait_all') }}</label>
227-
<input type="checkbox" class="form-check-input" id="waitAll" v-model="editForm['wait-all']"
228-
true-value="true" false-value="false" />
229-
<div class="form-text">{{ $t('apps.wait_all_desc') }}</div>
230-
</div>
226+
<Checkbox class="mb-3"
227+
id="waitAll"
228+
label="apps.wait_all"
229+
desc="apps.wait_all_desc"
230+
v-model="editForm['wait-all']"
231+
default="true"
232+
></Checkbox>
231233
<!-- exit timeout -->
232234
<div class="mb-3">
233235
<label for="exitTimeout" class="form-label">{{ $t('apps.exit_timeout') }}</label>
@@ -358,11 +360,13 @@ <h4>{{ $t('apps.env_vars_about') }}</h4>
358360
import { createApp } from 'vue'
359361
import { initApp } from './init'
360362
import Navbar from './Navbar.vue'
363+
import Checkbox from './Checkbox.vue'
361364
import { Dropdown } from 'bootstrap/dist/js/bootstrap'
362365

363366
const app = createApp({
364367
components: {
365-
Navbar
368+
Navbar,
369+
Checkbox
366370
},
367371
data() {
368372
return {
@@ -415,9 +419,9 @@ <h4>{{ $t('apps.env_vars_about') }}</h4>
415419
if (this.editForm["detached"] === undefined)
416420
this.editForm["detached"] = [];
417421
if (this.editForm["exclude-global-prep-cmd"] === undefined)
418-
this.editForm["exclude-global-prep-cmd"] = [];
422+
this.editForm["exclude-global-prep-cmd"] = false;
419423
if (this.editForm["elevated"] === undefined && this.platform === 'windows') {
420-
this.editForm["elevated"] = [];
424+
this.editForm["elevated"] = false;
421425
}
422426
if (this.editForm["auto-detach"] === undefined) {
423427
this.editForm["auto-detach"] = true;

src_assets/common/assets/web/configs/tabs/AudioVideo.vue

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import AdapterNameSelector from './audiovideo/AdapterNameSelector.vue'
66
import DisplayOutputSelector from './audiovideo/DisplayOutputSelector.vue'
77
import DisplayDeviceOptions from "./audiovideo/DisplayDeviceOptions.vue";
88
import DisplayModesSettings from "./audiovideo/DisplayModesSettings.vue";
9+
import Checkbox from "../../Checkbox.vue";
910
1011
const props = defineProps([
1112
'platform',
@@ -54,14 +55,12 @@ const config = ref(props.config)
5455
</div>
5556

5657
<!-- Install Steam Audio Drivers -->
57-
<div class="mb-3">
58-
<label for="install_steam_audio_drivers" class="form-label">{{ $t('config.install_steam_audio_drivers') }}</label>
59-
<select id="install_steam_audio_drivers" class="form-select" v-model="config.install_steam_audio_drivers">
60-
<option value="disabled">{{ $t('_common.disabled') }}</option>
61-
<option value="enabled">{{ $t('_common.enabled_def') }}</option>
62-
</select>
63-
<div class="form-text">{{ $t('config.install_steam_audio_drivers_desc') }}</div>
64-
</div>
58+
<Checkbox class="mb-3"
59+
id="install_steam_audio_drivers"
60+
locale-prefix="config"
61+
v-model="config.install_steam_audio_drivers"
62+
default="true"
63+
></Checkbox>
6564
</template>
6665
</PlatformLayout>
6766

src_assets/common/assets/web/configs/tabs/General.vue

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup>
2+
import Checkbox from '../../Checkbox.vue'
23
import { ref } from 'vue'
34
45
const props = defineProps({
@@ -100,12 +101,12 @@ function removeCmd(index) {
100101
<td>
101102
<input type="text" class="form-control monospace" v-model="c.undo" />
102103
</td>
103-
<td v-if="platform === 'windows'">
104-
<div class="form-check">
105-
<input type="checkbox" class="form-check-input" :id="'prep-cmd-admin-' + i" v-model="c.elevated"
106-
true-value="true" false-value="false" />
107-
<label :for="'prep-cmd-admin-' + i" class="form-check-label">{{ $t('config.elevated') }}</label>
108-
</div>
104+
<td v-if="platform === 'windows'" class="align-middle">
105+
<Checkbox :id="'prep-cmd-admin-' + i"
106+
label="_common.elevated"
107+
desc=""
108+
v-model="c.elevated"
109+
></Checkbox>
109110
</td>
110111
<td>
111112
<button class="btn btn-danger" @click="removeCmd(i)">
@@ -124,14 +125,12 @@ function removeCmd(index) {
124125
</div>
125126

126127
<!-- Notify Pre-Releases -->
127-
<div class="mb-3">
128-
<label for="notify_pre_releases" class="form-label">{{ $t('config.notify_pre_releases') }}</label>
129-
<select id="notify_pre_releases" class="form-select" v-model="config.notify_pre_releases">
130-
<option value="disabled">{{ $t('_common.disabled') }}</option>
131-
<option value="enabled">{{ $t('_common.enabled') }}</option>
132-
</select>
133-
<div class="form-text">{{ $t('config.notify_pre_releases_desc') }}</div>
134-
</div>
128+
<Checkbox class="mb-3"
129+
id="notify_pre_releases"
130+
locale-prefix="config"
131+
v-model="config.notify_pre_releases"
132+
default="false"
133+
></Checkbox>
135134
</div>
136135
</template>
137136

0 commit comments

Comments
 (0)