Refactor my actor avatar edit
This commit is contained in:
parent
464e4ed92c
commit
9e401fde36
|
@ -13,6 +13,7 @@ import { FormReactiveService } from '@app/shared/shared-forms'
|
|||
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||
import { HTMLServerConfig, VideoChannelUpdate } from '@shared/models'
|
||||
import { VideoChannelEdit } from './video-channel-edit'
|
||||
import { shallowCopy } from '@shared/core-utils'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-channel-update',
|
||||
|
@ -118,6 +119,9 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
|
|||
this.notifier.success($localize`Avatar changed.`)
|
||||
|
||||
this.videoChannel.updateAvatar(data.avatars)
|
||||
|
||||
// So my-actor-avatar component detects changes
|
||||
this.videoChannel = shallowCopy(this.videoChannel)
|
||||
},
|
||||
|
||||
error: (err: HttpErrorResponse) => genericUploadErrorHandler({
|
||||
|
@ -135,6 +139,9 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
|
|||
this.notifier.success($localize`Avatar deleted.`)
|
||||
|
||||
this.videoChannel.resetAvatar()
|
||||
|
||||
// So my-actor-avatar component detects changes
|
||||
this.videoChannel = shallowCopy(this.videoChannel)
|
||||
},
|
||||
|
||||
error: err => this.notifier.error(err.message)
|
||||
|
|
|
@ -3,6 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http'
|
|||
import { AfterViewChecked, Component, OnInit } from '@angular/core'
|
||||
import { AuthService, Notifier, User, UserService } from '@app/core'
|
||||
import { genericUploadErrorHandler } from '@app/helpers'
|
||||
import { shallowCopy } from '@shared/core-utils'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-settings',
|
||||
|
@ -44,6 +45,9 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
|||
this.notifier.success($localize`Avatar changed.`)
|
||||
|
||||
this.user.updateAccountAvatar(data.avatars)
|
||||
|
||||
// So my-actor-avatar component detects changes
|
||||
this.user.account = shallowCopy(this.user.account)
|
||||
},
|
||||
|
||||
error: (err: HttpErrorResponse) => genericUploadErrorHandler({
|
||||
|
@ -57,10 +61,13 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
|
|||
onAvatarDelete () {
|
||||
this.userService.deleteAvatar()
|
||||
.subscribe({
|
||||
next: data => {
|
||||
next: () => {
|
||||
this.notifier.success($localize`Avatar deleted.`)
|
||||
|
||||
this.user.updateAccountAvatar()
|
||||
|
||||
// So my-actor-avatar component detects changes
|
||||
this.user.account = shallowCopy(this.user.account)
|
||||
},
|
||||
|
||||
error: (err: HttpErrorResponse) => this.notifier.error(err.message)
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
<div class="actor" *ngIf="actor">
|
||||
<div class="d-flex">
|
||||
<div class="position-relative me-3">
|
||||
<my-actor-avatar [actor]="actor" [actorType]="getActorType()" [previewImage]="preview" size="100"></my-actor-avatar>
|
||||
|
||||
<div class="actor-img-edit-container">
|
||||
<div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body">
|
||||
<my-global-icon iconName="upload"></my-global-icon>
|
||||
<label class="visually-hidden" for="avatarfile" i18n>Upload a new avatar</label>
|
||||
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
|
||||
</div>
|
||||
|
||||
<div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body">
|
||||
<my-global-icon iconName="upload"></my-global-icon>
|
||||
<label class="visually-hidden" for="avatarfile" i18n>Upload a new avatar</label>
|
||||
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="editable && hasAvatar()" class="actor-img-edit-button"
|
||||
#avatarPopover="ngbPopover" [ngbPopover]="avatarEditContent" popoverClass="popover-image-info" autoClose="outside" placement="right"
|
||||
>
|
||||
<div *ngIf="editable && hasAvatar()" ngbDropdown placement="right">
|
||||
<div class="actor-img-edit-button" ngbDropdownToggle>
|
||||
<my-global-icon iconName="edit"></my-global-icon>
|
||||
<label class="visually-hidden" for="avatarMenu" i18n>Change your avatar</label>
|
||||
</div>
|
||||
|
||||
<div ngbDropdownMenu>
|
||||
<div class="dropdown-item c-hand dropdown-file" [ngbTooltip]="avatarFormat">
|
||||
<my-global-icon iconName="upload"></my-global-icon>
|
||||
<span for="avatarfile" i18n>Upload a new avatar</span>
|
||||
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()">
|
||||
<my-global-icon iconName="delete"></my-global-icon>
|
||||
<span i18n>Remove avatar</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -27,16 +36,3 @@
|
|||
<div *ngIf="displaySubscribers" i18n class="actor-info-followers">{{ actor.followersCount }} subscribers</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #avatarEditContent>
|
||||
<div class="dropdown-item c-hand" [ngbTooltip]="avatarFormat" placement="right" container="body">
|
||||
<my-global-icon iconName="upload"></my-global-icon>
|
||||
<span for="avatarfile" i18n>Upload a new avatar</span>
|
||||
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()">
|
||||
<my-global-icon iconName="delete"></my-global-icon>
|
||||
<span i18n>Remove avatar</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
my-actor-avatar {
|
||||
@include margin-right(15px);
|
||||
}
|
||||
|
||||
.actor-info {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
|
@ -16,12 +12,12 @@ my-actor-avatar {
|
|||
|
||||
.actor-info-display-name {
|
||||
@include peertube-word-wrap;
|
||||
@include font-size(1.25rem);
|
||||
|
||||
font-size: 20px;
|
||||
font-weight: $font-bold;
|
||||
|
||||
@media screen and (max-width: $small-view) {
|
||||
font-size: 16px;
|
||||
@include font-size(18px);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,17 +31,18 @@ my-actor-avatar {
|
|||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.actor-img-edit-container {
|
||||
position: relative;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.actor-img-edit-button {
|
||||
top: 55px;
|
||||
right: 45px;
|
||||
border-radius: 50%;
|
||||
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
@include dropdown-with-icon-item;
|
||||
}
|
||||
|
||||
.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
||||
import { Notifier, ServerService } from '@app/core'
|
||||
import { Account, VideoChannel } from '@app/shared/shared-main'
|
||||
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { getBytes } from '@root-helpers/bytes'
|
||||
import { imageToDataURL } from '@root-helpers/images'
|
||||
|
||||
|
@ -15,7 +14,6 @@ import { imageToDataURL } from '@root-helpers/images'
|
|||
})
|
||||
export class ActorAvatarEditComponent implements OnInit {
|
||||
@ViewChild('avatarfileInput') avatarfileInput: ElementRef<HTMLInputElement>
|
||||
@ViewChild('avatarPopover') avatarPopover: NgbPopover
|
||||
|
||||
@Input() actor: VideoChannel | Account
|
||||
@Input() editable = true
|
||||
|
@ -58,7 +56,6 @@ export class ActorAvatarEditComponent implements OnInit {
|
|||
|
||||
const formData = new FormData()
|
||||
formData.append('avatarfile', avatarfile)
|
||||
this.avatarPopover?.close()
|
||||
this.avatarChange.emit(formData)
|
||||
|
||||
if (this.previewImage) {
|
||||
|
|
|
@ -8,27 +8,26 @@
|
|||
<ng-container *ngTemplateOutlet="uploadNewBanner"></ng-container>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="hasBanner()" class="actor-img-edit-button"
|
||||
#bannerPopover="ngbPopover" [ngbPopover]="bannerEditContent" popoverClass="popover-image-info" autoClose="outside" placement="right"
|
||||
>
|
||||
<my-global-icon iconName="edit"></my-global-icon>
|
||||
<label for="bannerMenu" i18n>Change your banner</label>
|
||||
<div *ngIf="hasBanner()" ngbDropdown placement="right">
|
||||
<div class="actor-img-edit-button" ngbDropdownToggle>
|
||||
<my-global-icon iconName="edit"></my-global-icon>
|
||||
<label for="bannerMenu" i18n>Change your banner</label>
|
||||
</div>
|
||||
|
||||
<div ngbDropdownMenu>
|
||||
<div class="dropdown-item c-hand dropdown-file" [ngbTooltip]="bannerFormat">
|
||||
<ng-container *ngTemplateOutlet="uploadNewBanner"></ng-container>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-item c-hand" (click)="deleteBanner()" (key.enter)="deleteBanner()">
|
||||
<my-global-icon iconName="delete"></my-global-icon>
|
||||
<span i18n>Remove banner</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #bannerEditContent>
|
||||
<div class="dropdown-item c-hand" [ngbTooltip]="bannerFormat" placement="right" container="body">
|
||||
<ng-container *ngTemplateOutlet="uploadNewBanner"></ng-container>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-item c-hand" (click)="deleteBanner()" (key.enter)="deleteBanner()">
|
||||
<my-global-icon iconName="delete"></my-global-icon>
|
||||
<span i18n>Remove banner</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #uploadNewBanner>
|
||||
<my-global-icon iconName="upload"></my-global-icon>
|
||||
<span for="bannerfile" i18n>Upload a new banner</span>
|
||||
|
|
|
@ -16,12 +16,28 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.actor-img-edit-button {
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
|
||||
> .actor-img-edit-button {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.actor-img-edit-button {
|
||||
width: auto;
|
||||
position: absolute;
|
||||
|
||||
label {
|
||||
font-weight: $font-semibold;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
@include dropdown-with-icon-item;
|
||||
}
|
||||
|
||||
.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
@use '_variables' as *;
|
||||
@use '_mixins' as *;
|
||||
|
||||
.actor ::ng-deep .popover-image-info .popover-body {
|
||||
padding: 0;
|
||||
|
||||
.dropdown-item {
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:first-child {
|
||||
@include peertube-file;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.dropdown-file {
|
||||
@include peertube-file;
|
||||
}
|
||||
|
||||
.actor-img-edit-button {
|
||||
|
@ -22,8 +12,6 @@
|
|||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
input {
|
||||
|
|
|
@ -50,15 +50,15 @@ export class ActorAvatarComponent implements OnInit, OnChanges {
|
|||
ngOnInit () {
|
||||
this.buildDefaultAvatarUrl()
|
||||
|
||||
this.buildClasses()
|
||||
this.buildAlt()
|
||||
this.buildAvatarUrl()
|
||||
this.buildClasses()
|
||||
}
|
||||
|
||||
ngOnChanges () {
|
||||
this.buildClasses()
|
||||
this.buildAlt()
|
||||
this.buildAvatarUrl()
|
||||
this.buildClasses()
|
||||
}
|
||||
|
||||
private buildClasses () {
|
||||
|
@ -114,12 +114,13 @@ export class ActorAvatarComponent implements OnInit, OnChanges {
|
|||
|
||||
displayImage () {
|
||||
if (this.actorType === 'unlogged') return true
|
||||
if (this.previewImage) return true
|
||||
|
||||
return !!(this.actor && this.avatarUrl)
|
||||
}
|
||||
|
||||
displayActorInitial () {
|
||||
return this.actor && !this.avatarUrl
|
||||
return !this.displayImage() && this.actor && !this.avatarUrl
|
||||
}
|
||||
|
||||
displayPlaceholder () {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
@import 'bootstrap/scss/helpers';
|
||||
@import 'bootstrap/scss/utilities/api';
|
||||
|
||||
:root {
|
||||
body {
|
||||
--bs-border-color-translucent: #{pvar(--inputBorderColor)};
|
||||
}
|
||||
|
||||
|
|
|
@ -41,9 +41,14 @@ function sortObjectComparator (key: string, order: 'asc' | 'desc') {
|
|||
}
|
||||
}
|
||||
|
||||
function shallowCopy <T> (o: T): T {
|
||||
return Object.assign(Object.create(Object.getPrototypeOf(o)), o)
|
||||
}
|
||||
|
||||
export {
|
||||
pick,
|
||||
omit,
|
||||
getKeys,
|
||||
shallowCopy,
|
||||
sortObjectComparator
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue