Merge branch 'develop' into refactor/notification_settings

This commit is contained in:
Mark Felder 2020-07-13 13:25:23 -05:00
commit da94935aaa
116 changed files with 4446 additions and 544 deletions

View file

@ -30,7 +30,7 @@
height: 100vh;
}
.panel-body {
>.panel-body {
height: 100%;
overflow-y: hidden;

View file

@ -37,6 +37,9 @@ const FilteringTab = {
})
},
deep: true
},
replyVisibility () {
this.$store.dispatch('queueFlushAll')
}
}
}

View file

@ -1,4 +1,5 @@
import unescape from 'lodash/unescape'
import merge from 'lodash/merge'
import ImageCropper from 'src/components/image_cropper/image_cropper.vue'
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import fileSizeFormatService from 'src/components/../services/file_size_format/file_size_format.js'
@ -16,6 +17,7 @@ const ProfileTab = {
newLocked: this.$store.state.users.currentUser.locked,
newNoRichText: this.$store.state.users.currentUser.no_rich_text,
newDefaultScope: this.$store.state.users.currentUser.default_scope,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
hideFollows: this.$store.state.users.currentUser.hide_follows,
hideFollowers: this.$store.state.users.currentUser.hide_followers,
hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count,
@ -63,6 +65,45 @@ const ProfileTab = {
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
] })
},
userSuggestor () {
return suggestor({
users: this.$store.state.users.users,
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
})
},
fieldsLimits () {
return this.$store.state.instance.fieldsLimits
},
maxFields () {
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
},
defaultAvatar () {
return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar
},
defaultBanner () {
return this.$store.state.instance.server + this.$store.state.instance.defaultBanner
},
isDefaultAvatar () {
const baseAvatar = this.$store.state.instance.defaultAvatar
return !(this.$store.state.users.currentUser.profile_image_url) ||
this.$store.state.users.currentUser.profile_image_url.includes(baseAvatar)
},
isDefaultBanner () {
const baseBanner = this.$store.state.instance.defaultBanner
return !(this.$store.state.users.currentUser.cover_photo) ||
this.$store.state.users.currentUser.cover_photo.includes(baseBanner)
},
isDefaultBackground () {
return !(this.$store.state.users.currentUser.background_image)
},
avatarImgSrc () {
const src = this.$store.state.users.currentUser.profile_image_url_original
return (!src) ? this.defaultAvatar : src
},
bannerImgSrc () {
const src = this.$store.state.users.currentUser.cover_photo
return (!src) ? this.defaultBanner : src
}
},
methods: {
@ -75,6 +116,7 @@ const ProfileTab = {
// Backend notation.
/* eslint-disable camelcase */
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
default_scope: this.newDefaultScope,
no_rich_text: this.newNoRichText,
hide_follows: this.hideFollows,
@ -87,6 +129,8 @@ const ProfileTab = {
show_role: this.showRole
/* eslint-enable camelcase */
} }).then((user) => {
this.newFields.splice(user.fields.length)
merge(this.newFields, user.fields)
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
})
@ -94,6 +138,16 @@ const ProfileTab = {
changeVis (visibility) {
this.newDefaultScope = visibility
},
addField () {
if (this.newFields.length < this.maxFields) {
this.newFields.push({ name: '', value: '' })
return true
}
return false
},
deleteField (index, event) {
this.$delete(this.newFields, index)
},
uploadFile (slot, e) {
const file = e.target.files[0]
if (!file) { return }
@ -123,11 +177,29 @@ const ProfileTab = {
}
reader.readAsDataURL(file)
},
resetAvatar () {
const confirmed = window.confirm(this.$t('settings.reset_avatar_confirm'))
if (confirmed) {
this.submitAvatar(undefined, '')
}
},
resetBanner () {
const confirmed = window.confirm(this.$t('settings.reset_banner_confirm'))
if (confirmed) {
this.submitBanner('')
}
},
resetBackground () {
const confirmed = window.confirm(this.$t('settings.reset_background_confirm'))
if (confirmed) {
this.submitBackground('')
}
},
submitAvatar (cropper, file) {
const that = this
return new Promise((resolve, reject) => {
function updateAvatar (avatar) {
that.$store.state.api.backendInteractor.updateAvatar({ avatar })
that.$store.state.api.backendInteractor.updateProfileImages({ avatar })
.then((user) => {
that.$store.commit('addNewUsers', [user])
that.$store.commit('setCurrentUser', user)
@ -145,11 +217,11 @@ const ProfileTab = {
}
})
},
submitBanner () {
if (!this.bannerPreview) { return }
submitBanner (banner) {
if (!this.bannerPreview && banner !== '') { return }
this.bannerUploading = true
this.$store.state.api.backendInteractor.updateBanner({ banner: this.banner })
this.$store.state.api.backendInteractor.updateProfileImages({ banner })
.then((user) => {
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
@ -160,11 +232,11 @@ const ProfileTab = {
})
.then(() => { this.bannerUploading = false })
},
submitBg () {
if (!this.backgroundPreview) { return }
let background = this.background
submitBackground (background) {
if (!this.backgroundPreview && background !== '') { return }
this.backgroundUploading = true
this.$store.state.api.backendInteractor.updateBg({ background }).then((data) => {
this.$store.state.api.backendInteractor.updateProfileImages({ background }).then((data) => {
if (!data.error) {
this.$store.commit('addNewUsers', [data])
this.$store.commit('setCurrentUser', data)

View file

@ -13,8 +13,14 @@
height: auto;
}
.banner {
.banner-background-preview {
max-width: 100%;
width: 300px;
position: relative;
img {
width: 100%;
}
}
.uploading {
@ -26,18 +32,40 @@
width: 100%;
}
.bg {
max-width: 100%;
.current-avatar-container {
position: relative;
width: 150px;
height: 150px;
}
.current-avatar {
display: block;
width: 150px;
height: 150px;
width: 100%;
height: 100%;
border-radius: $fallback--avatarRadius;
border-radius: var(--avatarRadius, $fallback--avatarRadius);
}
.reset-button {
position: absolute;
top: 0.2em;
right: 0.2em;
border-radius: $fallback--tooltipRadius;
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
background-color: rgba(0, 0, 0, 0.6);
opacity: 0.7;
color: white;
width: 1.5em;
height: 1.5em;
text-align: center;
line-height: 1.5em;
font-size: 1.5em;
cursor: pointer;
&:hover {
opacity: 1;
}
}
.oauth-tokens {
width: 100%;
@ -79,4 +107,22 @@
.setting-subitem {
margin-left: 1.75em;
}
.profile-fields {
display: flex;
&>.emoji-input {
flex: 1 1 auto;
margin: 0 .2em .5em;
min-width: 0;
}
&>.icon-container {
width: 20px;
&>.icon-cancel {
vertical-align: sub;
}
}
}
}

View file

@ -95,6 +95,54 @@
{{ $t('settings.discoverable') }}
</Checkbox>
</p>
<div v-if="maxFields > 0">
<p>{{ $t('settings.profile_fields.label') }}</p>
<div
v-for="(_, i) in newFields"
:key="i"
class="profile-fields"
>
<EmojiInput
v-model="newFields[i].name"
enable-emoji-picker
hide-emoji-button
:suggest="userSuggestor"
>
<input
v-model="newFields[i].name"
:placeholder="$t('settings.profile_fields.name')"
>
</EmojiInput>
<EmojiInput
v-model="newFields[i].value"
enable-emoji-picker
hide-emoji-button
:suggest="userSuggestor"
>
<input
v-model="newFields[i].value"
:placeholder="$t('settings.profile_fields.value')"
>
</EmojiInput>
<div
class="icon-container"
>
<i
v-show="newFields.length > 1"
class="icon-cancel"
@click="deleteField(i)"
/>
</div>
</div>
<a
v-if="newFields.length < maxFields"
class="add-field faint"
@click="addField"
>
<i class="icon-plus" />
{{ $t("settings.profile_fields.add_field") }}
</a>
</div>
<p>
<Checkbox v-model="bot">
{{ $t('settings.bot') }}
@ -113,11 +161,19 @@
<p class="visibility-notice">
{{ $t('settings.avatar_size_instruction') }}
</p>
<p>{{ $t('settings.current_avatar') }}</p>
<img
:src="user.profile_image_url_original"
class="current-avatar"
>
<div class="current-avatar-container">
<img
:src="user.profile_image_url_original"
class="current-avatar"
>
<i
v-if="!isDefaultAvatar && pickAvatarBtnVisible"
:title="$t('settings.reset_avatar')"
class="reset-button icon-cancel"
type="button"
@click="resetAvatar"
/>
</div>
<p>{{ $t('settings.set_new_avatar') }}</p>
<button
v-show="pickAvatarBtnVisible"
@ -136,15 +192,20 @@
</div>
<div class="setting-item">
<h2>{{ $t('settings.profile_banner') }}</h2>
<p>{{ $t('settings.current_profile_banner') }}</p>
<img
:src="user.cover_photo"
class="banner"
>
<div class="banner-background-preview">
<img :src="user.cover_photo">
<i
v-if="!isDefaultBanner"
:title="$t('settings.reset_profile_banner')"
class="reset-button icon-cancel"
type="button"
@click="resetBanner"
/>
</div>
<p>{{ $t('settings.set_new_profile_banner') }}</p>
<img
v-if="bannerPreview"
class="banner"
class="banner-background-preview"
:src="bannerPreview"
>
<div>
@ -160,7 +221,7 @@
<button
v-else-if="bannerPreview"
class="btn btn-default"
@click="submitBanner"
@click="submitBanner(banner)"
>
{{ $t('general.submit') }}
</button>
@ -177,10 +238,20 @@
</div>
<div class="setting-item">
<h2>{{ $t('settings.profile_background') }}</h2>
<div class="banner-background-preview">
<img :src="user.background_image">
<i
v-if="!isDefaultBackground"
:title="$t('settings.reset_profile_background')"
class="reset-button icon-cancel"
type="button"
@click="resetBackground"
/>
</div>
<p>{{ $t('settings.set_new_profile_background') }}</p>
<img
v-if="backgroundPreview"
class="bg"
class="banner-background-preview"
:src="backgroundPreview"
>
<div>
@ -196,7 +267,7 @@
<button
v-else-if="backgroundPreview"
class="btn btn-default"
@click="submitBg"
@click="submitBackground(background)"
>
{{ $t('general.submit') }}
</button>

View file

@ -99,7 +99,8 @@ export default {
avatarRadiusLocal: '',
avatarAltRadiusLocal: '',
attachmentRadiusLocal: '',
tooltipRadiusLocal: ''
tooltipRadiusLocal: '',
chatMessageRadiusLocal: ''
}
},
created () {
@ -214,7 +215,8 @@ export default {
avatar: this.avatarRadiusLocal,
avatarAlt: this.avatarAltRadiusLocal,
tooltip: this.tooltipRadiusLocal,
attachment: this.attachmentRadiusLocal
attachment: this.attachmentRadiusLocal,
chatMessage: this.chatMessageRadiusLocal
}
},
preview () {

View file

@ -735,6 +735,65 @@
/>
<ContrastRatio :contrast="previewContrast.selectedMenuLink" />
</div>
<div class="color-item">
<h4>{{ $t('chats.chats') }}</h4>
<ColorInput
v-model="chatBgColorLocal"
name="chatBgColor"
:fallback="previewTheme.colors.bg || 1"
:label="$t('settings.background')"
/>
<h5>{{ $t('settings.style.advanced_colors.chat.incoming') }}</h5>
<ColorInput
v-model="chatMessageIncomingBgColorLocal"
name="chatMessageIncomingBgColor"
:fallback="previewTheme.colors.bg || 1"
:label="$t('settings.background')"
/>
<ColorInput
v-model="chatMessageIncomingTextColorLocal"
name="chatMessageIncomingTextColor"
:fallback="previewTheme.colors.text || 1"
:label="$t('settings.text')"
/>
<ColorInput
v-model="chatMessageIncomingLinkColorLocal"
name="chatMessageIncomingLinkColor"
:fallback="previewTheme.colors.link || 1"
:label="$t('settings.links')"
/>
<ColorInput
v-model="chatMessageIncomingBorderColorLocal"
name="chatMessageIncomingBorderLinkColor"
:fallback="previewTheme.colors.fg || 1"
:label="$t('settings.style.advanced_colors.chat.border')"
/>
<h5>{{ $t('settings.style.advanced_colors.chat.outgoing') }}</h5>
<ColorInput
v-model="chatMessageOutgoingBgColorLocal"
name="chatMessageOutgoingBgColor"
:fallback="previewTheme.colors.bg || 1"
:label="$t('settings.background')"
/>
<ColorInput
v-model="chatMessageOutgoingTextColorLocal"
name="chatMessageOutgoingTextColor"
:fallback="previewTheme.colors.text || 1"
:label="$t('settings.text')"
/>
<ColorInput
v-model="chatMessageOutgoingLinkColorLocal"
name="chatMessageOutgoingLinkColor"
:fallback="previewTheme.colors.link || 1"
:label="$t('settings.links')"
/>
<ColorInput
v-model="chatMessageOutgoingBorderColorLocal"
name="chatMessageOutgoingBorderLinkColor"
:fallback="previewTheme.colors.bg || 1"
:label="$t('settings.style.advanced_colors.chat.border')"
/>
</div>
</div>
<div
@ -814,6 +873,14 @@
max="50"
hard-min="0"
/>
<RangeInput
v-model="chatMessageRadiusLocal"
name="chatMessageRadius"
:label="$t('settings.chatMessageRadius')"
:fallback="previewTheme.radii.chatMessage || 2"
max="50"
hard-min="0"
/>
</div>
<div