Add channel/account avatars in miniature (#2838)
authorRigel Kent <sendmemail@rigelk.eu>
Mon, 8 Jun 2020 06:52:06 +0000 (08:52 +0200)
committerGitHub <noreply@github.com>
Mon, 8 Jun 2020 06:52:06 +0000 (08:52 +0200)
* add small avatar to miniature

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

* parametrize avatar in miniature display options

client/src/app/shared/channel/avatar.component.html
client/src/app/shared/channel/avatar.component.scss
client/src/app/shared/channel/avatar.component.ts
client/src/app/shared/video/abstract-video-list.ts
client/src/app/shared/video/video-miniature.component.html
client/src/app/shared/video/video-miniature.component.ts
client/src/app/videos/recommendations/recommended-videos.component.html
client/src/app/videos/recommendations/recommended-videos.component.ts
client/src/assets/images/global/search.svg
client/src/assets/images/menu/trending.svg

index 362feacd74157fb55b19a3a419df4887e0edbfaa..062ef5bde8df36344ab0eb573d603795ac2c6f72 100644 (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>
index 6629a432794873b0f07d635ebb625703573c873f..77b90c5790c13180aa1ddcba3978b7ea033991a3 100644 (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;
   }
index 2201c04cac74884d1eee21ca7d9a698940358730..2c8eeb4b215dc2fdf75d1666433aa2e7a1c20089 100644 (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 }
+    )
+  }
 }
index b146d701499838f050321f00719a501073c321d4..69d5c001096c85967fed6c912526ece94b91d954 100644 (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,
index 8e948ce422ff6d3d01cc57150d0eeabe84856784..c9ac97762ae7414a9e555ca786e5521fb41fbe81 100644 (file)
         [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">
index 72b6524489263bc6f7daf954ceff279f3b097d29..88b21b3a56c9ca8769668c66800ba987b0b66a5a 100644 (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,
index 74f9ed2a5a6e1c4a70ed2007581eb3e6b8f17136..c6bdfee4632777f635c90882a0560148ea9b9409 100644 (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" />
index d4b4c929b42dcd79e0f81ce9a01180d205f2fe89..d4a5df19a05cd01146b48bd75aeb116035f8741d 100644 (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[]>
 
index 55c85101476c6c46dc68a2d871a5af254338a130..1583c437b88ae1156241c5a7cb0ca6055df7846f 100644 (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"/>
index b21bb1e9f21fdc0b3721a6bcc1ca118302bf48b7..8f821f3d7d13de0f4d39291009d4a91faf61f8e0 100644 (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"/>