diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index bd5c2e39..49438a4b 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -6,7 +6,7 @@ import { faStickyNote, faSmileBeam } from '@fortawesome/free-solid-svg-icons' -import { trim } from 'lodash' +import { trim, escapeRegExp, startCase } from 'lodash' library.add( faBoxOpen, @@ -21,23 +21,6 @@ const LOAD_EMOJI_BY = 60 // When to start loading new batch emoji, in pixels const LOAD_EMOJI_MARGIN = 64 -const filterByKeyword = (list, keyword = '') => { - if (keyword === '') return list - - const keywordLowercase = keyword.toLowerCase() - let orderedEmojiList = [] - for (const emoji of list) { - const indexOfKeyword = emoji.displayText.toLowerCase().indexOf(keywordLowercase) - if (indexOfKeyword > -1) { - if (!Array.isArray(orderedEmojiList[indexOfKeyword])) { - orderedEmojiList[indexOfKeyword] = [] - } - orderedEmojiList[indexOfKeyword].push(emoji) - } - } - return orderedEmojiList.flat() -} - const EmojiPicker = { props: { enableStickerPicker: { @@ -49,7 +32,7 @@ const EmojiPicker = { data () { return { keyword: '', - activeGroup: 'custom', + activeGroup: 'standard', showingStickers: false, groupsScrolledClass: 'scrolled-top', keepOpen: false, @@ -80,13 +63,8 @@ const EmojiPicker = { this.triggerLoadMore(target) }, highlight (key) { - const ref = this.$refs['group-' + key] - const top = ref.offsetTop this.setShowStickers(false) this.activeGroup = key - this.$nextTick(() => { - this.$refs['emoji-groups'].scrollTop = top + 1 - }) }, updateScrolledClass (target) { if (target.scrollTop <= 5) { @@ -155,6 +133,13 @@ const EmojiPicker = { }, setShowStickers (value) { this.showingStickers = value + }, + filterByKeyword (list) { + if (this.keyword === '') return list + const regex = new RegExp(escapeRegExp(trim(this.keyword)), 'i') + return list.filter(emoji => { + return regex.test(emoji.displayText) + }) } }, watch: { @@ -175,9 +160,8 @@ const EmojiPicker = { return 0 }, filteredEmoji () { - return filterByKeyword( - this.$store.state.instance.customEmoji || [], - trim(this.keyword) + return this.filterByKeyword( + this.$store.state.instance.customEmoji || [] ) }, customEmojiBuffer () { @@ -185,25 +169,50 @@ const EmojiPicker = { }, emojis () { const standardEmojis = this.$store.state.instance.emoji || [] - const customEmojis = this.customEmojiBuffer - + const customEmojis = this.sortedEmoji + const emojiPacks = [] + customEmojis.forEach((pack, id) => { + emojiPacks.push({ + id: id.replace(/^pack:/, ''), + text: startCase(id.replace(/^pack:/, '')), + first: pack[0], + emojis: this.filterByKeyword(pack) + }) + }) return [ - { - id: 'custom', - text: this.$t('emoji.custom'), - icon: 'smile-beam', - emojis: customEmojis - }, { id: 'standard', text: this.$t('emoji.unicode'), - icon: 'box-open', - emojis: filterByKeyword(standardEmojis, trim(this.keyword)) + first: { + imageUrl: '', + replacement: '🥴' + }, + emojis: this.filterByKeyword(standardEmojis) } - ] + ].concat(emojiPacks) + }, + sortedEmoji () { + const customEmojis = this.$store.state.instance.customEmoji || [] + const sortedEmojiGroups = new Map() + customEmojis.forEach((emoji) => { + if (!sortedEmojiGroups.has(emoji.tags[0])) { + sortedEmojiGroups.set(emoji.tags[0], [emoji]) + } else { + sortedEmojiGroups.get(emoji.tags[0]).push(emoji) + } + }) + return new Map([...sortedEmojiGroups.entries()].sort()) }, emojisView () { - return this.emojis.filter(value => value.emojis.length > 0) + if (this.keyword === '') { + return this.emojis.filter(pack => { + return pack.id === this.activeGroup + }) + } else { + return this.emojis.filter(pack => { + return pack.emojis.length > 0 + }) + } }, stickerPickerEnabled () { return (this.$store.state.instance.stickers || []).length !== 0 diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss index 2055e02e..9c814e15 100644 --- a/src/components/emoji_picker/emoji_picker.scss +++ b/src/components/emoji_picker/emoji_picker.scss @@ -35,9 +35,8 @@ } .heading { - display: flex; - height: 32px; - padding: 10px 7px 5px; + margin-top: 10px; + height: 4.8em; } .content { @@ -65,15 +64,34 @@ .additional-tabs, .emoji-tabs { + position: absolute; display: block; - min-width: 0; - flex-basis: auto; - flex-shrink: 1; + flex-wrap: nowrap; + overflow: auto; + width: 100%; + + white-space: nowrap; + &-item { - padding: 0 7px; + vertical-align: top; + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: .4em; cursor: pointer; - font-size: 1.85em; + + img { + max-width: 100%; + max-height: 100%; + object-fit: contain; + } + + span { + font-size: 1.9em; + } &.disabled { opacity: 0.5; diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index a7269120..408048d2 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -13,10 +13,11 @@ :title="group.text" @click.prevent="highlight(group.id)" > - + {{ group.first.replacement }} +