feat: added emoji picker

This commit is contained in:
Shariq Ansari 2024-04-20 20:59:11 +05:30
parent b214d76e93
commit e81d4abd8c
5 changed files with 136 additions and 1 deletions

View File

@ -14,6 +14,7 @@
"@vueuse/integrations": "^10.3.0",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.52",
"gemoji": "^8.1.0",
"mime": "^4.0.1",
"pinia": "^2.0.33",
"socket.io-client": "^4.7.2",

View File

@ -0,0 +1,90 @@
<template>
<Popover transition="default">
<template #target="{ togglePopover, isOpen }">
<slot v-bind="{ isOpen, togglePopover }">
<span class="text-base"> {{ modelValue || '' }} </span>
</slot>
</template>
<template #body>
<div class="my-3 max-w-max transform bg-white px-4 sm:px-0">
<div
class="relative max-h-96 overflow-y-auto rounded-lg pb-3 shadow-2xl ring-1 ring-black ring-opacity-5"
>
<div class="flex gap-2 px-3 pb-1 pt-3">
<div class="flex-1">
<FormControl
type="text"
placeholder="Search by keyword"
v-model="search"
:debounce="300"
/>
</div>
<Button @click="setRandom">Random</Button>
</div>
<div class="w-96"></div>
<div class="px-3" v-for="(emojis, group) in emojiGroups" :key="group">
<div class="sticky top-0 bg-white pb-2 pt-3 text-sm text-gray-700">
{{ group }}
</div>
<div class="grid w-96 grid-cols-12 place-items-center">
<button
class="h-8 w-8 rounded-md p-1 text-2xl hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-200"
v-for="_emoji in emojis"
:key="_emoji.description"
@click="emoji = _emoji.emoji"
:title="_emoji.description"
>
{{ _emoji.emoji }}
</button>
</div>
</div>
</div>
</div>
</template>
</Popover>
</template>
<script setup>
import { gemoji } from 'gemoji'
import { Popover } from 'frappe-ui'
import { ref, computed } from 'vue'
const search = ref('')
const emoji = defineModel()
const emojiGroups = computed(() => {
let groups = {}
for (let _emoji of gemoji) {
if (search.value) {
let keywords = [_emoji.description, ..._emoji.names, ..._emoji.tags]
.join(' ')
.toLowerCase()
if (!keywords.includes(search.value.toLowerCase())) {
continue
}
}
let group = groups[_emoji.category]
if (!group) {
groups[_emoji.category] = []
group = groups[_emoji.category]
}
group.push(_emoji)
}
if (!Object.keys(groups).length) {
groups['No results'] = []
}
return groups
})
function setRandom() {
let total = gemoji.length
let index = randomInt(0, total - 1)
emoji.value = gemoji[index].emoji
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
defineExpose({ setRandom })
</script>

View File

@ -0,0 +1,19 @@
<template>
<svg
viewBox="0 0 24 24"
height="24"
width="24"
preserveAspectRatio="xMidYMid meet"
class=""
version="1.1"
x="0px"
y="0px"
enable-background="new 0 0 24 24"
>
<title>smiley</title>
<path
fill="currentColor"
d="M9.153,11.603c0.795,0,1.439-0.879,1.439-1.962S9.948,7.679,9.153,7.679 S7.714,8.558,7.714,9.641S8.358,11.603,9.153,11.603z M5.949,12.965c-0.026-0.307-0.131,5.218,6.063,5.551 c6.066-0.25,6.066-5.551,6.066-5.551C12,14.381,5.949,12.965,5.949,12.965z M17.312,14.073c0,0-0.669,1.959-5.051,1.959 c-3.505,0-5.388-1.164-5.607-1.959C6.654,14.073,12.566,15.128,17.312,14.073z M11.804,1.011c-6.195,0-10.826,5.022-10.826,11.217 s4.826,10.761,11.021,10.761S23.02,18.423,23.02,12.228C23.021,6.033,17.999,1.011,11.804,1.011z M12,21.354 c-5.273,0-9.381-3.886-9.381-9.159s3.942-9.548,9.215-9.548s9.548,4.275,9.548,9.548C21.381,17.467,17.273,21.354,12,21.354z M15.108,11.603c0.795,0,1.439-0.879,1.439-1.962s-0.644-1.962-1.439-1.962s-1.439,0.879-1.439,1.962S14.313,11.603,15.108,11.603z"
></path>
</svg>
</template>

View File

@ -1,6 +1,6 @@
<template>
<div class="flex items-end gap-2 px-10 py-2.5">
<div class="flex h-8 items-center">
<div class="flex h-8 items-center gap-2">
<FileUploader @success="(file) => uploadFile(file)">
<template v-slot="{ file, progress, uploading, openFileSelector }">
<div class="flex items-center space-x-2">
@ -16,6 +16,21 @@
</div>
</template>
</FileUploader>
<IconPicker
v-model="emoji"
v-slot="{ togglePopover }"
@update:modelValue="
() => {
content += emoji
$refs.textarea.$el.focus()
}
"
>
<SmileIcon
@click="togglePopover"
class="flex size-4.5 rounded-sm text-xl leading-none text-gray-500 cursor-pointer"
/>
</IconPicker>
</div>
<Textarea
ref="textarea"
@ -41,6 +56,8 @@
</template>
<script setup>
import IconPicker from '@/components/IconPicker.vue'
import SmileIcon from '@/components/Icons/SmileIcon.vue'
import { createResource, Textarea, FileUploader, Dropdown } from 'frappe-ui'
import FeatherIcon from 'frappe-ui/src/components/FeatherIcon.vue'
import { ref, computed, nextTick } from 'vue'
@ -53,6 +70,7 @@ const doc = defineModel()
const whatsapp = defineModel('whatsapp')
const rows = ref(1)
const textarea = ref(null)
const emoji = ref('')
const content = ref('')
const placeholder = ref(__('Type your message here...'))

View File

@ -1795,6 +1795,11 @@ function-bind@^1.1.2:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
gemoji@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/gemoji/-/gemoji-8.1.0.tgz#3d47a26e569c51efa95198822a6f483d7a7ae600"
integrity sha512-HA4Gx59dw2+tn+UAa7XEV4ufUKI4fH1KgcbenVA9YKSj1QJTT0xh5Mwv5HMFNN3l2OtUe3ZIfuRwSyZS5pLIWw==
get-east-asian-width@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e"
@ -3124,6 +3129,7 @@ string-argv@0.3.2:
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -3151,6 +3157,7 @@ string-width@^7.0.0:
strip-ansi "^7.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
name strip-ansi-cjs
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==