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:
@@ -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) -->
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
1397
frontend/package-lock.json
generated
1397
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user