@@ -16,8 +16,11 @@
v-if="emojiPicker"
ref="picker"
:class="{ hide: !showPicker }"
+ :sticker-picker="stickerPicker"
class="emoji-picker-panel"
@emoji="insert"
+ @sticker-uploaded="onStickerUploaded"
+ @sticker-upload-failed="onStickerUploadFailed"
/>
{
return list.filter(x => x.displayText.includes(keyword))
}
const EmojiPicker = {
+ props: {
+ stickerPicker: {
+ required: false,
+ type: Boolean,
+ default: false
+ }
+ },
data () {
return {
keyword: '',
- activeGroup: 'standard',
- showingAdditional: false
+ activeGroup: 'custom',
+ showingStickers: false
}
},
+ components: {
+ StickerPicker: () => import('../sticker_picker/sticker_picker.vue')
+ },
methods: {
onEmoji (emoji) {
const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
@@ -19,37 +30,72 @@ const EmojiPicker = {
highlight (key) {
const ref = this.$refs['group-' + key]
const top = ref[0].offsetTop
- this.$refs['emoji-groups'].scrollTop = top + 1
+ this.setShowStickers(false)
this.activeGroup = key
- },
- scrolledGroup (e) {
- const top = e.target.scrollTop
- Object.keys(this.emojis).forEach(key => {
- if (this.$refs['group-' + key][0].offsetTop < top) {
- this.activeGroup = key
- }
+ this.$nextTick(() => {
+ this.$refs['emoji-groups'].scrollTop = top + 1
})
},
- toggleAdditional (value) {
- this.showingAdditional = value
+ scrolledGroup (e) {
+ const target = (e && e.target) || this.$refs['emoji-groups']
+ const top = target.scrollTop + 5
+ this.$nextTick(() => {
+ this.emojisView.forEach(group => {
+ const ref = this.$refs['group-' + group.id]
+ if (ref[0].offsetTop <= top) {
+ this.activeGroup = group.id
+ }
+ })
+ })
+ },
+ toggleStickers () {
+ this.showingStickers = !this.showingStickers
+ },
+ setShowStickers (value) {
+ this.showingStickers = value
+ },
+ onStickerUploaded (e) {
+ this.$emit('sticker-uploaded', e)
+ },
+ onStickerUploadFailed (e) {
+ this.$emit('sticker-upload-failed', e)
+ }
+ },
+ watch: {
+ keyword () {
+ this.scrolledGroup()
}
},
computed: {
+ activeGroupView () {
+ return this.showingStickers ? '' : this.activeGroup
+ },
+ stickersAvailable () {
+ if (this.$store.state.instance.stickers) {
+ return this.$store.state.instance.stickers.length > 0
+ }
+ return 0
+ },
emojis () {
const standardEmojis = this.$store.state.instance.emoji || []
const customEmojis = this.$store.state.instance.customEmoji || []
- return {
- custom: {
- text: 'Custom',
- icon: 'icon-picture',
+ return [
+ {
+ id: 'custom',
+ text: this.$t('emoji.custom'),
+ icon: 'icon-smile',
emojis: filterByKeyword(customEmojis, this.keyword)
},
- standard: {
- text: 'Standard',
- icon: 'icon-star',
+ {
+ id: 'standard',
+ text: this.$t('emoji.unicode'),
+ icon: 'icon-picture',
emojis: filterByKeyword(standardEmojis, this.keyword)
}
- }
+ ]
+ },
+ emojisView () {
+ return this.emojis.filter(value => value.emojis.length > 0)
}
}
}
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 72889441..6c13e82b 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -1,39 +1,78 @@
@import '../../_variables.scss';
.emoji-picker {
- position: absolute;
- z-index: 1;
- right: 0;
- width: 300px;
- height: 300px;
display: flex;
flex-direction: column;
+ position: absolute;
+ right: 0;
+ left: 0;
+ height: 300px;
margin: 0 !important;
+ z-index: 1;
- .emoji {
- &-tabs {
- &-item {
- padding: 0 5px;
+ .panel-body {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 0;
+ min-height: 0px;
+ }
- &.active {
- border-bottom: 4px solid;
+ .additional-tabs {
+ border-left: 1px solid;
+ border-left-color: $fallback--icon;
+ border-left-color: var(--icon, $fallback--icon);
+ padding-left: 5px;
+ flex: 0 0 0;
+ }
- i {
- color: $fallback--lightText;
- color: var(--lightText, $fallback--lightText);
- }
+ .emoji-tabs {
+ flex: 1 1 0;
+ }
+
+ .additional-tabs,
+ .emoji-tabs {
+ &-item {
+ padding: 0 5px;
+ cursor: pointer;
+ font-size: 24px;
+
+ &.disabled {
+ opacity: 0.5;
+ pointer-events: none;
+ }
+ &.active {
+ border-bottom: 4px solid;
+
+ i {
+ color: $fallback--lightText;
+ color: var(--lightText, $fallback--lightText);
}
}
}
+ }
+ .sticker-picker {
+ flex: 1 1 0
+ }
+
+ .stickers,
+ .emoji {
&-content {
display: flex;
flex-direction: column;
- }
+ flex: 1 1 0;
+ min-height: 0;
+ &.hidden {
+ display: none
+ }
+ }
+ }
+
+ .emoji {
&-search {
padding: 5px;
- flex: 0 0 1px;
+ flex: 0 0 0;
input {
width: 100%;
@@ -50,13 +89,16 @@
display: flex;
align-items: center;
flex-wrap: wrap;
- padding: 5px;
- justify-content: space-between;
+ padding-left: 5px;
+ justify-content: left;
&-title {
font-size: 12px;
width: 100%;
margin: 0;
+ &.disabled {
+ display: none;
+ }
}
}
@@ -68,7 +110,7 @@
font-size: 32px;
align-items: center;
justify-content: center;
- margin: 2px;
+ margin: 4px;
cursor: pointer;
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index ec1702f3..12b1569e 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -3,30 +3,44 @@
-
+
-
-
+
+
+
+
-
+
- {{ value.text }}
+ {{ group.text }}
{{ emoji.replacement }}
-
-
+
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index f646aeb5..1359e75a 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -3,7 +3,6 @@ import MediaUpload from '../media_upload/media_upload.vue'
import ScopeSelector from '../scope_selector/scope_selector.vue'
import EmojiInput from '../emoji_input/emoji_input.vue'
import PollForm from '../poll/poll_form.vue'
-import StickerPicker from '../sticker_picker/sticker_picker.vue'
import fileTypeService from '../../services/file_type/file_type.service.js'
import { reject, map, uniqBy } from 'lodash'
import suggestor from '../emoji_input/suggestor.js'
@@ -35,7 +34,6 @@ const PostStatusForm = {
MediaUpload,
EmojiInput,
PollForm,
- StickerPicker,
ScopeSelector
},
mounted () {
@@ -84,8 +82,7 @@ const PostStatusForm = {
contentType
},
caret: 0,
- pollFormVisible: false,
- stickerPickerVisible: false
+ pollFormVisible: false
}
},
computed: {
@@ -161,12 +158,6 @@ const PostStatusForm = {
safeDMEnabled () {
return this.$store.state.instance.safeDM
},
- stickersAvailable () {
- if (this.$store.state.instance.stickers) {
- return this.$store.state.instance.stickers.length > 0
- }
- return 0
- },
pollsAvailable () {
return this.$store.state.instance.pollsAvailable &&
this.$store.state.instance.pollLimits.max_options >= 2
@@ -222,7 +213,6 @@ const PostStatusForm = {
poll: {}
}
this.pollFormVisible = false
- this.stickerPickerVisible = false
this.$refs.mediaUpload.clearFile()
this.clearPollForm()
this.$emit('posted')
@@ -239,7 +229,6 @@ const PostStatusForm = {
addMediaFile (fileInfo) {
this.newStatus.files.push(fileInfo)
this.enableSubmit()
- this.stickerPickerVisible = false
},
removeMediaFile (fileInfo) {
let index = this.newStatus.files.indexOf(fileInfo)
@@ -293,20 +282,16 @@ const PostStatusForm = {
target.style.height = null
}
},
+ showEmoji () {
+ this.$refs['textarea'].focus()
+ this.$refs['emoji-input'].triggerShowPicker()
+ },
clearError () {
this.error = null
},
changeVis (visibility) {
this.newStatus.visibility = visibility
},
- toggleStickerPicker () {
- this.stickerPickerVisible = !this.stickerPickerVisible
- },
- clearStickerPicker () {
- if (this.$refs.stickerPicker) {
- this.$refs.stickerPicker.clear()
- }
- },
togglePollForm () {
this.pollFormVisible = !this.pollFormVisible
},
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index e691acad..ad2c2218 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -74,10 +74,15 @@
>
{{ $t('post_status.attachments_sensitive') }}
-
@@ -327,7 +325,7 @@
}
}
- .poll-icon, .sticker-icon {
+ .poll-icon, .emoji-icon {
font-size: 26px;
flex: 1;
@@ -337,7 +335,7 @@
}
}
- .sticker-icon {
+ .emoji-icon {
flex: 0;
min-width: 50px;
}
diff --git a/src/components/sticker_picker/sticker_picker.js b/src/components/sticker_picker/sticker_picker.js
index a6dcded3..8daf3f07 100644
--- a/src/components/sticker_picker/sticker_picker.js
+++ b/src/components/sticker_picker/sticker_picker.js
@@ -3,9 +3,9 @@ import statusPosterService from '../../services/status_poster/status_poster.serv
import TabSwitcher from '../tab_switcher/tab_switcher.js'
const StickerPicker = {
- components: [
+ components: {
TabSwitcher
- ],
+ },
data () {
return {
meta: {
diff --git a/src/components/sticker_picker/sticker_picker.vue b/src/components/sticker_picker/sticker_picker.vue
index 938204c8..323855b9 100644
--- a/src/components/sticker_picker/sticker_picker.vue
+++ b/src/components/sticker_picker/sticker_picker.vue
@@ -2,32 +2,30 @@
-
-
-
-
-
-
-
+
+
@@ -37,22 +35,24 @@
@import '../../_variables.scss';
.sticker-picker {
- .sticker-picker-panel {
- display: inline-block;
- width: 100%;
- .sticker-picker-content {
- max-height: 300px;
- overflow-y: scroll;
- overflow-x: auto;
- .sticker {
- display: inline-block;
- width: 20%;
- height: 20%;
- img {
- width: 100%;
- &:hover {
- filter: drop-shadow(0 0 5px var(--link, $fallback--link));
- }
+ width: 100%;
+ position: relative;
+ .tab-switcher {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ }
+ .sticker-picker-content {
+ .sticker {
+ display: inline-block;
+ width: 20%;
+ height: 20%;
+ img {
+ width: 100%;
+ &:hover {
+ filter: drop-shadow(0 0 5px var(--link, $fallback--link));
}
}
}
diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js
index a5fe019c..99428044 100644
--- a/src/components/tab_switcher/tab_switcher.js
+++ b/src/components/tab_switcher/tab_switcher.js
@@ -4,7 +4,26 @@ import './tab_switcher.scss'
export default Vue.component('tab-switcher', {
name: 'TabSwitcher',
- props: ['renderOnlyFocused', 'onSwitch', 'customActive'],
+ props: {
+ renderOnlyFocused: {
+ required: false,
+ type: Boolean,
+ default: false
+ },
+ onSwitch: {
+ required: false,
+ type: Function
+ },
+ customActive: {
+ required: false,
+ type: String
+ },
+ scrollableTabs: {
+ required: false,
+ type: Boolean,
+ default: false
+ }
+ },
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
@@ -18,7 +37,8 @@ export default Vue.component('tab-switcher', {
},
methods: {
activateTab (index, dataset) {
- return () => {
+ return (e) => {
+ e.preventDefault()
if (typeof this.onSwitch === 'function') {
this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset)
}
@@ -85,7 +105,7 @@ export default Vue.component('tab-switcher', {
{tabs}
-
diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss
index 4eeb42e0..3e5eacd5 100644
--- a/src/components/tab_switcher/tab_switcher.scss
+++ b/src/components/tab_switcher/tab_switcher.scss
@@ -1,10 +1,21 @@
@import '../../_variables.scss';
.tab-switcher {
+ display: flex;
+ flex-direction: column;
+
.contents {
+ flex: 1 0 auto;
+ min-height: 0px;
+
.hidden {
display: none;
}
+
+ &.scrollable-tabs {
+ flex-basis: 0;
+ overflow-y: auto;
+ }
}
.tabs {
display: flex;
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 60a3e284..13f7168f 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -106,8 +106,13 @@
"expired": "Poll ended {0} ago",
"not_enough_options": "Too few unique options in poll"
},
- "stickers": {
- "add_sticker": "Add Sticker"
+ "emoji": {
+ "stickers": "Stickers",
+ "emoji": "Emoji",
+ "search_emoji": "Search for an emoji",
+ "add_emoji": "Insert emoji",
+ "custom": "Custom emoji",
+ "unicode": "Unicode emoji"
},
"interactions": {
"favs_repeats": "Repeats and Favorites",