aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/emoji_input/emoji_input.js (renamed from src/components/emoji-input/emoji-input.js)61
-rw-r--r--src/components/emoji_input/emoji_input.vue (renamed from src/components/emoji-input/emoji-input.vue)52
-rw-r--r--src/components/emoji_input/suggestor.js (renamed from src/components/emoji-input/suggestor.js)0
-rw-r--r--src/components/emoji_picker/emoji_picker.js103
-rw-r--r--src/components/emoji_picker/emoji_picker.scss125
-rw-r--r--src/components/emoji_picker/emoji_picker.vue92
-rw-r--r--src/components/post_status_form/post_status_form.js29
-rw-r--r--src/components/post_status_form/post_status_form.vue33
-rw-r--r--src/components/sticker_picker/sticker_picker.js4
-rw-r--r--src/components/sticker_picker/sticker_picker.vue72
-rw-r--r--src/components/tab_switcher/tab_switcher.js26
-rw-r--r--src/components/tab_switcher/tab_switcher.scss11
-rw-r--r--src/components/user_settings/user_settings.js4
13 files changed, 529 insertions, 83 deletions
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji_input/emoji_input.js
index fab64a69..5ff27b20 100644
--- a/src/components/emoji-input/emoji-input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -1,4 +1,5 @@
import Completion from '../../services/completion/completion.js'
+import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import { take } from 'lodash'
/**
@@ -52,6 +53,21 @@ const EmojiInput = {
*/
required: true,
type: String
+ },
+ emojiPicker: {
+ required: false,
+ type: Boolean,
+ default: false
+ },
+ emojiPickerExternalTrigger: {
+ required: false,
+ type: Boolean,
+ default: false
+ },
+ stickerPicker: {
+ required: false,
+ type: Boolean,
+ default: false
}
},
data () {
@@ -60,9 +76,13 @@ const EmojiInput = {
highlighted: 0,
caret: 0,
focused: false,
- blurTimeout: null
+ blurTimeout: null,
+ showPicker: false
}
},
+ components: {
+ EmojiPicker
+ },
computed: {
suggestions () {
const firstchar = this.textAtCaret.charAt(0)
@@ -79,7 +99,7 @@ const EmojiInput = {
highlighted: index === this.highlighted
}))
},
- showPopup () {
+ showSuggestions () {
return this.focused && this.suggestions && this.suggestions.length > 0
},
textAtCaret () {
@@ -120,11 +140,34 @@ const EmojiInput = {
}
},
methods: {
+ triggerShowPicker () {
+ this.showPicker = true
+ },
+ togglePicker () {
+ this.showPicker = !this.showPicker
+ },
replace (replacement) {
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
this.$emit('input', newValue)
this.caret = 0
},
+ insert (insertion) {
+ const newValue = [
+ this.value.substring(0, this.caret),
+ insertion,
+ this.value.substring(this.caret)
+ ].join('')
+ this.$emit('input', newValue)
+ const position = this.caret + insertion.length
+
+ this.$nextTick(function () {
+ // Re-focus inputbox after clicking suggestion
+ this.input.elm.focus()
+ // Set selection right after the replacement instead of the very end
+ this.input.elm.setSelectionRange(position, position)
+ this.caret = position
+ })
+ },
replaceText (e, suggestion) {
const len = this.suggestions.length || 0
if (this.textAtCaret.length === 1) { return }
@@ -191,6 +234,7 @@ const EmojiInput = {
this.blurTimeout = null
}
+ this.showPicker = false
this.focused = true
this.setCaret(e)
this.resize()
@@ -227,6 +271,7 @@ const EmojiInput = {
}
},
onInput (e) {
+ this.showPicker = false
this.setCaret(e)
this.$emit('input', e.target.value)
},
@@ -235,6 +280,17 @@ const EmojiInput = {
this.resize()
this.$emit('input', e.target.value)
},
+ onClickOutside () {
+ this.showPicker = false
+ },
+ onStickerUploaded (e) {
+ this.showPicker = false
+ this.$emit('sticker-uploaded', e)
+ },
+ onStickerUploadFailed (e) {
+ this.showPicker = false
+ this.$emit('sticker-upload-Failed', e)
+ },
setCaret ({ target: { selectionStart } }) {
this.caret = selectionStart
},
@@ -243,6 +299,7 @@ const EmojiInput = {
if (!panel) return
const { offsetHeight, offsetTop } = this.input.elm
this.$refs.panel.style.top = (offsetTop + offsetHeight) + 'px'
+ this.$refs.picker.$el.style.top = (offsetTop + offsetHeight) + 'px'
}
}
}
diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji_input/emoji_input.vue
index 48739ec8..b077e6e9 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -1,10 +1,32 @@
<template>
- <div class="emoji-input">
+ <div
+ v-click-outside="onClickOutside"
+ class="emoji-input"
+ >
<slot />
+ <template v-if="emojiPicker">
+ <div
+ v-if="!emojiPickerExternalTrigger"
+ class="emoji-picker-icon"
+ @click.prevent="togglePicker"
+ >
+ <i class="icon-smile" />
+ </div>
+ <EmojiPicker
+ v-if="emojiPicker"
+ ref="picker"
+ :class="{ hide: !showPicker }"
+ :sticker-picker="stickerPicker"
+ class="emoji-picker-panel"
+ @emoji="insert"
+ @sticker-uploaded="onStickerUploaded"
+ @sticker-upload-failed="onStickerUploadFailed"
+ />
+ </template>
<div
ref="panel"
class="autocomplete-panel"
- :class="{ hide: !showPopup }"
+ :class="{ hide: !showSuggestions }"
>
<div class="autocomplete-panel-body">
<div
@@ -31,7 +53,7 @@
</div>
</template>
-<script src="./emoji-input.js"></script>
+<script src="./emoji_input.js"></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -39,6 +61,30 @@
.emoji-input {
display: flex;
flex-direction: column;
+ position: relative;
+
+ .emoji-picker-icon {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 0 .25em;
+ font-size: 16px;
+ cursor: pointer;
+
+ &:hover i {
+ color: $fallback--text;
+ color: var(--text, $fallback--text);
+ }
+ }
+ .emoji-picker-panel {
+ position: absolute;
+ z-index: 9;
+ margin-top: 2px;
+
+ &.hide {
+ display: none
+ }
+ }
.autocomplete {
&-panel {
diff --git a/src/components/emoji-input/suggestor.js b/src/components/emoji_input/suggestor.js
index aec5c39d..aec5c39d 100644
--- a/src/components/emoji-input/suggestor.js
+++ b/src/components/emoji_input/suggestor.js
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
new file mode 100644
index 00000000..0a64f759
--- /dev/null
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -0,0 +1,103 @@
+
+const filterByKeyword = (list, keyword = '') => {
+ return list.filter(x => x.displayText.includes(keyword))
+}
+
+const EmojiPicker = {
+ props: {
+ stickerPicker: {
+ required: false,
+ type: Boolean,
+ default: false
+ }
+ },
+ data () {
+ return {
+ keyword: '',
+ activeGroup: 'custom',
+ showingStickers: false
+ }
+ },
+ components: {
+ StickerPicker: () => import('../sticker_picker/sticker_picker.vue')
+ },
+ methods: {
+ onEmoji (emoji) {
+ const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
+ this.$emit('emoji', ` ${value} `)
+ this.open = false
+ },
+ highlight (key) {
+ const ref = this.$refs['group-' + key]
+ const top = ref[0].offsetTop
+ this.setShowStickers(false)
+ this.activeGroup = key
+ this.$nextTick(() => {
+ this.$refs['emoji-groups'].scrollTop = top + 1
+ })
+ },
+ 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 [
+ {
+ id: 'custom',
+ text: this.$t('emoji.custom'),
+ icon: 'icon-smile',
+ emojis: filterByKeyword(customEmojis, this.keyword)
+ },
+ {
+ 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)
+ }
+ }
+}
+
+export default EmojiPicker
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
new file mode 100644
index 00000000..6c13e82b
--- /dev/null
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -0,0 +1,125 @@
+@import '../../_variables.scss';
+
+.emoji-picker {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ right: 0;
+ left: 0;
+ height: 300px;
+ margin: 0 !important;
+ z-index: 1;
+
+ .panel-body {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 0;
+ min-height: 0px;
+ }
+
+ .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;
+ }
+
+ .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 0;
+
+ input {
+ width: 100%;
+ }
+ }
+
+ &-groups {
+ flex: 1 1 1px;
+ position: relative;
+ overflow: auto;
+ }
+
+ &-group {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ padding-left: 5px;
+ justify-content: left;
+
+ &-title {
+ font-size: 12px;
+ 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 {
+ max-width: 100%;
+ max-height: 100%;
+ }
+ }
+
+ }
+
+}
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
new file mode 100644
index 00000000..12b1569e
--- /dev/null
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -0,0 +1,92 @@
+<template>
+ <div class="emoji-picker panel panel-default">
+ <div class="panel-heading">
+ <span class="emoji-tabs">
+ <span
+ v-for="group in emojis"
+ :key="group.id"
+ class="emoji-tabs-item"
+ :class="{
+ active: activeGroupView === group.id,
+ disabled: group.emojis.length === 0
+ }"
+ :title="group.text"
+ @click.prevent="highlight(group.id)"
+ >
+ <i :class="group.icon" />
+ </span>
+ </span>
+ <span
+ v-if="stickerPicker"
+ class="additional-tabs"
+ >
+ <span
+ class="stickers-tab-icon additional-tabs-item"
+ :class="{active: showingStickers}"
+ :title="$t('emoji.stickers')"
+ @click.prevent="toggleStickers"
+ >
+ <i class="icon-star" />
+ </span>
+ </span>
+ </div>
+ <div class="panel-body">
+ <div
+ class="emoji-content"
+ :class="{hidden: showingStickers}"
+ >
+ <div class="emoji-search">
+ <input
+ v-model="keyword"
+ type="text"
+ class="form-control"
+ :placeholder="$t('emoji.search_emoji')"
+ >
+ </div>
+ <div
+ ref="emoji-groups"
+ class="emoji-groups"
+ @scroll="scrolledGroup"
+ >
+ <div
+ v-for="group in emojisView"
+ :key="group.id"
+ class="emoji-group"
+ >
+ <h6
+ :ref="'group-' + group.id"
+ class="emoji-group-title"
+ >
+ {{ group.text }}
+ </h6>
+ <span
+ v-for="emoji in group.emojis"
+ :key="group.id + emoji.displayText"
+ :title="emoji.displayText"
+ class="emoji-item"
+ @click.stop.prevent="onEmoji(emoji)"
+ >
+ <span v-if="!emoji.imageUrl">{{ emoji.replacement }}</span>
+ <img
+ v-else
+ :src="emoji.imageUrl"
+ >
+ </span>
+ </div>
+ </div>
+ </div>
+ <div
+ v-if="showingStickers"
+ class="stickers-content"
+ >
+ <sticker-picker
+ @uploaded="onStickerUploaded"
+ @upload-failed="onStickerUploadFailed"
+ />
+ </div>
+ </div>
+ </div>
+</template>
+
+<script src="./emoji_picker.js"></script>
+<style lang="scss" src="./emoji_picker.scss"></style>
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 40bbf6d4..1359e75a 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -1,12 +1,11 @@
import statusPoster from '../../services/status_poster/status_poster.service.js'
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 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'
+import suggestor from '../emoji_input/suggestor.js'
const buildMentionsString = ({ user, attentions }, currentUser) => {
let allAttentions = [...attentions]
@@ -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 d29d47e4..ad2c2218 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -61,6 +61,7 @@
<EmojiInput
v-if="newStatus.spoilerText || alwaysShowSubject"
v-model="newStatus.spoilerText"
+ emoji-picker
:suggest="emojiSuggestor"
class="form-control"
>
@@ -73,9 +74,15 @@
>
</EmojiInput>
<EmojiInput
+ ref="emoji-input"
v-model="newStatus.status"
:suggest="emojiUserSuggestor"
class="form-control main-input"
+ emoji-picker
+ emoji-picker-external-trigger
+ sticker-picker
+ @sticker-uploaded="addMediaFile"
+ @sticker-upload-failed="uploadFailed"
>
<textarea
ref="textarea"
@@ -158,14 +165,12 @@
@upload-failed="uploadFailed"
/>
<div
- v-if="stickersAvailable"
- class="sticker-icon"
+ class="emoji-icon"
>
<i
- :title="$t('stickers.add_sticker')"
- class="icon-picture btn btn-default"
- :class="{ selected: stickerPickerVisible }"
- @click="toggleStickerPicker"
+ :title="$t('emoji.add_emoji')"
+ class="icon-smile btn btn-default"
+ @click.stop.prevent="showEmoji"
/>
</div>
<div
@@ -258,11 +263,6 @@
<label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label>
</div>
</form>
- <sticker-picker
- v-if="stickerPickerVisible"
- ref="stickerPicker"
- @uploaded="addMediaFile"
- />
</div>
</template>
@@ -325,7 +325,7 @@
}
}
- .poll-icon, .sticker-icon {
+ .poll-icon, .emoji-icon {
font-size: 26px;
flex: 1;
@@ -335,7 +335,7 @@
}
}
- .sticker-icon {
+ .emoji-icon {
flex: 0;
min-width: 50px;
}
@@ -369,6 +369,13 @@
}
}
+ .status-input-wrapper {
+ display: flex;
+ position: relative;
+ width: 100%;
+ flex-direction: column;
+ }
+
.attachments {
padding: 0 0.5em;
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 @@
<div
class="sticker-picker"
>
- <div
- class="sticker-picker-panel"
+ <tab-switcher
+ class="tab-switcher"
+ :render-only-focused="true"
+ scrollable-tabs
>
- <tab-switcher
- :render-only-focused="true"
+ <div
+ v-for="stickerpack in pack"
+ :key="stickerpack.path"
+ :image-tooltip="stickerpack.meta.title"
+ :image="stickerpack.path + stickerpack.meta.tabIcon"
+ class="sticker-picker-content"
>
<div
- v-for="stickerpack in pack"
- :key="stickerpack.path"
- :image-tooltip="stickerpack.meta.title"
- :image="stickerpack.path + stickerpack.meta.tabIcon"
- class="sticker-picker-content"
+ v-for="sticker in stickerpack.meta.stickers"
+ :key="sticker"
+ class="sticker"
+ @click.stop.prevent="pick(stickerpack.path + sticker, stickerpack.meta.title)"
>
- <div
- v-for="sticker in stickerpack.meta.stickers"
- :key="sticker"
- class="sticker"
- @click="pick(stickerpack.path + sticker, stickerpack.meta.title)"
+ <img
+ :src="stickerpack.path + sticker"
>
- <img
- :src="stickerpack.path + sticker"
- >
- </div>
</div>
- </tab-switcher>
- </div>
+ </div>
+ </tab-switcher>
</div>
</template>
@@ -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 08d5d08f..3ca316b9 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', 'activeTab'],
+ props: {
+ renderOnlyFocused: {
+ required: false,
+ type: Boolean,
+ default: false
+ },
+ onSwitch: {
+ required: false,
+ type: Function
+ },
+ activeTab: {
+ required: false,
+ type: String
+ },
+ scrollableTabs: {
+ required: false,
+ type: Boolean,
+ default: false
+ }
+ },
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
@@ -28,7 +47,8 @@ export default Vue.component('tab-switcher', {
},
methods: {
activateTab (index) {
- return () => {
+ return (e) => {
+ e.preventDefault()
if (typeof this.onSwitch === 'function') {
this.onSwitch.call(null, this.$slots.default[index].key)
}
@@ -87,7 +107,7 @@ export default Vue.component('tab-switcher', {
<div class="tabs">
{tabs}
</div>
- <div class="contents">
+ <div class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}>
{contents}
</div>
</div>
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/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js
index b5a7f0df..ae04ce73 100644
--- a/src/components/user_settings/user_settings.js
+++ b/src/components/user_settings/user_settings.js
@@ -11,8 +11,8 @@ import BlockCard from '../block_card/block_card.vue'
import MuteCard from '../mute_card/mute_card.vue'
import SelectableList from '../selectable_list/selectable_list.vue'
import ProgressButton from '../progress_button/progress_button.vue'
-import EmojiInput from '../emoji-input/emoji-input.vue'
-import suggestor from '../emoji-input/suggestor.js'
+import EmojiInput from '../emoji_input/emoji_input.vue'
+import suggestor from '../emoji_input/suggestor.js'
import Autosuggest from '../autosuggest/autosuggest.vue'
import Importer from '../importer/importer.vue'
import Exporter from '../exporter/exporter.vue'