feat: Markdown editor support (#1657)

Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Nithin David Thomas
2021-01-18 11:20:19 +05:30
committed by GitHub
parent 58fad2561d
commit 54f15b73d3
7 changed files with 378 additions and 87 deletions

View File

@@ -0,0 +1,118 @@
<template>
<div ref="editor" class="editor-root"></div>
</template>
<script>
import { EditorState } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import {
schema,
defaultMarkdownParser,
defaultMarkdownSerializer,
} from 'prosemirror-markdown';
import { wootWriterSetup } from '@chatwoot/prosemirror-schema';
const TYPING_INDICATOR_IDLE_TIME = 4000;
const createState = (content, placeholder) =>
EditorState.create({
doc: defaultMarkdownParser.parse(content),
plugins: wootWriterSetup({ schema, placeholder }),
});
export default {
name: 'WootMessageEditor',
props: {
value: { type: String, default: '' },
placeholder: { type: String, default: '' },
},
data() {
return {
lastValue: null,
};
},
watch: {
value(newValue) {
if (newValue !== this.lastValue) {
this.state = createState(newValue, this.placeholder);
this.view.updateState(this.state);
}
},
},
created() {
this.state = createState(this.value, this.placeholder);
},
mounted() {
this.view = new EditorView(this.$refs.editor, {
state: this.state,
dispatchTransaction: tx => {
this.state = this.state.apply(tx);
this.view.updateState(this.state);
this.lastValue = defaultMarkdownSerializer.serialize(this.state.doc);
this.$emit('input', this.lastValue);
},
handleDOMEvents: {
keyup: () => {
this.onKeyup();
},
focus: () => {
this.onFocus();
},
blur: () => {
this.onBlur();
},
},
});
},
methods: {
resetTyping() {
this.$emit('typing-off');
this.idleTimer = null;
},
turnOffIdleTimer() {
if (this.idleTimer) {
clearTimeout(this.idleTimer);
}
},
onKeyup() {
if (!this.idleTimer) {
this.$emit('typing-on');
}
this.turnOffIdleTimer();
this.idleTimer = setTimeout(
() => this.resetTyping(),
TYPING_INDICATOR_IDLE_TIME
);
},
onBlur() {
this.turnOffIdleTimer();
this.resetTyping();
this.$emit('blur');
},
onFocus() {
this.$emit('focus');
},
},
};
</script>
<style lang="scss">
.ProseMirror-menubar-wrapper {
display: flex;
flex-direction: column;
> .ProseMirror {
padding: 0;
}
}
.editor-root {
width: 100%;
}
.ProseMirror-woot-style {
min-height: 8rem;
max-height: 12rem;
overflow: auto;
}
</style>

View File

@@ -1,12 +1,17 @@
<template>
<div class="bottom-box" :class="wrapClass">
<div class="left-wrap">
<button class="button clear button--emoji" @click="toggleEmojiPicker">
<button
class="button clear button--emoji"
:title="$t('CONVERSATION.REPLYBOX.TIP_EMOJI_ICON')"
@click="toggleEmojiPicker"
>
<emoji-or-icon icon="ion-happy-outline" emoji="😊" />
</button>
<button
v-if="showAttachButton"
class="button clear button--emoji button--upload"
:title="$t('CONVERSATION.REPLYBOX.TIP_ATTACH_ICON')"
>
<file-upload
:size="4096 * 4096"
@@ -16,6 +21,14 @@
<emoji-or-icon icon="ion-android-attach" emoji="📎" />
</file-upload>
</button>
<button
v-if="enableRichEditor"
class="button clear button--emoji"
:title="$t('CONVERSATION.REPLYBOX.TIP_FORMAT_ICON')"
@click="toggleFormatMode"
>
<emoji-or-icon icon="ion-quote" emoji="🖊️" />
</button>
</div>
<div class="right-wrap">
<button
@@ -70,6 +83,18 @@ export default {
type: Boolean,
default: false,
},
setFormatMode: {
type: Function,
default: () => {},
},
isFormatMode: {
type: Boolean,
default: false,
},
enableRichEditor: {
type: Boolean,
default: false,
},
},
computed: {
isNote() {
@@ -90,6 +115,11 @@ export default {
return this.showFileUpload || this.isNote;
},
},
methods: {
toggleFormatMode() {
this.setFormatMode(!this.isFormatMode);
},
},
};
</script>
@@ -108,34 +138,14 @@ export default {
}
.button {
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
padding: var(--space-one) var(--space-slab);
display: flex;
align-items: center;
justify-content: space-between;
&:hover {
background: var(--w-300);
}
&.is-active {
background: white;
}
&.button--emoji {
font-size: var(--font-size-small);
padding: var(--space-small);
border-radius: 9px;
background: var(--b-50);
border: 1px solid var(--color-border-light);
margin-right: var(--space-small);
&:hover {
background: var(--b-200);
}
}
&.button--note {
background: var(--y-800);
color: white;