Add channel/account avatars in miniature (#2838)

* add small avatar to miniature

* fix svg size for trending and search icons in plugins view

* parametrize avatar in miniature display options
This commit is contained in:
Rigel Kent 2020-06-08 08:52:06 +02:00 committed by GitHub
parent c87d45df9b
commit c2caa99b94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 75 additions and 33 deletions

View File

@ -1,8 +1,8 @@
<div class="wrapper">
<a [routerLink]="[ '/video-channels', video.byVideoChannel ]" i18n-title title="Go the channel page">
<div class="wrapper" [ngClass]="'avatar-' + size">
<a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle">
<img [src]="video.videoChannelAvatarUrl" alt="Channel avatar" />
</a>
<a [routerLink]="[ '/accounts', video.byAccount ]" i18n-title title="Go to the account page">
<a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle">
<img [src]="video.accountAvatarUrl" alt="Account avatar" />
</a>
</div>

View File

@ -1,13 +1,18 @@
@import '_mixins';
.wrapper {
width: 35px;
height: 35px;
min-width: 35px;
min-height: 35px;
$avatar-size: 35px;
width: $avatar-size;
height: $avatar-size;
position: relative;
margin-right: 5px;
&.avatar-sm {
width: 28px;
height: 28px;
}
a {
@include disable-outline;
}

View File

@ -1,11 +1,31 @@
import { Component, Input } from '@angular/core'
import { VideoDetails } from '../video/video-details.model'
import { Component, Input, OnInit } from '@angular/core'
import { Video } from '../video/video.model'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
selector: 'avatar-channel',
templateUrl: './avatar.component.html',
styleUrls: [ './avatar.component.scss' ]
})
export class AvatarComponent {
@Input() video: VideoDetails
export class AvatarComponent implements OnInit {
@Input() video: Video
@Input() size: 'md' | 'sm' = 'md'
channelLinkTitle = ''
accountLinkTitle = ''
constructor (
private i18n: I18n
) {}
ngOnInit () {
this.channelLinkTitle = this.i18n(
'Go to the channel page of {{name}} ({{handle}})',
{ name: this.video.channel.name, handle: this.video.byVideoChannel }
)
this.accountLinkTitle = this.i18n(
'Go to the account page of {{name}} ({{handle}})',
{ name: this.video.account.name, handle: this.video.byAccount }
)
}
}

View File

@ -56,6 +56,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
date: true,
views: true,
by: true,
avatar: true,
privacyLabel: true,
privacyText: false,
state: false,

View File

@ -15,26 +15,32 @@
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }"
>{{ video.name }}</a>
<span class="video-miniature-created-at-views">
<my-date-toggle *ngIf="displayOptions.date" [date]="video.publishedAt"></my-date-toggle>
<div class="d-inline-flex">
<avatar-channel *ngIf="displayOptions.avatar" class="mr-1 pt-1" [video]="video" size="sm"></avatar-channel>
<span class="views">
<ng-container *ngIf="displayOptions.date && displayOptions.views"></ng-container>
<ng-container i18n *ngIf="displayOptions.views">{video.views, plural, =1 {1 view} other {{{ video.views | myNumberFormatter }} views}}</ng-container>
</span>
</span>
<a tabindex="-1" *ngIf="displayOptions.by && displayOwnerAccount()" class="video-miniature-account" [routerLink]="[ '/accounts', video.byAccount ]">
{{ video.byAccount }}
</a>
<a tabindex="-1" *ngIf="displayOptions.by && displayOwnerVideoChannel()" class="video-miniature-channel" [routerLink]="[ '/video-channels', video.byVideoChannel ]">
{{ video.byVideoChannel }}
</a>
<div class="video-info-privacy">
<ng-container *ngIf="displayOptions.privacyText">{{ video.privacy.label }}</ng-container>
<ng-container *ngIf="displayOptions.privacyText && displayOptions.state && getStateLabel(video)"> - </ng-container>
<ng-container *ngIf="displayOptions.state">{{ getStateLabel(video) }}</ng-container>
<div class="d-flex flex-column">
<span class="video-miniature-created-at-views">
<my-date-toggle *ngIf="displayOptions.date" [date]="video.publishedAt"></my-date-toggle>
<span class="views">
<ng-container *ngIf="displayOptions.date && displayOptions.views"></ng-container>
<ng-container i18n *ngIf="displayOptions.views">{video.views, plural, =1 {1 view} other {{{ video.views | myNumberFormatter }} views}}</ng-container>
</span>
</span>
<a tabindex="-1" *ngIf="displayOptions.by && displayOwnerAccount()" class="video-miniature-account" [routerLink]="[ '/accounts', video.byAccount ]">
{{ video.byAccount }}
</a>
<a tabindex="-1" *ngIf="displayOptions.by && displayOwnerVideoChannel()" class="video-miniature-channel" [routerLink]="[ '/video-channels', video.byVideoChannel ]">
{{ video.byVideoChannel }}
</a>
<div class="video-info-privacy">
<ng-container *ngIf="displayOptions.privacyText">{{ video.privacy.label }}</ng-container>
<ng-container *ngIf="displayOptions.privacyText && displayOptions.state && getStateLabel(video)"> - </ng-container>
<ng-container *ngIf="displayOptions.state">{{ getStateLabel(video) }}</ng-container>
</div>
</div>
</div>
<div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blacklisted">

View File

@ -24,6 +24,7 @@ export type MiniatureDisplayOptions = {
date?: boolean
views?: boolean
by?: boolean
avatar?: boolean
privacyLabel?: boolean
privacyText?: boolean
state?: boolean
@ -46,6 +47,7 @@ export class VideoMiniatureComponent implements OnInit {
date: true,
views: true,
by: true,
avatar: false,
privacyLabel: false,
privacyText: false,
state: false,

View File

@ -13,7 +13,7 @@
</div>
<div *ngFor="let video of (videos$ | async); let i = index; let length = count">
<my-video-miniature [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
<my-video-miniature [displayOptions]="displayOptions" [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
</my-video-miniature>
<hr *ngIf="!playlist && i == 0 && length > 1" />

View File

@ -9,6 +9,7 @@ import { AuthService, Notifier } from '@app/core'
import { UserService } from '@app/shared/users/user.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { SessionStorageService } from '@app/shared/misc/storage.service'
import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
@Component({
selector: 'my-recommended-videos',
@ -24,6 +25,13 @@ export class RecommendedVideosComponent implements OnChanges {
autoPlayNextVideo: boolean
autoPlayNextVideoTooltip: string
displayOptions: MiniatureDisplayOptions = {
date: true,
views: true,
by: true,
avatar: true
}
readonly hasVideos$: Observable<boolean>
readonly videos$: Observable<Video[]>

View File

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" viewBox="0 0 24 24">
<defs/>
<g fill="none" fill-rule="evenodd" stroke="#000" stroke-width="2">
<circle cx="10" cy="10" r="7"/>

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 291 B

View File

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" viewBox="0 0 24 24">
<defs/>
<g fill="none" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
<path d="M3 3v18h18"/>

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 317 B