mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-05 12:07:22 -04:00
133 lines
4.3 KiB
Vue
133 lines
4.3 KiB
Vue
<template>
|
|
<ListInput v-model="v" :prototype="prototype" :group="group" :maxitems="maxitems">
|
|
<template #default="s">
|
|
<button
|
|
type="button"
|
|
:class="['btn', 'btn-outline-secondary', showOpinionSelector === s.i ? 'btn-secondary text-white border' : validate(s.val) ? 'btn-outline-danger' : '']"
|
|
@click="showOpinionSelector = showOpinionSelector === s.i ? false : s.i"
|
|
>
|
|
<Icon :v="getIcon(s.val.opinion)" />
|
|
</button>
|
|
<input v-model="s.val.value" :class="['form-control', 'mw-input', validate(s.val) ? 'border-danger' : '']" required :maxlength="maxlength" @keyup="s.update(s.val)">
|
|
<slot name="additional" :val="s.val"></slot>
|
|
|
|
<div v-if="showOpinionSelector === s.i" class="bg-light border rounded hanging shadow shadow-lg">
|
|
<ul class="list-unstyled icons-list p-1 text-center mb-0">
|
|
<li
|
|
v-for="(opinion, key) in opinions"
|
|
class="list-inline-item"
|
|
>
|
|
<button
|
|
type="button"
|
|
:class="['btn', key === s.val.opinion ? 'btn-dark' : 'btn-outline-dark', 'border-0 my-2']"
|
|
@click="s.val.opinion = key; showOpinionSelector = false"
|
|
>
|
|
<Icon :v="opinion.icon" />
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<ul v-if="customOpinions.length" class="list-unstyled icons-list p-1 text-center mb-0">
|
|
<li
|
|
v-for="opinion in customOpinions"
|
|
class="list-inline-item"
|
|
>
|
|
<button
|
|
type="button"
|
|
:class="['btn', opinion.icon === s.val.opinion ? 'btn-dark' : 'btn-outline-dark', 'border-0 my-2']"
|
|
@click="s.val.opinion = opinion.icon; showOpinionSelector = false"
|
|
>
|
|
<Icon :v="opinion.icon" />
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
<template #validation="s">
|
|
<p v-if="validate(s.val)" class="small text-danger">
|
|
<Icon v="exclamation-triangle" />
|
|
<span class="ml-1">{{ $t(validate(s.val)) }}</span>
|
|
</p>
|
|
</template>
|
|
</ListInput>
|
|
</template>
|
|
|
|
<script>
|
|
import opinions from '../src/opinions.ts';
|
|
|
|
export default {
|
|
props: {
|
|
modelValue: {},
|
|
prototype: {
|
|
default: () => {
|
|
return { value: '', opinion: 'meh' };
|
|
},
|
|
type: Object,
|
|
},
|
|
group: {},
|
|
validation: {},
|
|
customOpinions: {
|
|
default: () => {
|
|
return [];
|
|
},
|
|
type: Array,
|
|
},
|
|
maxlength: { default: 32 },
|
|
maxitems: { default: null, type: Number },
|
|
},
|
|
emits: ['update:modelValue'],
|
|
data() {
|
|
return {
|
|
v: this.modelValue,
|
|
showOpinionSelector: false,
|
|
opinions,
|
|
};
|
|
},
|
|
watch: {
|
|
v() {
|
|
this.$emit('update:modelValue', this.v);
|
|
},
|
|
modelValue(v) {
|
|
this.v = v;
|
|
},
|
|
},
|
|
methods: {
|
|
validate(val) {
|
|
if (!this.getIcon(val.opinion)) {
|
|
return 'profile.opinions.validation.invalidOpinion';
|
|
}
|
|
|
|
if (!val.value) {
|
|
return null;
|
|
}
|
|
|
|
return this.validation && this.validation(val.value);
|
|
},
|
|
getIcon(opinion) {
|
|
if (Object.hasOwn(opinions, opinion)) {
|
|
return opinions[opinion].icon;
|
|
}
|
|
for (const op of this.customOpinions) {
|
|
if (op.icon === opinion) {
|
|
return opinion;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "assets/variables";
|
|
|
|
.hanging {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
width: 100%;
|
|
max-width: 300px;
|
|
z-index: 5000;
|
|
}
|
|
</style>
|