})
export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string
- marginContent = false // Disable margin
loadOnInit = false
private account: Account
<my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
</div>
- <my-video-thumbnail [video]="video"></my-video-thumbnail>
-
- <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>
+ <my-video-miniature [video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions"></my-video-miniature>
<!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
</div>
</div>
- <div class="video-buttons" *ngIf="isInSelectionMode() === false">
- <my-button
- i18n-label
- label="Unblacklist"
- icon="tick"
- (click)="removeVideoFromBlacklist(video)"
- ></my-button>
- </div>
+ <my-button
+ *ngIf="isInSelectionMode() === false"
+ i18n-label
+ label="Unblacklist"
+ icon="tick"
+ (click)="removeVideoFromBlacklist(video)"
+ ></my-button>
</div>
</div>
margin-left: 12px;
}
- my-video-thumbnail {
- margin-right: 10px;
- }
-
- .video-info {
+ my-video-miniature {
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;
}
}
.video {
flex-direction: column;
height: auto;
- text-align: center;
-
- .video-info-name {
- margin: auto;
- }
- input[type=checkbox] {
+ .checkbox-container {
display: none;
}
- my-video-thumbnail {
- margin-right: 0;
- }
-
- .video-buttons {
+ my-button {
margin-top: 10px;
}
}
-import { Component, OnInit, OnDestroy } from '@angular/core'
-import { Location } from '@angular/common'
+import { Component, OnDestroy, OnInit } from '@angular/core'
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 { 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 { VideoBlacklistService } from '@app/shared'
import { immutableAssign } from '@app/shared/misc/utils'
import { ScreenService } from '@app/shared/misc/screen.service'
+import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
@Component({
selector: 'my-video-auto-blacklist-list',
totalItems: null
}
+ miniatureDisplayOptions: MiniatureDisplayOptions = {
+ date: true,
+ views: false,
+ by: true,
+ privacyLabel: false,
+ privacyText: true,
+ state: false,
+ blacklistInfo: false,
+ nsfw: true
+ }
+
constructor (
protected router: Router,
protected route: ActivatedRoute,
<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" class="videos">
<div class="video" *ngFor="let video of videos">
- <my-video-thumbnail [video]="video"></my-video-thumbnail>
-
- <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>
+ <my-video-miniature [video]="video" [displayAsRow]="true"></my-video-miniature>
</div>
</div>
.video {
@include row-blocks;
- my-video-thumbnail {
- margin-right: 10px;
- }
-
- .video-info {
+ .my-video-miniature {
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;
- }
}
}
<my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
</div>
- <my-video-thumbnail [video]="video"></my-video-thumbnail>
-
- <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>
+ <my-video-miniature [video]="video" [displayOptions]="miniatureDisplayOptions" [displayAsRow]="true"></my-video-miniature>
<!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
margin-left: 12px;
}
- my-video-thumbnail {
- margin-right: 10px;
- }
-
- .video-info {
+ my-video-miniature {
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 {
flex-direction: column;
height: auto;
- text-align: center;
- .video-info-name {
- margin: auto;
- }
-
- input[type=checkbox] {
+ .checkbox-container {
display: none;
}
- my-video-thumbnail {
- margin-right: 0;
- }
-
.video-buttons {
margin-top: 10px;
}
import { VideoPrivacy, VideoState } from '../../../../../shared/models/videos'
import { ScreenService } from '@app/shared/misc/screen.service'
import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component'
+import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
@Component({
selector: 'my-account-videos',
itemsPerPage: 5,
totalItems: null
}
+ miniatureDisplayOptions: MiniatureDisplayOptions = {
+ date: true,
+ views: true,
+ by: false,
+ privacyLabel: false,
+ privacyText: true,
+ state: true,
+ blacklistInfo: true
+ }
constructor (
protected router: Router,
})
export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string
- marginContent = false // Disable margin
loadOnInit = false
private videoChannel: VideoChannel
</div>
<div *ngIf="isVideo(result)" class="entry video">
- <my-video-thumbnail [video]="result" [nsfw]="isVideoBlur(result)"></my-video-thumbnail>
-
- <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>
+ <my-video-miniature [video]="result" [user]="user" [displayAsRow]="true"></my-video-miniature>
</div>
</ng-container>
padding-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 {
-
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
+
+ @include avatar($image-size);
- margin: 0 50px 0 40px;
+ margin: 0 ($margin-size + 10) 0 $margin-size;
}
.video-channel-info {
private metaService: MetaService,
private notifier: Notifier,
private searchService: SearchService,
- private authService: AuthService,
- private serverService: ServerService
+ private authService: AuthService
) { }
+ get user () {
+ return this.authService.getUser()
+ }
+
ngOnInit () {
this.subActivatedRoute = this.route.queryParams.subscribe(
queryParams => {
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 {
return d instanceof VideoChannel
}
-<div class="video-miniature">
+<div class="video-miniature" [ngClass]="{ 'display-as-row': displayAsRow }">
<my-video-thumbnail [video]="video" [nsfw]="isVideoBlur"></my-video-thumbnail>
<div class="video-miniature-information">
class="video-miniature-name"
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }"
>
- <span *ngIf="isUnlistedVideo()" class="badge badge-warning" i18n>Unlisted</span>
- <span *ngIf="isPrivateVideo()" class="badge badge-danger" i18n>Private</span>
+ <ng-container *ngIf="displayOptions.privacyLabel">
+ <span *ngIf="isUnlistedVideo()" class="badge badge-warning" i18n>Unlisted</span>
+ <span *ngIf="isPrivateVideo()" class="badge badge-danger" i18n>Private</span>
+ </ng-container>
{{ video.name }}
</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 }}
</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 }}
</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>
.video-miniature {
width: $video-miniature-width;
-
- display: inline-block;
+ display: inline-flex;
+ flex-direction: column;
margin-bottom: 30px;
height: 195px;
vertical-align: top;
.video-miniature-information {
width: 200px;
- margin-top: 2px;
line-height: normal;
.video-miniature-name {
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;
+ }
+ }
}
}
-import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'
+import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'
import { User } from '../users'
import { Video } from './video.model'
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 MiniatureDisplayOptions = {
+ date?: boolean
+ views?: boolean
+ by?: boolean
+ privacyLabel?: boolean
+ privacyText?: boolean
+ state?: boolean
+ blacklistInfo?: boolean
+ nsfw?: boolean
+}
@Component({
selector: 'my-video-miniature',
export class VideoMiniatureComponent implements OnInit {
@Input() user: User
@Input() video: Video
+
@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'
- constructor (private serverService: ServerService) { }
+ constructor (
+ private serverService: ServerService,
+ private i18n: I18n,
+ @Inject(LOCALE_ID) private localeId: string
+ ) { }
get isVideoBlur () {
return this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig())
isPrivateVideo () {
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 ''
+ }
}
@include ellipsis-multiline(1.1em, 2);
transition: color 0.2s;
- font-size: 16px;
font-weight: $font-semibold;
color: var(--mainForegroundColor);
margin-top: 10px;
@media screen and (max-width: 800px) {
flex-direction: column;
height: auto;
- text-align: center;
align-items: center;
}
}