704e01fece
Signed-off-by: Sebastian <krupinski01@gmail.com>
263 lines
5.8 KiB
Vue
263 lines
5.8 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import type { PropType } from 'vue'
|
|
import { EditorContent, type Editor } from '@tiptap/vue-3'
|
|
import { documentsSelectorAvailable } from '@/services/documentsSelector'
|
|
|
|
defineProps({
|
|
editor: {
|
|
type: Object as PropType<Editor | null>,
|
|
default: null,
|
|
},
|
|
format: {
|
|
type: String as PropType<'rich' | 'plain'>,
|
|
required: true,
|
|
},
|
|
text: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
isBoldActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
isItalicActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
isUnderlineActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
isBulletListActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
isOrderedListActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
isLinkActive: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
bold: []
|
|
italic: []
|
|
underline: []
|
|
bulletList: []
|
|
orderedList: []
|
|
link: []
|
|
toggleFormat: []
|
|
'update:text': [value: string]
|
|
attachFromDevice: [files: File[]]
|
|
attachFromDocuments: []
|
|
}>()
|
|
|
|
const fileInput = ref<HTMLInputElement | null>(null)
|
|
|
|
function openFilePicker() {
|
|
fileInput.value?.click()
|
|
}
|
|
|
|
function handleFileChange(event: Event) {
|
|
const input = event.target as HTMLInputElement | null
|
|
const files = input?.files ? Array.from(input.files) : []
|
|
if (files.length > 0) {
|
|
emit('attachFromDevice', files)
|
|
}
|
|
if (input) {
|
|
input.value = ''
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<v-toolbar density="compact" elevation="0" class="editor-toolbar">
|
|
<template v-if="format === 'rich'">
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isBoldActive }"
|
|
@click="$emit('bold')"
|
|
>
|
|
<v-icon>mdi-format-bold</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Bold</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isItalicActive }"
|
|
@click="$emit('italic')"
|
|
>
|
|
<v-icon>mdi-format-italic</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Italic</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isUnderlineActive }"
|
|
@click="$emit('underline')"
|
|
>
|
|
<v-icon>mdi-format-underline</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Underline</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-divider vertical class="mx-2" />
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isBulletListActive }"
|
|
@click="$emit('bulletList')"
|
|
>
|
|
<v-icon>mdi-format-list-bulleted</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Bullet List</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isOrderedListActive }"
|
|
@click="$emit('orderedList')"
|
|
>
|
|
<v-icon>mdi-format-list-numbered</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Numbered List</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-divider vertical class="mx-2" />
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': isLinkActive }"
|
|
@click="$emit('link')"
|
|
>
|
|
<v-icon>mdi-link</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Link</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-divider vertical class="mx-2" />
|
|
</template>
|
|
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
:class="{ 'v-btn--active': format === 'plain' }"
|
|
@click="$emit('toggleFormat')"
|
|
>
|
|
<v-icon>{{ format === 'plain' ? 'mdi-format-text' : 'mdi-code-tags' }}</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">
|
|
{{ format === 'plain' ? 'Rich Text' : 'Plain Text' }}
|
|
</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-spacer />
|
|
|
|
<input
|
|
ref="fileInput"
|
|
type="file"
|
|
multiple
|
|
class="sr-only"
|
|
@change="handleFileChange"
|
|
>
|
|
|
|
<v-btn icon size="small" @click="openFilePicker">
|
|
<v-icon>mdi-paperclip</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Attach Files</v-tooltip>
|
|
</v-btn>
|
|
|
|
<v-btn v-if="documentsSelectorAvailable()" icon size="small" @click="$emit('attachFromDocuments')">
|
|
<v-icon>mdi-folder-search-outline</v-icon>
|
|
<v-tooltip activator="parent" location="bottom">Attach from Documents</v-tooltip>
|
|
</v-btn>
|
|
</v-toolbar>
|
|
|
|
<v-divider />
|
|
|
|
<div class="editor-container">
|
|
<EditorContent v-if="format === 'rich'" :editor="editor ?? undefined" />
|
|
<v-textarea
|
|
v-else
|
|
:model-value="text"
|
|
variant="plain"
|
|
auto-grow
|
|
hide-details
|
|
placeholder="Write your message..."
|
|
class="text-editor pa-4"
|
|
@update:model-value="$emit('update:text', $event)"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.editor-toolbar {
|
|
flex-shrink: 0;
|
|
border-bottom: 1px solid rgb(var(--v-border-color));
|
|
}
|
|
|
|
.editor-container {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
background-color: rgb(var(--v-theme-background));
|
|
}
|
|
|
|
.sr-only {
|
|
display: none;
|
|
}
|
|
|
|
.v-btn--active {
|
|
background-color: rgba(var(--v-theme-primary), 0.12);
|
|
color: rgb(var(--v-theme-primary));
|
|
}
|
|
|
|
.text-editor :deep(textarea) {
|
|
min-height: 300px;
|
|
font-family: inherit;
|
|
}
|
|
|
|
:deep(.tiptap-editor) {
|
|
outline: none;
|
|
min-height: 300px;
|
|
|
|
p.is-editor-empty:first-child::before {
|
|
color: rgb(var(--v-theme-on-surface-variant));
|
|
content: attr(data-placeholder);
|
|
float: left;
|
|
height: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
h1, h2, h3, h4, h5, h6 {
|
|
line-height: 1.3;
|
|
margin-top: 1em;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
p {
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
ul, ol {
|
|
padding-left: 1.5em;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
blockquote {
|
|
border-left: 3px solid rgb(var(--v-border-color));
|
|
padding-left: 1em;
|
|
margin-left: 0;
|
|
margin-bottom: 0.5em;
|
|
color: rgb(var(--v-theme-on-surface-variant));
|
|
}
|
|
|
|
a {
|
|
color: rgb(var(--v-theme-primary));
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
</style> |