summaryrefslogtreecommitdiff
path: root/packages/client/src/components/global/emoji.vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/client/src/components/global/emoji.vue')
-rw-r--r--packages/client/src/components/global/emoji.vue125
1 files changed, 125 insertions, 0 deletions
diff --git a/packages/client/src/components/global/emoji.vue b/packages/client/src/components/global/emoji.vue
new file mode 100644
index 0000000000..67a3dea2c5
--- /dev/null
+++ b/packages/client/src/components/global/emoji.vue
@@ -0,0 +1,125 @@
+<template>
+<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
+<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt" decoding="async"/>
+<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
+<span v-else>{{ emoji }}</span>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import { getStaticImageUrl } from '@/scripts/get-static-image-url';
+import { twemojiSvgBase } from '@/scripts/twemoji-base';
+
+export default defineComponent({
+ props: {
+ emoji: {
+ type: String,
+ required: true
+ },
+ normal: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ noStyle: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ customEmojis: {
+ required: false
+ },
+ isReaction: {
+ type: Boolean,
+ default: false
+ },
+ },
+
+ data() {
+ return {
+ url: null,
+ char: null,
+ customEmoji: null
+ }
+ },
+
+ computed: {
+ isCustom(): boolean {
+ return this.emoji.startsWith(':');
+ },
+
+ alt(): string {
+ return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
+ },
+
+ useOsNativeEmojis(): boolean {
+ return this.$store.state.useOsNativeEmojis && !this.isReaction;
+ },
+
+ ce() {
+ return this.customEmojis || this.$instance?.emojis || [];
+ }
+ },
+
+ watch: {
+ ce: {
+ handler() {
+ if (this.isCustom) {
+ const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
+ if (customEmoji) {
+ this.customEmoji = customEmoji;
+ this.url = this.$store.state.disableShowingAnimatedImages
+ ? getStaticImageUrl(customEmoji.url)
+ : customEmoji.url;
+ }
+ }
+ },
+ immediate: true
+ },
+ },
+
+ created() {
+ if (!this.isCustom) {
+ this.char = this.emoji;
+ }
+
+ if (this.char) {
+ let codes = Array.from(this.char).map(x => x.codePointAt(0).toString(16));
+ if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
+ codes = codes.filter(x => x && x.length);
+
+ this.url = `${twemojiSvgBase}/${codes.join('-')}.svg`;
+ }
+ },
+});
+</script>
+
+<style lang="scss" scoped>
+.mk-emoji {
+ height: 1.25em;
+ vertical-align: -0.25em;
+
+ &.custom {
+ height: 2.5em;
+ vertical-align: middle;
+ transition: transform 0.2s ease;
+
+ &:hover {
+ transform: scale(1.2);
+ }
+
+ &.normal {
+ height: 1.25em;
+ vertical-align: -0.25em;
+
+ &:hover {
+ transform: none;
+ }
+ }
+ }
+
+ &.noStyle {
+ height: auto !important;
+ }
+}
+</style>