Skip to content

Commit ded0197

Browse files
committed
(feature) add emojis autocompletion
1 parent 7bcbec6 commit ded0197

File tree

3 files changed

+135
-26
lines changed

3 files changed

+135
-26
lines changed

src/ChatWindow/Room/Room.vue

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,21 @@
132132
</template>
133133
</room-message-reply>
134134

135+
<room-emojis
136+
:filtered-emojis="filteredEmojis"
137+
@select-emoji="selectEmoji($event)"
138+
/>
139+
135140
<room-users-tag
136141
:filtered-users-tag="filteredUsersTag"
137142
@select-user-tag="selectUserTag($event)"
138143
/>
139144

140145
<div
141146
class="vac-box-footer"
142-
:class="{ 'vac-app-box-shadow': filteredUsersTag.length }"
147+
:class="{
148+
'vac-app-box-shadow': filteredEmojis.length || filteredUsersTag.length
149+
}"
143150
>
144151
<div
145152
v-if="showAudio && !imageFile && !videoFile"
@@ -330,6 +337,7 @@ import EmojiPicker from '../../components/EmojiPicker'
330337
import RoomHeader from './RoomHeader'
331338
import RoomMessageReply from './RoomMessageReply'
332339
import RoomUsersTag from './RoomUsersTag'
340+
import RoomEmojis from './RoomEmojis'
333341
import Message from '../Message/Message'
334342
335343
import filteredUsers from '../../utils/filter-items'
@@ -348,6 +356,7 @@ export default {
348356
RoomHeader,
349357
RoomMessageReply,
350358
RoomUsersTag,
359+
RoomEmojis,
351360
Message
352361
},
353362
@@ -402,6 +411,7 @@ export default {
402411
scrollMessagesCount: 0,
403412
newMessages: [],
404413
keepKeyboardOpen: false,
414+
filteredEmojis: [],
405415
filteredUsersTag: [],
406416
selectedUsersTag: [],
407417
textareaCursorPosition: null,
@@ -521,16 +531,18 @@ export default {
521531
}
522532
}
523533
524-
this.updateShowUsersTag()
534+
this.updateFooterList('@')
535+
this.updateFooterList(':')
525536
})
526537
527538
this.$refs['roomTextarea'].addEventListener('click', () => {
528539
if (isMobile) this.keepKeyboardOpen = true
529-
this.updateShowUsersTag()
540+
this.updateFooterList('@')
541+
this.updateFooterList(':')
530542
})
531543
532544
this.$refs['roomTextarea'].addEventListener('blur', () => {
533-
this.resetUsersTag()
545+
this.resetFooterList()
534546
if (isMobile) setTimeout(() => (this.keepKeyboardOpen = false), 0)
535547
})
536548
},
@@ -550,9 +562,15 @@ export default {
550562
this.scrollIcon = bottomScroll > 500 || this.scrollMessagesCount
551563
}, 200)
552564
},
553-
updateShowUsersTag() {
565+
updateFooterList(tagChar) {
554566
if (!this.$refs['roomTextarea']) return
555-
if (!this.room.users || this.room.users.length <= 2) return
567+
568+
if (
569+
tagChar === '@' &&
570+
(!this.room.users || this.room.users.length <= 2)
571+
) {
572+
return
573+
}
556574
557575
if (
558576
this.textareaCursorPosition ===
@@ -567,7 +585,7 @@ export default {
567585
568586
while (
569587
position > 0 &&
570-
this.message.charAt(position - 1) !== '@' &&
588+
this.message.charAt(position - 1) !== tagChar &&
571589
this.message.charAt(position - 1) !== ' '
572590
) {
573591
position--
@@ -577,25 +595,23 @@ export default {
577595
const notLetterNumber = !beforeTag.match(/^[0-9a-zA-Z]+$/)
578596
579597
if (
580-
this.message.charAt(position - 1) === '@' &&
598+
this.message.charAt(position - 1) === tagChar &&
581599
(!beforeTag || beforeTag === ' ' || notLetterNumber)
582600
) {
583601
const query = this.message.substring(
584602
position,
585603
this.textareaCursorPosition
586604
)
587-
588-
this.filteredUsersTag = filteredUsers(
589-
this.room.users,
590-
'username',
591-
query,
592-
true
593-
).filter(user => user._id !== this.currentUserId)
605+
if (tagChar === ':') {
606+
this.updateEmojis(query)
607+
} else if (tagChar === '@') {
608+
this.updateShowUsersTag(query)
609+
}
594610
} else {
595-
this.resetUsersTag()
611+
this.resetFooterList()
596612
}
597613
},
598-
selectUserTag(user) {
614+
getCharPosition() {
599615
const cursorPosition = this.$refs['roomTextarea'].selectionStart
600616
601617
let position = cursorPosition
@@ -611,6 +627,37 @@ export default {
611627
endPosition++
612628
}
613629
630+
return { position, endPosition }
631+
},
632+
updateEmojis(query) {
633+
if (!query) return
634+
635+
const emojisListKeys = Object.keys(this.emojisList)
636+
const matchingKeys = emojisListKeys.filter(key => key.startsWith(query))
637+
638+
this.filteredEmojis = matchingKeys.map(key => this.emojisList[key])
639+
},
640+
selectEmoji(emoji) {
641+
const { position, endPosition } = this.getCharPosition()
642+
643+
this.message =
644+
this.message.substr(0, position - 1) +
645+
emoji +
646+
this.message.substr(endPosition, this.message.length - 1)
647+
648+
this.focusTextarea()
649+
},
650+
updateShowUsersTag(query) {
651+
this.filteredUsersTag = filteredUsers(
652+
this.room.users,
653+
'username',
654+
query,
655+
true
656+
).filter(user => user._id !== this.currentUserId)
657+
},
658+
selectUserTag(user) {
659+
const { position, endPosition } = this.getCharPosition()
660+
614661
const space = this.message.substr(endPosition, endPosition).length
615662
? ''
616663
: ' '
@@ -625,7 +672,8 @@ export default {
625672
626673
this.focusTextarea()
627674
},
628-
resetUsersTag() {
675+
resetFooterList() {
676+
this.filteredEmojis = []
629677
this.filteredUsersTag = []
630678
this.textareaCursorPosition = null
631679
},
@@ -657,7 +705,7 @@ export default {
657705
}
658706
659707
this.selectedUsersTag = []
660-
this.resetUsersTag()
708+
this.resetFooterList()
661709
this.resetTextareaSize()
662710
this.message = ''
663711
this.editedMessage = {}

src/ChatWindow/Room/RoomEmojis.vue

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<template>
2+
<transition name="vac-slide-up">
3+
<div
4+
v-if="filteredEmojis.length"
5+
class="vac-emojis-container vac-app-box-shadow"
6+
:style="{ bottom: `${$parent.$refs.roomFooter.clientHeight}px` }"
7+
>
8+
<div
9+
v-for="emoji in filteredEmojis"
10+
:key="emoji"
11+
class="vac-emoji-element"
12+
@click="$emit('select-emoji', emoji)"
13+
>
14+
{{ emoji }}
15+
</div>
16+
</div>
17+
</transition>
18+
</template>
19+
20+
<script>
21+
export default {
22+
name: 'RoomEmojis',
23+
24+
props: {
25+
filteredEmojis: { type: Array, required: true }
26+
}
27+
}
28+
</script>
29+
30+
<style lang="scss" scoped>
31+
.vac-emojis-container {
32+
position: absolute;
33+
width: 100%;
34+
padding: 10px 8px;
35+
background: var(--chat-footer-bg-color);
36+
display: flex;
37+
align-items: center;
38+
overflow: auto;
39+
40+
.vac-emoji-element {
41+
padding: 0 8px;
42+
font-size: 30px;
43+
border-radius: 4px;
44+
cursor: pointer;
45+
46+
&:hover {
47+
background: var(--chat-footer-bg-color-tag-active);
48+
transition: background-color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
49+
}
50+
51+
&:not(:hover) {
52+
transition: background-color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
53+
}
54+
}
55+
}
56+
57+
@media only screen and (max-width: 768px) {
58+
.vac-emojis-container {
59+
padding: 7px 5px;
60+
61+
.vac-emoji-element {
62+
padding: 0 7px;
63+
font-size: 26px;
64+
}
65+
}
66+
}
67+
</style>

src/ChatWindow/Room/RoomUsersTag.vue

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
v-for="user in filteredUsersTag"
1010
:key="user._id"
1111
class="vac-tags-box"
12-
@click="selectUserTag(user)"
12+
@click="$emit('select-user-tag', user)"
1313
>
1414
<div class="vac-tags-info">
1515
<div
@@ -32,12 +32,6 @@ export default {
3232
3333
props: {
3434
filteredUsersTag: { type: Array, required: true }
35-
},
36-
37-
methods: {
38-
selectUserTag(user) {
39-
this.$emit('select-user-tag', user)
40-
}
4135
}
4236
}
4337
</script>

0 commit comments

Comments
 (0)