diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.js b/src/components/emoji_reaction_picker/emoji_reaction_picker.js deleted file mode 100644 index 6b589079..00000000 --- a/src/components/emoji_reaction_picker/emoji_reaction_picker.js +++ /dev/null @@ -1,213 +0,0 @@ -import { defineAsyncComponent } from 'vue' -import Checkbox from '../checkbox/checkbox.vue' -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faBoxOpen, - faStickyNote, - faSmileBeam -} from '@fortawesome/free-solid-svg-icons' - -library.add( - faBoxOpen, - faStickyNote, - faSmileBeam -) - -// At widest, approximately 20 emoji are visible in a row, -// loading 3 rows, could be overkill for narrow picker -const LOAD_EMOJI_BY = 60 - -// When to start loading new batch emoji, in pixels -const LOAD_EMOJI_MARGIN = 64 - -const filterByKeyword = (list, keyword = '') => { - if (keyword === '') return list - - const keywordLowercase = keyword.toLowerCase() - let orderedEmojiList = [] - for (const emoji of list) { - const indexOfKeyword = emoji.displayText.toLowerCase().indexOf(keywordLowercase) - if (indexOfKeyword > -1) { - if (!Array.isArray(orderedEmojiList[indexOfKeyword])) { - orderedEmojiList[indexOfKeyword] = [] - } - orderedEmojiList[indexOfKeyword].push(emoji) - } - } - return orderedEmojiList.flat() -} - -const EmojiPicker = { - props: { - enableStickerPicker: { - required: false, - type: Boolean, - default: false - } - }, - data () { - return { - keyword: '', - activeGroup: 'custom', - showingStickers: false, - groupsScrolledClass: 'scrolled-top', - keepOpen: false, - customEmojiBufferSlice: LOAD_EMOJI_BY, - customEmojiTimeout: null, - customEmojiLoadAllConfirmed: false - } - }, - components: { - StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')), - Checkbox - }, - methods: { - onStickerUploaded (e) { - this.$emit('sticker-uploaded', e) - }, - onStickerUploadFailed (e) { - this.$emit('sticker-upload-failed', e) - }, - onEmoji (emoji) { - const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement - this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) - }, - onScroll (e) { - const target = (e && e.target) || this.$refs['emoji-groups'] - this.updateScrolledClass(target) - this.scrolledGroup(target) - this.triggerLoadMore(target) - }, - highlight (key) { - const ref = this.$refs['group-' + key] - const top = ref.offsetTop - this.setShowStickers(false) - this.activeGroup = key - this.$nextTick(() => { - this.$refs['emoji-groups'].scrollTop = top + 1 - }) - }, - updateScrolledClass (target) { - if (target.scrollTop <= 5) { - this.groupsScrolledClass = 'scrolled-top' - } else if (target.scrollTop >= target.scrollTopMax - 5) { - this.groupsScrolledClass = 'scrolled-bottom' - } else { - this.groupsScrolledClass = 'scrolled-middle' - } - }, - triggerLoadMore (target) { - const ref = this.$refs['group-end-custom'] - if (!ref) return - const bottom = ref.offsetTop + ref.offsetHeight - - const scrollerBottom = target.scrollTop + target.clientHeight - const scrollerTop = target.scrollTop - const scrollerMax = target.scrollHeight - - // Loads more emoji when they come into view - const approachingBottom = bottom - scrollerBottom < LOAD_EMOJI_MARGIN - // Always load when at the very top in case there's no scroll space yet - const atTop = scrollerTop < 5 - // Don't load when looking at unicode category or at the very bottom - const bottomAboveViewport = bottom < scrollerTop || scrollerBottom === scrollerMax - if (!bottomAboveViewport && (approachingBottom || atTop)) { - this.loadEmoji() - } - }, - scrolledGroup (target) { - const top = target.scrollTop + 5 - this.$nextTick(() => { - this.emojisView.forEach(group => { - const ref = this.$refs['group-' + group.id] - if (ref.offsetTop <= top) { - this.activeGroup = group.id - } - }) - }) - }, - loadEmoji () { - const allLoaded = this.customEmojiBuffer.length === this.filteredEmoji.length - - if (allLoaded) { - return - } - - this.customEmojiBufferSlice += LOAD_EMOJI_BY - }, - startEmojiLoad (forceUpdate = false) { - if (!forceUpdate) { - this.keyword = '' - } - this.$nextTick(() => { - this.$refs['emoji-groups'].scrollTop = 0 - }) - const bufferSize = this.customEmojiBuffer.length - const bufferPrefilledAll = bufferSize === this.filteredEmoji.length - if (bufferPrefilledAll && !forceUpdate) { - return - } - this.customEmojiBufferSlice = LOAD_EMOJI_BY - }, - toggleStickers () { - this.showingStickers = !this.showingStickers - }, - setShowStickers (value) { - this.showingStickers = value - } - }, - watch: { - keyword () { - this.customEmojiLoadAllConfirmed = false - this.onScroll() - this.startEmojiLoad(true) - } - }, - computed: { - activeGroupView () { - return this.showingStickers ? '' : this.activeGroup - }, - stickersAvailable () { - if (this.$store.state.instance.stickers) { - return this.$store.state.instance.stickers.length > 0 - } - return 0 - }, - filteredEmoji () { - return filterByKeyword( - this.$store.state.instance.customEmoji || [], - this.keyword - ) - }, - customEmojiBuffer () { - return this.filteredEmoji.slice(0, this.customEmojiBufferSlice) - }, - emojis () { - const standardEmojis = this.$store.state.instance.emoji || [] - const customEmojis = this.customEmojiBuffer - - return [ - { - id: 'custom', - text: this.$t('emoji.custom'), - icon: 'smile-beam', - emojis: customEmojis - }, - { - id: 'standard', - text: this.$t('emoji.unicode'), - icon: 'box-open', - emojis: filterByKeyword(standardEmojis, this.keyword) - } - ] - }, - emojisView () { - return this.emojis.filter(value => value.emojis.length > 0) - }, - stickerPickerEnabled () { - return (this.$store.state.instance.stickers || []).length !== 0 - } - } -} - -export default EmojiPicker diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.scss b/src/components/emoji_reaction_picker/emoji_reaction_picker.scss deleted file mode 100644 index 2055e02e..00000000 --- a/src/components/emoji_reaction_picker/emoji_reaction_picker.scss +++ /dev/null @@ -1,186 +0,0 @@ -@import '../../_variables.scss'; - -.emoji-picker { - display: flex; - flex-direction: column; - position: absolute; - right: 0; - left: 0; - margin: 0 !important; - z-index: 100; - background-color: $fallback--bg; - background-color: var(--popover, $fallback--bg); - color: $fallback--link; - color: var(--popoverText, $fallback--link); - --lightText: var(--popoverLightText, $fallback--faint); - --faint: var(--popoverFaintText, $fallback--faint); - --faintLink: var(--popoverFaintLink, $fallback--faint); - --lightText: var(--popoverLightText, $fallback--lightText); - --icon: var(--popoverIcon, $fallback--icon); - - .keep-open, - .too-many-emoji { - padding: 7px; - line-height: normal; - } - - .too-many-emoji { - display: flex; - flex-direction: column; - } - - .keep-open-label { - padding: 0 7px; - display: flex; - } - - .heading { - display: flex; - height: 32px; - padding: 10px 7px 5px; - } - - .content { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0px; - } - - .emoji-tabs { - flex-grow: 1; - } - - .emoji-groups { - min-height: 200px; - } - - .additional-tabs { - border-left: 1px solid; - border-left-color: $fallback--icon; - border-left-color: var(--icon, $fallback--icon); - padding-left: 7px; - flex: 0 0 auto; - } - - .additional-tabs, - .emoji-tabs { - display: block; - min-width: 0; - flex-basis: auto; - flex-shrink: 1; - - &-item { - padding: 0 7px; - cursor: pointer; - font-size: 1.85em; - - &.disabled { - opacity: 0.5; - pointer-events: none; - } - - &.active { - border-bottom: 4px solid; - - svg { - color: $fallback--lightText; - color: var(--lightText, $fallback--lightText); - } - } - } - } - - .sticker-picker { - flex: 1 1 auto - } - - .stickers, - .emoji { - &-content { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0; - - &.hidden { - opacity: 0; - pointer-events: none; - position: absolute; - } - } - } - - .emoji { - &-search { - padding: 5px; - flex: 0 0 auto; - - input { - width: 100%; - } - } - - &-groups { - flex: 1 1 1px; - position: relative; - overflow: auto; - 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); - 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: exclude; - &.scrolled { - &-top { - mask-size: 100% 20px, 100% 0, auto; - } - &-bottom { - mask-size: 100% 0, 100% 20px, auto; - } - } - } - - &-group { - display: flex; - align-items: center; - flex-wrap: wrap; - padding-left: 5px; - justify-content: left; - - &-title { - font-size: 0.85em; - width: 100%; - margin: 0; - - &.disabled { - display: none; - } - } - } - - &-item { - width: 32px; - height: 32px; - box-sizing: border-box; - display: flex; - font-size: 32px; - align-items: center; - justify-content: center; - margin: 4px; - - cursor: pointer; - - img { - object-fit: contain; - max-width: 100%; - max-height: 100%; - } - } - - } - -} diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.vue b/src/components/emoji_reaction_picker/emoji_reaction_picker.vue deleted file mode 100644 index a24eeb7e..00000000 --- a/src/components/emoji_reaction_picker/emoji_reaction_picker.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - - diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 9f415e11..ac939b26 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -1,5 +1,6 @@ import Popover from '../popover/popover.vue' import EmojiReactionPicker from '../emoji_reaction_picker/emoji_reaction_picker.vue' +import EmojiPicker from '../emoji_picker/emoji_picker.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' @@ -14,6 +15,7 @@ const ReactButton = { }, components: { Popover, + EmojiPicker, EmojiReactionPicker }, methods: { diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue index afb9df4e..cc94f2fa 100644 --- a/src/components/react_button/react_button.vue +++ b/src/components/react_button/react_button.vue @@ -9,7 +9,8 @@ @show="focusInput" >