Files
vuefilemanager/resources/js/components/Others/EmojiPicker.vue
2022-02-01 12:21:38 +01:00

170 lines
6.0 KiB
Vue

<template>
<div>
<!-- Search field -->
<div class="relative mb-3 flex items-center">
<!-- Selected emoji preview -->
<div v-if="defaultEmoji" class="mr-3 select-none">
<Emoji :emoji="defaultEmoji" class="text-5xl" />
</div>
<!-- Search input -->
<input @click="openList" v-model="query" class="focus-border-theme input-dark" type="text" :placeholder="$t('Select or search emoji icon...')" />
</div>
<!-- Spinner -->
<div v-if="isOpen && !isLoaded" class="relative h-20 select-none">
<Spinner />
</div>
<!-- Emojis List -->
<div v-if="isOpen && isLoaded && emojis" @scroll="checkGroupInView" id="group-box" class="relative h-96 select-none overflow-y-auto lg:h-60 2xl:h-96">
<!-- Navigation of Emojis Groups -->
<ul v-if="!query" class="sticky top-0 z-10 flex items-center justify-between space-x-1 bg-white dark:bg-dark-background sm:dark:bg-4x-dark-foreground" id="group-bar">
<li
@click.stop="scrollToGroup(group.name)"
v-for="(group, i) in emojis.groups"
:key="i"
class="flex h-14 w-14 cursor-pointer items-center justify-center rounded-xl hover:bg-light-background dark:hover:bg-2x-dark-foreground"
:class="{
'bg-light-background dark:bg-2x-dark-foreground': group.name === groupInView,
}"
>
<Emoji :emoji="group.emoji" class="text-3xl" />
</li>
</ul>
<!-- All Emojis -->
<div v-if="!query" v-for="(group, name) in allEmoji" :key="name" :id="`group-${name}`">
<label class="mt-4 mb-2 block text-sm font-bold">
{{ name }}
</label>
<ul class="space-between grid grid-cols-7 gap-4 md:grid-cols-9">
<li @click="setEmoji(emoji)" v-for="(emoji, i) in group" :key="i" class="flex cursor-pointer items-center justify-center">
<Emoji :emoji="emoji" class="text-4xl" />
</li>
</ul>
</div>
<!-- Searched emojis -->
<ul v-if="query" class="space-between grid grid-cols-7 gap-4 md:grid-cols-9">
<li @click="setEmoji(emoji)" v-for="(emoji, i) in filteredEmojis" :key="i" class="flex cursor-pointer items-center justify-center">
<Emoji :emoji="emoji" class="text-4xl" />
</li>
</ul>
<!-- Not found -->
<span class="ml-2 text-sm font-bold" v-if="filteredEmojis.length === 0 && query !== undefined">
{{ $t('There is nothing :(') }}
</span>
</div>
</div>
</template>
<script>
import Spinner from '../FilesView/Spinner'
import Emoji from './Emoji'
import { debounce, groupBy } from 'lodash'
import { XIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
export default {
name: 'EmojiPicker',
props: ['defaultEmoji'],
components: {
Spinner,
Emoji,
XIcon,
},
computed: {
...mapGetters(['emojis']),
allEmoji() {
return groupBy(this.emojis.list, 'group')
},
},
data() {
return {
query: undefined,
filteredEmojis: [],
isOpen: false,
isLoaded: false,
groupInView: 'Smileys & Emotion',
}
},
watch: {
query: debounce(function (val) {
// Clear search results
this.filteredEmojis = []
// Reset query
if (val === '' || val === undefined) return
// Filter emojis by query
this.filteredEmojis = this.emojis.list.filter((emoji) => emoji.name.includes(val.toLowerCase()))
if (this.filteredEmojis.length === 0) {
console.log('empty')
}
}, 200),
},
methods: {
checkGroupInView: _.debounce(function () {
this.emojis.groups.forEach((group) => {
let element = document.getElementById(`group-${group.name}`).getBoundingClientRect()
let groupBox = document.getElementById('group-box').getBoundingClientRect()
// Check if the group is in the viewport of group-box
if (element.top < groupBox.top && element.bottom > groupBox.top) {
this.groupInView = group.name
}
})
}, 300),
scrollToGroup(name) {
let groupBar = document.getElementById('group-bar')
let groupBox = document.getElementById('group-box')
let group = document.getElementById(`group-${name}`)
groupBox.scrollTo({
top: group.offsetTop - groupBar.clientHeight - 5,
left: 0,
behavior: 'smooth',
})
this.groupInView = name
},
openList() {
// Open list if it's not opened
if (!this.isOpen) this.isOpen = true
// Load emojis from server just if not loaded already
if (this.isOpen && !this.emojis) {
axios
.get('/assets/emojis.json')
.then((response) => {
this.$store.commit('LOAD_EMOJIS_LIST', response.data)
})
.finally(() => (this.isLoaded = true))
}
// Simulate loading for the list processing
if (this.emojis) {
setTimeout(() => {
this.isLoaded = true
}, 20)
}
this.groupInView = 'Smileys & Emotion'
},
setEmoji(value) {
this.query = undefined
this.isOpen = false
this.$emit('input', value)
},
},
mounted() {
// Open list of there isn't set any emoji
if (!this.defaultEmoji) this.openList()
},
}
</script>