1
0
Fork 0

small refactor + clipboard copy on anchor click in instance page (#3318)

* Refacto scrollTo top and anchors

* Add on click clipboard copy and notifier to anchors about/instance page

* Fix margin top anchor middle title about page

* Use viewportscroller for scrolltoanchor

* Add  to Link copied notification on instance page

Co-authored-by: kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
Kimsible 2020-11-17 14:04:44 +01:00 committed by GitHub
parent 901c36d5f4
commit f3081d6401
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 117 additions and 41 deletions

View File

@ -23,7 +23,10 @@
<a
*ngIf="html.administrator || maintenanceLifetime || businessModel"
class="anchor-link"
routerLink="/about/instance" fragment="administrators-and-sustainability"
routerLink="/about/instance"
fragment="administrators-and-sustainability"
#anchorLink
(click)="onClickCopyLink(anchorLink)"
>
<h2 i18n class="middle-title">
ADMINISTRATORS & SUSTAINABILITY
@ -32,7 +35,12 @@
<div class="block administrator" *ngIf="html.administrator">
<div class="anchor" id="administrators"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="administrators">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="administrators"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Who we are</h3>
</a>
@ -41,7 +49,12 @@
<div class="block creation-reason" *ngIf="creationReason">
<div class="anchor" id="creation-reason"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="creation-reason">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="creation-reason"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Why we created this instance</h3>
</a>
@ -50,7 +63,12 @@
<div class="block maintenance-lifetime" *ngIf="maintenanceLifetime">
<div class="anchor" id="maintenance-lifetime"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="maintenance-lifetime">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="maintenance-lifetime"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">How long we plan to maintain this instance</h3>
</a>
@ -58,8 +76,13 @@
</div>
<div class="block business-model" *ngIf="businessModel">
<div class="anchor" id="buisiness-model"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="buisiness-model">
<div class="anchor" id="business-model"></div>
<a
class="anchor-link"
routerLink="/about/instance"
fragment="business-model"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">How we will pay for this instance</h3>
</a>
@ -67,7 +90,13 @@
</div>
<div class="anchor" id="information"></div>
<a *ngIf="html.description" class="anchor-link" routerLink="/about/instance" fragment="information">
<a
*ngIf="html.description"
class="anchor-link"
routerLink="/about/instance"
fragment="information"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h2 i18n class="middle-title">
INFORMATION
</h2>
@ -75,7 +104,12 @@
<div class="block description">
<div class="anchor" id="description"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="description">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="description"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Description</h3>
</a>
@ -85,8 +119,11 @@
<div class="anchor" id="moderation"></div>
<a
*ngIf="html.moderationInformation || html.codeOfConduct || html.terms"
class="anchor-link" routerLink="/about/instance" fragment="moderation"
>
class="anchor-link"
routerLink="/about/instance"
fragment="moderation"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h2 i18n class="middle-title">
MODERATION
</h2>
@ -94,7 +131,12 @@
<div class="block moderation-information" *ngIf="html.moderationInformation">
<div class="anchor" id="moderation-information"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="moderation-information">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="moderation-information"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Moderation information</h3>
</a>
@ -103,7 +145,12 @@
<div class="block code-of-conduct" *ngIf="html.codeOfConduct">
<div class="anchor" id="code-of-conduct"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="code-of-conduct">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="code-of-conduct"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Code of conduct</h3>
</a>
@ -112,7 +159,12 @@
<div class="block terms">
<div class="anchor" id="terms"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="terms">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="terms"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Terms</h3>
</a>
@ -120,7 +172,13 @@
</div>
<div class="anchor" id="other-information"></div>
<a *ngIf="html.hardwareInformation" class="anchor-link" routerLink="/about/instance" fragment="other-information">
<a
*ngIf="html.hardwareInformation"
class="anchor-link"
routerLink="/about/instance"
fragment="other-information"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h2 i18n class="middle-title">
OTHER INFORMATION
</h2>
@ -128,7 +186,12 @@
<div class="block hardware-information" *ngIf="html.hardwareInformation">
<div class="anchor" id="hardware-information"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="hardware-information">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="hardware-information"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h3 i18n class="section-title">Hardware information</h3>
</a>
@ -143,7 +206,12 @@
<div class="col">
<div class="anchor" id="statistics"></div>
<a class="anchor-link" routerLink="/about/instance" fragment="statistics">
<a
class="anchor-link"
routerLink="/about/instance"
fragment="statistics"
#anchorLink
(click)="onClickCopyLink(anchorLink)">
<h2 i18n class="middle-title">STATISTICS</h2>
</a>
<my-instance-statistics></my-instance-statistics>

View File

@ -43,12 +43,12 @@
.middle-title {
@include in-content-small-title;
margin-top: 45px;
margin-top: 0;
margin-bottom: 25px;
}
.block {
margin-bottom: 30px;
margin-bottom: 75px;
font-size: 15px;
}

View File

@ -2,7 +2,8 @@ import { ViewportScroller } from '@angular/common'
import { AfterViewChecked, Component, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
import { ServerService } from '@app/core'
import { Notifier } from '@app/core'
import { copyToClipboard } from '../../../assets/player/utils'
import { InstanceService } from '@app/shared/shared-instance'
import { ServerConfig } from '@shared/models'
import { ResolverData } from './about-instance.resolver'
@ -42,6 +43,7 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
constructor (
private viewportScroller: ViewportScroller,
private route: ActivatedRoute,
private notifier: Notifier,
private instanceService: InstanceService
) {}
@ -87,4 +89,10 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
openContactModal () {
return this.contactAdminModal.show()
}
onClickCopyLink (anchor: HTMLAnchorElement) {
const link = anchor.href
copyToClipboard(link)
this.notifier.success(link, $localize `Link copied`)
}
}

View File

@ -121,7 +121,7 @@ export class AppComponent implements OnInit, AfterViewInit {
// scrollToAnchor first to preserve anchor position when using history navigation
if (e.anchor) {
setTimeout(() => {
document.getElementById(e.anchor).scrollIntoView({ behavior: 'smooth', inline: 'nearest' })
this.viewportScroller.scrollToAnchor(e.anchor)
})
return

View File

@ -144,8 +144,12 @@ function sortBy (obj: any[], key1: string, key2?: string) {
})
}
function scrollToTop () {
window.scroll(0, 0)
function scrollToTop (behavior: 'auto' | 'smooth' = 'auto') {
window.scrollTo({
left: 0,
top: 0,
behavior
})
}
function isInViewport (el: HTMLElement) {

View File

@ -3,7 +3,7 @@
<div class="top-menu">
<div *ngIf="isLoggedIn" class="logged-in-block">
<div>
<my-avatar-notification [user]="user" (navigate)="onSameUrlRestoreScrollPosition($event)"></my-avatar-notification>
<my-avatar-notification [user]="user" (navigate)="onActiveLinkScrollToAnchor($event)"></my-avatar-notification>
<div class="logged-in-info">
<a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a>
@ -22,7 +22,8 @@
<div class="dropdown-divider"></div>
<a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/notifications">
<a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/notifications"
#notifications (click)="onActiveLinkScrollToAnchor(notifications)">
<my-global-icon iconName="inbox-full" aria-hidden="true"></my-global-icon> <ng-container i18n>My notifications</ng-container>
</a>
@ -35,7 +36,7 @@
</a>
<a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
#settingsLanguagesSubtitles (click)="onSameUrlRestoreScrollPosition(settingsLanguagesSubtitles)">
#settingsLanguagesSubtitles (click)="onActiveLinkScrollToAnchor(settingsLanguagesSubtitles)">
<my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon>
<span i18n>Videos:</span>
<span class="ml-auto text-muted">{{ videoLanguages.join(', ') }}</span>
@ -43,7 +44,7 @@
<a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
fragment="video-sensitive-content-policy" #settingsSensitiveContentPolicy
(click)="onSameUrlRestoreScrollPosition(settingsSensitiveContentPolicy)">
(click)="onActiveLinkScrollToAnchor(settingsSensitiveContentPolicy)">
<my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy === 'display' }" iconName="sensitive" aria-hidden="true"></my-global-icon>
<my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy !== 'display' }" iconName="unsensitive" aria-hidden="true"></my-global-icon>
<span i18n>Sensitive:</span>
@ -72,12 +73,12 @@
</div>
<div class="logged-in-menu">
<a routerLink="/my-account" routerLinkActive="active" #settingsLink (click)="onSameUrlRestoreScrollPosition(settingsLink)">
<a routerLink="/my-account" routerLinkActive="active" #settingsLink (click)="onActiveLinkScrollToAnchor(settingsLink)">
<my-global-icon iconName="user" aria-hidden="true"></my-global-icon>
<ng-container i18n>My account</ng-container>
</a>
<a routerLink="/my-library" routerLinkActive="active" #libraryLink (click)="onSameUrlRestoreScrollPosition(libraryLink)">
<a routerLink="/my-library" routerLinkActive="active" #libraryLink (click)="onActiveLinkScrollToAnchor(libraryLink)">
<my-global-icon iconName="channel" aria-hidden="true"></my-global-icon>
<ng-container i18n>My library</ng-container>
</a>

View File

@ -1,8 +1,10 @@
import { ViewportScroller } from '@angular/common'
import { HotkeysService } from 'angular2-hotkeys'
import * as debug from 'debug'
import { switchMap } from 'rxjs/operators'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Router } from '@angular/router'
import { scrollToTop } from '@app/helpers'
import { AuthService, AuthStatus, AuthUser, MenuService, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
@ -39,6 +41,7 @@ export class MenuComponent implements OnInit {
}
constructor (
private viewportScroller: ViewportScroller,
private authService: AuthService,
private userService: UserService,
private serverService: ServerService,
@ -199,23 +202,18 @@ export class MenuComponent implements OnInit {
return this.languages.find(lang => lang.id === localeId).label
}
onSameUrlRestoreScrollPosition (link: HTMLAnchorElement) {
onActiveLinkScrollToAnchor (link: HTMLAnchorElement) {
const linkURL = link.getAttribute('href')
const linkHash = link.getAttribute('fragment')
// On same url without fragment restore top scroll position
if (!linkHash && this.router.url.includes(linkURL)) {
window.scrollTo({
left: 0,
top: 0,
behavior: 'smooth'
})
scrollToTop('smooth')
}
// On same url with fragment restore anchor scroll position
if (linkHash && this.router.url === linkURL) {
const anchor = document.getElementById(link.getAttribute('fragment'))
anchor.scrollIntoView({ behavior: 'smooth', inline: 'nearest' })
this.viewportScroller.scrollToAnchor(linkHash)
}
if (this.screenService.isInSmallView()) {

View File

@ -3,6 +3,7 @@ import { filter } from 'rxjs/operators'
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { NavigationEnd, Router } from '@angular/router'
import { MenuService, ScreenService } from '@app/core'
import { scrollToTop } from '@app/helpers'
import { GlobalIconName } from '@app/shared/shared-icons'
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
@ -96,11 +97,7 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
onActiveLinkScrollToTop (link: HTMLAnchorElement) {
if (!this.isBroadcastMessageDisplayed && this.router.url.includes(link.getAttribute('href'))) {
window.scrollTo({
left: 0,
top: 0,
behavior: 'smooth'
})
scrollToTop('smooth')
}
}