feat: implement format toggle

Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
2026-08-28 22:29:22 -04:00
parent 45cb0bd817
commit 704e01fece
3 changed files with 155 additions and 58 deletions
+53
View File
@@ -12,6 +12,7 @@ import type { CollectionObject, MessageAddressObject } from '@MailManager/models
import { useMailOperationsStore } from '@/stores/mailOperationsStore'
import { useMailCompositionStore } from '@/stores/mailCompositionStore'
import { ComposerMode } from '@/types/composer'
import type { ComposerFormat } from '@/types/composer'
import { documentsSelectorComponent } from '@/services/documentsSelector'
import ComposerToolbar from '@/components/composer/ComposerToolbar.vue'
import ComposerSender from '@/components/composer/ComposerSender.vue'
@@ -48,6 +49,8 @@ const {
// State
const showCc = ref(false)
const showBcc = ref(false)
const format = ref<ComposerFormat>('rich')
const textEdited = ref(false)
const applyingDraftToEditor = ref(false)
const showDocumentSelector = ref(false)
const showCloseDialog = ref(false)
@@ -85,6 +88,14 @@ const subject = computed({
const attachments = computed(() => activeDraft.value?.attachments ?? {})
const text = computed({
get: () => activeDraft.value?.message.body.text ?? '',
set: value => {
textEdited.value = true
compositionStore.updateBody({ text: value, html: textToHtml(value) })
},
})
// Initialize Tiptap editor
const editor = useEditor({
extensions: [
@@ -118,6 +129,8 @@ watch(
compositionStore.openDraft(props.mode, props.source)
showCc.value = (activeDraft.value?.message.cc.length ?? 0) > 0
showBcc.value = (activeDraft.value?.message.bcc.length ?? 0) > 0
format.value = 'rich'
textEdited.value = false
applyingDraftToEditor.value = true
currentEditor.commands.setContent(activeDraft.value?.message.body.html || '')
@@ -249,6 +262,42 @@ const toggleLink = () => {
const isActive = (name: string, attrs?: any) => {
return editor.value?.isActive(name, attrs) || false
}
const toggleFormat = () => {
if (format.value === 'rich') {
if (editor.value) {
compositionStore.updateBody({
html: activeDraft.value?.message.body.html ?? '',
text: editor.value.getText(),
})
}
textEdited.value = false
format.value = 'plain'
return
}
format.value = 'rich'
if (textEdited.value && editor.value) {
applyingDraftToEditor.value = true
editor.value.commands.setContent(activeDraft.value?.message.body.html || '')
applyingDraftToEditor.value = false
}
}
function textToHtml(text: string): string {
if (!text) {
return ''
}
return text
.split(/\r?\n/)
.map(line => `<p>${escapeHtml(line) || '<br>'}</p>`)
.join('')
}
function escapeHtml(value: string): string {
return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
}
</script>
<template>
@@ -297,6 +346,8 @@ const isActive = (name: string, attrs?: any) => {
<ComposerEditor
:editor="editor"
:format="format"
:text="text"
:is-bold-active="isActive('bold')"
:is-italic-active="isActive('italic')"
:is-underline-active="isActive('underline')"
@@ -309,6 +360,8 @@ const isActive = (name: string, attrs?: any) => {
@bullet-list="toggleBulletList"
@ordered-list="toggleOrderedList"
@link="toggleLink"
@toggle-format="toggleFormat"
@update:text="text = $event"
@attach-from-device="handleAttachFromDevice"
@attach-from-documents="handleAttachFromDocuments"
/>