1
0
Fork 0

Refactor video miniatures

This commit is contained in:
Chocobozzz 2019-04-03 16:17:41 +02:00
parent 8fc02e4768
commit e2409062de
No known key found for this signature in database
GPG key ID: 583A612D890159BE
18 changed files with 199 additions and 244 deletions

View file

@ -23,7 +23,6 @@ import { Notifier, ServerService } from '@app/core'
}) })
export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string titlePage: string
marginContent = false // Disable margin
loadOnInit = false loadOnInit = false
private account: Account private account: Account

View file

@ -6,15 +6,7 @@
<my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox> <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
</div> </div>
<my-video-thumbnail [video]="video"></my-video-thumbnail> <my-video-miniature [video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions"></my-video-miniature>
<div class="video-info">
<a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
<div>{{ video.account.displayName }}</div>
<div>{{ video.publishedAt | myFromNow }}</div>
<div><span i18n>Privacy: </span><span>{{ video.privacy.label }}</span></div>
<div><span i18n>Sensitive: </span><span> {{ video.nsfw }}</span></div>
</div>
<!-- Display only once --> <!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0"> <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
@ -30,13 +22,12 @@
</div> </div>
</div> </div>
<div class="video-buttons" *ngIf="isInSelectionMode() === false"> <my-button
<my-button *ngIf="isInSelectionMode() === false"
i18n-label i18n-label
label="Unblacklist" label="Unblacklist"
icon="tick" icon="tick"
(click)="removeVideoFromBlacklist(video)" (click)="removeVideoFromBlacklist(video)"
></my-button> ></my-button>
</div>
</div> </div>
</div> </div>

View file

@ -46,26 +46,8 @@
margin-left: 12px; margin-left: 12px;
} }
my-video-thumbnail { my-video-miniature {
margin-right: 10px;
}
.video-info {
flex-grow: 1; flex-grow: 1;
.video-info-name {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
display: block;
width: fit-content;
font-size: 16px;
font-weight: $font-semibold;
}
}
.video-buttons {
min-width: 190px;
} }
} }
@ -73,21 +55,12 @@
.video { .video {
flex-direction: column; flex-direction: column;
height: auto; height: auto;
text-align: center;
.video-info-name { .checkbox-container {
margin: auto;
}
input[type=checkbox] {
display: none; display: none;
} }
my-video-thumbnail { my-button {
margin-right: 0;
}
.video-buttons {
margin-top: 10px; margin-top: 10px;
} }
} }

View file

@ -1,14 +1,14 @@
import { Component, OnInit, OnDestroy } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { Location } from '@angular/common'
import { I18n } from '@ngx-translate/i18n-polyfill' import { I18n } from '@ngx-translate/i18n-polyfill'
import { Router, ActivatedRoute } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AbstractVideoList } from '@app/shared/video/abstract-video-list' import { AbstractVideoList } from '@app/shared/video/abstract-video-list'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model' import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { Notifier, AuthService, ServerService } from '@app/core' import { AuthService, Notifier, ServerService } from '@app/core'
import { Video } from '@shared/models' import { Video } from '@shared/models'
import { VideoBlacklistService } from '@app/shared' import { VideoBlacklistService } from '@app/shared'
import { immutableAssign } from '@app/shared/misc/utils' import { immutableAssign } from '@app/shared/misc/utils'
import { ScreenService } from '@app/shared/misc/screen.service' import { ScreenService } from '@app/shared/misc/screen.service'
import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
@Component({ @Component({
selector: 'my-video-auto-blacklist-list', selector: 'my-video-auto-blacklist-list',
@ -24,6 +24,17 @@ export class VideoAutoBlacklistListComponent extends AbstractVideoList implement
totalItems: null totalItems: null
} }
miniatureDisplayOptions: MiniatureDisplayOptions = {
date: true,
views: false,
by: true,
privacyLabel: false,
privacyText: true,
state: false,
blacklistInfo: false,
nsfw: true
}
constructor ( constructor (
protected router: Router, protected router: Router,
protected route: ActivatedRoute, protected route: ActivatedRoute,

View file

@ -15,12 +15,6 @@
<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" class="videos"> <div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" class="videos">
<div class="video" *ngFor="let video of videos"> <div class="video" *ngFor="let video of videos">
<my-video-thumbnail [video]="video"></my-video-thumbnail> <my-video-miniature [video]="video" [displayAsRow]="true"></my-video-miniature>
<div class="video-info">
<a tabindex="-1" class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
<span i18n class="video-info-date-views">{{ video.views | myNumberFormatter }} views</span>
<a tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', video.byAccount ]">{{ video.byAccount }}</a>
</div>
</div> </div>
</div> </div>

View file

@ -34,63 +34,7 @@
.video { .video {
@include row-blocks; @include row-blocks;
my-video-thumbnail { .my-video-miniature {
margin-right: 10px;
}
.video-info {
flex-grow: 1; flex-grow: 1;
.video-info-name {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
display: block;
width: fit-content;
font-size: 18px;
font-weight: $font-semibold;
}
.video-info-date-views {
font-size: 14px;
}
.video-info-account {
@include disable-default-a-behaviour;
@include ellipsis;
display: block;
width: fit-content;
font-size: 14px;
color: $grey-foreground-color;
&:hover {
color: $grey-foreground-hover-color;
}
}
}
}
@media screen and (max-width: $small-view) {
.video {
flex-direction: column;
height: auto;
text-align: center;
.video-info-name {
margin: auto;
}
input[type=checkbox] {
display: none;
}
my-video-thumbnail {
margin-right: 0;
}
.video-buttons {
margin-top: 10px;
}
} }
} }

View file

@ -6,17 +6,7 @@
<my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox> <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
</div> </div>
<my-video-thumbnail [video]="video"></my-video-thumbnail> <my-video-miniature [video]="video" [displayOptions]="miniatureDisplayOptions" [displayAsRow]="true"></my-video-miniature>
<div class="video-info">
<a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
<span i18n class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
<div class="video-info-privacy">{{ video.privacy.label }}{{ getStateLabel(video) }}</div>
<div *ngIf="video.blacklisted" class="video-info-blacklisted">
<span class="blacklisted-label" i18n>Blacklisted</span>
<span class="blacklisted-reason" *ngIf="video.blacklistedReason">{{ video.blacklistedReason }}</span>
</div>
</div>
<!-- Display only once --> <!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0"> <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">

View file

@ -46,44 +46,8 @@
margin-left: 12px; margin-left: 12px;
} }
my-video-thumbnail { my-video-miniature {
margin-right: 10px;
}
.video-info {
flex-grow: 1; flex-grow: 1;
.video-info-name {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
display: block;
width: fit-content;
font-size: 16px;
font-weight: $font-semibold;
}
.video-info-date-views,
.video-info-privacy,
.video-info-blacklisted {
font-size: 13px;
&.video-info-privacy,
&.video-info-blacklisted .blacklisted-label {
font-weight: $font-semibold;
}
&.video-info-blacklisted {
color: red;
.blacklisted-reason {
&::before {
content: ' - ';
}
}
}
}
} }
.video-buttons { .video-buttons {
@ -99,20 +63,11 @@
.video { .video {
flex-direction: column; flex-direction: column;
height: auto; height: auto;
text-align: center;
.video-info-name { .checkbox-container {
margin: auto;
}
input[type=checkbox] {
display: none; display: none;
} }
my-video-thumbnail {
margin-right: 0;
}
.video-buttons { .video-buttons {
margin-top: 10px; margin-top: 10px;
} }

View file

@ -14,6 +14,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPrivacy, VideoState } from '../../../../../shared/models/videos' import { VideoPrivacy, VideoState } from '../../../../../shared/models/videos'
import { ScreenService } from '@app/shared/misc/screen.service' import { ScreenService } from '@app/shared/misc/screen.service'
import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component' import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component'
import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
@Component({ @Component({
selector: 'my-account-videos', selector: 'my-account-videos',
@ -30,6 +31,15 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
itemsPerPage: 5, itemsPerPage: 5,
totalItems: null totalItems: null
} }
miniatureDisplayOptions: MiniatureDisplayOptions = {
date: true,
views: true,
by: false,
privacyLabel: false,
privacyText: true,
state: true,
blacklistInfo: true
}
constructor ( constructor (
protected router: Router, protected router: Router,

View file

@ -23,7 +23,6 @@ import { Notifier, ServerService } from '@app/core'
}) })
export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string titlePage: string
marginContent = false // Disable margin
loadOnInit = false loadOnInit = false
private videoChannel: VideoChannel private videoChannel: VideoChannel

View file

@ -48,13 +48,7 @@
</div> </div>
<div *ngIf="isVideo(result)" class="entry video"> <div *ngIf="isVideo(result)" class="entry video">
<my-video-thumbnail [video]="result" [nsfw]="isVideoBlur(result)"></my-video-thumbnail> <my-video-miniature [video]="result" [user]="user" [displayAsRow]="true"></my-video-miniature>
<div class="video-info">
<a tabindex="-1" class="video-info-name" [routerLink]="['/videos/watch', result.uuid]" [attr.title]="result.name">{{ result.name }}</a>
<span i18n class="video-info-date-views">{{ result.publishedAt | myFromNow }} - {{ result.views | myNumberFormatter }} views</span>
<a tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', result.byAccount ]">{{ result.byAccount }}</a>
</div>
</div> </div>
</ng-container> </ng-container>

View file

@ -55,51 +55,14 @@
padding-bottom: 20px; padding-bottom: 20px;
margin-bottom: 20px; margin-bottom: 20px;
&.video {
my-video-thumbnail {
margin-right: 10px;
}
.video-info {
flex-grow: 1;
.video-info-name {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
display: block;
width: fit-content;
font-size: 18px;
font-weight: $font-semibold;
}
.video-info-date-views {
font-size: 14px;
}
.video-info-account {
@include disable-default-a-behaviour;
@include ellipsis;
display: block;
width: fit-content;
font-size: 14px;
color: $grey-foreground-color;
&:hover {
color: $grey-foreground-hover-color;
}
}
}
}
&.video-channel { &.video-channel {
img { img {
@include avatar(120px); $image-size: 130px;
$margin-size: ($video-thumbnail-width - $image-size) / 2; // So we have the same width than the video miniature
margin: 0 50px 0 40px; @include avatar($image-size);
margin: 0 ($margin-size + 10) 0 $margin-size;
} }
.video-channel-info { .video-channel-info {

View file

@ -41,10 +41,13 @@ export class SearchComponent implements OnInit, OnDestroy {
private metaService: MetaService, private metaService: MetaService,
private notifier: Notifier, private notifier: Notifier,
private searchService: SearchService, private searchService: SearchService,
private authService: AuthService, private authService: AuthService
private serverService: ServerService
) { } ) { }
get user () {
return this.authService.getUser()
}
ngOnInit () { ngOnInit () {
this.subActivatedRoute = this.route.queryParams.subscribe( this.subActivatedRoute = this.route.queryParams.subscribe(
queryParams => { queryParams => {
@ -76,10 +79,6 @@ export class SearchComponent implements OnInit, OnDestroy {
if (this.subActivatedRoute) this.subActivatedRoute.unsubscribe() if (this.subActivatedRoute) this.subActivatedRoute.unsubscribe()
} }
isVideoBlur (video: Video) {
return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig())
}
isVideoChannel (d: VideoChannel | Video): d is VideoChannel { isVideoChannel (d: VideoChannel | Video): d is VideoChannel {
return d instanceof VideoChannel return d instanceof VideoChannel
} }

View file

@ -1,4 +1,4 @@
<div class="video-miniature"> <div class="video-miniature" [ngClass]="{ 'display-as-row': displayAsRow }">
<my-video-thumbnail [video]="video" [nsfw]="isVideoBlur"></my-video-thumbnail> <my-video-thumbnail [video]="video" [nsfw]="isVideoBlur"></my-video-thumbnail>
<div class="video-miniature-information"> <div class="video-miniature-information">
@ -7,19 +7,41 @@
class="video-miniature-name" class="video-miniature-name"
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }" [routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }"
> >
<span *ngIf="isUnlistedVideo()" class="badge badge-warning" i18n>Unlisted</span> <ng-container *ngIf="displayOptions.privacyLabel">
<span *ngIf="isPrivateVideo()" class="badge badge-danger" i18n>Private</span> <span *ngIf="isUnlistedVideo()" class="badge badge-warning" i18n>Unlisted</span>
<span *ngIf="isPrivateVideo()" class="badge badge-danger" i18n>Private</span>
</ng-container>
{{ video.name }} {{ video.name }}
</a> </a>
<span i18n class="video-miniature-created-at-views">{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> <span class="video-miniature-created-at-views">
<ng-container *ngIf="displayOptions.date">{{ video.publishedAt | myFromNow }}</ng-container>
<ng-container *ngIf="displayOptions.date && displayOptions.views"> - </ng-container>
<ng-container i18n *ngIf="displayOptions.views">{{ video.views | myNumberFormatter }} views</ng-container>
</span>
<a tabindex="-1" *ngIf="displayOwnerAccount()" class="video-miniature-account" [routerLink]="[ '/accounts', video.byAccount ]"> <a tabindex="-1" *ngIf="displayOptions.by && displayOwnerAccount()" class="video-miniature-account" [routerLink]="[ '/accounts', video.byAccount ]">
{{ video.byAccount }} {{ video.byAccount }}
</a> </a>
<a tabindex="-1" *ngIf="displayOwnerVideoChannel()" class="video-miniature-channel" [routerLink]="[ '/video-channels', video.byVideoChannel ]"> <a tabindex="-1" *ngIf="displayOptions.by && displayOwnerVideoChannel()" class="video-miniature-channel" [routerLink]="[ '/video-channels', video.byVideoChannel ]">
{{ video.byVideoChannel }} {{ video.byVideoChannel }}
</a> </a>
<div class="video-info-privacy">
<ng-container *ngIf="displayOptions.privacyText">{{ video.privacy.label }}</ng-container>
<ng-container *ngIf="displayOptions.privacyText && displayOptions.state"> - </ng-container>
<ng-container *ngIf="displayOptions.state">{{ getStateLabel(video) }}</ng-container>
</div>
<div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blacklisted">
<span class="blacklisted-label" i18n>Blacklisted</span>
<span class="blacklisted-reason" *ngIf="video.blacklistedReason">{{ video.blacklistedReason }}</span>
</div>
<div i18n *ngIf="displayOptions.nsfw && video.nsfw" class="video-info-nsfw">
Sensitive
</div>
</div> </div>
</div> </div>

View file

@ -4,15 +4,14 @@
.video-miniature { .video-miniature {
width: $video-miniature-width; width: $video-miniature-width;
display: inline-flex;
display: inline-block; flex-direction: column;
margin-bottom: 30px; margin-bottom: 30px;
height: 195px; height: 195px;
vertical-align: top; vertical-align: top;
.video-miniature-information { .video-miniature-information {
width: 200px; width: 200px;
margin-top: 2px;
line-height: normal; line-height: normal;
.video-miniature-name { .video-miniature-name {
@ -37,5 +36,68 @@
color: $grey-foreground-hover-color; color: $grey-foreground-hover-color;
} }
} }
.video-info-privacy,
.video-info-blacklisted .blacklisted-label,
.video-info-nsfw {
font-weight: $font-semibold;
}
.video-info-blacklisted {
color: red;
.blacklisted-reason::before {
content: ' - ';
}
}
.video-info-nsfw {
color: red;
}
}
&.display-as-row {
flex-direction: row;
margin-bottom: 0;
height: auto;
width: 100%;
my-video-thumbnail {
margin-right: 10px;
}
.video-miniature-information {
width: auto;
.video-miniature-name {
@include ellipsis-multiline(1.3em, 2);
margin-top: 2px;
margin-bottom: 5px;
}
.video-miniature-created-at-views,
.video-miniature-account,
.video-miniature-channel {
font-size: 14px;
}
.video-info-privacy {
margin-top: 5px;
}
.video-info-blacklisted {
margin-top: 3px;
}
}
@media screen and (max-width: $small-view) {
flex-direction: column;
height: auto;
my-video-thumbnail {
margin-right: 0;
}
}
} }
} }

View file

@ -1,10 +1,21 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core' import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'
import { User } from '../users' import { User } from '../users'
import { Video } from './video.model' import { Video } from './video.model'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { VideoPrivacy } from '../../../../../shared' import { VideoPrivacy, VideoState } from '../../../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
export type OwnerDisplayType = 'account' | 'videoChannel' | 'auto' export type OwnerDisplayType = 'account' | 'videoChannel' | 'auto'
export type MiniatureDisplayOptions = {
date?: boolean
views?: boolean
by?: boolean
privacyLabel?: boolean
privacyText?: boolean
state?: boolean
blacklistInfo?: boolean
nsfw?: boolean
}
@Component({ @Component({
selector: 'my-video-miniature', selector: 'my-video-miniature',
@ -15,11 +26,26 @@ export type OwnerDisplayType = 'account' | 'videoChannel' | 'auto'
export class VideoMiniatureComponent implements OnInit { export class VideoMiniatureComponent implements OnInit {
@Input() user: User @Input() user: User
@Input() video: Video @Input() video: Video
@Input() ownerDisplayType: OwnerDisplayType = 'account' @Input() ownerDisplayType: OwnerDisplayType = 'account'
@Input() displayOptions: MiniatureDisplayOptions = {
date: true,
views: true,
by: true,
privacyLabel: false,
privacyText: false,
state: false,
blacklistInfo: false
}
@Input() displayAsRow = false
private ownerDisplayTypeChosen: 'account' | 'videoChannel' private ownerDisplayTypeChosen: 'account' | 'videoChannel'
constructor (private serverService: ServerService) { } constructor (
private serverService: ServerService,
private i18n: I18n,
@Inject(LOCALE_ID) private localeId: string
) { }
get isVideoBlur () { get isVideoBlur () {
return this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig()) return this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig())
@ -58,4 +84,29 @@ export class VideoMiniatureComponent implements OnInit {
isPrivateVideo () { isPrivateVideo () {
return this.video.privacy.id === VideoPrivacy.PRIVATE return this.video.privacy.id === VideoPrivacy.PRIVATE
} }
getStateLabel (video: Video) {
if (video.privacy.id !== VideoPrivacy.PRIVATE && video.state.id === VideoState.PUBLISHED) {
return this.i18n('Published')
}
if (video.scheduledUpdate) {
const updateAt = new Date(video.scheduledUpdate.updateAt.toString()).toLocaleString(this.localeId)
return this.i18n('Publication scheduled on ') + updateAt
}
if (video.state.id === VideoState.TO_TRANSCODE && video.waitTranscoding === true) {
return this.i18n('Waiting transcoding')
}
if (video.state.id === VideoState.TO_TRANSCODE) {
return this.i18n('To transcode')
}
if (video.state.id === VideoState.TO_IMPORT) {
return this.i18n('To import')
}
return ''
}
} }

View file

@ -5,7 +5,6 @@
@include ellipsis-multiline(1.1em, 2); @include ellipsis-multiline(1.1em, 2);
transition: color 0.2s; transition: color 0.2s;
font-size: 16px;
font-weight: $font-semibold; font-weight: $font-semibold;
color: var(--mainForegroundColor); color: var(--mainForegroundColor);
margin-top: 10px; margin-top: 10px;

View file

@ -515,7 +515,6 @@
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
flex-direction: column; flex-direction: column;
height: auto; height: auto;
text-align: center;
align-items: center; align-items: center;
} }
} }