diff options
author | Chocobozzz <me@florianbigard.com> | 2018-08-30 14:58:00 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-08-31 09:19:58 +0200 |
commit | 2d3741d6d92e9bd1f41694c7442a6d1da434e1f2 (patch) | |
tree | 93a1e609e14bc14ca9e77a6661ddc9c0e461d6f3 /client/src/app/videos | |
parent | d9eaee3939bf2e93e5d775d32bce77842201faba (diff) | |
download | PeerTube-2d3741d6d92e9bd1f41694c7442a6d1da434e1f2.tar.gz PeerTube-2d3741d6d92e9bd1f41694c7442a6d1da434e1f2.tar.zst PeerTube-2d3741d6d92e9bd1f41694c7442a6d1da434e1f2.zip |
Videos overview page: first version
Diffstat (limited to 'client/src/app/videos')
6 files changed, 140 insertions, 15 deletions
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 333c9d11b..2c8305777 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -38,7 +38,7 @@ | |||
38 | Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views | 38 | Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views |
39 | </div> | 39 | </div> |
40 | </div> | 40 | </div> |
41 | 41 | ||
42 | <div class="d-flex justify-content-between align-items-sm-end"> | 42 | <div class="d-flex justify-content-between align-items-sm-end"> |
43 | <div class="d-none d-sm-block"> | 43 | <div class="d-none d-sm-block"> |
44 | <div class="video-info-name">{{ video.name }}</div> | 44 | <div class="video-info-name">{{ video.name }}</div> |
@@ -46,7 +46,7 @@ | |||
46 | <div i18n class="video-info-date-views"> | 46 | <div i18n class="video-info-date-views"> |
47 | Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views | 47 | Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views |
48 | </div> | 48 | </div> |
49 | </div> | 49 | </div> |
50 | 50 | ||
51 | <div class="video-actions-rates"> | 51 | <div class="video-actions-rates"> |
52 | <div class="video-actions fullWidth justify-content-end"> | 52 | <div class="video-actions fullWidth justify-content-end"> |
@@ -56,57 +56,57 @@ | |||
56 | > | 56 | > |
57 | <span class="icon icon-like" i18n-title title="Like this video" ></span> | 57 | <span class="icon icon-like" i18n-title title="Like this video" ></span> |
58 | </div> | 58 | </div> |
59 | 59 | ||
60 | <div | 60 | <div |
61 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()" | 61 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()" |
62 | class="action-button action-button-dislike" role="button" [attr.aria-pressed]="userRating === 'dislike'" | 62 | class="action-button action-button-dislike" role="button" [attr.aria-pressed]="userRating === 'dislike'" |
63 | > | 63 | > |
64 | <span class="icon icon-dislike" i18n-title title="Dislike this video"></span> | 64 | <span class="icon icon-dislike" i18n-title title="Dislike this video"></span> |
65 | </div> | 65 | </div> |
66 | 66 | ||
67 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button action-button-support"> | 67 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button action-button-support"> |
68 | <span class="icon icon-support"></span> | 68 | <span class="icon icon-support"></span> |
69 | <span class="icon-text" i18n>Support</span> | 69 | <span class="icon-text" i18n>Support</span> |
70 | </div> | 70 | </div> |
71 | 71 | ||
72 | <div (click)="showShareModal()" class="action-button action-button-share" role="button"> | 72 | <div (click)="showShareModal()" class="action-button action-button-share" role="button"> |
73 | <span class="icon icon-share"></span> | 73 | <span class="icon icon-share"></span> |
74 | <span class="icon-text" i18n>Share</span> | 74 | <span class="icon-text" i18n>Share</span> |
75 | </div> | 75 | </div> |
76 | 76 | ||
77 | <div class="action-more" ngbDropdown placement="top" role="button"> | 77 | <div class="action-more" ngbDropdown placement="top" role="button"> |
78 | <div class="action-button" ngbDropdownToggle role="button"> | 78 | <div class="action-button" ngbDropdownToggle role="button"> |
79 | <span class="icon icon-more"></span> | 79 | <span class="icon icon-more"></span> |
80 | </div> | 80 | </div> |
81 | 81 | ||
82 | <div ngbDropdownMenu> | 82 | <div ngbDropdownMenu> |
83 | <a class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)"> | 83 | <a class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)"> |
84 | <span class="icon icon-download"></span> <ng-container i18n>Download</ng-container> | 84 | <span class="icon icon-download"></span> <ng-container i18n>Download</ng-container> |
85 | </a> | 85 | </a> |
86 | 86 | ||
87 | <a *ngIf="isUserLoggedIn()" class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)"> | 87 | <a *ngIf="isUserLoggedIn()" class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)"> |
88 | <span class="icon icon-alert"></span> <ng-container i18n>Report</ng-container> | 88 | <span class="icon icon-alert"></span> <ng-container i18n>Report</ng-container> |
89 | </a> | 89 | </a> |
90 | 90 | ||
91 | <a *ngIf="isVideoUpdatable()" class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]"> | 91 | <a *ngIf="isVideoUpdatable()" class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]"> |
92 | <span class="icon icon-edit"></span> <ng-container i18n>Update</ng-container> | 92 | <span class="icon icon-edit"></span> <ng-container i18n>Update</ng-container> |
93 | </a> | 93 | </a> |
94 | 94 | ||
95 | <a *ngIf="isVideoBlacklistable()" class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="showBlacklistModal($event)"> | 95 | <a *ngIf="isVideoBlacklistable()" class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="showBlacklistModal($event)"> |
96 | <span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container> | 96 | <span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container> |
97 | </a> | 97 | </a> |
98 | 98 | ||
99 | <a *ngIf="isVideoUnblacklistable()" class="dropdown-item" i18n-title title="Unblacklist this video" href="#" (click)="unblacklistVideo($event)"> | 99 | <a *ngIf="isVideoUnblacklistable()" class="dropdown-item" i18n-title title="Unblacklist this video" href="#" (click)="unblacklistVideo($event)"> |
100 | <span class="icon icon-unblacklist"></span> <ng-container i18n>Unblacklist</ng-container> | 100 | <span class="icon icon-unblacklist"></span> <ng-container i18n>Unblacklist</ng-container> |
101 | </a> | 101 | </a> |
102 | 102 | ||
103 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> | 103 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> |
104 | <span class="icon icon-delete"></span> <ng-container i18n>Delete</ng-container> | 104 | <span class="icon icon-delete"></span> <ng-container i18n>Delete</ng-container> |
105 | </a> | 105 | </a> |
106 | </div> | 106 | </div> |
107 | </div> | 107 | </div> |
108 | </div> | 108 | </div> |
109 | 109 | ||
110 | <div | 110 | <div |
111 | class="video-info-likes-dislikes-bar" | 111 | class="video-info-likes-dislikes-bar" |
112 | *ngIf="video.likes !== 0 || video.dislikes !== 0" | 112 | *ngIf="video.likes !== 0 || video.dislikes !== 0" |
@@ -125,7 +125,7 @@ | |||
125 | <img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" /> | 125 | <img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" /> |
126 | </a> | 126 | </a> |
127 | 127 | ||
128 | <my-subscribe-button [videoChannel]="video.channel" size="small"></my-subscribe-button> | 128 | <my-subscribe-button *ngIf="isUserLoggedIn()" [videoChannel]="video.channel" size="small"></my-subscribe-button> |
129 | </div> | 129 | </div> |
130 | 130 | ||
131 | <div class="video-info-by"> | 131 | <div class="video-info-by"> |
diff --git a/client/src/app/videos/video-list/video-overview.component.html b/client/src/app/videos/video-list/video-overview.component.html new file mode 100644 index 000000000..9282dd59c --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.html | |||
@@ -0,0 +1,35 @@ | |||
1 | <div class="margin-content"> | ||
2 | |||
3 | <div class="no-results" i18n *ngIf="notResults">No results.</div> | ||
4 | |||
5 | <div class="section" *ngFor="let object of overview.categories"> | ||
6 | <div class="section-title" i18n> | ||
7 | <a routerLink="/search" [queryParams]="{ categoryOneOf: [ object.category.id ] }">Category {{ object.category.label }}</a> | ||
8 | </div> | ||
9 | |||
10 | <div> | ||
11 | <my-video-miniature *ngFor="let video of object.videos" [video]="video" [user]="user"></my-video-miniature> | ||
12 | </div> | ||
13 | </div> | ||
14 | |||
15 | <div class="section" *ngFor="let object of overview.tags"> | ||
16 | <div class="section-title" i18n> | ||
17 | <a routerLink="/search" [queryParams]="{ categoryOneOf: [ object.category.id ] }">Tag {{ object.tag }}</a> | ||
18 | </div> | ||
19 | |||
20 | <div> | ||
21 | <my-video-miniature *ngFor="let video of object.videos" [video]="video" [user]="user"></my-video-miniature> | ||
22 | </div> | ||
23 | </div> | ||
24 | |||
25 | <div class="section" *ngFor="let object of overview.channels"> | ||
26 | <div class="section-title" i18n> | ||
27 | <a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]">Channel {{ object.channel.displayName }}</a> | ||
28 | </div> | ||
29 | |||
30 | <div> | ||
31 | <my-video-miniature *ngFor="let video of object.videos" [video]="video" [user]="user"></my-video-miniature> | ||
32 | </div> | ||
33 | </div> | ||
34 | |||
35 | </div> | ||
diff --git a/client/src/app/videos/video-list/video-overview.component.scss b/client/src/app/videos/video-list/video-overview.component.scss new file mode 100644 index 000000000..8d66cf80a --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.scss | |||
@@ -0,0 +1,22 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .section { | ||
5 | padding-top: 10px; | ||
6 | |||
7 | &:first-child { | ||
8 | padding-top: 30px; | ||
9 | } | ||
10 | } | ||
11 | |||
12 | .section-title { | ||
13 | font-size: 17px; | ||
14 | font-weight: $font-semibold; | ||
15 | margin-bottom: 20px; | ||
16 | |||
17 | a { | ||
18 | @include disable-default-a-behaviour; | ||
19 | |||
20 | color: #000; | ||
21 | } | ||
22 | } \ No newline at end of file | ||
diff --git a/client/src/app/videos/video-list/video-overview.component.ts b/client/src/app/videos/video-list/video-overview.component.ts new file mode 100644 index 000000000..c758e115c --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.ts | |||
@@ -0,0 +1,56 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { AuthService } from '@app/core' | ||
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | import { VideosOverview } from '@app/shared/overview/videos-overview.model' | ||
6 | import { OverviewService } from '@app/shared/overview' | ||
7 | import { Video } from '@app/shared/video/video.model' | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-video-overview', | ||
11 | templateUrl: './video-overview.component.html', | ||
12 | styleUrls: [ './video-overview.component.scss' ] | ||
13 | }) | ||
14 | export class VideoOverviewComponent implements OnInit { | ||
15 | overview: VideosOverview = { | ||
16 | categories: [], | ||
17 | channels: [], | ||
18 | tags: [] | ||
19 | } | ||
20 | notResults = false | ||
21 | |||
22 | constructor ( | ||
23 | private i18n: I18n, | ||
24 | private notificationsService: NotificationsService, | ||
25 | private authService: AuthService, | ||
26 | private overviewService: OverviewService | ||
27 | ) { } | ||
28 | |||
29 | get user () { | ||
30 | return this.authService.getUser() | ||
31 | } | ||
32 | |||
33 | ngOnInit () { | ||
34 | this.overviewService.getVideosOverview() | ||
35 | .subscribe( | ||
36 | overview => { | ||
37 | this.overview = overview | ||
38 | |||
39 | if ( | ||
40 | this.overview.categories.length === 0 && | ||
41 | this.overview.channels.length === 0 && | ||
42 | this.overview.tags.length === 0 | ||
43 | ) this.notResults = true | ||
44 | }, | ||
45 | |||
46 | err => { | ||
47 | console.log(err) | ||
48 | this.notificationsService.error('Error', err.text) | ||
49 | } | ||
50 | ) | ||
51 | } | ||
52 | |||
53 | buildVideoChannelBy (object: { videos: Video[] }) { | ||
54 | return object.videos[0].byVideoChannel | ||
55 | } | ||
56 | } | ||
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 18ed52570..58988ffd1 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts | |||
@@ -6,6 +6,7 @@ import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.c | |||
6 | import { VideoTrendingComponent } from './video-list/video-trending.component' | 6 | import { VideoTrendingComponent } from './video-list/video-trending.component' |
7 | import { VideosComponent } from './videos.component' | 7 | import { VideosComponent } from './videos.component' |
8 | import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' | 8 | import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' |
9 | import { VideoOverviewComponent } from '@app/videos/video-list/video-overview.component' | ||
9 | 10 | ||
10 | const videosRoutes: Routes = [ | 11 | const videosRoutes: Routes = [ |
11 | { | 12 | { |
@@ -14,6 +15,15 @@ const videosRoutes: Routes = [ | |||
14 | canActivateChild: [ MetaGuard ], | 15 | canActivateChild: [ MetaGuard ], |
15 | children: [ | 16 | children: [ |
16 | { | 17 | { |
18 | path: 'overview', | ||
19 | component: VideoOverviewComponent, | ||
20 | data: { | ||
21 | meta: { | ||
22 | title: 'Videos overview' | ||
23 | } | ||
24 | } | ||
25 | }, | ||
26 | { | ||
17 | path: 'trending', | 27 | path: 'trending', |
18 | component: VideoTrendingComponent, | 28 | component: VideoTrendingComponent, |
19 | data: { | 29 | data: { |
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts index 3c3877273..5cf1e944f 100644 --- a/client/src/app/videos/videos.module.ts +++ b/client/src/app/videos/videos.module.ts | |||
@@ -6,6 +6,7 @@ import { VideoTrendingComponent } from './video-list/video-trending.component' | |||
6 | import { VideosRoutingModule } from './videos-routing.module' | 6 | import { VideosRoutingModule } from './videos-routing.module' |
7 | import { VideosComponent } from './videos.component' | 7 | import { VideosComponent } from './videos.component' |
8 | import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' | 8 | import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' |
9 | import { VideoOverviewComponent } from '@app/videos/video-list/video-overview.component' | ||
9 | 10 | ||
10 | @NgModule({ | 11 | @NgModule({ |
11 | imports: [ | 12 | imports: [ |
@@ -19,7 +20,8 @@ import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-us | |||
19 | VideoTrendingComponent, | 20 | VideoTrendingComponent, |
20 | VideoRecentlyAddedComponent, | 21 | VideoRecentlyAddedComponent, |
21 | VideoLocalComponent, | 22 | VideoLocalComponent, |
22 | VideoUserSubscriptionsComponent | 23 | VideoUserSubscriptionsComponent, |
24 | VideoOverviewComponent | ||
23 | ], | 25 | ], |
24 | 26 | ||
25 | exports: [ | 27 | exports: [ |