fix(front): add a required attribute to the text editor and show error message if text empty on blur

Also improve text editor borders

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2024-01-09 16:10:56 +01:00
parent ef20585f8c
commit ba66874cc3
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
4 changed files with 48 additions and 6 deletions

View File

@ -32,6 +32,7 @@
v-if="currentActor"
:currentActor="currentActor"
:placeholder="t('Write a new message')"
:required="true"
/>
<o-notification
class="my-2"

View File

@ -217,7 +217,15 @@
</button>
</bubble-menu>
<editor-content class="editor__content" :editor="editor" v-if="editor" />
<editor-content
class="editor__content"
:class="{ editorErrorStatus }"
:editor="editor"
v-if="editor"
/>
<p v-if="editorErrorMessage" class="text-sm text-mbz-danger">
{{ editorErrorMessage }}
</p>
</div>
</div>
</template>
@ -249,7 +257,7 @@ import Underline from "@tiptap/extension-underline";
import Link from "@tiptap/extension-link";
import { AutoDir } from "./Editor/Autodir";
// import sanitizeHtml from "sanitize-html";
import { computed, inject, onBeforeUnmount, watch } from "vue";
import { computed, inject, onBeforeUnmount, ref, watch } from "vue";
import { Dialog } from "@/plugins/dialog";
import { useI18n } from "vue-i18n";
import { useMutation } from "@vue/apollo-composable";
@ -279,11 +287,13 @@ const props = withDefaults(
currentActor: IPerson;
placeholder?: string;
headingLevel?: Level[];
required?: boolean;
}>(),
{
mode: "description",
maxSize: 100_000_000,
headingLevel: () => [3, 4, 5],
required: false,
}
);
@ -333,7 +343,7 @@ const editor = useEditor({
"aria-label": ariaLabel.value ?? "",
role: "textbox",
class:
"prose dark:prose-invert prose-sm lg:prose-lg xl:prose-xl bg-zinc-50 dark:bg-zinc-700 focus:outline-none !max-w-full",
"prose dark:prose-invert prose-sm lg:prose-lg xl:prose-xl bg-white dark:bg-zinc-700 focus:outline-none !max-w-full",
},
transformPastedHTML: transformPastedHTML,
},
@ -373,6 +383,13 @@ const editor = useEditor({
onUpdate: () => {
emit("update:modelValue", editor.value?.getHTML());
},
onBlur: () => {
checkEditorEmpty();
},
onFocus: () => {
editorErrorStatus.value = false;
editorErrorMessage.value = "";
},
});
watch(value, (val: string) => {
@ -470,6 +487,18 @@ defineExpose({ replyToComment, focus });
onBeforeUnmount(() => {
editor.value?.destroy();
});
const editorErrorStatus = ref(false);
const editorErrorMessage = ref("");
const isEmpty = computed(
() => props.required === true && editor.value?.isEmpty === true
);
const checkEditorEmpty = () => {
editorErrorStatus.value = isEmpty.value;
editorErrorMessage.value = isEmpty.value ? t("You need to enter a text") : "";
};
</script>
<style lang="scss">
@use "@/styles/_mixins" as *;
@ -525,7 +554,6 @@ onBeforeUnmount(() => {
min-height: 2.5rem;
box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
border-radius: 4px;
border: 1px solid #dbdbdb;
padding: 12px 6px;
&:focus {
@ -655,4 +683,15 @@ onBeforeUnmount(() => {
.mention[data-id] {
@apply inline-block border border-zinc-600 dark:border-zinc-300 rounded py-0.5 px-1;
}
.editor__content {
@apply border focus:border-[#2563eb] rounded border-[#6b7280];
}
.editorErrorStatus {
@apply border-red-500;
}
.editor__content p.is-editor-empty:first-child::before {
@apply text-slate-300;
}
</style>

View File

@ -1642,5 +1642,6 @@
"Visit {instance_domain}": "Visit {instance_domain}",
"Software details: {software_details}": "Software details: {software_details}",
"Only instances with an application actor can be followed": "Only instances with an application actor can be followed",
"Domain or instance name": "Domain or instance name"
"Domain or instance name": "Domain or instance name",
"You need to enter a text": "You need to enter a text"
}

View File

@ -1636,5 +1636,6 @@
"Visit {instance_domain}": "Visiter {instance_domain}",
"Software details: {software_details}": "Détails du logiciel : {software_details}",
"Only instances with an application actor can be followed": "Seules les instances avec un acteur application peuvent être suivies",
"Domain or instance name": "Domaine ou nom de l'instance"
"Domain or instance name": "Domaine ou nom de l'instance",
"You need to enter a text": "Vous devez entrer un texte"
}