diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/emoji-input/emoji-input.js | 10 | ||||
| -rw-r--r-- | src/components/emoji-input/emoji-input.vue | 5 | ||||
| -rw-r--r-- | src/components/emoji-selector/emoji-selector.js | 45 | ||||
| -rw-r--r-- | src/components/emoji-selector/emoji-selector.vue | 133 |
4 files changed, 193 insertions, 0 deletions
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js index a5bb6eaf..8f7598ca 100644 --- a/src/components/emoji-input/emoji-input.js +++ b/src/components/emoji-input/emoji-input.js @@ -1,4 +1,6 @@ import Completion from '../../services/completion/completion.js' +import EmojiSelector from '../emoji-selector/emoji-selector.vue' + import { take, filter, map } from 'lodash' const EmojiInput = { @@ -14,6 +16,9 @@ const EmojiInput = { caret: 0 } }, + components: { + EmojiSelector + }, computed: { suggestions () { const firstchar = this.textAtCaret.charAt(0) @@ -100,6 +105,11 @@ const EmojiInput = { }, setCaret ({target: {selectionStart}}) { this.caret = selectionStart + }, + onEmoji (emoji) { + const newValue = this.value.substr(0, this.caret) + emoji + this.value.substr(this.caret) + this.$refs.input.focus() + this.$emit('input', newValue) } } } diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue index 338b77cd..151861de 100644 --- a/src/components/emoji-input/emoji-input.vue +++ b/src/components/emoji-input/emoji-input.vue @@ -15,6 +15,7 @@ @keydown.shift.tab="cycleBackward" @keydown.tab="cycleForward" @keydown.enter="replaceEmoji" + ref="input" /> <textarea v-else @@ -30,7 +31,9 @@ @keydown.shift.tab="cycleBackward" @keydown.tab="cycleForward" @keydown.enter="replaceEmoji" + ref="input" ></textarea> + <EmojiSelector @emoji="onEmoji" /> <div class="autocomplete-panel" v-if="suggestions"> <div class="autocomplete-panel-body"> <div @@ -57,6 +60,8 @@ @import '../../_variables.scss'; .emoji-input { + position: relative; + .form-control { width: 100%; } diff --git a/src/components/emoji-selector/emoji-selector.js b/src/components/emoji-selector/emoji-selector.js new file mode 100644 index 00000000..133506b7 --- /dev/null +++ b/src/components/emoji-selector/emoji-selector.js @@ -0,0 +1,45 @@ +const filterByKeyword = (list, keyword = '') => { + return list.filter(x => x.shortcode.indexOf(keyword) !== -1) +} + +const EmojiSelector = { + data () { + return { + open: false, + keyword: '' + } + }, + methods: { + togglePanel () { + this.open = !this.open + }, + onEmoji (emoji) { + const value = emoji.image_url ? `:${emoji.shortcode}:` : emoji.utf + this.$emit('emoji', ` ${value} `) + this.open = false + } + }, + computed: { + emojis () { + const standardEmojis = this.$store.state.instance.emoji || [] + const customEmojis = this.$store.state.instance.customEmoji || [] + return { + standard: { + text: 'Standard', + icon: 'icon-star', + emojis: filterByKeyword(standardEmojis, this.keyword) + }, + custom: { + text: 'Custom', + icon: 'icon-picture', + emojis: filterByKeyword(customEmojis, this.keyword) + } + } + }, + serverUrl () { + return this.$store.state.instance.server + } + } +} + +export default EmojiSelector diff --git a/src/components/emoji-selector/emoji-selector.vue b/src/components/emoji-selector/emoji-selector.vue new file mode 100644 index 00000000..f05ff1e9 --- /dev/null +++ b/src/components/emoji-selector/emoji-selector.vue @@ -0,0 +1,133 @@ +<template> + <div class="emoji-dropdown"> + <span class="emoji-dropdown-toggle" @click="togglePanel"> + <i class="icon-smile"></i> + </span> + <div class="emoji-dropdown-menu panel panel-default" v-if="open"> + <div class="panel-heading emoji-tabs"> + <span class="emoji-tabs-item" v-for="(value, key) in emojis" :key="key" :title="value.text"> + <i :class="value.icon"></i> + </span> + </div> + <div class="panel-body emoji-dropdown-menu-content"> + <div class="emoji-search"> + <input type="text" class="form-control" v-model="keyword" /> + </div> + <div class="emoji-groups"> + <div v-for="(value, key) in emojis" :key="key" class="emoji-group"> + <h6 class="emoji-group-title">{{value.text}}</h6> + <span + v-for="emoji in value.emojis" + :key="key + emoji.shortcode" + :title="emoji.shortcode" + class="emoji-item" + @click="onEmoji(emoji)" + > + <span v-if="!emoji.image_url">{{emoji.utf}}</span> + <img :src="serverUrl + emoji.image_url" v-else> + </span> + </div> + </div> + </div> + </div> + </div> +</template> + +<script src="./emoji-selector.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.emoji { + &-dropdown { + position: absolute; + right: 0; + top: 100%; + z-index: 1; + + &-toggle { + cursor: pointer; + position: absolute; + top: -25px; + right: 2px; + + i { + font-size: 18px; + } + } + + &-menu { + position: absolute; + z-index: 1; + right: 0; + width: 300px; + height: 300px; + display: flex; + flex-direction: column; + margin: 0 !important; + + &-content { + flex: 1 1 1px; + display: flex; + flex-direction: column; + } + } + } + + &-tabs { + &-item { + padding: 0 5px; + + &:first-child, &.active { + border-bottom: 4px solid; + + i { + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); + } + } + } + } + + &-search { + padding: 5px; + } + + &-groups { + flex: 1 1 1px; + overflow: auto; + } + + &-group { + display: flex; + align-items: center; + flex-wrap: wrap; + width: 100%; + + &-title { + font-size: 12px; + width: 100%; + margin: 0; + padding: 5px; + } + } + + &-item { + width: 34px; + height: 34px; + box-sizing: border-box; + display: flex; + font-size: 16px; + align-items: center; + justify-content: center; + padding: 5px; + cursor: pointer; + + img { + max-width: 100%; + max-height: 100%; + } + } + +} +</style> |
