199 lines
5.0 KiB
Vue
199 lines
5.0 KiB
Vue
<template>
|
|
<TextEditor
|
|
ref="textEditor"
|
|
:editor-class="['prose-sm max-w-none', editable && 'min-h-[7rem]']"
|
|
:content="content"
|
|
@change="editable ? (content = $event) : null"
|
|
:starterkit-options="{ heading: { levels: [2, 3, 4, 5, 6] } }"
|
|
:placeholder="placeholder"
|
|
:editable="editable"
|
|
:mentions="users"
|
|
>
|
|
<template v-slot:editor="{ editor }">
|
|
<EditorContent
|
|
:class="[
|
|
editable &&
|
|
'sm:mx-10 mx-4 max-h-[50vh] overflow-y-auto border-t py-3',
|
|
]"
|
|
:editor="editor"
|
|
/>
|
|
</template>
|
|
<template v-slot:bottom>
|
|
<div v-if="editable" class="flex flex-col gap-2">
|
|
<div class="flex flex-wrap gap-2 sm:px-10 px-4">
|
|
<AttachmentItem
|
|
v-for="a in attachments"
|
|
:key="a.file_url"
|
|
:label="a.file_name"
|
|
>
|
|
<template #suffix>
|
|
<FeatherIcon
|
|
class="h-3.5"
|
|
name="x"
|
|
@click.stop="removeAttachment(a)"
|
|
/>
|
|
</template>
|
|
</AttachmentItem>
|
|
</div>
|
|
<div
|
|
class="flex justify-between gap-2 overflow-hidden border-t sm:px-10 px-4 py-2.5"
|
|
>
|
|
<div class="flex gap-1 items-center overflow-x-auto">
|
|
<TextEditorBubbleMenu :buttons="textEditorMenuButtons" />
|
|
<IconPicker
|
|
v-model="emoji"
|
|
v-slot="{ togglePopover }"
|
|
@update:modelValue="() => appendEmoji()"
|
|
>
|
|
<Button
|
|
:tooltip="__('Insert Emoji')"
|
|
:icon="SmileIcon"
|
|
variant="ghost"
|
|
@click="togglePopover()"
|
|
/>
|
|
</IconPicker>
|
|
<FileUploader
|
|
:upload-args="{
|
|
doctype: doctype,
|
|
docname: modelValue.name,
|
|
private: true,
|
|
}"
|
|
@success="(f) => attachments.push(f)"
|
|
>
|
|
<template #default="{ openFileSelector }">
|
|
<Button
|
|
:tooltip="__('Attach a file')"
|
|
variant="ghost"
|
|
:icon="AttachmentIcon"
|
|
@click="openFileSelector()"
|
|
/>
|
|
</template>
|
|
</FileUploader>
|
|
</div>
|
|
<div class="mt-2 flex items-center justify-end space-x-2 sm:mt-0">
|
|
<Button v-bind="discardButtonProps || {}" :label="__('Discard')" />
|
|
<Button
|
|
variant="solid"
|
|
v-bind="submitButtonProps || {}"
|
|
:label="__('Comment')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</TextEditor>
|
|
</template>
|
|
<script setup>
|
|
import IconPicker from '@/components/IconPicker.vue'
|
|
import SmileIcon from '@/components/Icons/SmileIcon.vue'
|
|
import AttachmentIcon from '@/components/Icons/AttachmentIcon.vue'
|
|
import AttachmentItem from '@/components/AttachmentItem.vue'
|
|
import { usersStore } from '@/stores/users'
|
|
import { TextEditorBubbleMenu, TextEditor, FileUploader } from 'frappe-ui'
|
|
import { capture } from '@/telemetry'
|
|
import { EditorContent } from '@tiptap/vue-3'
|
|
import { ref, computed } from 'vue'
|
|
|
|
const props = defineProps({
|
|
placeholder: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
editable: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
doctype: {
|
|
type: String,
|
|
default: 'CRM Lead',
|
|
},
|
|
editorProps: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
submitButtonProps: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
discardButtonProps: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
})
|
|
|
|
const modelValue = defineModel()
|
|
const attachments = defineModel('attachments')
|
|
const content = defineModel('content')
|
|
|
|
const { users: usersList } = usersStore()
|
|
|
|
const textEditor = ref(null)
|
|
const emoji = ref('')
|
|
|
|
const editor = computed(() => {
|
|
return textEditor.value.editor
|
|
})
|
|
|
|
function appendEmoji() {
|
|
editor.value.commands.insertContent(emoji.value)
|
|
editor.value.commands.focus()
|
|
emoji.value = ''
|
|
capture('emoji_inserted_in_comment', { emoji: emoji.value })
|
|
}
|
|
|
|
function removeAttachment(attachment) {
|
|
attachments.value = attachments.value.filter((a) => a !== attachment)
|
|
}
|
|
|
|
const users = computed(() => {
|
|
return (
|
|
usersList.data?.crmUsers
|
|
?.filter((user) => user.enabled)
|
|
.map((user) => ({
|
|
label: user.full_name.trimEnd(),
|
|
value: user.name,
|
|
})) || []
|
|
)
|
|
})
|
|
|
|
defineExpose({ editor })
|
|
|
|
const textEditorMenuButtons = [
|
|
'Paragraph',
|
|
['Heading 2', 'Heading 3', 'Heading 4', 'Heading 5', 'Heading 6'],
|
|
'Separator',
|
|
'Bold',
|
|
'Italic',
|
|
'Separator',
|
|
'Bullet List',
|
|
'Numbered List',
|
|
'Separator',
|
|
'Align Left',
|
|
'Align Center',
|
|
'Align Right',
|
|
'FontColor',
|
|
'Separator',
|
|
'Image',
|
|
'Video',
|
|
'Link',
|
|
'Blockquote',
|
|
'Code',
|
|
'Horizontal Rule',
|
|
[
|
|
'InsertTable',
|
|
'AddColumnBefore',
|
|
'AddColumnAfter',
|
|
'DeleteColumn',
|
|
'AddRowBefore',
|
|
'AddRowAfter',
|
|
'DeleteRow',
|
|
'MergeCells',
|
|
'SplitCell',
|
|
'ToggleHeaderColumn',
|
|
'ToggleHeaderRow',
|
|
'ToggleHeaderCell',
|
|
'DeleteTable',
|
|
],
|
|
]
|
|
</script>
|