Skip to content

Commit

Permalink
Add badge display type to select fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Fajfa committed Jan 20, 2025
1 parent 31d38a2 commit 65be113
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 53 deletions.
110 changes: 94 additions & 16 deletions client/web/compose/src/components/ModuleFields/Configurator/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@
</b-form-checkbox>
</b-form-group>

<b-form-group
:label="$t('kind.select.displayType.label')"
label-class="text-primary"
>
<b-form-radio-group
v-model="f.options.displayType"
:options="displayOptions"
stacked
/>
</b-form-group>

<b-form-group
:label="$t('kind.select.optionsLabel')"
label-class="text-primary"
Expand All @@ -36,6 +47,7 @@
<b-table-simple
borderless
small
responsive
>
<b-thead>
<b-tr>
Expand All @@ -45,13 +57,27 @@
class="text-primary"
style="min-width: 200px;"
>
{{ $t('kind.select.optionValuePlaceholder') }}
{{ $t('kind.select.options.value') }}
</b-th>

<b-th
class="text-primary"
>
{{ $t('kind.select.optionLabelPlaceholder') }}
{{ $t('kind.select.options.label') }}
</b-th>

<b-th
v-if="f.options.displayType === 'badge'"
class="text-primary"
>
{{ $t('kind.select.options.style.textColor') }}
</b-th>

<b-th
v-if="f.options.displayType === 'badge'"
class="text-primary"
>
{{ $t('kind.select.options.style.backgroundColor') }}
</b-th>

<b-th />
Expand Down Expand Up @@ -80,8 +106,7 @@
<b-form-input
v-model.trim="f.options.options[index].value"
plain
size="sm"
:placeholder="$t('kind.select.optionValuePlaceholder')"
:placeholder="$t('kind.select.options.value')"
:state="f.options.options[index].value ? null : false"
/>
</b-td>
Expand All @@ -92,8 +117,7 @@
<b-form-input
v-model.trim="f.options.options[index].text"
plain
size="sm"
:placeholder="$t('kind.select.optionLabelPlaceholder')"
:placeholder="$t('kind.select.options.label')"
:state="f.options.options[index].text ? null : false"
/>

Expand All @@ -110,6 +134,39 @@
</b-input-group>
</b-td>

<b-td
v-if="f.options.displayType === 'badge'"
style="min-width: 120px;"
>
<c-input-color-picker
v-model="f.options.options[index].style.textColor"
:default-value="defaultTextColor"
:theme-settings="themeSettings"
:translations="{
modalTitle: $t('kind.select.options.style.textColor'),
cancelBtnLabel: $t('general:label.cancel'),
saveBtnLabel: $t('general:label.saveAndClose')
}"
/>
</b-td>

<b-td
v-if="f.options.displayType === 'badge'"
style="min-width: 130px;"
>
<c-input-color-picker
v-model="f.options.options[index].style.backgroundColor"
:default-value="defaultBackgroundColor"
:theme-settings="themeSettings"
:translations="{
modalTitle: $t('kind.select.options.style.backgroundColor'),
defaultBtnLabel: $t('general:label.default'),
cancelBtnLabel: $t('general:label.cancel'),
saveBtnLabel: $t('general:label.saveAndClose')
}"
/>
</b-td>

<b-td class="align-middle text-right">
<c-input-confirm
show-icon
Expand All @@ -130,6 +187,8 @@ import base from './base'
import Draggable from 'vuedraggable'
import { NoID } from '@cortezaproject/corteza-js'
import FieldSelectTranslator from 'corteza-webapp-compose/src/components/Admin/Module/FieldSelectTranslator'
import { components } from '@cortezaproject/corteza-vue'
const { CInputColorPicker } = components
export default {
i18nOptions: {
Expand All @@ -139,6 +198,7 @@ export default {
components: {
FieldSelectTranslator,
Draggable,
CInputColorPicker,
},
extends: base,
Expand All @@ -147,7 +207,7 @@ export default {
return {
newOption: { value: undefined, text: undefined, new: true },
options: [
selectTypes: [
{ text: this.$t('kind.select.optionType.default'), value: 'default', allowDuplicates: true },
{ text: this.$t('kind.select.optionType.multiple'), value: 'multiple', onlyMulti: true },
{ text: this.$t('kind.select.optionType.each'), value: 'each', allowDuplicates: true, onlyMulti: true },
Expand Down Expand Up @@ -182,7 +242,7 @@ export default {
},
selectOptions () {
const selectOptions = this.options.map((o) => {
const selectOptions = this.selectTypes.map((o) => {
if (o.value === 'list') {
o.text = this.$t(`kind.select.optionType.${this.f.isMulti ? 'checkbox' : 'radio'}`)
}
Expand All @@ -197,12 +257,31 @@ export default {
return selectOptions.filter(({ onlyMulti }) => !onlyMulti)
},
displayOptions () {
return [
{ text: this.$t('kind.select.displayType.text'), value: 'text' },
{ text: this.$t('kind.select.displayType.badge'), value: 'badge' },
]
},
shouldAllowDuplicates () {
if (!this.f.isMulti) return false
const { allowDuplicates } = this.options.find(({ value }) => value === this.f.options.selectType) || {}
const { allowDuplicates } = this.selectTypes.find(({ value }) => value === this.f.options.selectType) || {}
return !!allowDuplicates
},
themeSettings () {
return this.$Settings.get('ui.studio.themes', [])
},
defaultTextColor () {
return getComputedStyle(document.documentElement).getPropertyValue('--dark')
},
defaultBackgroundColor () {
return getComputedStyle(document.documentElement).getPropertyValue('--extra-light')
},
},
created () {
Expand All @@ -219,23 +298,22 @@ export default {
methods: {
handleAddOption () {
this.f.options.options.push({
value: undefined,
text: undefined,
new: true,
})
const option = this.f.createSelectOption()
option.new = true
this.f.options.options.push(option)
},
updateIsUniqueMultiValue (value) {
const { allowDuplicates = false } = this.options.find(({ value: v }) => v === value) || {}
const { allowDuplicates = false } = this.selectTypes.find(({ value: v }) => v === value) || {}
if (!allowDuplicates) {
this.f.options.isUniqueMultiValue = true
}
},
setDefaultValues () {
this.newOption = {}
this.options = []
this.selectTypes = []
},
},
}
Expand Down
48 changes: 42 additions & 6 deletions client/web/compose/src/components/ModuleFields/Editor/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,23 @@

<template v-if="field.isMulti">
<template v-if="field.options.selectType === 'list'">
<b-form-checkbox-group
v-model="value"
:options="selectOptions"
stacked
/>
<div>
<b-form-checkbox
v-for="option in selectOptions"
:key="option.value"
v-model="value"
:value="option.value"
class="d-block mb-1"
>
<span
class="pointer"
:class="{ 'badge badge-pill': field.options.displayType === 'badge' }"
:style="getOptionStyle(option.value)"
>
{{ option.text }}
</span>
</b-form-checkbox>
</div>

<errors :errors="errors" />
</template>
Expand All @@ -58,6 +70,7 @@
:reduce="o => o.value"
:selectable="isSelectable"
label="text"
:badge="field.options.displayType === 'badge'"
@input="selectChange"
/>

Expand All @@ -70,6 +83,7 @@
:selectable="isSelectable"
label="text"
multiple
:badge="field.options.displayType === 'badge'"
/>
</template>

Expand All @@ -82,10 +96,17 @@
:placeholder="$t('kind.select.placeholder')"
:selectable="isSelectable"
label="text"
:badge="field.options.displayType === 'badge'"
@input="setMultiValue($event, ctx.index)"
/>

<span v-else>{{ findLabel(value[ctx.index]) }}</span>
<span
v-else
:class="{ 'badge badge-pill': field.options.displayType === 'badge' }"
:style="getOptionStyle(value[ctx.index])"
>
{{ findLabel(value[ctx.index]) }}
</span>
</template>
</multi>
</template>
Expand All @@ -101,6 +122,7 @@
:reduce="o => o.value"
:selectable="isSelectable"
label="text"
:badge="field.options.displayType === 'badge'"
/>

<b-form-radio-group
Expand Down Expand Up @@ -155,6 +177,20 @@ export default {
return this.value !== value
}
},
getOptionStyle (v) {
const style = {}
if (this.field.options.displayType === 'badge') {
const opt = this.selectOptions.find(({ value }) => value === v) || { style: {} }
style.fontSize = '0.9rem'
style.color = opt.style.textColor || 'var(--dark)'
style.backgroundColor = opt.style.backgroundColor || 'var(--extra-light)'
}
return style
},
},
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div
v-for="(v, index) of val"
:key="index"
class="d-flex w-100 align-items-center mb-1 px-2"
class="d-flex w-100 align-items-center mb-2 px-1"
>
<font-awesome-icon
v-b-tooltip.noninteractive.hover="{ title: $t('tooltip.dragAndDrop'), container: '#body' }"
Expand Down
58 changes: 46 additions & 12 deletions client/web/compose/src/components/ModuleFields/Viewer/Select.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
<template>
<div>
<span
v-for="(v, index) of value"
:key="index"
:class="{ 'd-block mb-2': field.options.multiDelimiter === '\n' }"
>
<span
:class="{ 'badge badge-pill': field.options.displayType === 'badge' }"
:style="v.style"
>
{{ v.text }}
</span>

{{ index !== value.length - 1 ? field.options.multiDelimiter : '' }}
</span>

<errors :errors="errors" />
</div>
</template>

<script>
import base from './base'
/**
* Helper to find a label for the given value
* @param {String} v Value in question
* @param {Array<Object>} options Available options
* @returns {String|undefined}
*/
function findLabel (v, options) {
return (options.find(({ value }) => value === v) || {}).text
}
export default {
extends: base,
Expand All @@ -31,11 +42,34 @@ export default {
v = []
}
return v.map(v => findLabel(v, this.field.options.options) || v)
return v.map(v => this.resolveValue(v) || v).filter(Boolean)
} else {
return findLabel(v, this.field.options.options) || v
return [this.resolveValue(v) || v].filter(Boolean)
}
},
},
methods: {
resolveValue (v) {
const opt = this.field.options.options.find(({ value }) => value === v) || { text: v }
return {
text: opt.text,
style: this.getOptionStyle(opt),
}
},
getOptionStyle (opt) {
const style = {}
if (this.field.options.displayType === 'badge') {
style.fontSize = '0.9rem'
style.color = opt.style.textColor || 'var(--dark)'
style.backgroundColor = opt.style.backgroundColor || 'var(--extra-light)'
}
return style
},
},
}
</script>
Loading

0 comments on commit 65be113

Please sign in to comment.