aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/menu
diff options
context:
space:
mode:
authorKim <1877318+kimsible@users.noreply.github.com>2020-08-17 10:13:31 +0200
committerGitHub <noreply@github.com>2020-08-17 10:13:31 +0200
commit30d55e75cae1adec3fc43c84691975bf8b97db34 (patch)
tree74df7fabda72d88b60d6d8d20ba9cd95d1cf4858 /client/src/app/menu
parent28fbb88f93859a7f6bbf124cb8df1e1a37fd1285 (diff)
downloadPeerTube-30d55e75cae1adec3fc43c84691975bf8b97db34.tar.gz
PeerTube-30d55e75cae1adec3fc43c84691975bf8b97db34.tar.zst
PeerTube-30d55e75cae1adec3fc43c84691975bf8b97db34.zip
Add restore scroll position on user-dropdown anchors links and scroll to top on active sub-menu links (#3066)
* Add restore scroll position on router same url * Remove settings top anchor * Add scrollToTop on active links fixed sub-menu * Add restore scroll position on notification avatar links * Toggle menu and close pophover when click on active dropdown menu-left link * Add onSameUrlRestoreScrollPosition on user dropdown channels link * Same behavior scrollTop and scroll to anchor everywhere Co-authored-by: kimsible <kimsible@users.noreply.github.com>
Diffstat (limited to 'client/src/app/menu')
-rw-r--r--client/src/app/menu/avatar-notification.component.html3
-rw-r--r--client/src/app/menu/avatar-notification.component.ts7
-rw-r--r--client/src/app/menu/menu.component.html18
-rw-r--r--client/src/app/menu/menu.component.ts33
4 files changed, 50 insertions, 11 deletions
diff --git a/client/src/app/menu/avatar-notification.component.html b/client/src/app/menu/avatar-notification.component.html
index 7999b3346..b24bd0309 100644
--- a/client/src/app/menu/avatar-notification.component.html
+++ b/client/src/app/menu/avatar-notification.component.html
@@ -21,6 +21,7 @@
21 <a 21 <a
22 i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog" 22 i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog"
23 routerLink="/my-account/settings" fragment="notifications" 23 routerLink="/my-account/settings" fragment="notifications"
24 #settingsNotifications (click)="onNavigate(settingsNotifications)"
24 ></a> 25 ></a>
25 </div> 26 </div>
26 </div> 27 </div>
@@ -34,7 +35,7 @@
34 [markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()" 35 [markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
35 ></my-user-notifications> 36 ></my-user-notifications>
36 37
37 <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications"> 38 <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)">
38 <my-global-icon class="mr-1" iconName="inbox-full" aria-hidden="true"></my-global-icon> 39 <my-global-icon class="mr-1" iconName="inbox-full" aria-hidden="true"></my-global-icon>
39 <span i18n>See all your notifications</span> 40 <span i18n>See all your notifications</span>
40 </a> 41 </a>
diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts
index 9a64faa6a..8b9955069 100644
--- a/client/src/app/menu/avatar-notification.component.ts
+++ b/client/src/app/menu/avatar-notification.component.ts
@@ -1,6 +1,6 @@
1import { Subject, Subscription } from 'rxjs' 1import { Subject, Subscription } from 'rxjs'
2import { filter } from 'rxjs/operators' 2import { filter } from 'rxjs/operators'
3import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core' 3import { Component, EventEmitter, Input, Output, OnDestroy, OnInit, ViewChild } from '@angular/core'
4import { NavigationEnd, Router } from '@angular/router' 4import { NavigationEnd, Router } from '@angular/router'
5import { Notifier, User, UserNotificationSocket } from '@app/core' 5import { Notifier, User, UserNotificationSocket } from '@app/core'
6import { UserNotificationService } from '@app/shared/shared-main' 6import { UserNotificationService } from '@app/shared/shared-main'
@@ -15,6 +15,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
15 @ViewChild('popover', { static: true }) popover: NgbPopover 15 @ViewChild('popover', { static: true }) popover: NgbPopover
16 16
17 @Input() user: User 17 @Input() user: User
18 @Output() navigate = new EventEmitter<HTMLAnchorElement>()
18 19
19 unreadNotifications = 0 20 unreadNotifications = 0
20 loaded = false 21 loaded = false
@@ -65,6 +66,10 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
65 this.loaded = true 66 this.loaded = true
66 } 67 }
67 68
69 onNavigate (link: HTMLAnchorElement) {
70 this.navigate.emit(link)
71 }
72
68 markAllAsRead () { 73 markAllAsRead () {
69 this.markAllAsReadSubject.next(true) 74 this.markAllAsReadSubject.next(true)
70 } 75 }
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index 7f83a6fb8..2011899d3 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -2,7 +2,7 @@
2 <menu [ngClass]="{ 'logged-in': isLoggedIn }"> 2 <menu [ngClass]="{ 'logged-in': isLoggedIn }">
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 <my-avatar-notification [user]="user"></my-avatar-notification> 5 <my-avatar-notification [user]="user" (navigate)="onSameUrlRestoreScrollPosition($event)"></my-avatar-notification>
6 6
7 <div class="logged-in-info"> 7 <div class="logged-in-info">
8 <a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a> 8 <a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a>
@@ -21,11 +21,13 @@
21 21
22 <div class="dropdown-divider"></div> 22 <div class="dropdown-divider"></div>
23 23
24 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="top"> 24 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
25 #settingsLink (click)="onSameUrlRestoreScrollPosition(settingsLink)">
25 <my-global-icon iconName="user" aria-hidden="true"></my-global-icon> <ng-container i18n>Account settings</ng-container> 26 <my-global-icon iconName="user" aria-hidden="true"></my-global-icon> <ng-container i18n>Account settings</ng-container>
26 </a> 27 </a>
27 28
28 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/video-channels"> 29 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/video-channels"
30 #channelsLink (click)="onSameUrlRestoreScrollPosition(channelsLink)">
29 <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> <ng-container i18n>Channels settings</ng-container> 31 <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> <ng-container i18n>Channels settings</ng-container>
30 </a> 32 </a>
31 33
@@ -37,13 +39,16 @@
37 <span class="ml-auto text-muted">{{ language }}</span> 39 <span class="ml-auto text-muted">{{ language }}</span>
38 </a> 40 </a>
39 41
40 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"> 42 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
43 #settingsLanguagesSubtitles (click)="onSameUrlRestoreScrollPosition(settingsLanguagesSubtitles)">
41 <my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon> 44 <my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon>
42 <span i18n>Videos:</span> 45 <span i18n>Videos:</span>
43 <span class="ml-auto text-muted">{{ videoLanguages.join(', ') }}</span> 46 <span class="ml-auto text-muted">{{ videoLanguages.join(', ') }}</span>
44 </a> 47 </a>
45 48
46 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-sensitive-content-policy"> 49 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
50 fragment="video-sensitive-content-policy" #settingsSensitiveContentPolicy
51 (click)="onSameUrlRestoreScrollPosition(settingsSensitiveContentPolicy)">
47 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy === 'display' }" iconName="sensitive" aria-hidden="true"></my-global-icon> 52 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy === 'display' }" iconName="sensitive" aria-hidden="true"></my-global-icon>
48 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy !== 'display' }" iconName="unsensitive" aria-hidden="true"></my-global-icon> 53 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy !== 'display' }" iconName="unsensitive" aria-hidden="true"></my-global-icon>
49 <span i18n>Sensitive:</span> 54 <span i18n>Sensitive:</span>
@@ -56,7 +61,8 @@
56 <input type="checkbox" [checked]="user.webTorrentEnabled"/><label class="ml-auto" for="switch">Toggle p2p</label> 61 <input type="checkbox" [checked]="user.webTorrentEnabled"/><label class="ml-auto" for="switch">Toggle p2p</label>
57 </a> 62 </a>
58 63
59 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="top"> 64 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
65 #settingsMoreLink (click)="onSameUrlRestoreScrollPosition(settingsMoreLink)">
60 <my-global-icon iconName="more-horizontal" aria-hidden="true"></my-global-icon> <ng-container i18n>More account settings</ng-container> 66 <my-global-icon iconName="more-horizontal" aria-hidden="true"></my-global-icon> <ng-container i18n>More account settings</ng-container>
61 </a> 67 </a>
62 68
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
index 3d6cbda24..f9a0a9f57 100644
--- a/client/src/app/menu/menu.component.ts
+++ b/client/src/app/menu/menu.component.ts
@@ -2,7 +2,8 @@ import { HotkeysService } from 'angular2-hotkeys'
2import * as debug from 'debug' 2import * as debug from 'debug'
3import { switchMap } from 'rxjs/operators' 3import { switchMap } from 'rxjs/operators'
4import { Component, OnInit, ViewChild } from '@angular/core' 4import { Component, OnInit, ViewChild } from '@angular/core'
5import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core' 5import { Router } from '@angular/router'
6import { AuthService, AuthStatus, AuthUser, MenuService, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
6import { LanguageChooserComponent } from '@app/menu/language-chooser.component' 7import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
7import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component' 8import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
8import { ServerConfig, UserRight, VideoConstant } from '@shared/models' 9import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
@@ -43,8 +44,10 @@ export class MenuComponent implements OnInit {
43 private serverService: ServerService, 44 private serverService: ServerService,
44 private redirectService: RedirectService, 45 private redirectService: RedirectService,
45 private hotkeysService: HotkeysService, 46 private hotkeysService: HotkeysService,
46 private screenService: ScreenService 47 private screenService: ScreenService,
47 ) { } 48 private menuService: MenuService,
49 private router: Router
50 ) { }
48 51
49 get isInMobileView () { 52 get isInMobileView () {
50 return this.screenService.isInMobileView() 53 return this.screenService.isInMobileView()
@@ -192,6 +195,30 @@ export class MenuComponent implements OnInit {
192 return this.languages.find(lang => lang.id === localeId).label 195 return this.languages.find(lang => lang.id === localeId).label
193 } 196 }
194 197
198 onSameUrlRestoreScrollPosition (link: HTMLAnchorElement) {
199 const linkURL = link.getAttribute('href')
200 const linkHash = link.getAttribute('fragment')
201
202 // On same url without fragment restore top scroll position
203 if (!linkHash && this.router.url.includes(linkURL)) {
204 window.scrollTo({
205 left: 0,
206 top: 0,
207 behavior: 'smooth'
208 })
209 }
210
211 // On same url with fragment restore anchor scroll position
212 if (linkHash && this.router.url === linkURL) {
213 const anchor = document.getElementById(link.getAttribute('fragment'))
214 anchor.scrollIntoView({ behavior: 'smooth', inline: 'nearest' })
215 }
216
217 if (this.screenService.isInSmallView()) {
218 this.menuService.toggleMenu()
219 }
220 }
221
195 private buildUserLanguages () { 222 private buildUserLanguages () {
196 if (!this.user) { 223 if (!this.user) {
197 this.videoLanguages = [] 224 this.videoLanguages = []