forked from AkkomaGang/akkoma-fe
add recently used emojis panel to emoji picker (#283)
~~(not intended for merging yet, just submitting this for preliminary review and discussion)~~ this patch adds a tab with recently used emojis to the emoji picker: https://akko.lain.gay/notice/ASoGCtyoiXbYPJjqpk there's a couple of things i'm ~~still trying to work out~~ not totally happy with and i'd appreciate any feedback on them: * the recentEmojis getter is called very frequently and has to do a possibly somewhat expensive lookup of emoji objects by their `displayName` each time, which i'm not sure is ideal * ~~emoji reactions on posts added through the picker are picked up by the recentEmojis module, but clicks on existing emoji reactions are not, because `addReaction` in `react_button.js` only currently receives the replacement and not the full emoji object (if there even is one wherever that method is called from)~~ this works now and does the same stupid full search of all emojis by their name which i guess is less bad because this only happens when you hit a reaction emoji button that already existed Reviewed-on: AkkomaGang/akkoma-fe#283 Co-authored-by: flisk <akkomadev.mvch71fq@flisk.xyz> Co-committed-by: flisk <akkomadev.mvch71fq@flisk.xyz>
This commit is contained in:
parent
9d450953b6
commit
1e66217c16
6 changed files with 77 additions and 4 deletions
|
@ -51,6 +51,7 @@ const EmojiPicker = {
|
|||
onEmoji (emoji) {
|
||||
const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
|
||||
this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
|
||||
this.$store.commit('emojiUsed', emoji)
|
||||
},
|
||||
onWheel (e) {
|
||||
e.preventDefault()
|
||||
|
@ -96,6 +97,7 @@ const EmojiPicker = {
|
|||
)
|
||||
},
|
||||
emojis () {
|
||||
const recentEmojis = this.$store.getters.recentEmojis
|
||||
const standardEmojis = this.$store.state.instance.emoji || []
|
||||
const customEmojis = this.sortedEmoji
|
||||
const emojiPacks = []
|
||||
|
@ -108,6 +110,15 @@ const EmojiPicker = {
|
|||
})
|
||||
})
|
||||
return [
|
||||
{
|
||||
id: 'recent',
|
||||
text: this.$t('emoji.recent'),
|
||||
first: {
|
||||
imageUrl: '',
|
||||
replacement: '🕒',
|
||||
},
|
||||
emojis: this.filterByKeyword(recentEmojis)
|
||||
},
|
||||
{
|
||||
id: 'standard',
|
||||
text: this.$t('emoji.unicode'),
|
||||
|
|
|
@ -3,6 +3,11 @@ import UserListPopover from '../user_list_popover/user_list_popover.vue'
|
|||
|
||||
const EMOJI_REACTION_COUNT_CUTOFF = 12
|
||||
|
||||
const findEmojiByReplacement = (state, replacement) => {
|
||||
const allEmojis = state.instance.emoji.concat(state.instance.customEmoji)
|
||||
return allEmojis.find(emoji => emoji.replacement === replacement)
|
||||
}
|
||||
|
||||
const EmojiReactions = {
|
||||
name: 'EmojiReactions',
|
||||
components: {
|
||||
|
@ -54,6 +59,8 @@ const EmojiReactions = {
|
|||
},
|
||||
reactWith (emoji) {
|
||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||
const emojiObject = findEmojiByReplacement(this.$store.state, emoji)
|
||||
this.$store.commit('emojiUsed', emojiObject)
|
||||
},
|
||||
unreact (emoji) {
|
||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||
|
|
|
@ -86,7 +86,8 @@
|
|||
"load_all_hint": "Loaded first {saneAmount} emojo, loading all emojo may cause performance issues.",
|
||||
"search_emoji": "Search for an emojo",
|
||||
"stickers": "Stickers",
|
||||
"unicode": "Unicode emojo"
|
||||
"unicode": "Unicode emojo",
|
||||
"recent": "Recently used"
|
||||
},
|
||||
"errors": {
|
||||
"storage_unavailable": "Akkoma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies."
|
||||
|
|
|
@ -19,7 +19,8 @@ const saveImmedeatelyActions = [
|
|||
'setOption',
|
||||
'setClientData',
|
||||
'setToken',
|
||||
'clearToken'
|
||||
'clearToken',
|
||||
'emojiUsed',
|
||||
]
|
||||
|
||||
const defaultStorage = (() => {
|
||||
|
|
|
@ -22,6 +22,7 @@ import announcementsModule from './modules/announcements.js'
|
|||
import editStatusModule from './modules/editStatus.js'
|
||||
import statusHistoryModule from './modules/statusHistory.js'
|
||||
import tagModule from './modules/tags.js'
|
||||
import recentEmojisModule from './modules/recentEmojis.js'
|
||||
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
|
@ -47,7 +48,8 @@ const persistedStateOptions = {
|
|||
paths: [
|
||||
'config',
|
||||
'users.lastLoginName',
|
||||
'oauth'
|
||||
'oauth',
|
||||
'recentEmojis.emojis',
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -98,7 +100,8 @@ const persistedStateOptions = {
|
|||
announcements: announcementsModule,
|
||||
editStatus: editStatusModule,
|
||||
statusHistory: statusHistoryModule,
|
||||
tags: tagModule
|
||||
tags: tagModule,
|
||||
recentEmojis: recentEmojisModule,
|
||||
},
|
||||
plugins,
|
||||
strict: false // Socket modifies itself, let's ignore this for now.
|
||||
|
|
50
src/modules/recentEmojis.js
Normal file
50
src/modules/recentEmojis.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
// each row is 7 emojis, 6 rows chosen arbitrarily. i don't think more than
|
||||
// that are going to be useful.
|
||||
const RECENT_MAX = 7 * 6
|
||||
|
||||
const defaultState = {
|
||||
emojis: [],
|
||||
}
|
||||
|
||||
const recentEmojis = {
|
||||
state: defaultState,
|
||||
|
||||
mutations: {
|
||||
emojiUsed ({ emojis }, emoji) {
|
||||
if (emoji.displayText === undefined || emoji.displayText === null) {
|
||||
console.error('emojiUsed was called with a bad emoji object: ', emoji)
|
||||
return
|
||||
} else if (emoji.displayText.includes('@')) {
|
||||
console.error('emojiUsed was called with a remote emoji: ', emoji)
|
||||
return
|
||||
}
|
||||
|
||||
const i = emojis.indexOf(emoji.displayText)
|
||||
|
||||
if (i === -1) {
|
||||
// not in `emojis` yet, insert and truncate if necessary
|
||||
const newLength = emojis.unshift(emoji.displayText)
|
||||
if (newLength > RECENT_MAX) {
|
||||
emojis.pop()
|
||||
}
|
||||
} else if (i !== 0) {
|
||||
// emoji is already in `emojis` but needs to be bumped to the top
|
||||
emojis.splice(i, 1)
|
||||
emojis.unshift(emoji.displayText)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
getters: {
|
||||
recentEmojis: (state, getters, rootState) => state.emojis.reduce((objects, displayText) => {
|
||||
const allEmojis = rootState.instance.emoji.concat(rootState.instance.customEmoji)
|
||||
let emojiObject = allEmojis.find(emoji => emoji.displayText === displayText)
|
||||
if (emojiObject !== undefined) {
|
||||
objects.push(emojiObject)
|
||||
}
|
||||
return objects
|
||||
}, []),
|
||||
},
|
||||
}
|
||||
|
||||
export default recentEmojis
|
Loading…
Reference in a new issue