commit: 998aa8f732bbf9d074abeb5916ceb5effd8afe5c
parent 8abaf8fa375d8453b2284fbf529cd03ff565bcd4
Author: Alexander Tumin <iamtakingiteasy@eientei.org>
Date: Sun, 18 Dec 2022 22:04:58 +0300
Allow custom emoji reactions
Diffstat:
6 files changed, 89 insertions(+), 161 deletions(-)
diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
@@ -2,7 +2,7 @@
<div class="EmojiReactions">
<UserListPopover
v-for="(reaction) in emojiReactions"
- :key="reaction.name"
+ :key="reaction.url || reaction.name"
:users="accountsForEmoji[reaction.name]"
>
<button
@@ -11,7 +11,21 @@
@click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()"
>
- <span class="reaction-emoji">{{ reaction.name }}</span>
+ <span
+ v-if="reaction.url"
+ class="reaction-emoji"
+ >
+ <img
+ :src="reaction.url"
+ :title="reaction.name"
+ class="reaction-emoji-content"
+ width="1em"
+ >
+ </span>
+ <span
+ v-else
+ class="reaction-emoji reaction-emoji-content"
+ >{{ reaction.name }}</span>
<span>{{ reaction.count }}</span>
</button>
</UserListPopover>
@@ -46,9 +60,18 @@
.reaction-emoji {
width: 1.25em;
+ height: 1.25em;
margin-right: 0.25em;
}
+ .reaction-emoji-content {
+ max-width: 1.25em;
+ max-height: 1.25em;
+ width: auto;
+ height: auto;
+ overflow: hidden;
+ }
+
&:focus {
outline: none;
}
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
@@ -121,7 +121,16 @@
scope="global"
keypath="notifications.reacted_with"
>
- <span class="emoji-reaction-emoji">{{ notification.emoji }}</span>
+ <img
+ v-if="notification.emoji_url"
+ class="emoji-reaction-emoji emoji-reaction-emoji-image"
+ :src="notification.emoji_url"
+ :name="notification.emoji"
+ >
+ <span
+ v-else
+ class="emoji-reaction-emoji"
+ >{{ notification.emoji }}</span>
</i18n-t>
</small>
</span>
@@ -153,9 +162,9 @@
</router-link>
<button
class="button-unstyled expand-icon"
- @click.prevent="toggleStatusExpanded"
- :title="$t('tool_tip.toggle_expand')"
:aria-expanded="statusExpanded"
+ :title="$t('tool_tip.toggle_expand')"
+ @click.prevent="toggleStatusExpanded"
>
<FAIcon
class="fa-scale-110"
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
@@ -129,6 +129,13 @@
.emoji-reaction-emoji {
font-size: 1.3em;
+ max-width: 1.25em;
+ height: 1.25em;
+ width: auto;
+ }
+
+ .emoji-reaction-emoji-image {
+ vertical-align: middle;
}
.notification-details {
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js
@@ -1,9 +1,8 @@
import Popover from '../popover/popover.vue'
-import { ensureFinalFallback } from '../../i18n/languages.js'
+import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons'
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
-import { trim } from 'lodash'
library.add(
faPlus,
@@ -20,103 +19,32 @@ const ReactButton = {
}
},
components: {
- Popover
+ Popover,
+ EmojiPicker
},
methods: {
- addReaction (event, emoji, close) {
+ addReaction (event) {
+ const emoji = event.insertion
const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji)
if (existingReaction && existingReaction.me) {
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
} else {
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
}
- close()
+ },
+ show () {
+ if (!this.expanded) {
+ this.$refs.picker.showPicker()
+ }
},
onShow () {
this.expanded = true
- this.focusInput()
},
onClose () {
this.expanded = false
- },
- focusInput () {
- this.$nextTick(() => {
- const input = document.querySelector('.reaction-picker-filter > input')
- if (input) input.focus()
- })
- },
- // Vaguely adjusted copypaste from emoji_input and emoji_picker!
- maybeLocalizedEmojiNamesAndKeywords (emoji) {
- const names = [emoji.displayText]
- const keywords = []
-
- if (emoji.displayTextI18n) {
- names.push(this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args))
- }
-
- if (emoji.annotations) {
- this.languages.forEach(lang => {
- names.push(emoji.annotations[lang]?.name)
-
- keywords.push(...(emoji.annotations[lang]?.keywords || []))
- })
- }
-
- return {
- names: names.filter(k => k),
- keywords: keywords.filter(k => k)
- }
- },
- maybeLocalizedEmojiName (emoji) {
- if (!emoji.annotations) {
- return emoji.displayText
- }
-
- if (emoji.displayTextI18n) {
- return this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args)
- }
-
- for (const lang of this.languages) {
- if (emoji.annotations[lang]?.name) {
- return emoji.annotations[lang].name
- }
- }
-
- return emoji.displayText
}
},
computed: {
- commonEmojis () {
- const hardcodedSet = new Set(['👍', '😠', '👀', '😂', '🔥'])
- return this.$store.getters.standardEmojiList.filter(emoji => hardcodedSet.has(emoji.replacement))
- },
- languages () {
- return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage)
- },
- emojis () {
- if (this.filterWord !== '') {
- const keywordLowercase = trim(this.filterWord.toLowerCase())
-
- const orderedEmojiList = []
- for (const emoji of this.$store.getters.standardEmojiList) {
- const indices = this.maybeLocalizedEmojiNamesAndKeywords(emoji)
- .keywords
- .map(k => k.toLowerCase().indexOf(keywordLowercase))
- .filter(k => k > -1)
-
- const indexOfKeyword = indices.length ? Math.min(...indices) : -1
-
- if (indexOfKeyword > -1) {
- if (!Array.isArray(orderedEmojiList[indexOfKeyword])) {
- orderedEmojiList[indexOfKeyword] = []
- }
- orderedEmojiList[indexOfKeyword].push(emoji)
- }
- }
- return orderedEmojiList.flat()
- }
- return this.$store.getters.standardEmojiList || []
- },
mergedConfig () {
return this.$store.getters.mergedConfig
}
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
@@ -1,73 +1,38 @@
<template>
- <Popover
- trigger="click"
- class="ReactButton"
- placement="top"
- :offset="{ y: 5 }"
- :bound-to="{ x: 'container' }"
- remove-padding
- popover-class="ReactButton popover-default"
- @show="onShow"
- @close="onClose"
- >
- <template #content="{close}">
- <div class="reaction-picker-filter">
- <input
- v-model="filterWord"
- size="1"
- :placeholder="$t('emoji.search_emoji')"
- @input="$event.target.composing = false"
- >
- </div>
- <div class="reaction-picker">
- <span
- v-for="emoji in commonEmojis"
- :key="emoji.replacement"
- class="emoji-button"
- :title="maybeLocalizedEmojiName(emoji)"
- @click="addReaction($event, emoji.replacement, close)"
- >
- {{ emoji.replacement }}
- </span>
- <div class="reaction-picker-divider" />
- <span
- v-for="(emoji, key) in emojis"
- :key="key"
- class="emoji-button"
- :title="maybeLocalizedEmojiName(emoji)"
- @click="addReaction($event, emoji.replacement, close)"
- >
- {{ emoji.replacement }}
- </span>
- <div class="reaction-bottom-fader" />
- </div>
- </template>
- <template #trigger>
- <span
- class="button-unstyled popover-trigger"
- :title="$t('tool_tip.add_reaction')"
- >
- <FALayers>
- <FAIcon
- class="fa-scale-110 fa-old-padding"
- :icon="['far', 'smile-beam']"
- />
- <FAIcon
- v-show="!expanded"
- class="focus-marker"
- transform="shrink-6 up-9 right-17"
- icon="plus"
- />
- <FAIcon
- v-show="expanded"
- class="focus-marker"
- transform="shrink-6 up-9 right-17"
- icon="times"
- />
- </FALayers>
- </span>
- </template>
- </Popover>
+ <span class="ReactButton">
+ <EmojiPicker
+ ref="picker"
+ :enable-sticker-picker="enableStickerPicker"
+ class="emoji-picker-panel"
+ @emoji="addReaction"
+ @show="onShow"
+ @close="onClose"
+ />
+ <span
+ class="button-unstyled popover-trigger"
+ :title="$t('tool_tip.add_reaction')"
+ @click.stop.prevent="show"
+ >
+ <FALayers>
+ <FAIcon
+ class="fa-scale-110 fa-old-padding"
+ :icon="['far', 'smile-beam']"
+ />
+ <FAIcon
+ v-show="!expanded"
+ class="focus-marker"
+ transform="shrink-6 up-9 right-17"
+ icon="plus"
+ />
+ <FAIcon
+ v-show="expanded"
+ class="focus-marker"
+ transform="shrink-6 up-9 right-17"
+ icon="times"
+ />
+ </FALayers>
+ </span>
+ </span>
</template>
<script src="./react_button.js"></script>
@@ -135,11 +100,6 @@
color: $fallback--text;
color: var(--text, $fallback--text);
}
- }
-
- .popover-trigger-button {
- /* override of popover internal stuff */
- width: auto;
@include unfocused-style {
.focus-marker {
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -441,6 +441,7 @@ export const parseNotification = (data) => {
: parseUser(data.target)
output.from_profile = parseUser(data.account)
output.emoji = data.emoji
+ output.emoji_url = data.emoji_url
if (data.report) {
output.report = data.report
output.report.content = data.report.content