mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 19:48:08 +00:00
This PR has the following fixes 1. preview of article inside the iframe, earlier this didn't work because the iframe didn't get the URL correctly. We fix that by passing the URL is a query instead 2. Emoji picker caused a weird redirect, this was only happening when the chunk was loaded async, this PR changes it to use regular loading instead
227 lines
5.3 KiB
Vue
Executable File
227 lines
5.3 KiB
Vue
Executable File
<script>
|
|
import { mapGetters } from 'vuex';
|
|
|
|
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
|
|
import ChatSendButton from 'widget/components/ChatSendButton.vue';
|
|
import configMixin from '../mixins/configMixin';
|
|
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
|
import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
|
|
import { useDarkMode } from 'widget/composables/useDarkMode';
|
|
|
|
import EmojiInput from 'shared/components/emoji/EmojiInput.vue';
|
|
|
|
export default {
|
|
name: 'ChatInputWrap',
|
|
components: {
|
|
ChatAttachmentButton,
|
|
ChatSendButton,
|
|
EmojiInput,
|
|
FluentIcon,
|
|
ResizableTextArea,
|
|
},
|
|
mixins: [configMixin],
|
|
props: {
|
|
onSendMessage: {
|
|
type: Function,
|
|
default: () => {},
|
|
},
|
|
onSendAttachment: {
|
|
type: Function,
|
|
default: () => {},
|
|
},
|
|
},
|
|
setup() {
|
|
const { getThemeClass } = useDarkMode();
|
|
return { getThemeClass };
|
|
},
|
|
data() {
|
|
return {
|
|
userInput: '',
|
|
showEmojiPicker: false,
|
|
isFocused: false,
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
...mapGetters({
|
|
widgetColor: 'appConfig/getWidgetColor',
|
|
isWidgetOpen: 'appConfig/getIsWidgetOpen',
|
|
}),
|
|
showAttachment() {
|
|
return this.hasAttachmentsEnabled && this.userInput.length === 0;
|
|
},
|
|
showSendButton() {
|
|
return this.userInput.length > 0;
|
|
},
|
|
inputColor() {
|
|
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
|
|
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}`;
|
|
},
|
|
emojiIconColor() {
|
|
return this.showEmojiPicker
|
|
? `text-woot-500 ${this.getThemeClass(
|
|
'text-black-900',
|
|
'dark:text-slate-100'
|
|
)}`
|
|
: `${this.getThemeClass('text-black-900', 'dark:text-slate-100')}`;
|
|
},
|
|
},
|
|
watch: {
|
|
isWidgetOpen(isWidgetOpen) {
|
|
if (isWidgetOpen) {
|
|
this.focusInput();
|
|
}
|
|
},
|
|
},
|
|
unmounted() {
|
|
document.removeEventListener('keypress', this.handleEnterKeyPress);
|
|
},
|
|
mounted() {
|
|
document.addEventListener('keypress', this.handleEnterKeyPress);
|
|
if (this.isWidgetOpen) {
|
|
this.focusInput();
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
onBlur() {
|
|
this.isFocused = false;
|
|
},
|
|
onFocus() {
|
|
this.isFocused = true;
|
|
},
|
|
handleButtonClick() {
|
|
if (this.userInput && this.userInput.trim()) {
|
|
this.onSendMessage(this.userInput);
|
|
}
|
|
this.userInput = '';
|
|
this.focusInput();
|
|
},
|
|
handleEnterKeyPress(e) {
|
|
if (e.keyCode === 13 && !e.shiftKey) {
|
|
e.preventDefault();
|
|
this.handleButtonClick();
|
|
}
|
|
},
|
|
toggleEmojiPicker() {
|
|
this.showEmojiPicker = !this.showEmojiPicker;
|
|
},
|
|
hideEmojiPicker(e) {
|
|
if (this.showEmojiPicker) {
|
|
e.stopPropagation();
|
|
this.toggleEmojiPicker();
|
|
}
|
|
},
|
|
emojiOnClick(emoji) {
|
|
this.userInput = `${this.userInput}${emoji} `;
|
|
},
|
|
onTypingOff() {
|
|
this.toggleTyping('off');
|
|
},
|
|
onTypingOn() {
|
|
this.toggleTyping('on');
|
|
},
|
|
toggleTyping(typingStatus) {
|
|
this.$store.dispatch('conversation/toggleUserTyping', { typingStatus });
|
|
},
|
|
focusInput() {
|
|
this.$refs.chatInput.focus();
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
class="chat-message--input is-focused"
|
|
:class="getThemeClass('bg-white ', 'dark:bg-slate-600')"
|
|
@keydown.esc="hideEmojiPicker"
|
|
>
|
|
<ResizableTextArea
|
|
id="chat-input"
|
|
ref="chatInput"
|
|
v-model="userInput"
|
|
:rows="1"
|
|
:aria-label="$t('CHAT_PLACEHOLDER')"
|
|
:placeholder="$t('CHAT_PLACEHOLDER')"
|
|
class="form-input user-message-input is-focused"
|
|
:class="inputColor"
|
|
@typing-off="onTypingOff"
|
|
@typing-on="onTypingOn"
|
|
@focus="onFocus"
|
|
@blur="onBlur"
|
|
/>
|
|
<div class="button-wrap">
|
|
<ChatAttachmentButton
|
|
v-if="showAttachment"
|
|
:class="getThemeClass('text-black-900', 'dark:text-slate-100')"
|
|
:on-attach="onSendAttachment"
|
|
/>
|
|
<button
|
|
v-if="hasEmojiPickerEnabled"
|
|
class="flex items-center justify-center icon-button"
|
|
:aria-label="$t('EMOJI.ARIA_LABEL')"
|
|
@click="toggleEmojiPicker"
|
|
>
|
|
<FluentIcon icon="emoji" :class="emojiIconColor" />
|
|
</button>
|
|
<EmojiInput
|
|
v-if="showEmojiPicker"
|
|
v-on-clickaway="hideEmojiPicker"
|
|
:on-click="emojiOnClick"
|
|
@keydown.esc="hideEmojiPicker"
|
|
/>
|
|
<ChatSendButton
|
|
v-if="showSendButton"
|
|
:color="widgetColor"
|
|
@click="handleButtonClick"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
@import 'widget/assets/scss/variables.scss';
|
|
@import 'widget/assets/scss/mixins.scss';
|
|
|
|
.chat-message--input {
|
|
align-items: center;
|
|
display: flex;
|
|
padding: 0 $space-small 0 $space-slab;
|
|
border-radius: 7px;
|
|
|
|
&.is-focused {
|
|
box-shadow:
|
|
0 0 0 1px $color-woot,
|
|
0 0 2px 3px $color-primary-light;
|
|
}
|
|
}
|
|
|
|
.emoji-dialog {
|
|
right: 20px;
|
|
top: -302px;
|
|
max-width: 100%;
|
|
|
|
&::before {
|
|
right: $space-one;
|
|
}
|
|
}
|
|
|
|
.button-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
padding-left: $space-small;
|
|
}
|
|
|
|
.user-message-input {
|
|
border: 0;
|
|
height: $space-large;
|
|
min-height: $space-large;
|
|
max-height: 2.4 * $space-mega;
|
|
resize: none;
|
|
padding: $space-smaller 0;
|
|
margin-top: $space-small;
|
|
margin-bottom: $space-small;
|
|
}
|
|
</style>
|