diff options
Diffstat (limited to 'src/components/react_button')
| -rw-r--r-- | src/components/react_button/react_button.js | 94 | ||||
| -rw-r--r-- | src/components/react_button/react_button.vue | 65 |
2 files changed, 121 insertions, 38 deletions
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 37d6e7d0..47a48623 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -1,15 +1,22 @@ import Popover from '../popover/popover.vue' +import { ensureFinalFallback } from '../../i18n/languages.js' 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(faSmileBeam) +library.add( + faPlus, + faTimes, + faSmileBeam +) const ReactButton = { props: ['status'], data () { return { - filterWord: '' + filterWord: '', + expanded: false } }, components: { @@ -25,41 +32,90 @@ const ReactButton = { } close() }, + onShow () { + this.expanded = true + this.focusInput() + }, + onClose () { + this.expanded = false + }, focusInput () { this.$nextTick(() => { - const input = this.$el.querySelector('input') + 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 () { - return [ - { displayText: 'thumbsup', replacement: '👍' }, - { displayText: 'angry', replacement: '😠' }, - { displayText: 'eyes', replacement: '👀' }, - { displayText: 'joy', replacement: '😂' }, - { displayText: 'fire', replacement: '🔥' } - ] + 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 filterWordLowercase = trim(this.filterWord.toLowerCase()) + const keywordLowercase = trim(this.filterWord.toLowerCase()) + const orderedEmojiList = [] - for (const emoji of this.$store.state.instance.emoji) { - if (emoji.replacement === this.filterWord) return [emoji] + 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 - const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase) - if (indexOfFilterWord > -1) { - if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) { - orderedEmojiList[indexOfFilterWord] = [] + if (indexOfKeyword > -1) { + if (!Array.isArray(orderedEmojiList[indexOfKeyword])) { + orderedEmojiList[indexOfKeyword] = [] } - orderedEmojiList[indexOfFilterWord].push(emoji) + orderedEmojiList[indexOfKeyword].push(emoji) } } return orderedEmojiList.flat() } - return this.$store.state.instance.emoji || [] + 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 index 5a809847..a813b6fd 100644 --- a/src/components/react_button/react_button.vue +++ b/src/components/react_button/react_button.vue @@ -7,7 +7,8 @@ :bound-to="{ x: 'container' }" remove-padding popover-class="ReactButton popover-default" - @show="focusInput" + @show="onShow" + @close="onClose" > <template #content="{close}"> <div class="reaction-picker-filter"> @@ -23,7 +24,7 @@ v-for="emoji in commonEmojis" :key="emoji.replacement" class="emoji-button" - :title="emoji.displayText" + :title="maybeLocalizedEmojiName(emoji)" @click="addReaction($event, emoji.replacement, close)" > {{ emoji.replacement }} @@ -33,7 +34,7 @@ v-for="(emoji, key) in emojis" :key="key" class="emoji-button" - :title="emoji.displayText" + :title="maybeLocalizedEmojiName(emoji)" @click="addReaction($event, emoji.replacement, close)" > {{ emoji.replacement }} @@ -46,10 +47,24 @@ class="button-unstyled popover-trigger" :title="$t('tool_tip.add_reaction')" > - <FAIcon - class="fa-scale-110 fa-old-padding" - :icon="['far', 'smile-beam']" - /> + <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> @@ -58,7 +73,8 @@ <script src="./react_button.js"></script> <style lang="scss"> -@import '../../_variables.scss'; +@import "../../variables"; +@import "../../mixins"; .ReactButton { .reaction-picker-filter { @@ -88,20 +104,19 @@ text-align: center; align-content: flex-start; user-select: none; - - mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat, - linear-gradient(to bottom, white 0, transparent 100%) top no-repeat, - linear-gradient(to top, white, white); + mask: + linear-gradient(to top, white 0, transparent 100%) bottom no-repeat, + linear-gradient(to bottom, white 0, transparent 100%) top no-repeat, + linear-gradient(to top, white, white); transition: mask-size 150ms; mask-size: 100% 20px, 100% 20px, auto; /* Autoprefixed seem to ignore this one, and also syntax is different */ - -webkit-mask-composite: xor; + mask-composite: xor; mask-composite: exclude; .emoji-button { cursor: pointer; - flex-basis: 20%; line-height: 1.5; align-content: center; @@ -112,11 +127,6 @@ } } - /* override of popover internal stuff */ - .popover-trigger-button { - width: auto; - } - .popover-trigger { padding: 10px; margin: -10px; @@ -126,6 +136,23 @@ color: var(--text, $fallback--text); } } + + .popover-trigger-button { + /* override of popover internal stuff */ + width: auto; + + @include unfocused-style { + .focus-marker { + visibility: hidden; + } + } + + @include focused-style { + .focus-marker { + visibility: visible; + } + } + } } </style> |
