feat(rich-text) : migrer vers MalioInputRichText (layer-ui 1.4.7)

Remplace les éditeurs markdown locaux et les textareas
description par <MalioInputRichText> (TipTap v3 + StarterKit +
tiptap-markdown) du paquet @malio/layer-ui.

Sites migrés :
- TaskModal (description tâche)
- TaskGroupDrawer (description groupe de tâches)
- TimeEntryDrawer (description time entry)
- ClientTicketDetailModal (édition + lecture seule)
- ProjectClientTickets (panneau admin lecture seule)
- new-ticket (formulaire portail client)
- client-tickets (vue admin lecture seule)

Stockage en BDD inchangé : le markdown existant est parsé à
l'ouverture, le composant émet du HTML par défaut sur les
sauvegardes (migration lazy au fil des éditions).

Bumpe @malio/layer-ui de ^1.2.3 à ^1.4.7 et ajoute les
dépendances TipTap utilisées par le composant.

Co-Authored-By: RuFlo <ruv@ruv.net>
This commit is contained in:
2026-05-04 19:54:57 +02:00
parent 2898b22440
commit 2a68d2f9c6
9 changed files with 1376 additions and 116 deletions

View File

@@ -66,14 +66,10 @@
</div> </div>
<div class="mt-4"> <div class="mt-4">
<label class="mb-1 block text-sm font-medium text-neutral-700"> <MalioInputRichText
{{ $t('clientTicket.description') }}
</label>
<textarea
v-model="editForm.description" v-model="editForm.description"
rows="5" :label="$t('clientTicket.description')"
class="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500" min-height="180px"
style="resize: vertical; min-height: 140px; max-height: 500px"
/> />
</div> </div>
@@ -129,7 +125,13 @@
<!-- Description --> <!-- Description -->
<div class="mt-4"> <div class="mt-4">
<p class="text-sm font-medium text-neutral-700">{{ $t('clientTicket.description') }}</p> <p class="text-sm font-medium text-neutral-700">{{ $t('clientTicket.description') }}</p>
<p class="mt-1 whitespace-pre-wrap text-sm text-neutral-600">{{ ticket.description }}</p> <MalioInputRichText
v-if="ticket.description"
:model-value="ticket.description"
:editable="false"
group-class="mt-1"
/>
<p v-else class="mt-1 text-sm italic text-neutral-400"></p>
</div> </div>
<!-- URL (if bug) --> <!-- URL (if bug) -->

View File

@@ -116,7 +116,12 @@
<!-- Expanded details --> <!-- Expanded details -->
<div v-if="expandedId === ticket.id" class="border-t border-neutral-100 px-3 py-3"> <div v-if="expandedId === ticket.id" class="border-t border-neutral-100 px-3 py-3">
<p class="text-sm text-neutral-600 whitespace-pre-wrap">{{ ticket.description }}</p> <MalioInputRichText
v-if="ticket.description"
:model-value="ticket.description"
:editable="false"
/>
<p v-else class="text-sm italic text-neutral-400"></p>
<div v-if="ticket.url" class="mt-2"> <div v-if="ticket.url" class="mt-2">
<a <a
:href="ticket.url" :href="ticket.url"

View File

@@ -8,10 +8,10 @@
:error="touched.title && !form.title.trim() ? 'Le titre est requis' : ''" :error="touched.title && !form.title.trim() ? 'Le titre est requis' : ''"
@blur="touched.title = true" @blur="touched.title = true"
/> />
<MalioInputTextArea <MalioInputRichText
v-model="form.description" v-model="form.description"
label="Description" label="Description"
:size="3" min-height="120px"
/> />
<div class="mt-4"> <div class="mt-4">
<ColorPicker v-model="form.color" /> <ColorPicker v-model="form.color" />

View File

@@ -196,33 +196,13 @@
<!-- Description --> <!-- Description -->
<div class="mt-5"> <div class="mt-5">
<div class="mb-1 flex items-center justify-between"> <MalioInputRichText
<label class="text-sm font-medium text-slate-700">Description</label>
<button
v-if="form.description"
type="button"
class="flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-slate-500 transition-colors hover:bg-slate-100 hover:text-slate-700"
@click="showMarkdownPreview = true"
>
<Icon name="heroicons:eye" class="size-3.5" />
Aperçu MD
</button>
</div>
<MalioInputTextArea
v-model="form.description" v-model="form.description"
:size="5" label="Description"
resize="vertical" min-height="180px"
:min-resize-height="140"
:max-resize-height="500"
/> />
</div> </div>
<MarkdownPreviewModal
v-model="showMarkdownPreview"
:content="form.description"
title="Aperçu de la description"
/>
<!-- Documents --> <!-- Documents -->
<TaskDocumentUpload <TaskDocumentUpload
v-if="isEditing && task && isAdmin" v-if="isEditing && task && isAdmin"
@@ -558,7 +538,7 @@ const isOpen = computed({
}) })
function close() { function close() {
if (confirmDeleteDocOpen.value || confirmDeleteOpen.value || showMarkdownPreview.value) return if (confirmDeleteDocOpen.value || confirmDeleteOpen.value) return
isOpen.value = false isOpen.value = false
} }
@@ -566,7 +546,6 @@ const isEditing = computed(() => !!props.task)
const isSubmitting = ref(false) const isSubmitting = ref(false)
const confirmDeleteOpen = ref(false) const confirmDeleteOpen = ref(false)
const activeTab = ref<'details' | 'planning'>('details') const activeTab = ref<'details' | 'planning'>('details')
const showMarkdownPreview = ref(false)
const giteaUrl = ref('') const giteaUrl = ref('')
const { getSettings: getGiteaSettings } = useGiteaService() const { getSettings: getGiteaSettings } = useGiteaService()

View File

@@ -11,14 +11,11 @@
/> />
</div> </div>
<div> <MalioInputRichText
<label class="mb-1 block text-sm font-semibold text-neutral-700">Description</label> v-model="form.description"
<textarea label="Description"
v-model="form.description" min-height="120px"
rows="3" />
class="w-full rounded-md border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none"
/>
</div>
<div> <div>
<label class="mb-1 block text-sm font-semibold text-neutral-700">Date</label> <label class="mb-1 block text-sm font-semibold text-neutral-700">Date</label>

File diff suppressed because it is too large Load Diff

View File

@@ -11,18 +11,24 @@
"build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist" "build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist"
}, },
"dependencies": { "dependencies": {
"@malio/layer-ui": "^1.2.3", "@malio/layer-ui": "^1.4.7",
"@nuxt/icon": "^2.2.1", "@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3", "@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0", "@nuxtjs/tailwindcss": "^6.14.0",
"@pinia/nuxt": "^0.11.3", "@pinia/nuxt": "^0.11.3",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"@tiptap/extension-link": "^2.10.3",
"@tiptap/extension-placeholder": "^2.10.3",
"@tiptap/pm": "^2.10.3",
"@tiptap/starter-kit": "^2.10.3",
"@tiptap/vue-3": "^2.10.3",
"@vuepic/vue-datepicker": "^12.1.0", "@vuepic/vue-datepicker": "^12.1.0",
"chart.js": "^4.5.1", "chart.js": "^4.5.1",
"marked": "^18.0.0", "marked": "^18.0.0",
"nuxt": "^4.3.1", "nuxt": "^4.3.1",
"nuxt-toast": "^1.4.0", "nuxt-toast": "^1.4.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"tiptap-markdown": "^0.8.10",
"vue": "^3.5.29", "vue": "^3.5.29",
"vue-advanced-cropper": "^2.8.9", "vue-advanced-cropper": "^2.8.9",
"vue-chartjs": "^5.3.3", "vue-chartjs": "^5.3.3",

View File

@@ -37,15 +37,10 @@
<!-- Description --> <!-- Description -->
<div class="mt-4"> <div class="mt-4">
<MalioInputTextArea <MalioInputRichText
v-model="form.description" v-model="form.description"
:label="$t('clientTicket.description')" :label="$t('clientTicket.description')"
:size="5" min-height="180px"
resize="vertical"
:min-resize-height="140"
:max-resize-height="500"
min-resize-width="100%"
max-resize-width="100%"
/> />
</div> </div>

View File

@@ -84,7 +84,12 @@
<!-- Expanded details --> <!-- Expanded details -->
<div v-if="expandedId === ticket.id" class="border-t border-neutral-100 px-4 py-3"> <div v-if="expandedId === ticket.id" class="border-t border-neutral-100 px-4 py-3">
<p class="text-sm text-neutral-600 whitespace-pre-wrap">{{ ticket.description }}</p> <MalioInputRichText
v-if="ticket.description"
:model-value="ticket.description"
:editable="false"
/>
<p v-else class="text-sm italic text-neutral-400"></p>
<div v-if="ticket.url" class="mt-2"> <div v-if="ticket.url" class="mt-2">
<a <a
:href="ticket.url" :href="ticket.url"