diff --git a/src/components/image_cropper/image_cropper.js b/src/components/image_cropper/image_cropper.js index 6d961e563..32b615265 100644 --- a/src/components/image_cropper/image_cropper.js +++ b/src/components/image_cropper/image_cropper.js @@ -22,6 +22,9 @@ const ImageCropper = { }, cancelButtonLabel: { type: String + }, + aspectRatio: { + type: Number } }, data () { diff --git a/src/components/image_cropper/image_cropper.vue b/src/components/image_cropper/image_cropper.vue index 4ef077ef6..9d8ecd173 100644 --- a/src/components/image_cropper/image_cropper.vue +++ b/src/components/image_cropper/image_cropper.vue @@ -23,8 +23,8 @@ /> { + this.$store.commit('addNewUsers', [data]) + this.$store.commit('setCurrentUser', data) + this.backgroundPreview = null + }) + .catch(this.displayUploadError) + .finally(() => { this.backgroundUploading = false }) }, propsToNative (props) { return propsToNative(props) diff --git a/src/components/user_avatar/user_avatar.js b/src/components/user_avatar/user_avatar.js index 09eadda61..855ea60e8 100644 --- a/src/components/user_avatar/user_avatar.js +++ b/src/components/user_avatar/user_avatar.js @@ -17,7 +17,8 @@ const UserAvatar = { props: [ 'user', 'compact', - 'showActorTypeIndicator' + 'showActorTypeIndicator', + 'url' ], data () { return { diff --git a/src/components/user_avatar/user_avatar.vue b/src/components/user_avatar/user_avatar.vue index 83608c505..e3398165c 100644 --- a/src/components/user_avatar/user_avatar.vue +++ b/src/components/user_avatar/user_avatar.vue @@ -8,7 +8,7 @@ class="avatar" :alt="user.screen_name_ui" :title="user.screen_name_ui" - :src="imgSrc(user.profile_image_url_original)" + :src="url ? url : imgSrc(user.profile_image_url_original)" :image-load-error="imageLoadError" :class="{ '-compact': compact, '-better-shadow': betterShadow }" /> diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index a86298737..e682fcb21 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -37,7 +37,9 @@ import { faExpandAlt, faBirthdayCake, faSave, - faChevronRight + faChevronRight, + faChevronDown, + faClockRotateLeft } from '@fortawesome/free-solid-svg-icons' import { useMediaViewerStore } from '../../stores/media_viewer' @@ -53,7 +55,9 @@ library.add( faTimes, faExpandAlt, faBirthdayCake, - faChevronRight + faChevronRight, + faChevronDown, + faClockRotateLeft ) export default { @@ -98,8 +102,12 @@ export default { // Editable stuff newName: user.name_unescaped, editingName: false, - newActorType: user.actor_type, editImage: false, + newAvatar: '', + newAvatarFile: null, + newBanner: '', + newBannerFile: null, + newActorType: user.actor_type, newBio: unescape(user.description), editingBio: false, newBirthday: user.birthday, @@ -133,7 +141,7 @@ export default { return { backgroundImage: [ 'linear-gradient(to bottom, var(--profileTint), var(--profileTint))', - `url(${this.newCoverPhoto})` + `url(${this.bannerImgSrc})` ].join(', ') } }, @@ -230,11 +238,25 @@ export default { }, // Editable stuff + avatarImgSrc () { + const src = this.newAvatar + return (!src) ? this.defaultAvatar : src + }, + bannerImgSrc () { + const src = this.newBanner + return (!src) ? this.defaultBanner : src + }, defaultAvatar () { - return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar + if (this.isDefaultAvatar) { + return this.$store.state.instance.server + this.$store.state.instance.defaultAvatar + } + return this.user.profile_image_url }, defaultBanner () { - return this.$store.state.instance.server + this.$store.state.instance.defaultBanner + if (this.isDefaultBanner) { + return this.$store.state.instance.server + this.$store.state.instance.defaultBanner + } + return this.user.cover_photo }, isDefaultAvatar () { const baseAvatar = this.$store.state.instance.defaultAvatar @@ -249,10 +271,6 @@ export default { 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 - }, fieldsLimits () { return this.$store.state.instance.fieldsLimits }, @@ -358,26 +376,27 @@ export default { } }, submitImage ({ canvas, file }) { - const reqData = {} - if (this.editImage === 'avatar') { - if (canvas) { - return canvas.toBlob((data) => this.submitImage({ canvas: null, file: data })) - } - reqData.avatar = file - reqData.avatarName = file.name - } else { - reqData.banner = file + if (canvas) { + return canvas.toBlob((data) => this.submitImage({ canvas: null, file: data })) } - return this.$store.state.api.backendInteractor.updateProfileImages(reqData) - .then((user) => { - this.$store.commit('addNewUsers', [user]) - this.$store.commit('setCurrentUser', user) - this.editImage = false - }) - .catch((error) => { - this.displayUploadError(error) - }) + const reader = new window.FileReader() + reader.onload = (e) => { + const dataUrl = e.target.result + + if (this.editImage === 'avatar') { + this.newAvatar = dataUrl + this.newAvatarFile = file + } else { + this.newBanner = dataUrl + this.newBannerFile = file + } + + this.editImage = false + } + + reader.readAsDataURL(file) + }, addField () { if (this.newFields.length < this.maxFields) { @@ -395,6 +414,23 @@ export default { cancelImageText () { return }, + resetNews () { + const user = this.$store.state.users.currentUser + + this.newName = user.name_unescaped + this.newAvatar = '' + this.newAvatarFile = null + this.newBanner = '' + this.newBannerFile = null + this.newActorType = user.actor_type + this.newBio = unescape(user.description) + this.newBirthday = user.birthday + this.newShowBirthday = user.show_birthday + this.newCoverPhoto = user.cover_photo + this.newFields = user.fields.map(field => ({ name: field.name, value: field.value })) + this.newLocked = user.locked + this.newShowRole = user.show_role + }, updateProfile () { const params = { note: this.newBio, @@ -403,10 +439,21 @@ export default { // Backend notation. display_name: this.newName, fields_attributes: this.newFields.filter(el => el != null), - actor_type: this.actorType, - show_role: this.showRole, + show_role: !!this.showRole, birthday: this.newBirthday || '', - show_birthday: this.showBirthday + show_birthday: !!this.showBirthday, + } + + if (this.actorType) { + params.actor_type = this.actorType + } + + if (this.newAvatar) { + params.avatar = this.newAvatarFile + } + + if (this.newBanner) { + params.header = this.newBannerFile } if (this.emailLanguage) { @@ -416,11 +463,22 @@ export default { this.$store.state.api.backendInteractor .updateProfile({ params }) .then((user) => { - this.newFields.splice(user.fields.length) + this.newFields.splice(this.newFields.length) merge(this.newFields, user.fields) this.$store.commit('addNewUsers', [user]) this.$store.commit('setCurrentUser', user) + this.resetNews() + }) + .catch((error) => { + this.displayUploadError(error) }) }, + displayUploadError (error) { + useInterfaceStore().pushGlobalNotice({ + messageKey: 'upload.error.message', + messageArgs: [error.message], + level: 'error' + }) + } } } diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss index d4537a07d..dee45ab23 100644 --- a/src/components/user_card/user_card.scss +++ b/src/components/user_card/user_card.scss @@ -26,7 +26,7 @@ color: var(--lightText); display: block; line-height: 1.3; - padding: 0.6em; + padding: 0 0.6em; margin: 0 0.6em; img { @@ -38,8 +38,6 @@ } .user-card-bio { - margin: 0.6em; - &, * { line-height: 1.5; } @@ -201,6 +199,7 @@ margin: -0.6em; &.save-profile-button, + &.reset-profile-button, &.edit-banner-button { width: auto; } @@ -280,6 +279,14 @@ .edit-button { width: 3em; text-align: center; + + &:hover .icon { + color: var(--textFaint); + } + + &:not(:hover) .icon { + color: var(--lightText); + } } .input, @@ -391,6 +398,7 @@ grid-template-columns: repeat(auto-fit, minmax(7.5em, 20%)); grid-gap: 0.6em; max-width: 98vw; + margin-bottom: 0.6em; .popover-trigger-button, .moderation-tools-button { width: 100%; @@ -575,4 +583,25 @@ aspect-ratio: unset; } } + + &.-banner { + .images-container { + grid-template-rows: 20em 5em 20em; + grid-template-columns: 1fr; + + > * { + flex: 1 0 10em; + width: 100%; + aspect-ratio: 3; + } + } + + .separator { + min-height: 1.1em; + font-size: 500%; + justify-self: center; + flex: 0 1 5em; + aspect-ratio: unset; + } + } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index d74754d9a..6d856d285 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -19,7 +19,10 @@ class="user-info-avatar -link" @click="zoomAvatar" > - + +
{{ $t('settings.toggle_edit') }} +