diff options
author | Kim <1877318+kimsible@users.noreply.github.com> | 2020-08-17 10:13:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-17 10:13:31 +0200 |
commit | 30d55e75cae1adec3fc43c84691975bf8b97db34 (patch) | |
tree | 74df7fabda72d88b60d6d8d20ba9cd95d1cf4858 /client/src/app/menu | |
parent | 28fbb88f93859a7f6bbf124cb8df1e1a37fd1285 (diff) | |
download | PeerTube-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.html | 3 | ||||
-rw-r--r-- | client/src/app/menu/avatar-notification.component.ts | 7 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.html | 18 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.ts | 33 |
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 @@ | |||
1 | import { Subject, Subscription } from 'rxjs' | 1 | import { Subject, Subscription } from 'rxjs' |
2 | import { filter } from 'rxjs/operators' | 2 | import { filter } from 'rxjs/operators' |
3 | import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core' | 3 | import { Component, EventEmitter, Input, Output, OnDestroy, OnInit, ViewChild } from '@angular/core' |
4 | import { NavigationEnd, Router } from '@angular/router' | 4 | import { NavigationEnd, Router } from '@angular/router' |
5 | import { Notifier, User, UserNotificationSocket } from '@app/core' | 5 | import { Notifier, User, UserNotificationSocket } from '@app/core' |
6 | import { UserNotificationService } from '@app/shared/shared-main' | 6 | import { 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' | |||
2 | import * as debug from 'debug' | 2 | import * as debug from 'debug' |
3 | import { switchMap } from 'rxjs/operators' | 3 | import { switchMap } from 'rxjs/operators' |
4 | import { Component, OnInit, ViewChild } from '@angular/core' | 4 | import { Component, OnInit, ViewChild } from '@angular/core' |
5 | import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core' | 5 | import { Router } from '@angular/router' |
6 | import { AuthService, AuthStatus, AuthUser, MenuService, RedirectService, ScreenService, ServerService, UserService } from '@app/core' | ||
6 | import { LanguageChooserComponent } from '@app/menu/language-chooser.component' | 7 | import { LanguageChooserComponent } from '@app/menu/language-chooser.component' |
7 | import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component' | 8 | import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component' |
8 | import { ServerConfig, UserRight, VideoConstant } from '@shared/models' | 9 | import { 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 = [] |