aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/menu
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/menu')
-rw-r--r--client/src/app/menu/avatar-notification.component.html23
-rw-r--r--client/src/app/menu/avatar-notification.component.scss91
-rw-r--r--client/src/app/menu/avatar-notification.component.ts65
-rw-r--r--client/src/app/menu/index.ts2
-rw-r--r--client/src/app/menu/language-chooser.component.html7
-rw-r--r--client/src/app/menu/language-chooser.component.scss7
-rw-r--r--client/src/app/menu/menu.component.html6
-rw-r--r--client/src/app/menu/menu.component.scss17
-rw-r--r--client/src/app/menu/menu.component.ts2
9 files changed, 203 insertions, 17 deletions
diff --git a/client/src/app/menu/avatar-notification.component.html b/client/src/app/menu/avatar-notification.component.html
new file mode 100644
index 000000000..4ef3f0e89
--- /dev/null
+++ b/client/src/app/menu/avatar-notification.component.html
@@ -0,0 +1,23 @@
1<div
2 [ngbPopover]="popContent" autoClose="outside" placement="bottom-left" container="body" popoverClass="popover-notifications"
3 i18n-title title="View your notifications" class="notification-avatar" #popover="ngbPopover"
4>
5 <div *ngIf="unreadNotifications > 0" class="unread-notifications">{{ unreadNotifications }}</div>
6
7 <img [src]="user.accountAvatarUrl" alt="Avatar" />
8</div>
9
10<ng-template #popContent>
11 <div class="notifications-header">
12 <div i18n>Notifications</div>
13
14 <a
15 i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog"
16 routerLink="/my-account/settings" fragment="notifications"
17 ></a>
18 </div>
19
20 <my-user-notifications [ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10"></my-user-notifications>
21
22 <a class="all-notifications" routerLink="/my-account/notifications" i18n>See all your notifications</a>
23</ng-template>
diff --git a/client/src/app/menu/avatar-notification.component.scss b/client/src/app/menu/avatar-notification.component.scss
new file mode 100644
index 000000000..e785db788
--- /dev/null
+++ b/client/src/app/menu/avatar-notification.component.scss
@@ -0,0 +1,91 @@
1@import '_variables';
2@import '_mixins';
3
4/deep/ {
5 .popover-notifications.popover {
6 max-width: none;
7
8 .popover-body {
9 padding: 0;
10 font-size: 14px;
11 font-family: $main-fonts;
12 overflow-y: auto;
13 max-height: 500px;
14 width: 400px;
15 box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30);
16
17 .notifications-header {
18 display: flex;
19 justify-content: space-between;
20
21 background-color: rgba(0, 0, 0, 0.10);
22 align-items: center;
23 padding: 0 10px;
24 font-size: 16px;
25 height: 50px;
26
27 a {
28 @include disable-default-a-behaviour;
29
30 color: rgba(20, 20, 20, 0.5);
31
32 &:hover {
33 color: rgba(20, 20, 20, 0.8);
34 }
35 }
36 }
37
38 .all-notifications {
39 display: flex;
40 align-items: center;
41 justify-content: center;
42 font-weight: $font-semibold;
43 color: var(--mainForegroundColor);
44 padding: 7px 0;
45 }
46 }
47 }
48}
49
50.notification-avatar {
51 cursor: pointer;
52 position: relative;
53
54 img,
55 .unread-notifications {
56 margin-left: 20px;
57 }
58
59 img {
60 @include avatar(34px);
61
62 margin-right: 10px;
63 }
64
65 .unread-notifications {
66 position: absolute;
67 top: -5px;
68 left: -5px;
69
70 display: flex;
71 align-items: center;
72 justify-content: center;
73
74 background-color: var(--mainColor);
75 color: var(#fff);
76 font-size: 10px;
77 font-weight: $font-semibold;
78
79 border-radius: 15px;
80 width: 15px;
81 height: 15px;
82 }
83}
84
85@media screen and (max-width: $mobile-view) {
86 /deep/ {
87 .popover-notifications.popover .popover-body {
88 width: 400px;
89 }
90 }
91}
diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts
new file mode 100644
index 000000000..f1af08096
--- /dev/null
+++ b/client/src/app/menu/avatar-notification.component.ts
@@ -0,0 +1,65 @@
1import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'
2import { User } from '../shared/users/user.model'
3import { UserNotificationService } from '@app/shared/users/user-notification.service'
4import { Subscription } from 'rxjs'
5import { Notifier, UserNotificationSocket } from '@app/core'
6import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
7import { NavigationEnd, Router } from '@angular/router'
8import { filter } from 'rxjs/operators'
9
10@Component({
11 selector: 'my-avatar-notification',
12 templateUrl: './avatar-notification.component.html',
13 styleUrls: [ './avatar-notification.component.scss' ]
14})
15export class AvatarNotificationComponent implements OnInit, OnDestroy {
16 @ViewChild('popover') popover: NgbPopover
17 @Input() user: User
18
19 unreadNotifications = 0
20
21 private notificationSub: Subscription
22 private routeSub: Subscription
23
24 constructor (
25 private userNotificationService: UserNotificationService,
26 private userNotificationSocket: UserNotificationSocket,
27 private notifier: Notifier,
28 private router: Router
29 ) {}
30
31 ngOnInit () {
32 this.userNotificationService.countUnreadNotifications()
33 .subscribe(
34 result => {
35 this.unreadNotifications = Math.min(result, 99) // Limit number to 99
36 this.subscribeToNotifications()
37 },
38
39 err => this.notifier.error(err.message)
40 )
41
42 this.routeSub = this.router.events
43 .pipe(filter(event => event instanceof NavigationEnd))
44 .subscribe(() => this.closePopover())
45 }
46
47 ngOnDestroy () {
48 if (this.notificationSub) this.notificationSub.unsubscribe()
49 if (this.routeSub) this.routeSub.unsubscribe()
50 }
51
52 closePopover () {
53 this.popover.close()
54 }
55
56 private subscribeToNotifications () {
57 this.notificationSub = this.userNotificationSocket.getMyNotificationsSocket()
58 .subscribe(data => {
59 if (data.type === 'new') return this.unreadNotifications++
60 if (data.type === 'read') return this.unreadNotifications--
61 if (data.type === 'read-all') return this.unreadNotifications = 0
62 })
63 }
64
65}
diff --git a/client/src/app/menu/index.ts b/client/src/app/menu/index.ts
index 421271c12..39dbde750 100644
--- a/client/src/app/menu/index.ts
+++ b/client/src/app/menu/index.ts
@@ -1 +1,3 @@
1export * from './language-chooser.component'
2export * from './avatar-notification.component'
1export * from './menu.component' 3export * from './menu.component'
diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html
index c37bf2826..a62b33dda 100644
--- a/client/src/app/menu/language-chooser.component.html
+++ b/client/src/app/menu/language-chooser.component.html
@@ -1,9 +1,14 @@
1<ng-template #modal let-hide="close"> 1<ng-template #modal let-hide="close">
2 <div class="modal-header"> 2 <div class="modal-header">
3 <h4 i18n class="modal-title">Change the language</h4> 3 <h4 i18n class="modal-title">Change the language</h4>
4 <span class="close" aria-label="Close" role="button" (click)="hide()"></span> 4 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
5 </div> 5 </div>
6 6
7
8 <a i18n class="help-to-translate" target="_blank" rel="noreferrer noopener" href="https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/translation.md">
9 Help to translate PeerTube!
10 </a>
11
7 <div class="modal-body"> 12 <div class="modal-body">
8 <a *ngFor="let lang of languages" [href]="buildLanguageLink(lang)">{{ lang.label }}</a> 13 <a *ngFor="let lang of languages" [href]="buildLanguageLink(lang)">{{ lang.label }}</a>
9 </div> 14 </div>
diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss
index 944e86f46..72deb3952 100644
--- a/client/src/app/menu/language-chooser.component.scss
+++ b/client/src/app/menu/language-chooser.component.scss
@@ -1,6 +1,11 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.help-to-translate {
5 @include peertube-button-link;
6 @include orange-button;
7}
8
4.modal-body { 9.modal-body {
5 text-align: center; 10 text-align: center;
6 11
@@ -9,4 +14,4 @@
9 font-size: 16px; 14 font-size: 16px;
10 margin: 15px; 15 margin: 15px;
11 } 16 }
12} \ No newline at end of file 17}
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index e04bdf3d6..aa5bfa9c9 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -2,9 +2,7 @@
2 <menu> 2 <menu>
3 <div class="top-menu"> 3 <div class="top-menu">
4 <div *ngIf="isLoggedIn" class="logged-in-block"> 4 <div *ngIf="isLoggedIn" class="logged-in-block">
5 <a routerLink="/my-account/settings"> 5 <my-avatar-notification [user]="user"></my-avatar-notification>
6 <img [src]="user.accountAvatarUrl" alt="Avatar" />
7 </a>
8 6
9 <div class="logged-in-info"> 7 <div class="logged-in-info">
10 <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a> 8 <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a>
@@ -97,4 +95,4 @@
97 </menu> 95 </menu>
98</div> 96</div>
99 97
100<my-language-chooser #languageChooserModal></my-language-chooser> \ No newline at end of file 98<my-language-chooser #languageChooserModal></my-language-chooser>
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index a842765ba..f30b89413 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -16,7 +16,7 @@ menu {
16 height: 100%; 16 height: 100%;
17 white-space: nowrap; 17 white-space: nowrap;
18 text-overflow: ellipsis; 18 text-overflow: ellipsis;
19 overflow: hidden; 19 overflow: auto;
20 color: var(--menuForegroundColor); 20 color: var(--menuForegroundColor);
21 display: flex; 21 display: flex;
22 flex-direction: column; 22 flex-direction: column;
@@ -39,13 +39,6 @@ menu {
39 justify-content: center; 39 justify-content: center;
40 margin-bottom: 35px; 40 margin-bottom: 35px;
41 41
42 img {
43 @include avatar(34px);
44
45 margin-left: 20px;
46 margin-right: 10px;
47 }
48
49 .logged-in-info { 42 .logged-in-info {
50 flex-grow: 1; 43 flex-grow: 1;
51 44
@@ -131,10 +124,14 @@ menu {
131 transition: background-color .1s ease-in-out; 124 transition: background-color .1s ease-in-out;
132 @include disable-default-a-behaviour; 125 @include disable-default-a-behaviour;
133 126
134 &:hover, &.focus-visible { 127 &.active {
135 background-color: rgba(255, 255, 255, 0.15); 128 background-color: rgba(255, 255, 255, 0.15);
136 } 129 }
137 130
131 &:hover, &.focus-visible {
132 background-color: rgba(255, 255, 255, 0.10);
133 }
134
138 .icon { 135 .icon {
139 @include icon(22px); 136 @include icon(22px);
140 137
@@ -246,7 +243,7 @@ menu {
246 } 243 }
247} 244}
248 245
249@media screen and (max-width: 400px) { 246@media screen and (max-width: $mobile-view) {
250 .menu-wrapper { 247 .menu-wrapper {
251 width: 100% !important; 248 width: 100% !important;
252 } 249 }
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
index 95926f5f0..371beb4a5 100644
--- a/client/src/app/menu/menu.component.ts
+++ b/client/src/app/menu/menu.component.ts
@@ -18,7 +18,7 @@ export class MenuComponent implements OnInit {
18 userHasAdminAccess = false 18 userHasAdminAccess = false
19 helpVisible = false 19 helpVisible = false
20 20
21 private routesPerRight = { 21 private routesPerRight: { [ role in UserRight ]?: string } = {
22 [UserRight.MANAGE_USERS]: '/admin/users', 22 [UserRight.MANAGE_USERS]: '/admin/users',
23 [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends', 23 [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
24 [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses', 24 [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses',