aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/package.json2
-rw-r--r--client/src/app/menu/menu.component.html4
-rw-r--r--client/src/app/shared/misc/from-now.pipe.ts37
-rw-r--r--client/src/app/shared/misc/number-formatter.pipe.ts19
-rw-r--r--client/src/app/shared/shared.module.ts26
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.ts2
-rw-r--r--client/src/app/videos/video-list/index.ts3
-rw-r--r--client/src/app/videos/video-list/my-videos.component.ts2
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.html18
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.scss14
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.ts28
-rw-r--r--client/src/app/videos/video-list/shared/index.ts1
-rw-r--r--client/src/app/videos/video-list/shared/video-miniature.component.html13
-rw-r--r--client/src/app/videos/video-list/shared/video-miniature.component.scss66
-rw-r--r--client/src/app/videos/video-list/shared/video-sort.component.html5
-rw-r--r--client/src/app/videos/video-list/shared/video-sort.component.ts39
-rw-r--r--client/src/app/videos/video-list/video-list.component.ts94
-rw-r--r--client/src/app/videos/video-list/video-recently-added.component.ts33
-rw-r--r--client/src/app/videos/video-list/video-trending.component.ts33
-rw-r--r--client/src/app/videos/videos-routing.module.ts26
-rw-r--r--client/src/app/videos/videos.module.ts10
-rw-r--r--client/src/sass/application.scss26
-rw-r--r--client/yarn.lock8
23 files changed, 213 insertions, 296 deletions
diff --git a/client/package.json b/client/package.json
index c551c995a..310860fec 100644
--- a/client/package.json
+++ b/client/package.json
@@ -43,7 +43,6 @@
43 "@types/webpack": "^3.0.0", 43 "@types/webpack": "^3.0.0",
44 "@types/webtorrent": "^0.98.4", 44 "@types/webtorrent": "^0.98.4",
45 "add-asset-html-webpack-plugin": "^2.0.1", 45 "add-asset-html-webpack-plugin": "^2.0.1",
46 "angular-pipes": "^6.0.0",
47 "angular2-notifications": "^0.7.7", 46 "angular2-notifications": "^0.7.7",
48 "angular2-template-loader": "^0.6.0", 47 "angular2-template-loader": "^0.6.0",
49 "assets-webpack-plugin": "^3.4.0", 48 "assets-webpack-plugin": "^3.4.0",
@@ -72,6 +71,7 @@
72 "ngc-webpack": "3.2.2", 71 "ngc-webpack": "3.2.2",
73 "ngx-bootstrap": "2.0.0-beta.9", 72 "ngx-bootstrap": "2.0.0-beta.9",
74 "ngx-chips": "1.5.3", 73 "ngx-chips": "1.5.3",
74 "ngx-pipes": "^2.0.5",
75 "node-sass": "^4.1.1", 75 "node-sass": "^4.1.1",
76 "normalize.css": "^7.0.0", 76 "normalize.css": "^7.0.0",
77 "optimize-js-plugin": "0.0.4", 77 "optimize-js-plugin": "0.0.4",
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index fb31c0734..21f8d8ba4 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -26,12 +26,12 @@
26 <div class="panel-block"> 26 <div class="panel-block">
27 <div class="block-title">Videos</div> 27 <div class="block-title">Videos</div>
28 28
29 <a routerLink="/videos/list" routerLinkActive="active"> 29 <a routerLink="/videos/trending" routerLinkActive="active">
30 <span class="icon icon-videos-trending"></span> 30 <span class="icon icon-videos-trending"></span>
31 Trending 31 Trending
32 </a> 32 </a>
33 33
34 <a routerLink="/videos/list" routerLinkActive="active"> 34 <a routerLink="/videos/recently-added" routerLinkActive="active">
35 <span class="icon icon-videos-recently-added"></span> 35 <span class="icon icon-videos-recently-added"></span>
36 Recently added 36 Recently added
37 </a> 37 </a>
diff --git a/client/src/app/shared/misc/from-now.pipe.ts b/client/src/app/shared/misc/from-now.pipe.ts
new file mode 100644
index 000000000..25e5d6a85
--- /dev/null
+++ b/client/src/app/shared/misc/from-now.pipe.ts
@@ -0,0 +1,37 @@
1import { Pipe, PipeTransform } from '@angular/core'
2
3// Thanks: https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
4
5@Pipe({name: 'fromNow'})
6export class FromNowPipe implements PipeTransform {
7
8 transform (value: number) {
9 const seconds = Math.floor((Date.now() - value) / 1000)
10
11 let interval = Math.floor(seconds / 31536000)
12 if (interval > 1) {
13 return interval + ' years ago'
14 }
15
16 interval = Math.floor(seconds / 2592000)
17 if (interval > 1) return interval + ' months ago'
18 if (interval === 1) return interval + ' month ago'
19
20 interval = Math.floor(seconds / 604800)
21 if (interval > 1) return interval + ' weeks ago'
22 if (interval === 1) return interval + ' week ago'
23
24 interval = Math.floor(seconds / 86400)
25 if (interval > 1) return interval + ' days ago'
26 if (interval === 1) return interval + ' day ago'
27
28 interval = Math.floor(seconds / 3600)
29 if (interval > 1) return interval + ' hours ago'
30 if (interval === 1) return interval + ' hour ago'
31
32 interval = Math.floor(seconds / 60)
33 if (interval >= 1) return interval + ' min ago'
34
35 return Math.floor(seconds) + ' sec ago'
36 }
37}
diff --git a/client/src/app/shared/misc/number-formatter.pipe.ts b/client/src/app/shared/misc/number-formatter.pipe.ts
new file mode 100644
index 000000000..2491fb1d6
--- /dev/null
+++ b/client/src/app/shared/misc/number-formatter.pipe.ts
@@ -0,0 +1,19 @@
1import { Pipe, PipeTransform } from '@angular/core'
2
3// Thanks: https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
4
5@Pipe({name: 'numberFormatter'})
6export class NumberFormatterPipe implements PipeTransform {
7 private dictionary: Array<{max: number, type: string}> = [
8 { max: 1000, type: '' },
9 { max: 1000000, type: 'K' },
10 { max: 1000000000, type: 'M' }
11 ]
12
13 transform (value: number) {
14 const format = this.dictionary.find(d => value < d.max) || this.dictionary[this.dictionary.length - 1]
15 const calc = Math.floor(value / (format.max / 1000))
16
17 return `${calc}${format.type}`
18 }
19}
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 456ce851e..c7ea6e603 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -1,25 +1,26 @@
1import { NgModule } from '@angular/core'
2import { HttpClientModule } from '@angular/common/http'
3import { CommonModule } from '@angular/common' 1import { CommonModule } from '@angular/common'
2import { HttpClientModule } from '@angular/common/http'
3import { NgModule } from '@angular/core'
4import { FormsModule, ReactiveFormsModule } from '@angular/forms' 4import { FormsModule, ReactiveFormsModule } from '@angular/forms'
5import { RouterModule } from '@angular/router' 5import { RouterModule } from '@angular/router'
6 6
7import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'
8import { KeysPipe } from 'angular-pipes/src/object/keys.pipe'
9import { BsDropdownModule } from 'ngx-bootstrap/dropdown' 7import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
10import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
11import { PaginationModule } from 'ngx-bootstrap/pagination'
12import { ModalModule } from 'ngx-bootstrap/modal' 8import { ModalModule } from 'ngx-bootstrap/modal'
13import { DataTableModule } from 'primeng/components/datatable/datatable' 9import { PaginationModule } from 'ngx-bootstrap/pagination'
10import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
11import { BytesPipe, KeysPipe } from 'ngx-pipes'
14import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared' 12import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
13import { DataTableModule } from 'primeng/components/datatable/datatable'
15 14
16import { AUTH_INTERCEPTOR_PROVIDER } from './auth' 15import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
16import { LoaderComponent } from './misc/loader.component'
17import { RestExtractor, RestService } from './rest' 17import { RestExtractor, RestService } from './rest'
18import { SearchComponent, SearchService } from './search' 18import { SearchComponent, SearchService } from './search'
19import { UserService } from './users' 19import { UserService } from './users'
20import { VideoAbuseService } from './video-abuse' 20import { VideoAbuseService } from './video-abuse'
21import { VideoBlacklistService } from './video-blacklist' 21import { VideoBlacklistService } from './video-blacklist'
22import { LoaderComponent } from './misc/loader.component' 22import { NumberFormatterPipe } from './misc/number-formatter.pipe'
23import { FromNowPipe } from './misc/from-now.pipe'
23 24
24@NgModule({ 25@NgModule({
25 imports: [ 26 imports: [
@@ -42,7 +43,9 @@ import { LoaderComponent } from './misc/loader.component'
42 BytesPipe, 43 BytesPipe,
43 KeysPipe, 44 KeysPipe,
44 SearchComponent, 45 SearchComponent,
45 LoaderComponent 46 LoaderComponent,
47 NumberFormatterPipe,
48 FromNowPipe
46 ], 49 ],
47 50
48 exports: [ 51 exports: [
@@ -62,7 +65,10 @@ import { LoaderComponent } from './misc/loader.component'
62 KeysPipe, 65 KeysPipe,
63 66
64 SearchComponent, 67 SearchComponent,
65 LoaderComponent 68 LoaderComponent,
69
70 NumberFormatterPipe,
71 FromNowPipe
66 ], 72 ],
67 73
68 providers: [ 74 providers: [
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts
index 1704cf486..76bfbb515 100644
--- a/client/src/app/videos/+video-edit/video-add.component.ts
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -184,7 +184,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
184 this.notificationsService.success('Success', 'Video uploaded.') 184 this.notificationsService.success('Success', 'Video uploaded.')
185 185
186 // Display all the videos once it's finished 186 // Display all the videos once it's finished
187 this.router.navigate([ '/videos/list' ]) 187 this.router.navigate([ '/videos/trending' ])
188 } 188 }
189 }, 189 },
190 190
diff --git a/client/src/app/videos/video-list/index.ts b/client/src/app/videos/video-list/index.ts
index ed2bb1657..a5a60364a 100644
--- a/client/src/app/videos/video-list/index.ts
+++ b/client/src/app/videos/video-list/index.ts
@@ -1,3 +1,4 @@
1export * from './my-videos.component' 1export * from './my-videos.component'
2export * from './video-list.component' 2export * from './video-recently-added.component'
3export * from './video-trending.component'
3export * from './shared' 4export * from './shared'
diff --git a/client/src/app/videos/video-list/my-videos.component.ts b/client/src/app/videos/video-list/my-videos.component.ts
index 648741a40..146db8262 100644
--- a/client/src/app/videos/video-list/my-videos.component.ts
+++ b/client/src/app/videos/video-list/my-videos.component.ts
@@ -27,7 +27,7 @@ export class MyVideosComponent extends AbstractVideoList implements OnInit, OnDe
27 } 27 }
28 28
29 ngOnDestroy () { 29 ngOnDestroy () {
30 this.subActivatedRoute.unsubscribe() 30 super.ngOnDestroy()
31 } 31 }
32 32
33 getVideosObservable () { 33 getVideosObservable () {
diff --git a/client/src/app/videos/video-list/shared/abstract-video-list.html b/client/src/app/videos/video-list/shared/abstract-video-list.html
index 680fba3f5..ab5530e68 100644
--- a/client/src/app/videos/video-list/shared/abstract-video-list.html
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.html
@@ -1,20 +1,8 @@
1<div class="row"> 1<div class="title-page">
2 <div class="content-padding"> 2 {{ titlePage }}
3 <div class="videos-info">
4 <div class="col-md-9 col-xs-5 videos-total-results">
5 <span *ngIf="pagination.totalItems !== null">{{ pagination.totalItems }} videos</span>
6
7 <my-loader [loading]="loading | async"></my-loader>
8 </div>
9
10 <my-video-sort class="col-md-3 col-xs-7" [currentSort]="sort" (sort)="onSort($event)"></my-video-sort>
11 </div>
12 </div>
13</div> 3</div>
14 4
15<div class="content-padding videos-miniatures"> 5<div class="videos-miniatures">
16 <div class="no-video" *ngIf="isThereNoVideo()">There is no video.</div>
17
18 <my-video-miniature 6 <my-video-miniature
19 class="ng-animate" 7 class="ng-animate"
20 *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort" 8 *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort"
diff --git a/client/src/app/videos/video-list/shared/abstract-video-list.scss b/client/src/app/videos/video-list/shared/abstract-video-list.scss
index 4b4409602..de174802b 100644
--- a/client/src/app/videos/video-list/shared/abstract-video-list.scss
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.scss
@@ -17,20 +17,6 @@
17 } 17 }
18} 18}
19 19
20.videos-miniatures {
21 text-align: center;
22 padding-top: 0;
23
24 my-video-miniature {
25 text-align: left;
26 }
27
28 .no-video {
29 margin-top: 50px;
30 text-align: center;
31 }
32}
33
34pagination { 20pagination {
35 display: block; 21 display: block;
36 text-align: center; 22 text-align: center;
diff --git a/client/src/app/videos/video-list/shared/abstract-video-list.ts b/client/src/app/videos/video-list/shared/abstract-video-list.ts
index 87d5bc48a..262ea4e21 100644
--- a/client/src/app/videos/video-list/shared/abstract-video-list.ts
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.ts
@@ -1,25 +1,19 @@
1import { OnDestroy, OnInit } from '@angular/core' 1import { OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { Subscription } from 'rxjs/Subscription'
4import { BehaviorSubject } from 'rxjs/BehaviorSubject'
5import { Observable } from 'rxjs/Observable'
6 3
7import { NotificationsService } from 'angular2-notifications' 4import { NotificationsService } from 'angular2-notifications'
5import { Observable } from 'rxjs/Observable'
6import { Subscription } from 'rxjs/Subscription'
8 7
9import { 8import { SortField, Video, VideoPagination } from '../../shared'
10 SortField,
11 Video,
12 VideoPagination
13} from '../../shared'
14 9
15export abstract class AbstractVideoList implements OnInit, OnDestroy { 10export abstract class AbstractVideoList implements OnInit, OnDestroy {
16 loading: BehaviorSubject<boolean> = new BehaviorSubject(false)
17 pagination: VideoPagination = { 11 pagination: VideoPagination = {
18 currentPage: 1, 12 currentPage: 1,
19 itemsPerPage: 25, 13 itemsPerPage: 25,
20 totalItems: null 14 totalItems: null
21 } 15 }
22 sort: SortField 16 sort: SortField = '-createdAt'
23 videos: Video[] = [] 17 videos: Video[] = []
24 18
25 protected notificationsService: NotificationsService 19 protected notificationsService: NotificationsService
@@ -28,6 +22,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
28 22
29 protected subActivatedRoute: Subscription 23 protected subActivatedRoute: Subscription
30 24
25 abstract titlePage: string
31 abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}> 26 abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
32 27
33 ngOnInit () { 28 ngOnInit () {
@@ -44,7 +39,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
44 } 39 }
45 40
46 getVideos () { 41 getVideos () {
47 this.loading.next(true)
48 this.videos = [] 42 this.videos = []
49 43
50 const observable = this.getVideosObservable() 44 const observable = this.getVideosObservable()
@@ -53,17 +47,11 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
53 ({ videos, totalVideos }) => { 47 ({ videos, totalVideos }) => {
54 this.videos = videos 48 this.videos = videos
55 this.pagination.totalItems = totalVideos 49 this.pagination.totalItems = totalVideos
56
57 this.loading.next(false)
58 }, 50 },
59 error => this.notificationsService.error('Error', error.text) 51 error => this.notificationsService.error('Error', error.text)
60 ) 52 )
61 } 53 }
62 54
63 isThereNoVideo () {
64 return !this.loading.getValue() && this.videos.length === 0
65 }
66
67 onPageChanged (event: { page: number }) { 55 onPageChanged (event: { page: number }) {
68 // Be sure the current page is set 56 // Be sure the current page is set
69 this.pagination.currentPage = event.page 57 this.pagination.currentPage = event.page
@@ -71,12 +59,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
71 this.navigateToNewParams() 59 this.navigateToNewParams()
72 } 60 }
73 61
74 onSort (sort: SortField) {
75 this.sort = sort
76
77 this.navigateToNewParams()
78 }
79
80 protected buildRouteParams () { 62 protected buildRouteParams () {
81 // There is always a sort and a current page 63 // There is always a sort and a current page
82 const params = { 64 const params = {
diff --git a/client/src/app/videos/video-list/shared/index.ts b/client/src/app/videos/video-list/shared/index.ts
index d8f73bcda..170ca4832 100644
--- a/client/src/app/videos/video-list/shared/index.ts
+++ b/client/src/app/videos/video-list/shared/index.ts
@@ -1,3 +1,2 @@
1export * from './abstract-video-list' 1export * from './abstract-video-list'
2export * from './video-miniature.component' 2export * from './video-miniature.component'
3export * from './video-sort.component'
diff --git a/client/src/app/videos/video-list/shared/video-miniature.component.html b/client/src/app/videos/video-list/shared/video-miniature.component.html
index 6bbd29666..aea85b6c6 100644
--- a/client/src/app/videos/video-list/shared/video-miniature.component.html
+++ b/client/src/app/videos/video-list/shared/video-miniature.component.html
@@ -6,8 +6,7 @@
6 <img [attr.src]="video.thumbnailUrl" alt="video thumbnail" [ngClass]="{ 'blur-filter': isVideoNSFWForThisUser() }" /> 6 <img [attr.src]="video.thumbnailUrl" alt="video thumbnail" [ngClass]="{ 'blur-filter': isVideoNSFWForThisUser() }" />
7 7
8 <div class="video-miniature-thumbnail-overlay"> 8 <div class="video-miniature-thumbnail-overlay">
9 <span class="video-miniature-thumbnail-overlay-views">{{ video.views }} views</span> 9 {{ video.durationLabel }}
10 <span class="video-miniature-thumbnail-overlay-duration">{{ video.durationLabel }}</span>
11 </div> 10 </div>
12 </a> 11 </a>
13 12
@@ -21,13 +20,7 @@
21 </a> 20 </a>
22 </span> 21 </span>
23 22
24 <div class="video-miniature-tags"> 23 <span class="video-miniature-created-at-views">{{ video.createdAt | fromNow }} - {{ video.views | numberFormatter }} views</span>
25 <span *ngFor="let tag of video.tags" class="video-miniature-tag"> 24 <span class="video-miniature-account">{{ video.by }}</span>
26 <a [routerLink]="['/videos/list', { field: 'tags', search: tag, sort: currentSort }]" class="label label-primary">{{ tag }}</a>
27 </span>
28 </div>
29
30 <a [routerLink]="['/videos/list', { field: 'account', search: video.account, sort: currentSort }]" class="video-miniature-account">{{ video.by }}</a>
31 <span class="video-miniature-created-at">{{ video.createdAt | date:'short' }}</span>
32 </div> 25 </div>
33</div> 26</div>
diff --git a/client/src/app/videos/video-list/shared/video-miniature.component.scss b/client/src/app/videos/video-list/shared/video-miniature.component.scss
index 507ace098..ed15864d9 100644
--- a/client/src/app/videos/video-list/shared/video-miniature.component.scss
+++ b/client/src/app/videos/video-list/shared/video-miniature.component.scss
@@ -1,14 +1,14 @@
1.video-miniature { 1.video-miniature {
2 margin: 15px 10px;
3 display: inline-block; 2 display: inline-block;
4 position: relative; 3 padding-right: 15px;
5 height: 190px; 4 margin-bottom: 30px;
5 height: 175px;
6 vertical-align: top; 6 vertical-align: top;
7 7
8 .video-miniature-thumbnail { 8 .video-miniature-thumbnail {
9 display: inline-block; 9 display: inline-block;
10 position: relative; 10 position: relative;
11 border-radius: 3px; 11 border-radius: 4px;
12 overflow: hidden; 12 overflow: hidden;
13 13
14 &:hover { 14 &:hover {
@@ -22,38 +22,33 @@
22 22
23 .video-miniature-thumbnail-overlay { 23 .video-miniature-thumbnail-overlay {
24 position: absolute; 24 position: absolute;
25 right: 0px; 25 right: 5px;
26 bottom: 0px; 26 bottom: 5px;
27 display: inline-block; 27 display: inline-block;
28 background-color: rgba(0, 0, 0, 0.7); 28 background-color: rgba(0, 0, 0, 0.7);
29 color: #fff; 29 color: #fff;
30 padding: 3px 5px; 30 font-size: 12px;
31 font-size: 11px; 31 font-weight: $font-bold;
32 font-weight: bold; 32 border-radius: 3px;
33 width: 100%; 33 padding: 0 5px;
34
35 .video-miniature-thumbnail-overlay-views {
36
37 }
38
39 .video-miniature-thumbnail-overlay-duration {
40 float: right;
41 }
42 } 34 }
43 } 35 }
44 36
45 .video-miniature-information { 37 .video-miniature-information {
46 width: 200px; 38 width: 200px;
39 margin-top: 2px;
40 line-height: normal;
47 41
48 .video-miniature-name { 42 .video-miniature-name {
49 height: 23px;
50 display: block; 43 display: block;
51 overflow: hidden; 44 overflow: hidden;
52 text-overflow: ellipsis; 45 text-overflow: ellipsis;
53 white-space: nowrap; 46 white-space: nowrap;
54 font-weight: bold; 47 font-weight: bold;
55 transition: color 0.2s; 48 transition: color 0.2s;
56 font-size: 15px; 49 font-size: 16px;
50 font-weight: $font-semibold;
51 color: #000;
57 52
58 &:hover { 53 &:hover {
59 text-decoration: none; 54 text-decoration: none;
@@ -63,39 +58,16 @@
63 filter: blur(3px); 58 filter: blur(3px);
64 padding-left: 4px; 59 padding-left: 4px;
65 } 60 }
66
67 .video-miniature-tags {
68 // Fix for chrome when tags are long
69 width: 201px;
70
71 .video-miniature-tag {
72 font-size: 13px;
73 cursor: pointer;
74 position: relative;
75 top: -2px;
76
77 .label {
78 transition: background-color 0.2s;
79 }
80 }
81 }
82 } 61 }
83 62
84 .video-miniature-account, .video-miniature-created-at { 63 .video-miniature-created-at-views {
85 display: block; 64 display: block;
86 margin-left: 1px; 65 font-size: 13px;
87 font-size: 11px;
88 color: $video-miniature-other-infos;
89 opacity: 0.9;
90 } 66 }
91 67
92 .video-miniature-account { 68 .video-miniature-account {
93 transition: color 0.2s; 69 font-size: 12px;
94 70 color: #585858;
95 &:hover {
96 color: #23527c;
97 text-decoration: none;
98 }
99 } 71 }
100 } 72 }
101} 73}
diff --git a/client/src/app/videos/video-list/shared/video-sort.component.html b/client/src/app/videos/video-list/shared/video-sort.component.html
deleted file mode 100644
index 3bece0b22..000000000
--- a/client/src/app/videos/video-list/shared/video-sort.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
1<select class="form-control input-sm" [(ngModel)]="currentSort" (ngModelChange)="onSortChange()">
2 <option *ngFor="let choice of choiceKeys" [value]="choice">
3 {{ getStringChoice(choice) }}
4 </option>
5</select>
diff --git a/client/src/app/videos/video-list/shared/video-sort.component.ts b/client/src/app/videos/video-list/shared/video-sort.component.ts
deleted file mode 100644
index 8aa89d32b..000000000
--- a/client/src/app/videos/video-list/shared/video-sort.component.ts
+++ /dev/null
@@ -1,39 +0,0 @@
1import { Component, EventEmitter, Input, Output } from '@angular/core'
2
3import { SortField } from '../../shared'
4
5@Component({
6 selector: 'my-video-sort',
7 templateUrl: './video-sort.component.html'
8})
9
10export class VideoSortComponent {
11 @Output() sort = new EventEmitter<any>()
12
13 @Input() currentSort: SortField
14
15 sortChoices: { [ P in SortField ]: string } = {
16 'name': 'Name - Asc',
17 '-name': 'Name - Desc',
18 'duration': 'Duration - Asc',
19 '-duration': 'Duration - Desc',
20 'createdAt': 'Created Date - Asc',
21 '-createdAt': 'Created Date - Desc',
22 'views': 'Views - Asc',
23 '-views': 'Views - Desc',
24 'likes': 'Likes - Asc',
25 '-likes': 'Likes - Desc'
26 }
27
28 get choiceKeys () {
29 return Object.keys(this.sortChoices)
30 }
31
32 getStringChoice (choiceKey: SortField) {
33 return this.sortChoices[choiceKey]
34 }
35
36 onSortChange () {
37 this.sort.emit(this.currentSort)
38 }
39}
diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts
deleted file mode 100644
index 784162679..000000000
--- a/client/src/app/videos/video-list/video-list.component.ts
+++ /dev/null
@@ -1,94 +0,0 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { Subscription } from 'rxjs/Subscription'
4
5import { NotificationsService } from 'angular2-notifications'
6
7import { VideoService } from '../shared'
8import { Search, SearchField, SearchService } from '../../shared'
9import { AbstractVideoList } from './shared'
10
11@Component({
12 selector: 'my-videos-list',
13 styleUrls: [ './shared/abstract-video-list.scss' ],
14 templateUrl: './shared/abstract-video-list.html'
15})
16export class VideoListComponent extends AbstractVideoList implements OnInit, OnDestroy {
17 private search: Search
18 private subSearch: Subscription
19
20 constructor (
21 protected router: Router,
22 protected route: ActivatedRoute,
23 protected notificationsService: NotificationsService,
24 private videoService: VideoService,
25 private searchService: SearchService
26 ) {
27 super()
28 }
29
30 ngOnInit () {
31 // Subscribe to route changes
32 this.subActivatedRoute = this.route.params.subscribe(routeParams => {
33 this.loadRouteParams(routeParams)
34
35 // Update the search service component
36 this.searchService.updateSearch.next(this.search)
37 this.getVideos()
38 })
39
40 // Subscribe to search changes
41 this.subSearch = this.searchService.searchUpdated.subscribe(search => {
42 this.search = search
43 // Reset pagination
44 this.pagination.currentPage = 1
45
46 this.navigateToNewParams()
47 })
48 }
49
50 ngOnDestroy () {
51 super.ngOnDestroy()
52
53 this.subSearch.unsubscribe()
54 }
55
56 getVideosObservable () {
57 let observable = null
58 if (this.search.value) {
59 observable = this.videoService.searchVideos(this.search, this.pagination, this.sort)
60 } else {
61 observable = this.videoService.getVideos(this.pagination, this.sort)
62 }
63
64 return observable
65 }
66
67 protected buildRouteParams () {
68 const params = super.buildRouteParams()
69
70 // Maybe there is a search
71 if (this.search.value) {
72 params['field'] = this.search.field
73 params['search'] = this.search.value
74 }
75
76 return params
77 }
78
79 protected loadRouteParams (routeParams: { [ key: string ]: any }) {
80 super.loadRouteParams(routeParams)
81
82 if (routeParams['search'] !== undefined) {
83 this.search = {
84 value: routeParams['search'],
85 field: routeParams['field'] as SearchField
86 }
87 } else {
88 this.search = {
89 value: '',
90 field: 'name'
91 }
92 }
93 }
94}
diff --git a/client/src/app/videos/video-list/video-recently-added.component.ts b/client/src/app/videos/video-list/video-recently-added.component.ts
new file mode 100644
index 000000000..dbba264df
--- /dev/null
+++ b/client/src/app/videos/video-list/video-recently-added.component.ts
@@ -0,0 +1,33 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications'
4import { VideoService } from '../shared'
5import { AbstractVideoList } from './shared'
6
7@Component({
8 selector: 'my-videos-recently-added',
9 styleUrls: [ './shared/abstract-video-list.scss' ],
10 templateUrl: './shared/abstract-video-list.html'
11})
12export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
13 titlePage = 'Recently added'
14
15 constructor (protected router: Router,
16 protected route: ActivatedRoute,
17 protected notificationsService: NotificationsService,
18 private videoService: VideoService) {
19 super()
20 }
21
22 ngOnInit () {
23 super.ngOnInit()
24 }
25
26 ngOnDestroy () {
27 super.ngOnDestroy()
28 }
29
30 getVideosObservable () {
31 return this.videoService.getVideos(this.pagination, this.sort)
32 }
33}
diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts
new file mode 100644
index 000000000..b97966c12
--- /dev/null
+++ b/client/src/app/videos/video-list/video-trending.component.ts
@@ -0,0 +1,33 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications'
4import { VideoService } from '../shared'
5import { AbstractVideoList } from './shared'
6
7@Component({
8 selector: 'my-videos-trending',
9 styleUrls: [ './shared/abstract-video-list.scss' ],
10 templateUrl: './shared/abstract-video-list.html'
11})
12export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy {
13 titlePage = 'Trending'
14
15 constructor (protected router: Router,
16 protected route: ActivatedRoute,
17 protected notificationsService: NotificationsService,
18 private videoService: VideoService) {
19 super()
20 }
21
22 ngOnInit () {
23 super.ngOnInit()
24 }
25
26 ngOnDestroy () {
27 super.ngOnDestroy()
28 }
29
30 getVideosObservable () {
31 return this.videoService.getVideos(this.pagination, this.sort)
32 }
33}
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts
index 3ca3e5486..1f894df7a 100644
--- a/client/src/app/videos/videos-routing.module.ts
+++ b/client/src/app/videos/videos-routing.module.ts
@@ -1,9 +1,9 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router' 2import { RouterModule, Routes } from '@angular/router'
3
4import { MetaGuard } from '@ngx-meta/core' 3import { MetaGuard } from '@ngx-meta/core'
5 4import { MyVideosComponent } from './video-list'
6import { VideoListComponent, MyVideosComponent } from './video-list' 5import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component'
6import { VideoTrendingComponent } from './video-list/video-trending.component'
7import { VideosComponent } from './videos.component' 7import { VideosComponent } from './videos.component'
8 8
9const videosRoutes: Routes = [ 9const videosRoutes: Routes = [
@@ -13,6 +13,11 @@ const videosRoutes: Routes = [
13 canActivateChild: [ MetaGuard ], 13 canActivateChild: [ MetaGuard ],
14 children: [ 14 children: [
15 { 15 {
16 path: 'list',
17 pathMatch: 'full',
18 redirectTo: 'recently-added'
19 },
20 {
16 path: 'mine', 21 path: 'mine',
17 component: MyVideosComponent, 22 component: MyVideosComponent,
18 data: { 23 data: {
@@ -22,11 +27,20 @@ const videosRoutes: Routes = [
22 } 27 }
23 }, 28 },
24 { 29 {
25 path: 'list', 30 path: 'trending',
26 component: VideoListComponent, 31 component: VideoTrendingComponent,
32 data: {
33 meta: {
34 title: 'Trending videos'
35 }
36 }
37 },
38 {
39 path: 'recently-added',
40 component: VideoRecentlyAddedComponent,
27 data: { 41 data: {
28 meta: { 42 meta: {
29 title: 'Videos list' 43 title: 'Recently added videos'
30 } 44 }
31 } 45 }
32 }, 46 },
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts
index 4f3054c3a..93193000c 100644
--- a/client/src/app/videos/videos.module.ts
+++ b/client/src/app/videos/videos.module.ts
@@ -1,7 +1,9 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { SharedModule } from '../shared' 2import { SharedModule } from '../shared'
3import { VideoService } from './shared' 3import { VideoService } from './shared'
4import { MyVideosComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list' 4import { MyVideosComponent, VideoMiniatureComponent } from './video-list'
5import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component'
6import { VideoTrendingComponent } from './video-list/video-trending.component'
5import { VideosRoutingModule } from './videos-routing.module' 7import { VideosRoutingModule } from './videos-routing.module'
6import { VideosComponent } from './videos.component' 8import { VideosComponent } from './videos.component'
7 9
@@ -14,10 +16,10 @@ import { VideosComponent } from './videos.component'
14 declarations: [ 16 declarations: [
15 VideosComponent, 17 VideosComponent,
16 18
17 VideoListComponent, 19 VideoTrendingComponent,
20 VideoRecentlyAddedComponent,
18 MyVideosComponent, 21 MyVideosComponent,
19 VideoMiniatureComponent, 22 VideoMiniatureComponent
20 VideoSortComponent
21 ], 23 ],
22 24
23 exports: [ 25 exports: [
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index 58f07612b..fc61a22da 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -33,24 +33,14 @@ input.readonly {
33} 33}
34 34
35.main-col { 35.main-col {
36 .content-padding { 36 padding: 30px;
37 padding: 15px 30px; 37
38 38 .title-page {
39 @media screen and (max-width: 800px) { 39 font-size: 16px;
40 padding: 15px 10px; 40 font-weight: $font-bold;
41 } 41 display: inline-block;
42 42 border-bottom: 2px solid $orange-color;
43 @media screen and (min-width: 1400px) { 43 margin-bottom: 25px;
44 padding: 15px 40px;
45 }
46
47 @media screen and (min-width: 1600px) {
48 padding: 15px 50px;
49 }
50
51 @media screen and (min-width: 1800px) {
52 padding: 15px 60px;
53 }
54 } 44 }
55} 45}
56 46
diff --git a/client/yarn.lock b/client/yarn.lock
index 8f148e431..fa1802a29 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -264,10 +264,6 @@ amdefine@>=0.0.4:
264 version "1.0.1" 264 version "1.0.1"
265 resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 265 resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
266 266
267angular-pipes@^6.0.0:
268 version "6.5.3"
269 resolved "https://registry.yarnpkg.com/angular-pipes/-/angular-pipes-6.5.3.tgz#6bed37c51ebc2adaf3412663bfe25179d0489b02"
270
271angular2-notifications@^0.7.7: 267angular2-notifications@^0.7.7:
272 version "0.7.8" 268 version "0.7.8"
273 resolved "https://registry.yarnpkg.com/angular2-notifications/-/angular2-notifications-0.7.8.tgz#ecbcb95a8d2d402af94a9a080d6664c70d33a029" 269 resolved "https://registry.yarnpkg.com/angular2-notifications/-/angular2-notifications-0.7.8.tgz#ecbcb95a8d2d402af94a9a080d6664c70d33a029"
@@ -4718,6 +4714,10 @@ ngx-chips@1.5.3:
4718 dependencies: 4714 dependencies:
4719 ng2-material-dropdown "0.7.10" 4715 ng2-material-dropdown "0.7.10"
4720 4716
4717ngx-pipes@^2.0.5:
4718 version "2.0.5"
4719 resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.0.5.tgz#743b827e350b1e66f5bdae49e90a02fa631d4c54"
4720
4721no-case@^2.2.0: 4721no-case@^2.2.0:
4722 version "2.3.2" 4722 version "2.3.2"
4723 resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" 4723 resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"