ldc-legaulois/resources/ts/bo/components/MainMenuNodeDataEditor.vue

556 lines
17 KiB
Vue

<template>
<hr>
<fieldset class="main-menu-node-data-editor-component container-fluid">
<legend>
<span class="fs-5">{{ __("Modification de données d'un noeud") }}</span>
</legend>
<span class="d-block fw-bold">{{ __('Partie gauche') }}</span>
<!-- SUB LABEL -->
<div class="mb-3 row">
<label
for="title-sub-label"
class="col-sm-2 col-form-label"
>
{{ __("Label du sous-menu") }}
</label>
<div class="col">
<WordCounter
id="title-sub-label"
class="ck-word-count"
/>
<input
id="title-sub-label"
type="text"
class="form-control"
:value="menuNodeData.sub_label"
@blur="($event) => saveNodeDataInput('sub_label', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">
{{ __('validation.between.string', {
attribute: "label du sous-menu",
min: "3",
max: "255",
}) }}
</small>
<template
v-for="(message, messageIndex) of errors.sub_label"
:key="messageIndex"
>
<small
v-if="errors.sub_label"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
</div>
<!-- SEPARATION -->
<hr>
<span class="d-block fw-bold">{{ __('Partie droite') }}</span>
<!-- TITLE -->
<div class="mb-3 row">
<label
for="title-text"
class="col-sm-2 col-form-label"
>
{{ __("Titre") }}
</label>
<div class="col">
<WordCounter
id="title-text"
class="ck-word-count"
/>
<input
id="title-text"
type="text"
class="form-control"
:value="menuNodeData.title"
@blur="($event) => saveNodeDataInput('title', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">
{{ __('validation.between.string', {
attribute: "titre",
min: "3",
max: "255",
}) }}
</small>
<template
v-for="(message, messageIndex) of errors.title"
:key="messageIndex"
>
<small
v-if="errors.title"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
</div>
<!-- TEXT -->
<div class="mb-3 row">
<label
for="text-text"
class="col-sm-2 col-form-label"
>
{{ __("Texte") }}
</label>
<div class="col">
<WordCounter
id="text-text"
class="ck-word-count"
/>
<textarea
id="text-text"
class="form-control"
@blur="($event) => $nextTick(() => saveNodeDataInput('text', ($event.target as HTMLTextAreaElement).value))"
:value="menuNodeData.text"
/>
<small class="form-text text-body-secondary">
{{ __('validation.between.string', {
attribute: "texte",
min: "3",
max: "255",
}) + " " + __('crud.minicrud.text_warning') }}
</small>
<template
v-for="(message, messageIndex) of errors.text"
:key="messageIndex"
>
<small
v-if="errors.text"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
</div>
<!-- COLOR -->
<div class="mb-3 row">
<label
for="text_color"
class="col-sm-2 col-form-label"
>
{{ __("Couleur du texte") }}
</label>
<div class="col">
<ColorPickerComponent
name="text_color"
:value="menuNodeData.text_color"
@update-color="($event) => $nextTick(() => saveNodeDataInput('text_color', ($event as HTMLInputElement).value))"
/>
<small class="form-text text-body-secondary">
{{ __('Choisissez une couleur qui se distingue bien de l\'image.') }}
</small>
<template
v-for="(message, messageIndex) of errors.text_color"
:key="messageIndex"
>
<small
v-if="errors.text_color"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
</div>
<!-- LINK -->
<div class="mb-3 row">
<!-- LINK URL -->
<label
for="link-text"
class="col-sm-2 col-form-label"
>
{{ __("URL du lien") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="link-text"
class="ck-word-count"
/>
<input
id="link-text"
type="text"
class="form-control"
:value="menuNodeData.link_url"
@blur="($event) => saveNodeDataInput('link_url', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">
{{ __('validation.between.string', {
attribute: "titre du lien",
min: "3",
max: "255",
}) + " " + __('Doît être une url valide.') }}
</small>
<template
v-for="(message, messageIndex) of errors.link_url"
:key="messageIndex"
>
<small
v-if="errors.link_url"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<!-- LINK TITLE -->
<label
for="link-title-text"
class="col-sm-2 col-form-label"
>
{{ __("Titre du lien") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="link-title-text"
class="ck-word-count"
/>
<input
id="link-title-text"
type="text"
class="form-control"
:value="menuNodeData.link_title"
@blur="($event) => saveNodeDataInput('link_title', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">
{{ __('validation.between.string', {
attribute: "titre du lien",
min: "3",
max: "255",
}) }}
</small>
<template
v-for="(message, messageIndex) of errors.link_title"
:key="messageIndex"
>
<small
v-if="errors.link_title"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<!-- LINK TARGET -->
<label
for="link-target-checkbox"
class="col-sm-2 col-form-label"
>
{{ __("Cible du lien") }}
</label>
<div class="col-sm-4 p-2">
<div class="form-check form-switch py-0">
<input
name="link_target"
class="form-check-input pt-3"
type="checkbox"
role="switch"
id="link-target-checkbox"
:checked="menuNodeData.link_target"
@change="($event) => saveNodeDataInput('link_target', ($event.target as HTMLInputElement).checked)"
>
<template
v-for="(message, messageIndex) of errors.link_target"
:key="messageIndex"
>
<small
v-if="errors.link_target"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<small class="form-text text-body-secondary">{{ __('Ouverture dans un nouvel onglet. Deux réponses possibles : oui ou non.') }}</small>
</div>
<!-- LINK STATUS -->
<label
class="col-sm-2 col-form-label"
for="link-status-checkbox"
>
{{ __("Statut du lien") }}
</label>
<div class="col-sm-4 p-2">
<div class="form-check form-switch py-0">
<input
name="link_status"
class="form-check-input pt-3"
type="checkbox"
role="switch"
id="link-status-checkbox"
:checked="menuNodeData.link_status"
@change="($event) => saveNodeDataInput('link_status', ($event.target as HTMLInputElement).checked)"
>
<template
v-for="(message, messageIndex) of errors.link_status"
:key="messageIndex"
>
<small
v-if="errors.link_status"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<small class="form-text text-body-secondary">{{ __('Visibilité du lien. Deux réponses possibles : visible ou caché.') }}</small>
</div>
</div>
<!-- PICTURE -->
<div class="mb-3 row">
<!-- PICTURE -->
<label
for="picture-input"
class="col-sm-2 col-form-label"
>
{{ __("Image") }}
</label>
<div class="col-sm-10 p-2">
<ImageInputComponent
id="picture-input"
:required="true"
:show-labels="true"
name="picture"
:helper="__('crud.minicrud.dimensions_must_be', {
widthpx: '180px',
heightpx: '228px',
})"
:width="180"
:height="228"
:value="menuNodeData.picture"
:preview="false"
:browse-event="false"
@image-file="(file) => file ? saveNodeDataInput('picture', file) : null"
/>
</div>
<template
v-for="(message, messageIndex) of errors.picture"
:key="messageIndex"
>
<small
v-if="errors.picture"
class="text-danger"
>"{{ message }}"</small>
</template>
<!-- PICTURE ALT -->
<label
for="picture-alt-text"
class="col-sm-2 col-form-label"
>
{{ __("Text alternatif de l'image") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="picture-alt-text"
class="ck-word-count"
/>
<input
id="picture-alt-text"
type="text"
class="form-control"
:value="menuNodeData.picture_alt"
@blur="($event) => saveNodeDataInput('picture_alt', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">{{ __('crud.minicrud.picture_alt_helper') }}</small>
<template
v-for="(message, messageIndex) of errors.picture_alt"
:key="messageIndex"
>
<small
v-if="errors.picture_alt"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<!-- PICTURE TITLE -->
<label
for="picture-title-text"
class="col-sm-2 col-form-label"
>
{{ __("Titre de l'image") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="picture-title-text"
class="ck-word-count"
/>
<input
id="picture-title-text"
type="text"
class="form-control"
:value="menuNodeData.picture_title"
@blur="($event) => saveNodeDataInput('picture_title', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">{{ __('crud.minicrud.picture_title_helper') }}</small>
<template
v-for="(message, messageIndex) of errors.picture_title"
:key="messageIndex"
>
<small
v-if="errors.picture_title"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<!-- PICTURE STATUS -->
<label
class="col-sm-2 col-form-label"
for="picture-status-checkbox"
>
{{ __("Statut de l'image") }}
</label>
<div class="col-sm-4 p-2">
<div class="form-check form-switch py-0">
<input
name="picture_status"
class="form-check-input pt-3"
type="checkbox"
role="switch"
id="picture-status-checkbox"
:checked="menuNodeData.picture_status"
@change="($event) => saveNodeDataInput('picture_status', ($event.target as HTMLInputElement).checked)"
>
<template
v-for="(message, messageIndex) of errors.picture_status"
:key="messageIndex"
>
<small
v-if="errors.picture_status"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<small class="form-text text-body-secondary">{{ __('Visibilité de l\'image. Deux réponses possibles : visible ou cachée.') }}</small>
</div>
</div>
<!-- BACKGROUND PICTURE-->
<div class="mb-3 row">
<label
for="background-picture-input"
class="col-sm-2 col-form-label p-2"
>
{{ __("Image de fond") }}
</label>
<!-- BACKGROUND PICTURE -->
<div class="col-sm-10 p-2">
<ImageInputComponent
id="background-picture-input"
:required="true"
:show-labels="true"
name="background_picture"
:helper="__('crud.minicrud.dimensions_must_be', {
widthpx: '500px',
heightpx: '231px',
})"
:width="500"
:height="231"
:value="menuNodeData.background_picture"
:preview="false"
:browse-event="false"
@image-file="(file) => file ? saveNodeDataInput('background_picture', file) : null"
/>
</div>
<template
v-for="(message, messageIndex) of errors.background_picture"
:key="messageIndex"
>
<small
v-if="errors.background_picture"
class="text-danger"
>"{{ message }}"</small>
</template>
<!-- BACKGROUND PICTURE ALT -->
<label
for="background-picture-alt-text"
class="col-sm-2 col-form-label p-2"
>
{{ __("Text alternatif de l'image de fond") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="background-picture-alt-text"
class="ck-word-count"
/>
<input
id="background-picture-alt-text"
type="text"
class="form-control"
:value="menuNodeData.background_picture_alt"
@blur="($event) => saveNodeDataInput('background_picture_alt', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">{{ __('crud.minicrud.picture_alt_helper') }}</small>
<template
v-for="(message, messageIndex) of errors.background_picture_alt"
:key="messageIndex"
>
<small
v-if="errors.background_picture_alt"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
<!-- BACKGROUND PICTURE TITLE -->
<label
for="background-picture-title-text"
class="col-sm-2 col-form-label p-2"
>
{{ __("Titre de l'image de fond") }}
</label>
<div class="col-sm-10 p-2">
<WordCounter
id="background-picture-title-text"
class="ck-word-count"
/>
<input
id="background-picture-title-text"
type="text"
class="form-control"
:value="menuNodeData.background_picture_title"
@blur="($event) => saveNodeDataInput('background_picture_title', ($event.target as HTMLInputElement).value)"
>
<small class="form-text text-body-secondary">{{ __('crud.minicrud.picture_title_helper') }}</small>
<template
v-for="(message, messageIndex) of errors.background_picture_title"
:key="messageIndex"
>
<small
v-if="errors.background_picture_title"
class="text-danger"
>"{{ message }}"</small>
</template>
</div>
</div>
</fieldset>
</template>
<script lang="ts" setup>
import { __ } from "@modules/trans";
import { reactive, watch, type PropType } from "vue";
import type { IMenuNodeDataInputInterface } from "../../interfaces/IMenuNodeDataInputInterface";
import type { MenuNodeDataInterface } from "../../types/models/MenuNodeData";
import ColorPickerComponent from "./ColorPickerComponent.vue";
import ImageInputComponent from "./ImageInputComponent.vue";
import WordCounter from "./WordCounterComponent.vue";
defineOptions({
name: "MainMenuNodeDataEditor"
});
// * EMITS
const emits = defineEmits<{
updatedNodeData: [prop: string, value: ValueOf<IMenuNodeDataInputInterface> ],
}>();
// * PROPS
const props = defineProps({
menuNodeData: {
type: Object as PropType<MenuNodeDataInterface>,
required: true
},
errors: {
type: Object as PropType<LaravelValidationErrors>,
required: true
}
});
// * DATA
let menuNodeData = reactive<MenuNodeDataInterface>(Object.assign({}, props.menuNodeData));
// * WATCHERS
watch(props, () => {
menuNodeData = Object.assign({}, props.menuNodeData);
});
// * METHODS
function saveNodeDataInput(inputName: string, inputValue: ValueOf<IMenuNodeDataInputInterface>): void {
emits("updatedNodeData", inputName, inputValue);
}
</script>