From aafd19c2d2a3e8f70f03596630a16b93d2868769 Mon Sep 17 00:00:00 2001 From: VIAUD Nathan <nathan.viaud@inria.fr> Date: Tue, 23 Jan 2024 09:14:05 +0000 Subject: [PATCH] feat: add hints to form inputs --- .../forms/components/inputs/FileInput.vue | 1 - .../forms/components/inputs/GenericInput.vue | 240 +++++++++++------- .../forms/components/inputs/HtmlInput.vue | 5 +- .../forms/components/inputs/ScoreInput.vue | 1 - .../forms/components/inputs/TextAreaInput.vue | 1 - .../forms/components/inputs/TextInput.vue | 1 - .../inputs/badges/components/IconPicker.vue | 5 +- .../inputs/card/components/RadioInput.vue | 1 - .../inputs/card/components/SelectInput.vue | 1 - src/global.scss | 12 +- src/shared/interfaces/form/input.interface.ts | 1 + 11 files changed, 160 insertions(+), 109 deletions(-) diff --git a/src/features/forms/components/inputs/FileInput.vue b/src/features/forms/components/inputs/FileInput.vue index d956af51..ffe14c0c 100644 --- a/src/features/forms/components/inputs/FileInput.vue +++ b/src/features/forms/components/inputs/FileInput.vue @@ -73,7 +73,6 @@ let savedState = ''; </script> <template> - <label class="input-label" :for="id">{{ label }}</label> <div v-show="url" class="show-input"> <div class="input-file"> <input ref="fileInput" class="file" type="file" :accept="accept" @change="changeImage" /> diff --git a/src/features/forms/components/inputs/GenericInput.vue b/src/features/forms/components/inputs/GenericInput.vue index 2492874a..bad6b0f0 100644 --- a/src/features/forms/components/inputs/GenericInput.vue +++ b/src/features/forms/components/inputs/GenericInput.vue @@ -14,7 +14,7 @@ import BadgesInput from './badges/BadgesInput.vue'; import IconPicker from './badges/components/IconPicker.vue'; import ConditionInput from './badges/components/ConditionInput.vue'; import { Input, RepeatInputEvent } from '@/src/shared/interfaces'; -import { computed } from 'vue'; +import { computed, ref } from 'vue'; const props = defineProps<{ input: Input; @@ -39,103 +39,149 @@ const inputId = computed(() => { return props.input.id; } }); + +//? This is a workaround to focus the WYSIWYG editor when clicking on the label +const htmlInput = ref(null); +function onLabelClick(inputType: string) { + if(inputType !== 'html') return; + + htmlInput.value.focusEditor(); +} + +function showLabel(inputType: string) { + return inputType !== 'checkbox' && inputType !== 'repeat' +} </script> <template> - <TextInput - v-if="input.type === 'text'" - :id="inputId" - :label="input.label" - :placeholder="input.placeholder" - :input-value="inputValue as string" - :inside-card="insideCard" - @input="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <HtmlInput - v-if="input.type === 'html'" - :id="inputId" - :label="input.label" - :placeholder="input.placeholder" - :input-value="inputValue as string" - :inside-card="insideCard" - @input="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <TextAreaInput - v-if="input.type === 'textarea'" - :id="inputId" - :label="input.label" - :placeholder="input.placeholder" - :input-value="inputValue as string" - :inside-card="insideCard" - @input="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <FileInput - v-if="input.type === 'file'" - :id="inputId" - :label="input.label" - :accept="input.accept" - :input-value="inputValue as string" - :placeholder="input.placeholder" - :target-directory="input.targetDirectory" - @input="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <ScoreInput - v-if="input.type === 'score'" - :id="inputId" - :label="input.label" - :input-value="Number(inputValue)" - @input="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <CheckBoxInput - v-if="input.type === 'checkbox'" - :id="inputId" - :label="input.label" - :input-value="inputValue as boolean" - @change="emit('check', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <RadioInput - v-if="input.type === 'radio-group'" - :id="inputId" - :label="input.label" - :input-value="inputValue as string" - :pos="pos" - @change="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <SelectInput - v-if="input.type === 'select'" - :id="inputId" - :label="input.label" - :placeholder="input.placeholder" - :input-value="inputValue as string" - :options="input.options" - :linked-options="input.linkedOptions" - @change="emit('input', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <RepeatInput - v-if="input.type === 'repeat'" - :id="inputId" - :label="input.label" - :input-values="inputValue as string[]" - :inputs="input.inputs" - :field-index="fieldIndex" - :add-button="input.addButton" - @change="emit('repeatInput', $event)" - @save-given-state="emit('saveGivenState', $event)" - /> - <BadgesInput v-if="input.type === 'badge'" :input-value="inputValue as string[]" /> - <IconPicker - v-if="input.type === 'icon-picker'" - :label="input.label" - :input-value="inputValue as string" - @input="emit('input', $event)" - /> - <ConditionInput v-if="input.type === 'badge-conditions'" /> + <div class="input-group"> + <div + v-if="input.label && showLabel(input.type)" + class="input-label" + > + <label + :for="inputId" + @click="onLabelClick(input.type)" + > + {{ input.label }} + </label> + <i + v-if="input.hint" + v-tippy="{ + content: input.hint, + placement: 'right', + arrow: true, + arrowType: 'round', + animation: 'fade', + }" + class="icon-help-circle" + /> + </div> + + <TextInput + v-if="input.type === 'text'" + :id="inputId" + :label="input.label" + :placeholder="input.placeholder" + :input-value="inputValue as string" + :inside-card="insideCard" + @input="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <HtmlInput + v-if="input.type === 'html'" + :id="inputId" + ref="htmlInput" + :label="input.label" + :placeholder="input.placeholder" + :input-value="inputValue as string" + :inside-card="insideCard" + @input="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <TextAreaInput + v-if="input.type === 'textarea'" + :id="inputId" + :label="input.label" + :placeholder="input.placeholder" + :input-value="inputValue as string" + :inside-card="insideCard" + @input="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <FileInput + v-if="input.type === 'file'" + :id="inputId" + :label="input.label" + :accept="input.accept" + :input-value="inputValue as string" + :placeholder="input.placeholder" + :target-directory="input.targetDirectory" + @input="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <ScoreInput + v-if="input.type === 'score'" + :id="inputId" + :label="input.label" + :input-value="Number(inputValue)" + @input="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <CheckBoxInput + v-if="input.type === 'checkbox'" + :id="inputId" + :label="input.label" + :input-value="inputValue as boolean" + @change="emit('check', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <RadioInput + v-if="input.type === 'radio-group'" + :id="inputId" + :label="input.label" + :input-value="inputValue as string" + :pos="pos" + @change="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <SelectInput + v-if="input.type === 'select'" + :id="inputId" + :label="input.label" + :placeholder="input.placeholder" + :input-value="inputValue as string" + :options="input.options" + :linked-options="input.linkedOptions" + @change="emit('input', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <RepeatInput + v-if="input.type === 'repeat'" + :id="inputId" + :label="input.label" + :input-values="inputValue as string[]" + :inputs="input.inputs" + :field-index="fieldIndex" + :add-button="input.addButton" + @change="emit('repeatInput', $event)" + @save-given-state="emit('saveGivenState', $event)" + /> + <BadgesInput v-if="input.type === 'badge'" :input-value="inputValue as string[]" /> + <IconPicker + v-if="input.type === 'icon-picker'" + :label="input.label" + :input-value="inputValue as string" + @input="emit('input', $event)" + /> + <ConditionInput v-if="input.type === 'badge-conditions'" /> + </div> </template> + +<style lang="scss" scoped > +.input-group { + display: flex; + flex-direction: column; +} + +</style> \ No newline at end of file diff --git a/src/features/forms/components/inputs/HtmlInput.vue b/src/features/forms/components/inputs/HtmlInput.vue index 669eb355..3135506e 100644 --- a/src/features/forms/components/inputs/HtmlInput.vue +++ b/src/features/forms/components/inputs/HtmlInput.vue @@ -101,10 +101,13 @@ function focusEditor() { const editor = getTinymce().activeEditor; editor.focus(); } + +defineExpose({ + focusEditor +}); </script> <template> - <label @click="focusEditor">{{ label }}</label> <Editor ref="editor" v-model="content" diff --git a/src/features/forms/components/inputs/ScoreInput.vue b/src/features/forms/components/inputs/ScoreInput.vue index 12592033..989b6bbc 100644 --- a/src/features/forms/components/inputs/ScoreInput.vue +++ b/src/features/forms/components/inputs/ScoreInput.vue @@ -45,7 +45,6 @@ function onBlur() { </script> <template> - <label :for="id">{{ label }}</label> <div class="input-score"> <button @click="minus(inputValue)"><i class="icon-minus-circle"></i></button> <input diff --git a/src/features/forms/components/inputs/TextAreaInput.vue b/src/features/forms/components/inputs/TextAreaInput.vue index 2788639e..bedc54f6 100644 --- a/src/features/forms/components/inputs/TextAreaInput.vue +++ b/src/features/forms/components/inputs/TextAreaInput.vue @@ -32,7 +32,6 @@ function onBlur() { </script> <template> - <label class="input-label" :for="id">{{ label }}</label> <textarea :id="id" class="input input-textarea" diff --git a/src/features/forms/components/inputs/TextInput.vue b/src/features/forms/components/inputs/TextInput.vue index f590926b..27bdfcd1 100644 --- a/src/features/forms/components/inputs/TextInput.vue +++ b/src/features/forms/components/inputs/TextInput.vue @@ -33,7 +33,6 @@ function onBlur() { </script> <template> - <label v-if="label !== ''" class="input-label" :for="id">{{ label }}</label> <input :id="id" class="input" diff --git a/src/features/forms/components/inputs/badges/components/IconPicker.vue b/src/features/forms/components/inputs/badges/components/IconPicker.vue index 5e7f5b7e..135fe49d 100644 --- a/src/features/forms/components/inputs/badges/components/IconPicker.vue +++ b/src/features/forms/components/inputs/badges/components/IconPicker.vue @@ -1,12 +1,10 @@ <script setup lang="ts"> import BadgeItem from '@/src/features/badge/components/BadgeItem.vue'; -import { iconsPath } from '@/src/shared/data'; import { useEditorStore } from '@/src/shared/stores'; -import { computed } from 'vue'; const editorStore = useEditorStore(); -const props = defineProps<{ +defineProps<{ inputValue: string; label: string; }>(); @@ -17,7 +15,6 @@ function openIconModal() { </script> <template> - <label v-if="label !== ''" class="input-label" :for="label">{{ label }}</label> <div :id="label" class="container"> <BadgeItem :icon="inputValue" :view-mode="true" :inactive="!inputValue" /> <button class="btn btn-form" @click="openIconModal"> diff --git a/src/features/forms/components/inputs/card/components/RadioInput.vue b/src/features/forms/components/inputs/card/components/RadioInput.vue index 171c9eed..626ca022 100644 --- a/src/features/forms/components/inputs/card/components/RadioInput.vue +++ b/src/features/forms/components/inputs/card/components/RadioInput.vue @@ -24,7 +24,6 @@ function onChange(value: string) { <template> <div class="radio"> - <label class="group-label" :for="String(pos)">Réponse</label> <div :id="String(pos)" class="radio-group"> <div class="radio-btn"> <input diff --git a/src/features/forms/components/inputs/card/components/SelectInput.vue b/src/features/forms/components/inputs/card/components/SelectInput.vue index c5731431..bdfe371c 100644 --- a/src/features/forms/components/inputs/card/components/SelectInput.vue +++ b/src/features/forms/components/inputs/card/components/SelectInput.vue @@ -35,7 +35,6 @@ function onChange(event: Event) { <template> <div class="select"> - <label :for="id">{{ label }}</label> <select :id="id" :value="inputValue" class="select-box" @change="onChange"> <option value="">Sélectionnez</option> <option v-for="(option, index) in getOptions()" :key="index" :value="option">{{ option }}</option> diff --git a/src/global.scss b/src/global.scss index 77e6ce88..7194e7ac 100644 --- a/src/global.scss +++ b/src/global.scss @@ -297,9 +297,19 @@ hr { } .input-label { - margin-bottom: 0.5rem; + display: flex; + gap: .3rem; + margin-bottom: 0.7rem; font-size: 1rem; font-family: 'Open Sans', sans-serif; + line-height: 1; + + i { + display: flex; + align-items: center; + margin: 0; + color: var(--text-secondary); + } } .form-icon { diff --git a/src/shared/interfaces/form/input.interface.ts b/src/shared/interfaces/form/input.interface.ts index bbe314e0..f0a1e7a2 100644 --- a/src/shared/interfaces/form/input.interface.ts +++ b/src/shared/interfaces/form/input.interface.ts @@ -11,4 +11,5 @@ export interface Input { options?: string[]; linkedOptions?: string; targetDirectory?: string; + hint?: string; } -- GitLab