diff options
Diffstat (limited to 'client/src')
-rw-r--r-- | client/src/app/app.component.html | 4 | ||||
-rw-r--r-- | client/src/app/app.component.scss | 11 | ||||
-rw-r--r-- | client/src/app/app.module.ts | 2 | ||||
-rw-r--r-- | client/src/app/menu/language-chooser.component.html | 15 | ||||
-rw-r--r-- | client/src/app/menu/language-chooser.component.scss | 15 | ||||
-rw-r--r-- | client/src/app/menu/language-chooser.component.ts | 32 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.html | 126 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.scss | 47 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.ts | 10 | ||||
-rw-r--r-- | client/src/assets/images/menu/language.png | bin | 0 -> 10937 bytes | |||
-rw-r--r-- | client/src/sass/application.scss | 2 | ||||
-rw-r--r-- | client/src/sass/include/_variables.scss | 2 |
12 files changed, 191 insertions, 75 deletions
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index e50546633..09b2c15be 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html | |||
@@ -18,9 +18,7 @@ | |||
18 | </div> | 18 | </div> |
19 | 19 | ||
20 | <div class="sub-header-container"> | 20 | <div class="sub-header-container"> |
21 | <div *ngIf="isMenuDisplayed" class="title-menu-left"> | 21 | <my-menu *ngIf="isMenuDisplayed"></my-menu> |
22 | <my-menu></my-menu> | ||
23 | </div> | ||
24 | 22 | ||
25 | <div class="main-col container-fluid" [ngClass]="{ expanded: isMenuDisplayed === false }"> | 23 | <div class="main-col container-fluid" [ngClass]="{ expanded: isMenuDisplayed === false }"> |
26 | 24 | ||
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index 6edf966f9..9eca31320 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss | |||
@@ -9,17 +9,6 @@ | |||
9 | margin-top: $header-height; | 9 | margin-top: $header-height; |
10 | } | 10 | } |
11 | 11 | ||
12 | .title-menu-left { | ||
13 | position: fixed; | ||
14 | height: calc(100vh - #{$header-height}); | ||
15 | padding: 0; | ||
16 | width: $menu-width; | ||
17 | |||
18 | .title-menu-left-block.menu { | ||
19 | height: 100%; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | .header { | 12 | .header { |
24 | height: $header-height; | 13 | height: $header-height; |
25 | position: fixed; | 14 | position: fixed; |
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 9cffdd31e..48886fd4e 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts | |||
@@ -17,6 +17,7 @@ import { SignupModule } from './signup' | |||
17 | import { VideosModule } from './videos' | 17 | import { VideosModule } from './videos' |
18 | import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' | 18 | import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' |
19 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' | 19 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' |
20 | import { LanguageChooserComponent } from '@app/menu/language-chooser.component' | ||
20 | 21 | ||
21 | export function metaFactory (serverService: ServerService): MetaLoader { | 22 | export function metaFactory (serverService: ServerService): MetaLoader { |
22 | return new MetaStaticLoader({ | 23 | return new MetaStaticLoader({ |
@@ -36,6 +37,7 @@ export function metaFactory (serverService: ServerService): MetaLoader { | |||
36 | AppComponent, | 37 | AppComponent, |
37 | 38 | ||
38 | MenuComponent, | 39 | MenuComponent, |
40 | LanguageChooserComponent, | ||
39 | HeaderComponent | 41 | HeaderComponent |
40 | ], | 42 | ], |
41 | imports: [ | 43 | imports: [ |
diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html new file mode 100644 index 000000000..f941e32f8 --- /dev/null +++ b/client/src/app/menu/language-chooser.component.html | |||
@@ -0,0 +1,15 @@ | |||
1 | <div bsModal #modal="bs-modal" class="modal" tabindex="-1"> | ||
2 | <div class="modal-dialog"> | ||
3 | <div class="modal-content"> | ||
4 | |||
5 | <div class="modal-header"> | ||
6 | <span class="close" aria-hidden="true" (click)="hide()"></span> | ||
7 | <h4 i18n class="modal-title">Change the language</h4> | ||
8 | </div> | ||
9 | |||
10 | <div class="modal-body" *ngFor="let lang of languages"> | ||
11 | <a [href]="buildLanguageLink(lang)">{{ lang.label }}</a> | ||
12 | </div> | ||
13 | </div> | ||
14 | </div> | ||
15 | </div> | ||
diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss new file mode 100644 index 000000000..4574f78c6 --- /dev/null +++ b/client/src/app/menu/language-chooser.component.scss | |||
@@ -0,0 +1,15 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .modal-title { | ||
5 | text-align: center; | ||
6 | } | ||
7 | |||
8 | .modal-body { | ||
9 | text-align: center; | ||
10 | |||
11 | a { | ||
12 | font-size: 16px; | ||
13 | margin-top: 10px; | ||
14 | } | ||
15 | } \ No newline at end of file | ||
diff --git a/client/src/app/menu/language-chooser.component.ts b/client/src/app/menu/language-chooser.component.ts new file mode 100644 index 000000000..3de6a129d --- /dev/null +++ b/client/src/app/menu/language-chooser.component.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import { Component, ViewChild } from '@angular/core' | ||
2 | import { ModalDirective } from 'ngx-bootstrap/modal' | ||
3 | import { I18N_LOCALES } from '../../../../shared' | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-language-chooser', | ||
7 | templateUrl: './language-chooser.component.html', | ||
8 | styleUrls: [ './language-chooser.component.scss' ] | ||
9 | }) | ||
10 | export class LanguageChooserComponent { | ||
11 | @ViewChild('modal') modal: ModalDirective | ||
12 | |||
13 | languages: { [ id: string ]: string }[] = [] | ||
14 | |||
15 | constructor () { | ||
16 | this.languages = Object.keys(I18N_LOCALES) | ||
17 | .map(k => ({ id: k, label: I18N_LOCALES[k] })) | ||
18 | } | ||
19 | |||
20 | show () { | ||
21 | this.modal.show() | ||
22 | } | ||
23 | |||
24 | hide () { | ||
25 | this.modal.hide() | ||
26 | } | ||
27 | |||
28 | buildLanguageLink (lang: { id: string }) { | ||
29 | return window.location.origin + '/' + lang.id | ||
30 | } | ||
31 | |||
32 | } | ||
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index 8e3b295f7..784b5cd85 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -1,70 +1,82 @@ | |||
1 | <menu> | 1 | <div class="menu-wrapper"> |
2 | <div *ngIf="isLoggedIn" class="logged-in-block"> | 2 | <menu> |
3 | <a routerLink="/my-account/settings"> | 3 | <div class="top-menu"> |
4 | <img [src]="user.accountAvatarUrl" alt="Avatar" /> | 4 | <div *ngIf="isLoggedIn" class="logged-in-block"> |
5 | </a> | 5 | <a routerLink="/my-account/settings"> |
6 | <img [src]="user.accountAvatarUrl" alt="Avatar" /> | ||
7 | </a> | ||
6 | 8 | ||
7 | <div class="logged-in-info"> | 9 | <div class="logged-in-info"> |
8 | <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a> | 10 | <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a> |
9 | <div class="logged-in-email">{{ user.email }}</div> | 11 | <div class="logged-in-email">{{ user.email }}</div> |
10 | </div> | 12 | </div> |
11 | 13 | ||
12 | <div class="logged-in-more" dropdown placement="right" container="body"> | 14 | <div class="logged-in-more" dropdown placement="right" container="body"> |
13 | <span class="glyphicon glyphicon-option-vertical" dropdownToggle></span> | 15 | <span class="glyphicon glyphicon-option-vertical" dropdownToggle></span> |
14 | 16 | ||
15 | <ul *dropdownMenu class="dropdown-menu"> | 17 | <ul *dropdownMenu class="dropdown-menu"> |
16 | <li> | 18 | <li> |
17 | <a i18n [routerLink]="[ '/accounts', user.account?.nameWithHost ]" class="dropdown-item" title="My public profile"> | 19 | <a i18n [routerLink]="[ '/accounts', user.account?.nameWithHost ]" class="dropdown-item" title="My public profile"> |
18 | My public profile | 20 | My public profile |
19 | </a> | 21 | </a> |
20 | 22 | ||
21 | <a i18n routerLink="/my-account" class="dropdown-item" title="My account"> | 23 | <a i18n routerLink="/my-account" class="dropdown-item" title="My account"> |
22 | My account | 24 | My account |
23 | </a> | 25 | </a> |
24 | 26 | ||
25 | <a i18n (click)="logout($event)" class="dropdown-item" title="Log out" href="#"> | 27 | <a i18n (click)="logout($event)" class="dropdown-item" title="Log out" href="#"> |
26 | Log out | 28 | Log out |
27 | </a> | 29 | </a> |
28 | </li> | 30 | </li> |
29 | </ul> | 31 | </ul> |
30 | </div> | 32 | </div> |
31 | </div> | 33 | </div> |
34 | |||
35 | <div *ngIf="!isLoggedIn" class="button-block"> | ||
36 | <a i18n routerLink="/login" class="login-button">Login</a> | ||
37 | <a i18n *ngIf="isRegistrationAllowed()" routerLink="/signup" class="create-account-button">Create an account</a> | ||
38 | </div> | ||
32 | 39 | ||
33 | <div *ngIf="!isLoggedIn" class="button-block"> | 40 | <div class="panel-block"> |
34 | <a i18n routerLink="/login" class="login-button">Login</a> | 41 | <div i18n class="block-title">Videos</div> |
35 | <a i18n *ngIf="isRegistrationAllowed()" routerLink="/signup" class="create-account-button">Create an account</a> | ||
36 | </div> | ||
37 | 42 | ||
38 | <div class="panel-block"> | 43 | <a routerLink="/videos/trending" routerLinkActive="active"> |
39 | <div i18n class="block-title">Videos</div> | 44 | <span class="icon icon-videos-trending"></span> |
45 | <ng-container i18n>Trending</ng-container> | ||
46 | </a> | ||
40 | 47 | ||
41 | <a routerLink="/videos/trending" routerLinkActive="active"> | 48 | <a routerLink="/videos/recently-added" routerLinkActive="active"> |
42 | <span class="icon icon-videos-trending"></span> | 49 | <span class="icon icon-videos-recently-added"></span> |
43 | <ng-container i18n>Trending</ng-container> | 50 | <ng-container i18n>Recently added</ng-container> |
44 | </a> | 51 | </a> |
45 | 52 | ||
46 | <a routerLink="/videos/recently-added" routerLinkActive="active"> | 53 | <a routerLink="/videos/local" routerLinkActive="active"> |
47 | <span class="icon icon-videos-recently-added"></span> | 54 | <span class="icon icon-videos-local"></span> |
48 | <ng-container i18n>Recently added</ng-container> | 55 | <ng-container i18n>Local</ng-container> |
49 | </a> | 56 | </a> |
57 | </div> | ||
50 | 58 | ||
51 | <a routerLink="/videos/local" routerLinkActive="active"> | 59 | <div class="panel-block"> |
52 | <span class="icon icon-videos-local"></span> | 60 | <div class="block-title">More</div> |
53 | <ng-container i18n>Local</ng-container> | ||
54 | </a> | ||
55 | </div> | ||
56 | 61 | ||
57 | <div class="panel-block"> | 62 | <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> |
58 | <div class="block-title">More</div> | 63 | <span class="icon icon-administration"></span> |
64 | <ng-container i18n>Administration</ng-container> | ||
65 | </a> | ||
59 | 66 | ||
60 | <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> | 67 | <a routerLink="/about" routerLinkActive="active"> |
61 | <span class="icon icon-administration"></span> | 68 | <span class="icon icon-about"></span> |
62 | <ng-container i18n>Administration</ng-container> | 69 | <ng-container i18n>About</ng-container> |
63 | </a> | 70 | </a> |
71 | </div> | ||
72 | </div> | ||
73 | |||
74 | <div class="footer"> | ||
75 | <span class="language"> | ||
76 | <span (click)="openLanguageChooser()" i18n-title title="Change the language" class="icon icon-language"></span> | ||
77 | </span> | ||
78 | </div> | ||
79 | </menu> | ||
80 | </div> | ||
64 | 81 | ||
65 | <a routerLink="/about" routerLinkActive="active"> | 82 | <my-language-chooser #languageChooserModal></my-language-chooser> \ No newline at end of file |
66 | <span class="icon icon-about"></span> | ||
67 | <ng-container i18n>About</ng-container> | ||
68 | </a> | ||
69 | </div> | ||
70 | </menu> | ||
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index c36a7aa36..e61f4acd3 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss | |||
@@ -1,6 +1,13 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .menu-wrapper { | ||
5 | position: fixed; | ||
6 | height: calc(100vh - #{$header-height}); | ||
7 | padding: 0; | ||
8 | width: $menu-width; | ||
9 | } | ||
10 | |||
4 | menu { | 11 | menu { |
5 | background-color: $black-background; | 12 | background-color: $black-background; |
6 | margin: 0; | 13 | margin: 0; |
@@ -11,6 +18,13 @@ menu { | |||
11 | overflow: hidden; | 18 | overflow: hidden; |
12 | z-index: 1000; | 19 | z-index: 1000; |
13 | color: $menu-color; | 20 | color: $menu-color; |
21 | overflow-y: auto; | ||
22 | display: flex; | ||
23 | flex-direction: column; | ||
24 | |||
25 | .top-menu { | ||
26 | flex-grow: 1; | ||
27 | } | ||
14 | 28 | ||
15 | .logged-in-block { | 29 | .logged-in-block { |
16 | height: 100px; | 30 | height: 100px; |
@@ -100,7 +114,7 @@ menu { | |||
100 | a { | 114 | a { |
101 | display: flex; | 115 | display: flex; |
102 | align-items: center; | 116 | align-items: center; |
103 | padding-left: 26px; | 117 | padding-left: $menu-left-padding; |
104 | color: $menu-color; | 118 | color: $menu-color; |
105 | cursor: pointer; | 119 | cursor: pointer; |
106 | height: 40px; | 120 | height: 40px; |
@@ -155,4 +169,35 @@ menu { | |||
155 | } | 169 | } |
156 | } | 170 | } |
157 | } | 171 | } |
172 | |||
173 | .footer { | ||
174 | margin-bottom: 15px; | ||
175 | padding-left: $menu-left-padding; | ||
176 | |||
177 | .language { | ||
178 | display: inline-block; | ||
179 | color: $menu-bottom-color; | ||
180 | cursor: pointer; | ||
181 | font-size: 12px; | ||
182 | font-weight: $font-semibold; | ||
183 | |||
184 | .icon { | ||
185 | @include icon(28px); | ||
186 | opacity: 0.9; | ||
187 | |||
188 | &.icon-language { | ||
189 | position: relative; | ||
190 | top: -1px; | ||
191 | width: 28px; | ||
192 | height: 24px; | ||
193 | |||
194 | background-image: url('../../assets/images/menu/language.png'); | ||
195 | } | ||
196 | |||
197 | &:hover { | ||
198 | opacity: 1; | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | } | ||
158 | } | 203 | } |
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts index c0aea89b3..dded6b4d5 100644 --- a/client/src/app/menu/menu.component.ts +++ b/client/src/app/menu/menu.component.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit, ViewChild } from '@angular/core' |
2 | import { Router } from '@angular/router' | ||
3 | import { UserRight } from '../../../../shared/models/users/user-right.enum' | 2 | import { UserRight } from '../../../../shared/models/users/user-right.enum' |
4 | import { AuthService, AuthStatus, RedirectService, ServerService } from '../core' | 3 | import { AuthService, AuthStatus, RedirectService, ServerService } from '../core' |
5 | import { User } from '../shared/users/user.model' | 4 | import { User } from '../shared/users/user.model' |
5 | import { LanguageChooserComponent } from '@app/menu/language-chooser.component' | ||
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-menu', | 8 | selector: 'my-menu', |
@@ -10,6 +10,8 @@ import { User } from '../shared/users/user.model' | |||
10 | styleUrls: [ './menu.component.scss' ] | 10 | styleUrls: [ './menu.component.scss' ] |
11 | }) | 11 | }) |
12 | export class MenuComponent implements OnInit { | 12 | export class MenuComponent implements OnInit { |
13 | @ViewChild('languageChooserModal') languageChooserModal: LanguageChooserComponent | ||
14 | |||
13 | user: User | 15 | user: User |
14 | isLoggedIn: boolean | 16 | isLoggedIn: boolean |
15 | userHasAdminAccess = false | 17 | userHasAdminAccess = false |
@@ -90,6 +92,10 @@ export class MenuComponent implements OnInit { | |||
90 | this.redirectService.redirectToHomepage() | 92 | this.redirectService.redirectToHomepage() |
91 | } | 93 | } |
92 | 94 | ||
95 | openLanguageChooser () { | ||
96 | this.languageChooserModal.show() | ||
97 | } | ||
98 | |||
93 | private computeIsUserHasAdminAccess () { | 99 | private computeIsUserHasAdminAccess () { |
94 | const right = this.getFirstAdminRightAvailable() | 100 | const right = this.getFirstAdminRightAvailable() |
95 | 101 | ||
diff --git a/client/src/assets/images/menu/language.png b/client/src/assets/images/menu/language.png new file mode 100644 index 000000000..60e6fec00 --- /dev/null +++ b/client/src/assets/images/menu/language.png | |||
Binary files differ | |||
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index dae0c52c2..96602dc38 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -288,7 +288,7 @@ table { | |||
288 | 288 | ||
289 | // On small screen, menu is absolute | 289 | // On small screen, menu is absolute |
290 | @media screen and (max-width: 600px) { | 290 | @media screen and (max-width: 600px) { |
291 | .title-menu-left { | 291 | .menu-wrapper { |
292 | width: 100% !important; | 292 | width: 100% !important; |
293 | position: absolute !important; | 293 | position: absolute !important; |
294 | z-index: 10000; | 294 | z-index: 10000; |
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index 092f8ed24..f1f755126 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -22,7 +22,9 @@ $header-border-color: #e9eff6; | |||
22 | $search-input-width: 375px; | 22 | $search-input-width: 375px; |
23 | 23 | ||
24 | $menu-color: #fff; | 24 | $menu-color: #fff; |
25 | $menu-bottom-color: #C6C6C6; | ||
25 | $menu-width: 240px; | 26 | $menu-width: 240px; |
27 | $menu-left-padding: 26px; | ||
26 | 28 | ||
27 | $footer-height: 30px; | 29 | $footer-height: 30px; |
28 | $footer-margin: 30px; | 30 | $footer-margin: 30px; |