diff options
Diffstat (limited to 'client/src')
19 files changed, 1046 insertions, 114 deletions
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 7e2a0c5f6..8c5285e4b 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html | |||
@@ -17,7 +17,7 @@ | |||
17 | <div class="panel-block"> | 17 | <div class="panel-block"> |
18 | <div id="panel-user-login" class="panel-button"> | 18 | <div id="panel-user-login" class="panel-button"> |
19 | <span class="glyphicon glyphicon-user"></span> | 19 | <span class="glyphicon glyphicon-user"></span> |
20 | <a *ngIf="!isLoggedIn" [routerLink]="['/users/login']">Login</a> | 20 | <a *ngIf="!isLoggedIn" [routerLink]="['/login']">Login</a> |
21 | <a *ngIf="isLoggedIn" (click)="logout()">Logout</a> | 21 | <a *ngIf="isLoggedIn" (click)="logout()">Logout</a> |
22 | </div> | 22 | </div> |
23 | </div> | 23 | </div> |
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 0cee6edbf..88b181f9c 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts | |||
@@ -1,52 +1,23 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core'; |
2 | import { HTTP_PROVIDERS } from '@angular/http'; | 2 | import { HTTP_PROVIDERS } from '@angular/http'; |
3 | import { Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, Routes } from '@angular/router'; | 3 | import { Router, ROUTER_DIRECTIVES } from '@angular/router'; |
4 | 4 | ||
5 | import { FriendService } from './friends'; | 5 | import { FriendService } from './friends'; |
6 | import { LoginComponent } from './login'; | ||
7 | import { | 6 | import { |
8 | AuthService, | 7 | AuthService, |
9 | AuthStatus, | 8 | AuthStatus, |
10 | Search, | 9 | Search, |
11 | SearchComponent | 10 | SearchComponent, |
11 | SearchService | ||
12 | } from './shared'; | 12 | } from './shared'; |
13 | import { | 13 | import { VideoService } from './videos'; |
14 | VideoAddComponent, | ||
15 | VideoListComponent, | ||
16 | VideoWatchComponent, | ||
17 | VideoService | ||
18 | } from './videos'; | ||
19 | import { SearchService } from './shared'; // Temporary | ||
20 | |||
21 | @Routes([ | ||
22 | { | ||
23 | path: '/users/login', | ||
24 | component: LoginComponent | ||
25 | }, | ||
26 | { | ||
27 | path: '/videos/list', | ||
28 | component: VideoListComponent | ||
29 | }, | ||
30 | { | ||
31 | path: '/videos/watch/:id', | ||
32 | component: VideoWatchComponent | ||
33 | }, | ||
34 | { | ||
35 | path: '/videos/add', | ||
36 | component: VideoAddComponent | ||
37 | }, | ||
38 | { | ||
39 | path: '/', | ||
40 | component: VideoListComponent | ||
41 | } | ||
42 | ]) | ||
43 | 14 | ||
44 | @Component({ | 15 | @Component({ |
45 | selector: 'my-app', | 16 | selector: 'my-app', |
46 | template: require('./app.component.html'), | 17 | template: require('./app.component.html'), |
47 | styles: [ require('./app.component.scss') ], | 18 | styles: [ require('./app.component.scss') ], |
48 | directives: [ ROUTER_DIRECTIVES, SearchComponent ], | 19 | directives: [ ROUTER_DIRECTIVES, SearchComponent ], |
49 | providers: [ AuthService, FriendService, HTTP_PROVIDERS, ROUTER_PROVIDERS, VideoService, SearchService ] | 20 | providers: [ AuthService, FriendService, HTTP_PROVIDERS, VideoService, SearchService ] |
50 | }) | 21 | }) |
51 | 22 | ||
52 | export class AppComponent { | 23 | export class AppComponent { |
@@ -75,6 +46,7 @@ export class AppComponent { | |||
75 | field: search.field, | 46 | field: search.field, |
76 | search: search.value | 47 | search: search.value |
77 | }; | 48 | }; |
49 | |||
78 | this.router.navigate(['/videos/list', params]); | 50 | this.router.navigate(['/videos/list', params]); |
79 | } else { | 51 | } else { |
80 | this.router.navigate(['/videos/list']); | 52 | this.router.navigate(['/videos/list']); |
diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts new file mode 100644 index 000000000..59ef4ce55 --- /dev/null +++ b/client/src/app/app.routes.ts | |||
@@ -0,0 +1,15 @@ | |||
1 | import { RouterConfig } from '@angular/router'; | ||
2 | |||
3 | import { LoginRoutes } from './login'; | ||
4 | import { VideosRoutes } from './videos'; | ||
5 | |||
6 | export const routes: RouterConfig = [ | ||
7 | { | ||
8 | path: '', | ||
9 | redirectTo: '/videos/list', | ||
10 | pathMatch: 'full' | ||
11 | }, | ||
12 | |||
13 | ...LoginRoutes, | ||
14 | ...VideosRoutes | ||
15 | ]; | ||
diff --git a/client/src/app/login/index.ts b/client/src/app/login/index.ts index 69c16441f..64d3f2a3c 100644 --- a/client/src/app/login/index.ts +++ b/client/src/app/login/index.ts | |||
@@ -1 +1,2 @@ | |||
1 | export * from './login.component'; | 1 | export * from './login.component'; |
2 | export * from './login.routes'; | ||
diff --git a/client/src/app/login/login.routes.ts b/client/src/app/login/login.routes.ts new file mode 100644 index 000000000..4f56d5eb2 --- /dev/null +++ b/client/src/app/login/login.routes.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | import { LoginComponent } from './login.component'; | ||
2 | |||
3 | export const LoginRoutes = [ | ||
4 | { path: 'login', component: LoginComponent } | ||
5 | ]; | ||
diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts index 9218850ed..d33701bc8 100644 --- a/client/src/app/shared/search/search.component.ts +++ b/client/src/app/shared/search/search.component.ts | |||
@@ -4,7 +4,7 @@ import { DROPDOWN_DIRECTIVES} from 'ng2-bootstrap/components/dropdown'; | |||
4 | 4 | ||
5 | import { Search } from './search.model'; | 5 | import { Search } from './search.model'; |
6 | import { SearchField } from './search-field.type'; | 6 | import { SearchField } from './search-field.type'; |
7 | import { SearchService } from './search.service'; // Temporary | 7 | import { SearchService } from './search.service'; |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-search', | 10 | selector: 'my-search', |
diff --git a/client/src/app/shared/search/search.service.ts b/client/src/app/shared/search/search.service.ts index 787c02d2b..0e41cdd34 100644 --- a/client/src/app/shared/search/search.service.ts +++ b/client/src/app/shared/search/search.service.ts | |||
@@ -3,7 +3,7 @@ import { Subject } from 'rxjs/Subject'; | |||
3 | 3 | ||
4 | import { Search } from './search.model'; | 4 | import { Search } from './search.model'; |
5 | 5 | ||
6 | // This class is needed to communicate between videos/list and search component | 6 | // This class is needed to communicate between videos/ and search component |
7 | // Remove it when we'll be able to subscribe to router changes | 7 | // Remove it when we'll be able to subscribe to router changes |
8 | @Injectable() | 8 | @Injectable() |
9 | export class SearchService { | 9 | export class SearchService { |
diff --git a/client/src/app/videos/index.ts b/client/src/app/videos/index.ts index 9a92fa57a..a9088a907 100644 --- a/client/src/app/videos/index.ts +++ b/client/src/app/videos/index.ts | |||
@@ -2,3 +2,5 @@ export * from './shared'; | |||
2 | export * from './video-add'; | 2 | export * from './video-add'; |
3 | export * from './video-list'; | 3 | export * from './video-list'; |
4 | export * from './video-watch'; | 4 | export * from './video-watch'; |
5 | export * from './videos.component'; | ||
6 | export * from './videos.routes'; | ||
diff --git a/client/src/app/videos/shared/pagination.model.ts b/client/src/app/videos/shared/pagination.model.ts index 06f7a7875..eda44ebfb 100644 --- a/client/src/app/videos/shared/pagination.model.ts +++ b/client/src/app/videos/shared/pagination.model.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface Pagination { | 1 | export interface Pagination { |
2 | currentPage: number; | 2 | currentPage: number; |
3 | itemsPerPage: number; | 3 | itemsPerPage: number; |
4 | total: number; | 4 | totalItems: number; |
5 | } | 5 | } |
diff --git a/client/src/app/videos/video-list/video-list.component.html b/client/src/app/videos/video-list/video-list.component.html index 52abc3dc2..0e17ef2c4 100644 --- a/client/src/app/videos/video-list/video-list.component.html +++ b/client/src/app/videos/video-list/video-list.component.html | |||
@@ -1,8 +1,8 @@ | |||
1 | <div class="row videos-info"> | 1 | <div class="row videos-info"> |
2 | <div class="col-md-9 videos-total-results"> | 2 | <div class="col-md-9 videos-total-results"> |
3 | {{ pagination.total }} videos | 3 | <span *ngIf="pagination.totalItems !== null">{{ pagination.totalItems }} videos</span> |
4 | 4 | ||
5 | <my-loader [loading]="loading"></my-loader> | 5 | <my-loader [loading]="loading | async"></my-loader> |
6 | </div> | 6 | </div> |
7 | <my-video-sort class="col-md-3" [currentSort]="sort" (sort)="onSort($event)"></my-video-sort> | 7 | <my-video-sort class="col-md-3" [currentSort]="sort" (sort)="onSort($event)"></my-video-sort> |
8 | </div> | 8 | </div> |
@@ -14,7 +14,7 @@ | |||
14 | </my-video-miniature> | 14 | </my-video-miniature> |
15 | </div> | 15 | </div> |
16 | 16 | ||
17 | <pagination | 17 | <pagination *ngIf="pagination.totalItems !== null" |
18 | [totalItems]="pagination.total" [itemsPerPage]="pagination.itemsPerPage" [maxSize]="6" [boundaryLinks]="true" [rotate]="false" | 18 | [totalItems]="pagination.totalItems" [itemsPerPage]="pagination.itemsPerPage" [maxSize]="6" [boundaryLinks]="true" [rotate]="false" |
19 | (ngModelChange)="getVideos()" [(ngModel)]="pagination.currentPage" | 19 | [(ngModel)]="pagination.currentPage" (pageChanged)="getVideos()" |
20 | ></pagination> | 20 | ></pagination> |
diff --git a/client/src/app/videos/video-list/video-list.component.scss b/client/src/app/videos/video-list/video-list.component.scss index dc2c065d8..1f491a6c3 100644 --- a/client/src/app/videos/video-list/video-list.component.scss +++ b/client/src/app/videos/video-list/video-list.component.scss | |||
@@ -24,7 +24,7 @@ | |||
24 | } | 24 | } |
25 | 25 | ||
26 | .videos-miniatures { | 26 | .videos-miniatures { |
27 | min-height: 600px; | 27 | min-height: 650px; |
28 | 28 | ||
29 | my-video-miniature { | 29 | my-video-miniature { |
30 | transition: all 0.5s ease; | 30 | transition: all 0.5s ease; |
diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts index 46263eb65..0ebf0ef5c 100644 --- a/client/src/app/videos/video-list/video-list.component.ts +++ b/client/src/app/videos/video-list/video-list.component.ts | |||
@@ -1,5 +1,7 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
2 | import { Router, ROUTER_DIRECTIVES, RouteSegment } from '@angular/router'; | 2 | import { AsyncPipe } from '@angular/common'; |
3 | import { ActivatedRoute, Router, ROUTER_DIRECTIVES } from '@angular/router'; | ||
4 | import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | ||
3 | 5 | ||
4 | import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination'; | 6 | import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination'; |
5 | 7 | ||
@@ -18,52 +20,64 @@ import { SearchService } from '../../shared'; | |||
18 | @Component({ | 20 | @Component({ |
19 | selector: 'my-videos-list', | 21 | selector: 'my-videos-list', |
20 | styles: [ require('./video-list.component.scss') ], | 22 | styles: [ require('./video-list.component.scss') ], |
23 | pipes: [ AsyncPipe ], | ||
21 | template: require('./video-list.component.html'), | 24 | template: require('./video-list.component.html'), |
22 | directives: [ LoaderComponent, PAGINATION_DIRECTIVES, ROUTER_DIRECTIVES, VideoMiniatureComponent, VideoSortComponent ] | 25 | directives: [ LoaderComponent, PAGINATION_DIRECTIVES, ROUTER_DIRECTIVES, VideoMiniatureComponent, VideoSortComponent ] |
23 | }) | 26 | }) |
24 | 27 | ||
25 | export class VideoListComponent implements OnInit { | 28 | export class VideoListComponent implements OnInit, OnDestroy { |
26 | loading = false; | 29 | loading: BehaviorSubject<boolean> = new BehaviorSubject(false); |
27 | pagination: Pagination = { | 30 | pagination: Pagination = { |
28 | currentPage: 1, | 31 | currentPage: 1, |
29 | itemsPerPage: 9, | 32 | itemsPerPage: 9, |
30 | total: 0 | 33 | totalItems: null |
31 | }; | 34 | }; |
32 | sort: SortField; | 35 | sort: SortField; |
33 | user: User = null; | 36 | user: User = null; |
34 | videos: Video[] = []; | 37 | videos: Video[] = []; |
35 | 38 | ||
36 | private search: Search; | 39 | private search: Search; |
40 | private sub: any; | ||
37 | 41 | ||
38 | constructor( | 42 | constructor( |
39 | private authService: AuthService, | 43 | private authService: AuthService, |
44 | private changeDetector: ChangeDetectorRef, | ||
40 | private router: Router, | 45 | private router: Router, |
41 | private routeSegment: RouteSegment, | 46 | private route: ActivatedRoute, |
42 | private videoService: VideoService, | 47 | private videoService: VideoService, |
43 | private searchService: SearchService // Temporary | 48 | private searchService: SearchService |
44 | ) {} | 49 | ) {} |
45 | 50 | ||
46 | ngOnInit() { | 51 | ngOnInit() { |
47 | if (this.authService.isLoggedIn()) { | 52 | this.sub = this.route.params.subscribe(routeParams => { |
48 | this.user = User.load(); | 53 | if (this.authService.isLoggedIn()) { |
49 | } | 54 | this.user = User.load(); |
55 | } | ||
50 | 56 | ||
51 | this.search = { | 57 | this.search = { |
52 | value: this.routeSegment.getParam('search'), | 58 | value: routeParams['search'], |
53 | field: <SearchField>this.routeSegment.getParam('field') | 59 | field: <SearchField>routeParams['field'] |
54 | }; | 60 | }; |
55 | 61 | ||
56 | // Temporary | 62 | // Update the search service component |
57 | this.searchChanged(this.search); | 63 | this.searchService.searchChanged.next(this.search); |
58 | 64 | ||
59 | this.sort = <SortField>this.routeSegment.getParam('sort') || '-createdDate'; | 65 | this.sort = <SortField>routeParams['sort'] || '-createdDate'; |
66 | |||
67 | this.getVideos(); | ||
68 | }); | ||
69 | } | ||
60 | 70 | ||
61 | this.getVideos(); | 71 | ngOnDestroy() { |
72 | this.sub.unsubscribe(); | ||
62 | } | 73 | } |
63 | 74 | ||
64 | getVideos() { | 75 | getVideos(detectChanges = true) { |
65 | this.loading = true; | 76 | this.loading.next(true); |
66 | this.videos = []; | 77 | this.videos = []; |
78 | this.pagination.currentPage = 1; | ||
79 | |||
80 | this.changeDetector.detectChanges(); | ||
67 | 81 | ||
68 | let observable = null; | 82 | let observable = null; |
69 | 83 | ||
@@ -76,9 +90,9 @@ export class VideoListComponent implements OnInit { | |||
76 | observable.subscribe( | 90 | observable.subscribe( |
77 | ({ videos, totalVideos }) => { | 91 | ({ videos, totalVideos }) => { |
78 | this.videos = videos; | 92 | this.videos = videos; |
79 | this.pagination.total = totalVideos; | 93 | this.pagination.totalItems = totalVideos; |
80 | 94 | ||
81 | this.loading = false; | 95 | this.loading.next(false); |
82 | }, | 96 | }, |
83 | error => alert(error) | 97 | error => alert(error) |
84 | ); | 98 | ); |
@@ -89,7 +103,7 @@ export class VideoListComponent implements OnInit { | |||
89 | } | 103 | } |
90 | 104 | ||
91 | onRemoved(video: Video) { | 105 | onRemoved(video: Video) { |
92 | this.getVideos(); | 106 | this.getVideos(false); |
93 | } | 107 | } |
94 | 108 | ||
95 | onSort(sort: SortField) { | 109 | onSort(sort: SortField) { |
@@ -106,8 +120,4 @@ export class VideoListComponent implements OnInit { | |||
106 | 120 | ||
107 | this.router.navigate(['/videos/list', params]); | 121 | this.router.navigate(['/videos/list', params]); |
108 | } | 122 | } |
109 | |||
110 | searchChanged(search: Search) { | ||
111 | this.searchService.searchChanged.next(search); | ||
112 | } | ||
113 | } | 123 | } |
diff --git a/client/src/app/videos/video-list/video-miniature.component.html b/client/src/app/videos/video-list/video-miniature.component.html index 92e19bb8b..3cf28620e 100644 --- a/client/src/app/videos/video-list/video-miniature.component.html +++ b/client/src/app/videos/video-list/video-miniature.component.html | |||
@@ -13,14 +13,16 @@ | |||
13 | 13 | ||
14 | <div class="video-miniature-informations"> | 14 | <div class="video-miniature-informations"> |
15 | <span class="video-miniature-name-tags"> | 15 | <span class="video-miniature-name-tags"> |
16 | <a [routerLink]="['/videos/watch', video.id]" class="video-miniature-name">{{ video.name }}</a> | 16 | <a [routerLink]="['/videos/watch', video.id]" [attr.title] class="video-miniature-name">{{ video.name }}</a> |
17 | 17 | ||
18 | <span *ngFor="let tag of video.tags" class="video-miniature-tag"> | 18 | <div class="video-miniature-tags"> |
19 | <a [routerLink]="['/videos/list', { field: 'tags', search: tag }]" class="label label-primary">{{ tag }}</a> | 19 | <span *ngFor="let tag of video.tags" class="video-miniature-tag"> |
20 | </span> | 20 | <a [routerLink]="['/videos/list', { field: 'tags', search: tag }]" class="label label-primary">{{ tag }}</a> |
21 | </span> | ||
22 | </div> | ||
21 | </span> | 23 | </span> |
22 | 24 | ||
23 | <a [routerLink]="['/videos/list', { field: 'author', search: video.author }]" class="video-miniature-author">by {{ video.by }}</a> | 25 | <a [routerLink]="['/videos/list', { field: 'author', search: video.author }]" class="video-miniature-author">{{ video.by }}</a> |
24 | <span class="video-miniature-created-date">on {{ video.createdDate | date:'short' }}</span> | 26 | <span class="video-miniature-created-date">{{ video.createdDate | date:'short' }}</span> |
25 | </div> | 27 | </div> |
26 | </div> | 28 | </div> |
diff --git a/client/src/app/videos/video-list/video-miniature.component.scss b/client/src/app/videos/video-list/video-miniature.component.scss index 40d37b83f..3a096dabd 100644 --- a/client/src/app/videos/video-list/video-miniature.component.scss +++ b/client/src/app/videos/video-list/video-miniature.component.scss | |||
@@ -1,3 +1,5 @@ | |||
1 | @import "../../../sass/pre-customizations.scss"; | ||
2 | |||
1 | .video-miniature { | 3 | .video-miniature { |
2 | margin-top: 30px; | 4 | margin-top: 30px; |
3 | display: inline-block; | 5 | display: inline-block; |
@@ -34,34 +36,40 @@ | |||
34 | } | 36 | } |
35 | 37 | ||
36 | .video-miniature-informations { | 38 | .video-miniature-informations { |
37 | margin-left: 3px; | ||
38 | width: 200px; | 39 | width: 200px; |
39 | 40 | ||
40 | .video-miniature-name-tags { | 41 | .video-miniature-name-tags { |
41 | display: block; | 42 | display: block; |
42 | 43 | ||
43 | .video-miniature-name { | 44 | .video-miniature-name { |
45 | height: 23px; | ||
46 | display: block; | ||
47 | overflow: hidden; | ||
48 | text-overflow: ellipsis; | ||
49 | white-space: nowrap; | ||
44 | font-weight: bold; | 50 | font-weight: bold; |
51 | transition: color 0.2s; | ||
52 | font-size: 15px; | ||
45 | 53 | ||
46 | &:hover { | 54 | &:hover { |
47 | text-decoration: none; | 55 | text-decoration: none; |
48 | } | 56 | } |
49 | |||
50 | &::after { | ||
51 | content: '\002022'; | ||
52 | margin-left: 3px; | ||
53 | } | ||
54 | } | 57 | } |
55 | 58 | ||
56 | .video-miniature-tag { | 59 | .video-miniature-tags { |
57 | font-size: 12px; | 60 | // Fix for chrome when tags a long |
58 | cursor: pointer; | 61 | width: 201px; |
59 | transition: opacity 0.5s; | ||
60 | position: relative; | ||
61 | top: -2px; | ||
62 | 62 | ||
63 | &:hover { | 63 | .video-miniature-tag { |
64 | opacity: 0.9; | 64 | font-size: 13px; |
65 | cursor: pointer; | ||
66 | position: relative; | ||
67 | top: -2px; | ||
68 | |||
69 | .label { | ||
70 | line-height: $line-height-base; | ||
71 | transition: background-color 0.2s; | ||
72 | } | ||
65 | } | 73 | } |
66 | } | 74 | } |
67 | } | 75 | } |
@@ -69,16 +77,17 @@ | |||
69 | .video-miniature-author, .video-miniature-created-date { | 77 | .video-miniature-author, .video-miniature-created-date { |
70 | display: block; | 78 | display: block; |
71 | margin-left: 1px; | 79 | margin-left: 1px; |
72 | font-size: 11px; | 80 | font-size: 12px; |
73 | color: rgb(54, 118, 173); | 81 | color: #337ab7; |
82 | opacity: 0.9; | ||
74 | } | 83 | } |
75 | 84 | ||
76 | .video-miniature-author { | 85 | .video-miniature-author { |
77 | transition: opacity 0.5s; | 86 | transition: color 0.2s; |
78 | 87 | ||
79 | &:hover { | 88 | &:hover { |
89 | color: #23527c; | ||
80 | text-decoration: none; | 90 | text-decoration: none; |
81 | opacity: 0.9; | ||
82 | } | 91 | } |
83 | } | 92 | } |
84 | } | 93 | } |
diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts index 99188bfb3..09255de5d 100644 --- a/client/src/app/videos/video-watch/video-watch.component.ts +++ b/client/src/app/videos/video-watch/video-watch.component.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Component, ElementRef, OnInit } from '@angular/core'; | 1 | import { Component, ElementRef, OnDestroy, OnInit } from '@angular/core'; |
2 | import { CanDeactivate, RouteSegment } from '@angular/router'; | 2 | import { ActivatedRoute } from '@angular/router'; |
3 | 3 | ||
4 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; | 4 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; |
5 | 5 | ||
@@ -15,7 +15,7 @@ import { WebTorrentService } from './webtorrent.service'; | |||
15 | pipes: [ BytesPipe ] | 15 | pipes: [ BytesPipe ] |
16 | }) | 16 | }) |
17 | 17 | ||
18 | export class VideoWatchComponent implements OnInit, CanDeactivate { | 18 | export class VideoWatchComponent implements OnInit, OnDestroy { |
19 | private static LOADTIME_TOO_LONG: number = 30000; | 19 | private static LOADTIME_TOO_LONG: number = 30000; |
20 | 20 | ||
21 | downloadSpeed: number; | 21 | downloadSpeed: number; |
@@ -26,11 +26,12 @@ export class VideoWatchComponent implements OnInit, CanDeactivate { | |||
26 | video: Video; | 26 | video: Video; |
27 | 27 | ||
28 | private errorTimer: NodeJS.Timer; | 28 | private errorTimer: NodeJS.Timer; |
29 | private sub: any; | ||
29 | private torrentInfosInterval: NodeJS.Timer; | 30 | private torrentInfosInterval: NodeJS.Timer; |
30 | 31 | ||
31 | constructor( | 32 | constructor( |
32 | private elementRef: ElementRef, | 33 | private elementRef: ElementRef, |
33 | private routeSegment: RouteSegment, | 34 | private route: ActivatedRoute, |
34 | private videoService: VideoService, | 35 | private videoService: VideoService, |
35 | private webTorrentService: WebTorrentService | 36 | private webTorrentService: WebTorrentService |
36 | ) {} | 37 | ) {} |
@@ -73,22 +74,25 @@ export class VideoWatchComponent implements OnInit, CanDeactivate { | |||
73 | }); | 74 | }); |
74 | } | 75 | } |
75 | 76 | ||
76 | ngOnInit() { | 77 | ngOnDestroy() { |
77 | let id = this.routeSegment.getParam('id'); | ||
78 | this.videoService.getVideo(id).subscribe( | ||
79 | video => { | ||
80 | this.video = video; | ||
81 | this.loadVideo(); | ||
82 | }, | ||
83 | error => alert(error) | ||
84 | ); | ||
85 | } | ||
86 | |||
87 | routerCanDeactivate() { | ||
88 | console.log('Removing video from webtorrent.'); | 78 | console.log('Removing video from webtorrent.'); |
89 | clearInterval(this.torrentInfosInterval); | 79 | clearInterval(this.torrentInfosInterval); |
90 | this.webTorrentService.remove(this.video.magnetUri); | 80 | this.webTorrentService.remove(this.video.magnetUri); |
91 | return Promise.resolve(true); | 81 | |
82 | this.sub.unsubscribe(); | ||
83 | } | ||
84 | |||
85 | ngOnInit() { | ||
86 | this.sub = this.route.params.subscribe(routeParams => { | ||
87 | let id = routeParams['id']; | ||
88 | this.videoService.getVideo(id).subscribe( | ||
89 | video => { | ||
90 | this.video = video; | ||
91 | this.loadVideo(); | ||
92 | }, | ||
93 | error => alert(error) | ||
94 | ); | ||
95 | }); | ||
92 | } | 96 | } |
93 | 97 | ||
94 | private loadTooLong() { | 98 | private loadTooLong() { |
diff --git a/client/src/app/videos/videos.component.ts b/client/src/app/videos/videos.component.ts new file mode 100644 index 000000000..76252afbb --- /dev/null +++ b/client/src/app/videos/videos.component.ts | |||
@@ -0,0 +1,10 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | import { ROUTER_DIRECTIVES } from '@angular/router'; | ||
3 | |||
4 | @Component({ | ||
5 | template: '<router-outlet></router-outlet>', | ||
6 | directives: [ ROUTER_DIRECTIVES ] | ||
7 | }) | ||
8 | |||
9 | export class VideosComponent { | ||
10 | } | ||
diff --git a/client/src/app/videos/videos.routes.ts b/client/src/app/videos/videos.routes.ts new file mode 100644 index 000000000..1f088b376 --- /dev/null +++ b/client/src/app/videos/videos.routes.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { RouterConfig } from '@angular/router'; | ||
2 | |||
3 | import { VideoAddComponent } from './video-add'; | ||
4 | import { VideoListComponent } from './video-list'; | ||
5 | import { VideosComponent } from './videos.component'; | ||
6 | import { VideoWatchComponent } from './video-watch'; | ||
7 | |||
8 | export const VideosRoutes: RouterConfig = [ | ||
9 | { | ||
10 | path: 'videos', | ||
11 | component: VideosComponent, | ||
12 | children: [ | ||
13 | { | ||
14 | path: 'list', | ||
15 | component: VideoListComponent | ||
16 | }, | ||
17 | { | ||
18 | path: 'add', | ||
19 | component: VideoAddComponent | ||
20 | }, | ||
21 | { | ||
22 | path: 'watch/:id', | ||
23 | component: VideoWatchComponent | ||
24 | } | ||
25 | ] | ||
26 | } | ||
27 | ]; | ||
diff --git a/client/src/main.ts b/client/src/main.ts index 76b3f498a..f9c1d50b8 100644 --- a/client/src/main.ts +++ b/client/src/main.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | import { enableProdMode } from '@angular/core'; | 1 | import { enableProdMode } from '@angular/core'; |
2 | import { bootstrap } from '@angular/platform-browser-dynamic'; | 2 | import { bootstrap } from '@angular/platform-browser-dynamic'; |
3 | import { provideRouter } from '@angular/router'; | ||
3 | 4 | ||
4 | import { AppComponent } from './app/app.component'; | 5 | import { AppComponent } from './app/app.component'; |
6 | import { routes } from './app/app.routes'; | ||
5 | 7 | ||
6 | if (process.env.ENV === 'production') { | 8 | if (process.env.ENV === 'production') { |
7 | enableProdMode(); | 9 | enableProdMode(); |
8 | } | 10 | } |
9 | 11 | ||
10 | bootstrap(AppComponent); | 12 | bootstrap(AppComponent, [ provideRouter(routes) ]); |
diff --git a/client/src/sass/pre-customizations.scss b/client/src/sass/pre-customizations.scss index e92004128..0703b0c9a 100644 --- a/client/src/sass/pre-customizations.scss +++ b/client/src/sass/pre-customizations.scss | |||
@@ -1 +1,874 @@ | |||
1 | // $icon-font-path: "/assets/fonts/"; | 1 | $bootstrap-sass-asset-helper: false !default; |
2 | // | ||
3 | // Variables | ||
4 | // -------------------------------------------------- | ||
5 | |||
6 | |||
7 | //== Colors | ||
8 | // | ||
9 | //## Gray and brand colors for use across Bootstrap. | ||
10 | |||
11 | $gray-base: #000 !default; | ||
12 | $gray-darker: lighten($gray-base, 13.5%) !default; // #222 | ||
13 | $gray-dark: lighten($gray-base, 20%) !default; // #333 | ||
14 | $gray: lighten($gray-base, 33.5%) !default; // #555 | ||
15 | $gray-light: lighten($gray-base, 46.7%) !default; // #777 | ||
16 | $gray-lighter: lighten($gray-base, 93.5%) !default; // #eee | ||
17 | |||
18 | $brand-primary: darken(#428bca, 6.5%) !default; // #337ab7 | ||
19 | $brand-success: #5cb85c !default; | ||
20 | $brand-info: #5bc0de !default; | ||
21 | $brand-warning: #f0ad4e !default; | ||
22 | $brand-danger: #d9534f !default; | ||
23 | |||
24 | |||
25 | //== Scaffolding | ||
26 | // | ||
27 | //## Settings for some of the most global styles. | ||
28 | |||
29 | //** Background color for `<body>`. | ||
30 | $body-bg: #fff !default; | ||
31 | //** Global text color on `<body>`. | ||
32 | $text-color: $gray-dark !default; | ||
33 | |||
34 | //** Global textual link color. | ||
35 | $link-color: $brand-primary !default; | ||
36 | //** Link hover color set via `darken()` function. | ||
37 | $link-hover-color: darken($link-color, 15%) !default; | ||
38 | //** Link hover decoration. | ||
39 | $link-hover-decoration: underline !default; | ||
40 | |||
41 | |||
42 | //== Typography | ||
43 | // | ||
44 | //## Font, line-height, and color for body text, headings, and more. | ||
45 | |||
46 | $font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default; | ||
47 | $font-family-serif: Georgia, "Times New Roman", Times, serif !default; | ||
48 | //** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`. | ||
49 | $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default; | ||
50 | $font-family-base: $font-family-sans-serif !default; | ||
51 | |||
52 | $font-size-base: 14px !default; | ||
53 | $font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px | ||
54 | $font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px | ||
55 | |||
56 | $font-size-h1: floor(($font-size-base * 2.6)) !default; // ~36px | ||
57 | $font-size-h2: floor(($font-size-base * 2.15)) !default; // ~30px | ||
58 | $font-size-h3: ceil(($font-size-base * 1.7)) !default; // ~24px | ||
59 | $font-size-h4: ceil(($font-size-base * 1.25)) !default; // ~18px | ||
60 | $font-size-h5: $font-size-base !default; | ||
61 | $font-size-h6: ceil(($font-size-base * 0.85)) !default; // ~12px | ||
62 | |||
63 | //** Unit-less `line-height` for use in components like buttons. | ||
64 | $line-height-base: 1.428571429 !default; // 20/14 | ||
65 | //** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc. | ||
66 | $line-height-computed: floor(($font-size-base * $line-height-base)) !default; // ~20px | ||
67 | |||
68 | //** By default, this inherits from the `<body>`. | ||
69 | $headings-font-family: inherit !default; | ||
70 | $headings-font-weight: 500 !default; | ||
71 | $headings-line-height: 1.1 !default; | ||
72 | $headings-color: inherit !default; | ||
73 | |||
74 | |||
75 | //== Iconography | ||
76 | // | ||
77 | //## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower. | ||
78 | |||
79 | //** Load fonts from this directory. | ||
80 | |||
81 | // [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path. | ||
82 | // [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths. | ||
83 | $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default; | ||
84 | |||
85 | //** File name for all font files. | ||
86 | $icon-font-name: "glyphicons-halflings-regular" !default; | ||
87 | //** Element ID within SVG icon file. | ||
88 | $icon-font-svg-id: "glyphicons_halflingsregular" !default; | ||
89 | |||
90 | |||
91 | //== Components | ||
92 | // | ||
93 | //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). | ||
94 | |||
95 | $padding-base-vertical: 6px !default; | ||
96 | $padding-base-horizontal: 12px !default; | ||
97 | |||
98 | $padding-large-vertical: 10px !default; | ||
99 | $padding-large-horizontal: 16px !default; | ||
100 | |||
101 | $padding-small-vertical: 5px !default; | ||
102 | $padding-small-horizontal: 10px !default; | ||
103 | |||
104 | $padding-xs-vertical: 1px !default; | ||
105 | $padding-xs-horizontal: 5px !default; | ||
106 | |||
107 | $line-height-large: 1.3333333 !default; // extra decimals for Win 8.1 Chrome | ||
108 | $line-height-small: 1.5 !default; | ||
109 | |||
110 | $border-radius-base: 4px !default; | ||
111 | $border-radius-large: 6px !default; | ||
112 | $border-radius-small: 3px !default; | ||
113 | |||
114 | //** Global color for active items (e.g., navs or dropdowns). | ||
115 | $component-active-color: #fff !default; | ||
116 | //** Global background color for active items (e.g., navs or dropdowns). | ||
117 | $component-active-bg: $brand-primary !default; | ||
118 | |||
119 | //** Width of the `border` for generating carets that indicator dropdowns. | ||
120 | $caret-width-base: 4px !default; | ||
121 | //** Carets increase slightly in size for larger components. | ||
122 | $caret-width-large: 5px !default; | ||
123 | |||
124 | |||
125 | //== Tables | ||
126 | // | ||
127 | //## Customizes the `.table` component with basic values, each used across all table variations. | ||
128 | |||
129 | //** Padding for `<th>`s and `<td>`s. | ||
130 | $table-cell-padding: 8px !default; | ||
131 | //** Padding for cells in `.table-condensed`. | ||
132 | $table-condensed-cell-padding: 5px !default; | ||
133 | |||
134 | //** Default background color used for all tables. | ||
135 | $table-bg: transparent !default; | ||
136 | //** Background color used for `.table-striped`. | ||
137 | $table-bg-accent: #f9f9f9 !default; | ||
138 | //** Background color used for `.table-hover`. | ||
139 | $table-bg-hover: #f5f5f5 !default; | ||
140 | $table-bg-active: $table-bg-hover !default; | ||
141 | |||
142 | //** Border color for table and cell borders. | ||
143 | $table-border-color: #ddd !default; | ||
144 | |||
145 | |||
146 | //== Buttons | ||
147 | // | ||
148 | //## For each of Bootstrap's buttons, define text, background and border color. | ||
149 | |||
150 | $btn-font-weight: normal !default; | ||
151 | |||
152 | $btn-default-color: #333 !default; | ||
153 | $btn-default-bg: #fff !default; | ||
154 | $btn-default-border: #ccc !default; | ||
155 | |||
156 | $btn-primary-color: #fff !default; | ||
157 | $btn-primary-bg: $brand-primary !default; | ||
158 | $btn-primary-border: darken($btn-primary-bg, 5%) !default; | ||
159 | |||
160 | $btn-success-color: #fff !default; | ||
161 | $btn-success-bg: $brand-success !default; | ||
162 | $btn-success-border: darken($btn-success-bg, 5%) !default; | ||
163 | |||
164 | $btn-info-color: #fff !default; | ||
165 | $btn-info-bg: $brand-info !default; | ||
166 | $btn-info-border: darken($btn-info-bg, 5%) !default; | ||
167 | |||
168 | $btn-warning-color: #fff !default; | ||
169 | $btn-warning-bg: $brand-warning !default; | ||
170 | $btn-warning-border: darken($btn-warning-bg, 5%) !default; | ||
171 | |||
172 | $btn-danger-color: #fff !default; | ||
173 | $btn-danger-bg: $brand-danger !default; | ||
174 | $btn-danger-border: darken($btn-danger-bg, 5%) !default; | ||
175 | |||
176 | $btn-link-disabled-color: $gray-light !default; | ||
177 | |||
178 | // Allows for customizing button radius independently from global border radius | ||
179 | $btn-border-radius-base: $border-radius-base !default; | ||
180 | $btn-border-radius-large: $border-radius-large !default; | ||
181 | $btn-border-radius-small: $border-radius-small !default; | ||
182 | |||
183 | |||
184 | //== Forms | ||
185 | // | ||
186 | //## | ||
187 | |||
188 | //** `<input>` background color | ||
189 | $input-bg: #fff !default; | ||
190 | //** `<input disabled>` background color | ||
191 | $input-bg-disabled: $gray-lighter !default; | ||
192 | |||
193 | //** Text color for `<input>`s | ||
194 | $input-color: $gray !default; | ||
195 | //** `<input>` border color | ||
196 | $input-border: #ccc !default; | ||
197 | |||
198 | // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4 | ||
199 | //** Default `.form-control` border radius | ||
200 | // This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS. | ||
201 | $input-border-radius: $border-radius-base !default; | ||
202 | //** Large `.form-control` border radius | ||
203 | $input-border-radius-large: $border-radius-large !default; | ||
204 | //** Small `.form-control` border radius | ||
205 | $input-border-radius-small: $border-radius-small !default; | ||
206 | |||
207 | //** Border color for inputs on focus | ||
208 | $input-border-focus: #66afe9 !default; | ||
209 | |||
210 | //** Placeholder text color | ||
211 | $input-color-placeholder: #999 !default; | ||
212 | |||
213 | //** Default `.form-control` height | ||
214 | $input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default; | ||
215 | //** Large `.form-control` height | ||
216 | $input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default; | ||
217 | //** Small `.form-control` height | ||
218 | $input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default; | ||
219 | |||
220 | //** `.form-group` margin | ||
221 | $form-group-margin-bottom: 15px !default; | ||
222 | |||
223 | $legend-color: $gray-dark !default; | ||
224 | $legend-border-color: #e5e5e5 !default; | ||
225 | |||
226 | //** Background color for textual input addons | ||
227 | $input-group-addon-bg: $gray-lighter !default; | ||
228 | //** Border color for textual input addons | ||
229 | $input-group-addon-border-color: $input-border !default; | ||
230 | |||
231 | //** Disabled cursor for form controls and buttons. | ||
232 | $cursor-disabled: not-allowed !default; | ||
233 | |||
234 | |||
235 | //== Dropdowns | ||
236 | // | ||
237 | //## Dropdown menu container and contents. | ||
238 | |||
239 | //** Background for the dropdown menu. | ||
240 | $dropdown-bg: #fff !default; | ||
241 | //** Dropdown menu `border-color`. | ||
242 | $dropdown-border: rgba(0,0,0,.15) !default; | ||
243 | //** Dropdown menu `border-color` **for IE8**. | ||
244 | $dropdown-fallback-border: #ccc !default; | ||
245 | //** Divider color for between dropdown items. | ||
246 | $dropdown-divider-bg: #e5e5e5 !default; | ||
247 | |||
248 | //** Dropdown link text color. | ||
249 | $dropdown-link-color: $gray-dark !default; | ||
250 | //** Hover color for dropdown links. | ||
251 | $dropdown-link-hover-color: darken($gray-dark, 5%) !default; | ||
252 | //** Hover background for dropdown links. | ||
253 | $dropdown-link-hover-bg: #f5f5f5 !default; | ||
254 | |||
255 | //** Active dropdown menu item text color. | ||
256 | $dropdown-link-active-color: $component-active-color !default; | ||
257 | //** Active dropdown menu item background color. | ||
258 | $dropdown-link-active-bg: $component-active-bg !default; | ||
259 | |||
260 | //** Disabled dropdown menu item background color. | ||
261 | $dropdown-link-disabled-color: $gray-light !default; | ||
262 | |||
263 | //** Text color for headers within dropdown menus. | ||
264 | $dropdown-header-color: $gray-light !default; | ||
265 | |||
266 | //** Deprecated `$dropdown-caret-color` as of v3.1.0 | ||
267 | $dropdown-caret-color: #000 !default; | ||
268 | |||
269 | |||
270 | //-- Z-index master list | ||
271 | // | ||
272 | // Warning: Avoid customizing these values. They're used for a bird's eye view | ||
273 | // of components dependent on the z-axis and are designed to all work together. | ||
274 | // | ||
275 | // Note: These variables are not generated into the Customizer. | ||
276 | |||
277 | $zindex-navbar: 1000 !default; | ||
278 | $zindex-dropdown: 1000 !default; | ||
279 | $zindex-popover: 1060 !default; | ||
280 | $zindex-tooltip: 1070 !default; | ||
281 | $zindex-navbar-fixed: 1030 !default; | ||
282 | $zindex-modal-background: 1040 !default; | ||
283 | $zindex-modal: 1050 !default; | ||
284 | |||
285 | |||
286 | //== Media queries breakpoints | ||
287 | // | ||
288 | //## Define the breakpoints at which your layout will change, adapting to different screen sizes. | ||
289 | |||
290 | // Extra small screen / phone | ||
291 | //** Deprecated `$screen-xs` as of v3.0.1 | ||
292 | $screen-xs: 480px !default; | ||
293 | //** Deprecated `$screen-xs-min` as of v3.2.0 | ||
294 | $screen-xs-min: $screen-xs !default; | ||
295 | //** Deprecated `$screen-phone` as of v3.0.1 | ||
296 | $screen-phone: $screen-xs-min !default; | ||
297 | |||
298 | // Small screen / tablet | ||
299 | //** Deprecated `$screen-sm` as of v3.0.1 | ||
300 | $screen-sm: 768px !default; | ||
301 | $screen-sm-min: $screen-sm !default; | ||
302 | //** Deprecated `$screen-tablet` as of v3.0.1 | ||
303 | $screen-tablet: $screen-sm-min !default; | ||
304 | |||
305 | // Medium screen / desktop | ||
306 | //** Deprecated `$screen-md` as of v3.0.1 | ||
307 | $screen-md: 992px !default; | ||
308 | $screen-md-min: $screen-md !default; | ||
309 | //** Deprecated `$screen-desktop` as of v3.0.1 | ||
310 | $screen-desktop: $screen-md-min !default; | ||
311 | |||
312 | // Large screen / wide desktop | ||
313 | //** Deprecated `$screen-lg` as of v3.0.1 | ||
314 | $screen-lg: 1200px !default; | ||
315 | $screen-lg-min: $screen-lg !default; | ||
316 | //** Deprecated `$screen-lg-desktop` as of v3.0.1 | ||
317 | $screen-lg-desktop: $screen-lg-min !default; | ||
318 | |||
319 | // So media queries don't overlap when required, provide a maximum | ||
320 | $screen-xs-max: ($screen-sm-min - 1) !default; | ||
321 | $screen-sm-max: ($screen-md-min - 1) !default; | ||
322 | $screen-md-max: ($screen-lg-min - 1) !default; | ||
323 | |||
324 | |||
325 | //== Grid system | ||
326 | // | ||
327 | //## Define your custom responsive grid. | ||
328 | |||
329 | //** Number of columns in the grid. | ||
330 | $grid-columns: 12 !default; | ||
331 | //** Padding between columns. Gets divided in half for the left and right. | ||
332 | $grid-gutter-width: 30px !default; | ||
333 | // Navbar collapse | ||
334 | //** Point at which the navbar becomes uncollapsed. | ||
335 | $grid-float-breakpoint: $screen-sm-min !default; | ||
336 | //** Point at which the navbar begins collapsing. | ||
337 | $grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default; | ||
338 | |||
339 | |||
340 | //== Container sizes | ||
341 | // | ||
342 | //## Define the maximum width of `.container` for different screen sizes. | ||
343 | |||
344 | // Small screen / tablet | ||
345 | $container-tablet: (720px + $grid-gutter-width) !default; | ||
346 | //** For `$screen-sm-min` and up. | ||
347 | $container-sm: $container-tablet !default; | ||
348 | |||
349 | // Medium screen / desktop | ||
350 | $container-desktop: (940px + $grid-gutter-width) !default; | ||
351 | //** For `$screen-md-min` and up. | ||
352 | $container-md: $container-desktop !default; | ||
353 | |||
354 | // Large screen / wide desktop | ||
355 | $container-large-desktop: (1140px + $grid-gutter-width) !default; | ||
356 | //** For `$screen-lg-min` and up. | ||
357 | $container-lg: $container-large-desktop !default; | ||
358 | |||
359 | |||
360 | //== Navbar | ||
361 | // | ||
362 | //## | ||
363 | |||
364 | // Basics of a navbar | ||
365 | $navbar-height: 50px !default; | ||
366 | $navbar-margin-bottom: $line-height-computed !default; | ||
367 | $navbar-border-radius: $border-radius-base !default; | ||
368 | $navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default; | ||
369 | $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default; | ||
370 | $navbar-collapse-max-height: 340px !default; | ||
371 | |||
372 | $navbar-default-color: #777 !default; | ||
373 | $navbar-default-bg: #f8f8f8 !default; | ||
374 | $navbar-default-border: darken($navbar-default-bg, 6.5%) !default; | ||
375 | |||
376 | // Navbar links | ||
377 | $navbar-default-link-color: #777 !default; | ||
378 | $navbar-default-link-hover-color: #333 !default; | ||
379 | $navbar-default-link-hover-bg: transparent !default; | ||
380 | $navbar-default-link-active-color: #555 !default; | ||
381 | $navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%) !default; | ||
382 | $navbar-default-link-disabled-color: #ccc !default; | ||
383 | $navbar-default-link-disabled-bg: transparent !default; | ||
384 | |||
385 | // Navbar brand label | ||
386 | $navbar-default-brand-color: $navbar-default-link-color !default; | ||
387 | $navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%) !default; | ||
388 | $navbar-default-brand-hover-bg: transparent !default; | ||
389 | |||
390 | // Navbar toggle | ||
391 | $navbar-default-toggle-hover-bg: #ddd !default; | ||
392 | $navbar-default-toggle-icon-bar-bg: #888 !default; | ||
393 | $navbar-default-toggle-border-color: #ddd !default; | ||
394 | |||
395 | |||
396 | //=== Inverted navbar | ||
397 | // Reset inverted navbar basics | ||
398 | $navbar-inverse-color: lighten($gray-light, 15%) !default; | ||
399 | $navbar-inverse-bg: #222 !default; | ||
400 | $navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default; | ||
401 | |||
402 | // Inverted navbar links | ||
403 | $navbar-inverse-link-color: lighten($gray-light, 15%) !default; | ||
404 | $navbar-inverse-link-hover-color: #fff !default; | ||
405 | $navbar-inverse-link-hover-bg: transparent !default; | ||
406 | $navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default; | ||
407 | $navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%) !default; | ||
408 | $navbar-inverse-link-disabled-color: #444 !default; | ||
409 | $navbar-inverse-link-disabled-bg: transparent !default; | ||
410 | |||
411 | // Inverted navbar brand label | ||
412 | $navbar-inverse-brand-color: $navbar-inverse-link-color !default; | ||
413 | $navbar-inverse-brand-hover-color: #fff !default; | ||
414 | $navbar-inverse-brand-hover-bg: transparent !default; | ||
415 | |||
416 | // Inverted navbar toggle | ||
417 | $navbar-inverse-toggle-hover-bg: #333 !default; | ||
418 | $navbar-inverse-toggle-icon-bar-bg: #fff !default; | ||
419 | $navbar-inverse-toggle-border-color: #333 !default; | ||
420 | |||
421 | |||
422 | //== Navs | ||
423 | // | ||
424 | //## | ||
425 | |||
426 | //=== Shared nav styles | ||
427 | $nav-link-padding: 10px 15px !default; | ||
428 | $nav-link-hover-bg: $gray-lighter !default; | ||
429 | |||
430 | $nav-disabled-link-color: $gray-light !default; | ||
431 | $nav-disabled-link-hover-color: $gray-light !default; | ||
432 | |||
433 | //== Tabs | ||
434 | $nav-tabs-border-color: #ddd !default; | ||
435 | |||
436 | $nav-tabs-link-hover-border-color: $gray-lighter !default; | ||
437 | |||
438 | $nav-tabs-active-link-hover-bg: $body-bg !default; | ||
439 | $nav-tabs-active-link-hover-color: $gray !default; | ||
440 | $nav-tabs-active-link-hover-border-color: #ddd !default; | ||
441 | |||
442 | $nav-tabs-justified-link-border-color: #ddd !default; | ||
443 | $nav-tabs-justified-active-link-border-color: $body-bg !default; | ||
444 | |||
445 | //== Pills | ||
446 | $nav-pills-border-radius: $border-radius-base !default; | ||
447 | $nav-pills-active-link-hover-bg: $component-active-bg !default; | ||
448 | $nav-pills-active-link-hover-color: $component-active-color !default; | ||
449 | |||
450 | |||
451 | //== Pagination | ||
452 | // | ||
453 | //## | ||
454 | |||
455 | $pagination-color: $link-color !default; | ||
456 | $pagination-bg: #fff !default; | ||
457 | $pagination-border: #ddd !default; | ||
458 | |||
459 | $pagination-hover-color: $link-hover-color !default; | ||
460 | $pagination-hover-bg: $gray-lighter !default; | ||
461 | $pagination-hover-border: #ddd !default; | ||
462 | |||
463 | $pagination-active-color: #fff !default; | ||
464 | $pagination-active-bg: $brand-primary !default; | ||
465 | $pagination-active-border: $brand-primary !default; | ||
466 | |||
467 | $pagination-disabled-color: $gray-light !default; | ||
468 | $pagination-disabled-bg: #fff !default; | ||
469 | $pagination-disabled-border: #ddd !default; | ||
470 | |||
471 | |||
472 | //== Pager | ||
473 | // | ||
474 | //## | ||
475 | |||
476 | $pager-bg: $pagination-bg !default; | ||
477 | $pager-border: $pagination-border !default; | ||
478 | $pager-border-radius: 15px !default; | ||
479 | |||
480 | $pager-hover-bg: $pagination-hover-bg !default; | ||
481 | |||
482 | $pager-active-bg: $pagination-active-bg !default; | ||
483 | $pager-active-color: $pagination-active-color !default; | ||
484 | |||
485 | $pager-disabled-color: $pagination-disabled-color !default; | ||
486 | |||
487 | |||
488 | //== Jumbotron | ||
489 | // | ||
490 | //## | ||
491 | |||
492 | $jumbotron-padding: 30px !default; | ||
493 | $jumbotron-color: inherit !default; | ||
494 | $jumbotron-bg: $gray-lighter !default; | ||
495 | $jumbotron-heading-color: inherit !default; | ||
496 | $jumbotron-font-size: ceil(($font-size-base * 1.5)) !default; | ||
497 | $jumbotron-heading-font-size: ceil(($font-size-base * 4.5)) !default; | ||
498 | |||
499 | |||
500 | //== Form states and alerts | ||
501 | // | ||
502 | //## Define colors for form feedback states and, by default, alerts. | ||
503 | |||
504 | $state-success-text: #3c763d !default; | ||
505 | $state-success-bg: #dff0d8 !default; | ||
506 | $state-success-border: darken(adjust-hue($state-success-bg, -10), 5%) !default; | ||
507 | |||
508 | $state-info-text: #31708f !default; | ||
509 | $state-info-bg: #d9edf7 !default; | ||
510 | $state-info-border: darken(adjust-hue($state-info-bg, -10), 7%) !default; | ||
511 | |||
512 | $state-warning-text: #8a6d3b !default; | ||
513 | $state-warning-bg: #fcf8e3 !default; | ||
514 | $state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%) !default; | ||
515 | |||
516 | $state-danger-text: #a94442 !default; | ||
517 | $state-danger-bg: #f2dede !default; | ||
518 | $state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%) !default; | ||
519 | |||
520 | |||
521 | //== Tooltips | ||
522 | // | ||
523 | //## | ||
524 | |||
525 | //** Tooltip max width | ||
526 | $tooltip-max-width: 200px !default; | ||
527 | //** Tooltip text color | ||
528 | $tooltip-color: #fff !default; | ||
529 | //** Tooltip background color | ||
530 | $tooltip-bg: #000 !default; | ||
531 | $tooltip-opacity: .9 !default; | ||
532 | |||
533 | //** Tooltip arrow width | ||
534 | $tooltip-arrow-width: 5px !default; | ||
535 | //** Tooltip arrow color | ||
536 | $tooltip-arrow-color: $tooltip-bg !default; | ||
537 | |||
538 | |||
539 | //== Popovers | ||
540 | // | ||
541 | //## | ||
542 | |||
543 | //** Popover body background color | ||
544 | $popover-bg: #fff !default; | ||
545 | //** Popover maximum width | ||
546 | $popover-max-width: 276px !default; | ||
547 | //** Popover border color | ||
548 | $popover-border-color: rgba(0,0,0,.2) !default; | ||
549 | //** Popover fallback border color | ||
550 | $popover-fallback-border-color: #ccc !default; | ||
551 | |||
552 | //** Popover title background color | ||
553 | $popover-title-bg: darken($popover-bg, 3%) !default; | ||
554 | |||
555 | //** Popover arrow width | ||
556 | $popover-arrow-width: 10px !default; | ||
557 | //** Popover arrow color | ||
558 | $popover-arrow-color: $popover-bg !default; | ||
559 | |||
560 | //** Popover outer arrow width | ||
561 | $popover-arrow-outer-width: ($popover-arrow-width + 1) !default; | ||
562 | //** Popover outer arrow color | ||
563 | $popover-arrow-outer-color: fade_in($popover-border-color, 0.05) !default; | ||
564 | //** Popover outer arrow fallback color | ||
565 | $popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default; | ||
566 | |||
567 | |||
568 | //== Labels | ||
569 | // | ||
570 | //## | ||
571 | |||
572 | //** Default label background color | ||
573 | $label-default-bg: $gray-light !default; | ||
574 | //** Primary label background color | ||
575 | $label-primary-bg: $brand-primary !default; | ||
576 | //** Success label background color | ||
577 | $label-success-bg: $brand-success !default; | ||
578 | //** Info label background color | ||
579 | $label-info-bg: $brand-info !default; | ||
580 | //** Warning label background color | ||
581 | $label-warning-bg: $brand-warning !default; | ||
582 | //** Danger label background color | ||
583 | $label-danger-bg: $brand-danger !default; | ||
584 | |||
585 | //** Default label text color | ||
586 | $label-color: #fff !default; | ||
587 | //** Default text color of a linked label | ||
588 | $label-link-hover-color: #fff !default; | ||
589 | |||
590 | |||
591 | //== Modals | ||
592 | // | ||
593 | //## | ||
594 | |||
595 | //** Padding applied to the modal body | ||
596 | $modal-inner-padding: 15px !default; | ||
597 | |||
598 | //** Padding applied to the modal title | ||
599 | $modal-title-padding: 15px !default; | ||
600 | //** Modal title line-height | ||
601 | $modal-title-line-height: $line-height-base !default; | ||
602 | |||
603 | //** Background color of modal content area | ||
604 | $modal-content-bg: #fff !default; | ||
605 | //** Modal content border color | ||
606 | $modal-content-border-color: rgba(0,0,0,.2) !default; | ||
607 | //** Modal content border color **for IE8** | ||
608 | $modal-content-fallback-border-color: #999 !default; | ||
609 | |||
610 | //** Modal backdrop background color | ||
611 | $modal-backdrop-bg: #000 !default; | ||
612 | //** Modal backdrop opacity | ||
613 | $modal-backdrop-opacity: .5 !default; | ||
614 | //** Modal header border color | ||
615 | $modal-header-border-color: #e5e5e5 !default; | ||
616 | //** Modal footer border color | ||
617 | $modal-footer-border-color: $modal-header-border-color !default; | ||
618 | |||
619 | $modal-lg: 900px !default; | ||
620 | $modal-md: 600px !default; | ||
621 | $modal-sm: 300px !default; | ||
622 | |||
623 | |||
624 | //== Alerts | ||
625 | // | ||
626 | //## Define alert colors, border radius, and padding. | ||
627 | |||
628 | $alert-padding: 15px !default; | ||
629 | $alert-border-radius: $border-radius-base !default; | ||
630 | $alert-link-font-weight: bold !default; | ||
631 | |||
632 | $alert-success-bg: $state-success-bg !default; | ||
633 | $alert-success-text: $state-success-text !default; | ||
634 | $alert-success-border: $state-success-border !default; | ||
635 | |||
636 | $alert-info-bg: $state-info-bg !default; | ||
637 | $alert-info-text: $state-info-text !default; | ||
638 | $alert-info-border: $state-info-border !default; | ||
639 | |||
640 | $alert-warning-bg: $state-warning-bg !default; | ||
641 | $alert-warning-text: $state-warning-text !default; | ||
642 | $alert-warning-border: $state-warning-border !default; | ||
643 | |||
644 | $alert-danger-bg: $state-danger-bg !default; | ||
645 | $alert-danger-text: $state-danger-text !default; | ||
646 | $alert-danger-border: $state-danger-border !default; | ||
647 | |||
648 | |||
649 | //== Progress bars | ||
650 | // | ||
651 | //## | ||
652 | |||
653 | //** Background color of the whole progress component | ||
654 | $progress-bg: #f5f5f5 !default; | ||
655 | //** Progress bar text color | ||
656 | $progress-bar-color: #fff !default; | ||
657 | //** Variable for setting rounded corners on progress bar. | ||
658 | $progress-border-radius: $border-radius-base !default; | ||
659 | |||
660 | //** Default progress bar color | ||
661 | $progress-bar-bg: $brand-primary !default; | ||
662 | //** Success progress bar color | ||
663 | $progress-bar-success-bg: $brand-success !default; | ||
664 | //** Warning progress bar color | ||
665 | $progress-bar-warning-bg: $brand-warning !default; | ||
666 | //** Danger progress bar color | ||
667 | $progress-bar-danger-bg: $brand-danger !default; | ||
668 | //** Info progress bar color | ||
669 | $progress-bar-info-bg: $brand-info !default; | ||
670 | |||
671 | |||
672 | //== List group | ||
673 | // | ||
674 | //## | ||
675 | |||
676 | //** Background color on `.list-group-item` | ||
677 | $list-group-bg: #fff !default; | ||
678 | //** `.list-group-item` border color | ||
679 | $list-group-border: #ddd !default; | ||
680 | //** List group border radius | ||
681 | $list-group-border-radius: $border-radius-base !default; | ||
682 | |||
683 | //** Background color of single list items on hover | ||
684 | $list-group-hover-bg: #f5f5f5 !default; | ||
685 | //** Text color of active list items | ||
686 | $list-group-active-color: $component-active-color !default; | ||
687 | //** Background color of active list items | ||
688 | $list-group-active-bg: $component-active-bg !default; | ||
689 | //** Border color of active list elements | ||
690 | $list-group-active-border: $list-group-active-bg !default; | ||
691 | //** Text color for content within active list items | ||
692 | $list-group-active-text-color: lighten($list-group-active-bg, 40%) !default; | ||
693 | |||
694 | //** Text color of disabled list items | ||
695 | $list-group-disabled-color: $gray-light !default; | ||
696 | //** Background color of disabled list items | ||
697 | $list-group-disabled-bg: $gray-lighter !default; | ||
698 | //** Text color for content within disabled list items | ||
699 | $list-group-disabled-text-color: $list-group-disabled-color !default; | ||
700 | |||
701 | $list-group-link-color: #555 !default; | ||
702 | $list-group-link-hover-color: $list-group-link-color !default; | ||
703 | $list-group-link-heading-color: #333 !default; | ||
704 | |||
705 | |||
706 | //== Panels | ||
707 | // | ||
708 | //## | ||
709 | |||
710 | $panel-bg: #fff !default; | ||
711 | $panel-body-padding: 15px !default; | ||
712 | $panel-heading-padding: 10px 15px !default; | ||
713 | $panel-footer-padding: $panel-heading-padding !default; | ||
714 | $panel-border-radius: $border-radius-base !default; | ||
715 | |||
716 | //** Border color for elements within panels | ||
717 | $panel-inner-border: #ddd !default; | ||
718 | $panel-footer-bg: #f5f5f5 !default; | ||
719 | |||
720 | $panel-default-text: $gray-dark !default; | ||
721 | $panel-default-border: #ddd !default; | ||
722 | $panel-default-heading-bg: #f5f5f5 !default; | ||
723 | |||
724 | $panel-primary-text: #fff !default; | ||
725 | $panel-primary-border: $brand-primary !default; | ||
726 | $panel-primary-heading-bg: $brand-primary !default; | ||
727 | |||
728 | $panel-success-text: $state-success-text !default; | ||
729 | $panel-success-border: $state-success-border !default; | ||
730 | $panel-success-heading-bg: $state-success-bg !default; | ||
731 | |||
732 | $panel-info-text: $state-info-text !default; | ||
733 | $panel-info-border: $state-info-border !default; | ||
734 | $panel-info-heading-bg: $state-info-bg !default; | ||
735 | |||
736 | $panel-warning-text: $state-warning-text !default; | ||
737 | $panel-warning-border: $state-warning-border !default; | ||
738 | $panel-warning-heading-bg: $state-warning-bg !default; | ||
739 | |||
740 | $panel-danger-text: $state-danger-text !default; | ||
741 | $panel-danger-border: $state-danger-border !default; | ||
742 | $panel-danger-heading-bg: $state-danger-bg !default; | ||
743 | |||
744 | |||
745 | //== Thumbnails | ||
746 | // | ||
747 | //## | ||
748 | |||
749 | //** Padding around the thumbnail image | ||
750 | $thumbnail-padding: 4px !default; | ||
751 | //** Thumbnail background color | ||
752 | $thumbnail-bg: $body-bg !default; | ||
753 | //** Thumbnail border color | ||
754 | $thumbnail-border: #ddd !default; | ||
755 | //** Thumbnail border radius | ||
756 | $thumbnail-border-radius: $border-radius-base !default; | ||
757 | |||
758 | //** Custom text color for thumbnail captions | ||
759 | $thumbnail-caption-color: $text-color !default; | ||
760 | //** Padding around the thumbnail caption | ||
761 | $thumbnail-caption-padding: 9px !default; | ||
762 | |||
763 | |||
764 | //== Wells | ||
765 | // | ||
766 | //## | ||
767 | |||
768 | $well-bg: #f5f5f5 !default; | ||
769 | $well-border: darken($well-bg, 7%) !default; | ||
770 | |||
771 | |||
772 | //== Badges | ||
773 | // | ||
774 | //## | ||
775 | |||
776 | $badge-color: #fff !default; | ||
777 | //** Linked badge text color on hover | ||
778 | $badge-link-hover-color: #fff !default; | ||
779 | $badge-bg: $gray-light !default; | ||
780 | |||
781 | //** Badge text color in active nav link | ||
782 | $badge-active-color: $link-color !default; | ||
783 | //** Badge background color in active nav link | ||
784 | $badge-active-bg: #fff !default; | ||
785 | |||
786 | $badge-font-weight: bold !default; | ||
787 | $badge-line-height: 1 !default; | ||
788 | $badge-border-radius: 10px !default; | ||
789 | |||
790 | |||
791 | //== Breadcrumbs | ||
792 | // | ||
793 | //## | ||
794 | |||
795 | $breadcrumb-padding-vertical: 8px !default; | ||
796 | $breadcrumb-padding-horizontal: 15px !default; | ||
797 | //** Breadcrumb background color | ||
798 | $breadcrumb-bg: #f5f5f5 !default; | ||
799 | //** Breadcrumb text color | ||
800 | $breadcrumb-color: #ccc !default; | ||
801 | //** Text color of current page in the breadcrumb | ||
802 | $breadcrumb-active-color: $gray-light !default; | ||
803 | //** Textual separator for between breadcrumb elements | ||
804 | $breadcrumb-separator: "/" !default; | ||
805 | |||
806 | |||
807 | //== Carousel | ||
808 | // | ||
809 | //## | ||
810 | |||
811 | $carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default; | ||
812 | |||
813 | $carousel-control-color: #fff !default; | ||
814 | $carousel-control-width: 15% !default; | ||
815 | $carousel-control-opacity: .5 !default; | ||
816 | $carousel-control-font-size: 20px !default; | ||
817 | |||
818 | $carousel-indicator-active-bg: #fff !default; | ||
819 | $carousel-indicator-border-color: #fff !default; | ||
820 | |||
821 | $carousel-caption-color: #fff !default; | ||
822 | |||
823 | |||
824 | //== Close | ||
825 | // | ||
826 | //## | ||
827 | |||
828 | $close-font-weight: bold !default; | ||
829 | $close-color: #000 !default; | ||
830 | $close-text-shadow: 0 1px 0 #fff !default; | ||
831 | |||
832 | |||
833 | //== Code | ||
834 | // | ||
835 | //## | ||
836 | |||
837 | $code-color: #c7254e !default; | ||
838 | $code-bg: #f9f2f4 !default; | ||
839 | |||
840 | $kbd-color: #fff !default; | ||
841 | $kbd-bg: #333 !default; | ||
842 | |||
843 | $pre-bg: #f5f5f5 !default; | ||
844 | $pre-color: $gray-dark !default; | ||
845 | $pre-border-color: #ccc !default; | ||
846 | $pre-scrollable-max-height: 340px !default; | ||
847 | |||
848 | |||
849 | //== Type | ||
850 | // | ||
851 | //## | ||
852 | |||
853 | //** Horizontal offset for forms and lists. | ||
854 | $component-offset-horizontal: 180px !default; | ||
855 | //** Text muted color | ||
856 | $text-muted: $gray-light !default; | ||
857 | //** Abbreviations and acronyms border color | ||
858 | $abbr-border-color: $gray-light !default; | ||
859 | //** Headings small color | ||
860 | $headings-small-color: $gray-light !default; | ||
861 | //** Blockquote small color | ||
862 | $blockquote-small-color: $gray-light !default; | ||
863 | //** Blockquote font size | ||
864 | $blockquote-font-size: ($font-size-base * 1.25) !default; | ||
865 | //** Blockquote border color | ||
866 | $blockquote-border-color: $gray-lighter !default; | ||
867 | //** Page header border color | ||
868 | $page-header-border-color: $gray-lighter !default; | ||
869 | //** Width of horizontal description list titles | ||
870 | $dl-horizontal-offset: $component-offset-horizontal !default; | ||
871 | //** Point at which .dl-horizontal becomes horizontal | ||
872 | $dl-horizontal-breakpoint: $grid-float-breakpoint !default; | ||
873 | //** Horizontal line color. | ||
874 | $hr-border: $gray-lighter !default; | ||