Merge branch 'wyatt777/pleroma-fe-issue-353' into 'develop'

Allow remove of banner, avatar images issue #353 v2

See merge request pleroma/pleroma-fe!1156
This commit is contained in:
lain 2020-07-08 10:11:17 +00:00
commit 4f96418143
10 changed files with 153 additions and 76 deletions

View File

@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Autocomplete domains from list of known instances - Autocomplete domains from list of known instances
- 'Bot' settings option and badge - 'Bot' settings option and badge
- Added profile meta data fields that can be set in profile settings - Added profile meta data fields that can be set in profile settings
- Added option to reset avatar/banner in profile settings
- Descriptions can be set on uploaded files before posting - Descriptions can be set on uploaded files before posting
- Added status preview option to preview your statuses before posting - Added status preview option to preview your statuses before posting
- When a post is a reply to an unavailable post, the 'Reply to'-text has a strike-through style - When a post is a reply to an unavailable post, the 'Reply to'-text has a strike-through style

View File

@ -77,6 +77,33 @@ const ProfileTab = {
}, },
maxFields () { maxFields () {
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0 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: { methods: {
@ -150,11 +177,29 @@ const ProfileTab = {
} }
reader.readAsDataURL(file) 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) { submitAvatar (cropper, file) {
const that = this const that = this
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
function updateAvatar (avatar) { function updateAvatar (avatar) {
that.$store.state.api.backendInteractor.updateAvatar({ avatar }) that.$store.state.api.backendInteractor.updateProfileImages({ avatar })
.then((user) => { .then((user) => {
that.$store.commit('addNewUsers', [user]) that.$store.commit('addNewUsers', [user])
that.$store.commit('setCurrentUser', user) that.$store.commit('setCurrentUser', user)
@ -172,11 +217,11 @@ const ProfileTab = {
} }
}) })
}, },
submitBanner () { submitBanner (banner) {
if (!this.bannerPreview) { return } if (!this.bannerPreview && banner !== '') { return }
this.bannerUploading = true this.bannerUploading = true
this.$store.state.api.backendInteractor.updateBanner({ banner: this.banner }) this.$store.state.api.backendInteractor.updateProfileImages({ banner })
.then((user) => { .then((user) => {
this.$store.commit('addNewUsers', [user]) this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user) this.$store.commit('setCurrentUser', user)
@ -187,11 +232,11 @@ const ProfileTab = {
}) })
.then(() => { this.bannerUploading = false }) .then(() => { this.bannerUploading = false })
}, },
submitBg () { submitBackground (background) {
if (!this.backgroundPreview) { return } if (!this.backgroundPreview && background !== '') { return }
let background = this.background
this.backgroundUploading = true this.backgroundUploading = true
this.$store.state.api.backendInteractor.updateBg({ background }).then((data) => { this.$store.state.api.backendInteractor.updateProfileImages({ background }).then((data) => {
if (!data.error) { if (!data.error) {
this.$store.commit('addNewUsers', [data]) this.$store.commit('addNewUsers', [data])
this.$store.commit('setCurrentUser', data) this.$store.commit('setCurrentUser', data)

View File

@ -13,8 +13,14 @@
height: auto; height: auto;
} }
.banner { .banner-background-preview {
max-width: 100%; max-width: 100%;
width: 300px;
position: relative;
img {
width: 100%;
}
} }
.uploading { .uploading {
@ -26,18 +32,40 @@
width: 100%; width: 100%;
} }
.bg { .current-avatar-container {
max-width: 100%; position: relative;
width: 150px;
height: 150px;
} }
.current-avatar { .current-avatar {
display: block; display: block;
width: 150px; width: 100%;
height: 150px; height: 100%;
border-radius: $fallback--avatarRadius; border-radius: $fallback--avatarRadius;
border-radius: var(--avatarRadius, $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 { .oauth-tokens {
width: 100%; width: 100%;
@ -86,6 +114,7 @@
&>.emoji-input { &>.emoji-input {
flex: 1 1 auto; flex: 1 1 auto;
margin: 0 .2em .5em; margin: 0 .2em .5em;
min-width: 0;
} }
&>.icon-container { &>.icon-container {

View File

@ -161,11 +161,19 @@
<p class="visibility-notice"> <p class="visibility-notice">
{{ $t('settings.avatar_size_instruction') }} {{ $t('settings.avatar_size_instruction') }}
</p> </p>
<p>{{ $t('settings.current_avatar') }}</p> <div class="current-avatar-container">
<img <img
:src="user.profile_image_url_original" :src="user.profile_image_url_original"
class="current-avatar" 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> <p>{{ $t('settings.set_new_avatar') }}</p>
<button <button
v-show="pickAvatarBtnVisible" v-show="pickAvatarBtnVisible"
@ -184,15 +192,20 @@
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.profile_banner') }}</h2> <h2>{{ $t('settings.profile_banner') }}</h2>
<p>{{ $t('settings.current_profile_banner') }}</p> <div class="banner-background-preview">
<img <img :src="user.cover_photo">
:src="user.cover_photo" <i
class="banner" 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> <p>{{ $t('settings.set_new_profile_banner') }}</p>
<img <img
v-if="bannerPreview" v-if="bannerPreview"
class="banner" class="banner-background-preview"
:src="bannerPreview" :src="bannerPreview"
> >
<div> <div>
@ -208,7 +221,7 @@
<button <button
v-else-if="bannerPreview" v-else-if="bannerPreview"
class="btn btn-default" class="btn btn-default"
@click="submitBanner" @click="submitBanner(banner)"
> >
{{ $t('general.submit') }} {{ $t('general.submit') }}
</button> </button>
@ -225,10 +238,20 @@
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.profile_background') }}</h2> <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> <p>{{ $t('settings.set_new_profile_background') }}</p>
<img <img
v-if="backgroundPreview" v-if="backgroundPreview"
class="bg" class="banner-background-preview"
:src="backgroundPreview" :src="backgroundPreview"
> >
<div> <div>
@ -244,7 +267,7 @@
<button <button
v-else-if="backgroundPreview" v-else-if="backgroundPreview"
class="btn btn-default" class="btn btn-default"
@click="submitBg" @click="submitBackground(background)"
> >
{{ $t('general.submit') }} {{ $t('general.submit') }}
</button> </button>

View File

@ -8,26 +8,20 @@ const UserAvatar = {
], ],
data () { data () {
return { return {
showPlaceholder: false showPlaceholder: false,
defaultAvatar: `${this.$store.state.instance.server + this.$store.state.instance.defaultAvatar}`
} }
}, },
components: { components: {
StillImage StillImage
}, },
computed: {
imgSrc () {
return this.showPlaceholder ? '/images/avi.png' : this.user.profile_image_url_original
}
},
methods: { methods: {
imgSrc (src) {
return (!src || this.showPlaceholder) ? this.defaultAvatar : src
},
imageLoadError () { imageLoadError () {
this.showPlaceholder = true this.showPlaceholder = true
} }
},
watch: {
src () {
this.showPlaceholder = false
}
} }
} }

View File

@ -3,7 +3,7 @@
class="avatar" class="avatar"
:alt="user.screen_name" :alt="user.screen_name"
:title="user.screen_name" :title="user.screen_name"
:src="imgSrc" :src="imgSrc(user.profile_image_url_original)"
:class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }" :class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }"
:image-load-error="imageLoadError" :image-load-error="imageLoadError"
/> />

View File

@ -7,7 +7,7 @@ function showWhoToFollow (panel, reply) {
panel.usersToFollow.forEach((toFollow, index) => { panel.usersToFollow.forEach((toFollow, index) => {
let user = shuffled[index] let user = shuffled[index]
let img = user.avatar || '/images/avi.png' let img = user.avatar || this.$store.state.instance.defaultAvatar
let name = user.acct let name = user.acct
toFollow.img = img toFollow.img = img
@ -38,13 +38,7 @@ function getWhoToFollow (panel) {
const WhoToFollowPanel = { const WhoToFollowPanel = {
data: () => ({ data: () => ({
usersToFollow: new Array(3).fill().map(x => ( usersToFollow: []
{
img: '/images/avi.png',
name: '',
id: 0
}
))
}), }),
computed: { computed: {
user: function () { user: function () {
@ -68,6 +62,13 @@ const WhoToFollowPanel = {
}, },
mounted: mounted:
function () { function () {
this.usersToFollow = new Array(3).fill().map(x => (
{
img: this.$store.state.instance.defaultAvatar,
name: '',
id: 0
}
))
if (this.suggestionsEnabled) { if (this.suggestionsEnabled) {
getWhoToFollow(this) getWhoToFollow(this)
} }

View File

@ -290,9 +290,7 @@
"collapse_subject": "Collapse posts with subjects", "collapse_subject": "Collapse posts with subjects",
"composing": "Composing", "composing": "Composing",
"confirm_new_password": "Confirm new password", "confirm_new_password": "Confirm new password",
"current_avatar": "Your current avatar",
"current_password": "Current password", "current_password": "Current password",
"current_profile_banner": "Your current profile banner",
"mutes_and_blocks": "Mutes and Blocks", "mutes_and_blocks": "Mutes and Blocks",
"data_import_export_tab": "Data Import / Export", "data_import_export_tab": "Data Import / Export",
"default_vis": "Default visibility scope", "default_vis": "Default visibility scope",
@ -399,6 +397,12 @@
"set_new_avatar": "Set new avatar", "set_new_avatar": "Set new avatar",
"set_new_profile_background": "Set new profile background", "set_new_profile_background": "Set new profile background",
"set_new_profile_banner": "Set new profile banner", "set_new_profile_banner": "Set new profile banner",
"reset_avatar": "Reset avatar",
"reset_profile_background": "Reset profile background",
"reset_profile_banner": "Reset profile banner",
"reset_avatar_confirm": "Do you really want to reset the avatar?",
"reset_banner_confirm": "Do you really want to reset the banner?",
"reset_background_confirm": "Do you really want to reset the background?",
"settings": "Settings", "settings": "Settings",
"subject_input_always_show": "Always show subject field", "subject_input_always_show": "Always show subject field",
"subject_line_behavior": "Copy subject when replying", "subject_line_behavior": "Copy subject when replying",

View File

@ -15,6 +15,8 @@ const defaultState = {
// Stuff from static/config.json // Stuff from static/config.json
alwaysShowSubjectInput: true, alwaysShowSubjectInput: true,
defaultAvatar: '/images/avi.png',
defaultBanner: '/images/banner.png',
background: '/static/aurora_borealis.jpg', background: '/static/aurora_borealis.jpg',
collapseMessageWithSubject: false, collapseMessageWithSubject: false,
disableChat: false, disableChat: false,

View File

@ -141,20 +141,11 @@ const updateNotificationSettings = ({ credentials, settings }) => {
}).then((data) => data.json()) }).then((data) => data.json())
} }
const updateAvatar = ({ credentials, avatar }) => { const updateProfileImages = ({ credentials, avatar = null, banner = null, background = null }) => {
const form = new FormData() const form = new FormData()
form.append('avatar', avatar) if (avatar !== null) form.append('avatar', avatar)
return fetch(MASTODON_PROFILE_UPDATE_URL, { if (banner !== null) form.append('header', banner)
headers: authHeaders(credentials), if (background !== null) form.append('pleroma_background_image', background)
method: 'PATCH',
body: form
}).then((data) => data.json())
.then((data) => parseUser(data))
}
const updateBg = ({ credentials, background }) => {
const form = new FormData()
form.append('pleroma_background_image', background)
return fetch(MASTODON_PROFILE_UPDATE_URL, { return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials), headers: authHeaders(credentials),
method: 'PATCH', method: 'PATCH',
@ -164,17 +155,6 @@ const updateBg = ({ credentials, background }) => {
.then((data) => parseUser(data)) .then((data) => parseUser(data))
} }
const updateBanner = ({ credentials, banner }) => {
const form = new FormData()
form.append('header', banner)
return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials),
method: 'PATCH',
body: form
}).then((data) => data.json())
.then((data) => parseUser(data))
}
const updateProfile = ({ credentials, params }) => { const updateProfile = ({ credentials, params }) => {
return promisedRequest({ return promisedRequest({
url: MASTODON_PROFILE_UPDATE_URL, url: MASTODON_PROFILE_UPDATE_URL,
@ -1206,10 +1186,8 @@ const apiService = {
deactivateUser, deactivateUser,
register, register,
getCaptcha, getCaptcha,
updateAvatar, updateProfileImages,
updateBg,
updateProfile, updateProfile,
updateBanner,
importBlocks, importBlocks,
importFollows, importFollows,
deleteAccount, deleteAccount,