diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-03-11 19:38:17 +0100 |
---|---|---|
committer | Rigel Kent <sendmemail@rigelk.eu> | 2020-03-11 19:38:17 +0100 |
commit | 45e0d6697c107d77dce73d8e354867dc1959741d (patch) | |
tree | 6acff1e8fdc59ed396a3da4439461d4a475ee8b5 /client | |
parent | 111fdc267b36201cf1be1fdf91017005102b4a5e (diff) | |
download | PeerTube-45e0d6697c107d77dce73d8e354867dc1959741d.tar.gz PeerTube-45e0d6697c107d77dce73d8e354867dc1959741d.tar.zst PeerTube-45e0d6697c107d77dce73d8e354867dc1959741d.zip |
Properly scroll to anchors in links, especially in admin config
Diffstat (limited to 'client')
7 files changed, 62 insertions, 17 deletions
diff --git a/client/src/app/+about/about-instance/about-instance.component.html b/client/src/app/+about/about-instance/about-instance.component.html index 043f63354..1df1ef2ad 100644 --- a/client/src/app/+about/about-instance/about-instance.component.html +++ b/client/src/app/+about/about-instance/about-instance.component.html | |||
@@ -96,9 +96,8 @@ | |||
96 | </div> | 96 | </div> |
97 | 97 | ||
98 | <div class="col"> | 98 | <div class="col"> |
99 | <div id="statistics" i18n class="middle-title"> | 99 | <div class="anchor" id="statistics"></div> |
100 | STATISTICS | 100 | <div i18n class="middle-title">STATISTICS</div> |
101 | </div> | ||
102 | <my-instance-statistics></my-instance-statistics> | 101 | <my-instance-statistics></my-instance-statistics> |
103 | </div> | 102 | </div> |
104 | </div> | 103 | </div> |
diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts index c8c156105..e1809d7b7 100644 --- a/client/src/app/+about/about-instance/about-instance.component.ts +++ b/client/src/app/+about/about-instance/about-instance.component.ts | |||
@@ -1,17 +1,18 @@ | |||
1 | import { Component, OnInit, ViewChild } from '@angular/core' | 1 | import { Component, OnInit, ViewChild, AfterViewChecked } from '@angular/core' |
2 | import { Notifier, ServerService } from '@app/core' | 2 | import { Notifier, ServerService } from '@app/core' |
3 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' | 3 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' |
4 | import { InstanceService } from '@app/shared/instance/instance.service' | 4 | import { InstanceService } from '@app/shared/instance/instance.service' |
5 | import { ServerConfig } from '@shared/models' | 5 | import { ServerConfig } from '@shared/models' |
6 | import { ActivatedRoute } from '@angular/router' | 6 | import { ActivatedRoute } from '@angular/router' |
7 | import { ResolverData } from './about-instance.resolver' | 7 | import { ResolverData } from './about-instance.resolver' |
8 | import { ViewportScroller } from '@angular/common' | ||
8 | 9 | ||
9 | @Component({ | 10 | @Component({ |
10 | selector: 'my-about-instance', | 11 | selector: 'my-about-instance', |
11 | templateUrl: './about-instance.component.html', | 12 | templateUrl: './about-instance.component.html', |
12 | styleUrls: [ './about-instance.component.scss' ] | 13 | styleUrls: [ './about-instance.component.scss' ] |
13 | }) | 14 | }) |
14 | export class AboutInstanceComponent implements OnInit { | 15 | export class AboutInstanceComponent implements OnInit, AfterViewChecked { |
15 | @ViewChild('contactAdminModal', { static: true }) contactAdminModal: ContactAdminModalComponent | 16 | @ViewChild('contactAdminModal', { static: true }) contactAdminModal: ContactAdminModalComponent |
16 | 17 | ||
17 | shortDescription = '' | 18 | shortDescription = '' |
@@ -35,8 +36,8 @@ export class AboutInstanceComponent implements OnInit { | |||
35 | serverConfig: ServerConfig | 36 | serverConfig: ServerConfig |
36 | 37 | ||
37 | constructor ( | 38 | constructor ( |
39 | private viewportScroller: ViewportScroller, | ||
38 | private route: ActivatedRoute, | 40 | private route: ActivatedRoute, |
39 | private notifier: Notifier, | ||
40 | private serverService: ServerService, | 41 | private serverService: ServerService, |
41 | private instanceService: InstanceService | 42 | private instanceService: InstanceService |
42 | ) {} | 43 | ) {} |
@@ -72,6 +73,10 @@ export class AboutInstanceComponent implements OnInit { | |||
72 | this.html = await this.instanceService.buildHtml(about) | 73 | this.html = await this.instanceService.buildHtml(about) |
73 | } | 74 | } |
74 | 75 | ||
76 | ngAfterViewChecked () { | ||
77 | if (window.location.hash) this.viewportScroller.scrollToAnchor(window.location.hash.replace('#', '')) | ||
78 | } | ||
79 | |||
75 | openContactModal () { | 80 | openContactModal () { |
76 | return this.contactAdminModal.show() | 81 | return this.contactAdminModal.show() |
77 | } | 82 | } |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index be89d8294..b3b4f7728 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -1,8 +1,8 @@ | |||
1 | <form role="form" [formGroup]="form"> | 1 | <form role="form" [formGroup]="form"> |
2 | 2 | ||
3 | <ngb-tabset class="root-tabset bootstrap"> | 3 | <ngb-tabset #tabs class="root-tabset bootstrap"> |
4 | 4 | ||
5 | <ngb-tab i18n-title title="Instance information"> | 5 | <ngb-tab id="instance-information" i18n-title title="Instance information"> |
6 | <ng-template ngbTabContent> | 6 | <ng-template ngbTabContent> |
7 | 7 | ||
8 | <ng-container formGroupName="instance"> | 8 | <ng-container formGroupName="instance"> |
@@ -210,7 +210,7 @@ | |||
210 | 210 | ||
211 | <div class="form-group"> | 211 | <div class="form-group"> |
212 | <label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label> | 212 | <label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label> |
213 | <div i18n class="label-small-info">2vCore 2GB RAM/or directly the link to the server you rent etc</div> | 213 | <div i18n class="label-small-info">i.e. 2vCore 2GB RAM, a direct the link to the server you rent, etc.</div> |
214 | 214 | ||
215 | <my-markdown-textarea | 215 | <my-markdown-textarea |
216 | name="instanceHardwareInformation" formControlName="hardwareInformation" textareaWidth="500px" textareaHeight="75px" [previewColumn]="true" | 216 | name="instanceHardwareInformation" formControlName="hardwareInformation" textareaWidth="500px" textareaHeight="75px" [previewColumn]="true" |
@@ -227,14 +227,14 @@ | |||
227 | </ng-template> | 227 | </ng-template> |
228 | </ngb-tab> | 228 | </ngb-tab> |
229 | 229 | ||
230 | <ngb-tab i18n-title title="Basic configuration"> | 230 | <ngb-tab id="basic-configuration" i18n-title title="Basic configuration"> |
231 | <ng-template ngbTabContent> | 231 | <ng-template ngbTabContent> |
232 | 232 | ||
233 | <div class="form-row mt-5"> <!-- appearance grid --> | 233 | <div class="form-row mt-5"> <!-- appearance grid --> |
234 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 234 | <div class="form-group col-12 col-lg-4 col-xl-3"> |
235 | <div i18n class="inner-form-title">APPEARANCE</div> | 235 | <div i18n class="inner-form-title">APPEARANCE</div> |
236 | <div i18n class="inner-for-description"> | 236 | <div i18n class="inner-for-description"> |
237 | Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes. | 237 | Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or <a routerLink="/admin/config/edit-custom" fragment="customizations" (click)="gotoAnchor()">add slight customizations</a>. |
238 | </div> | 238 | </div> |
239 | </div> | 239 | </div> |
240 | 240 | ||
@@ -391,6 +391,9 @@ | |||
391 | <div class="form-row mt-4"> <!-- federation grid --> | 391 | <div class="form-row mt-4"> <!-- federation grid --> |
392 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 392 | <div class="form-group col-12 col-lg-4 col-xl-3"> |
393 | <div i18n class="inner-form-title">FEDERATION</div> | 393 | <div i18n class="inner-form-title">FEDERATION</div> |
394 | <div i18n class="inner-form-description"> | ||
395 | Manage <a routerLink="/admin/follows">relations</a> with other instances. | ||
396 | </div> | ||
394 | </div> | 397 | </div> |
395 | 398 | ||
396 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 399 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> |
@@ -489,7 +492,7 @@ | |||
489 | </ng-template> | 492 | </ng-template> |
490 | </ngb-tab> | 493 | </ngb-tab> |
491 | 494 | ||
492 | <ngb-tab i18n-title title="Services"> | 495 | <ngb-tab id="services" i18n-title title="Services"> |
493 | <ng-template ngbTabContent> | 496 | <ng-template ngbTabContent> |
494 | 497 | ||
495 | <div class="form-row mt-5"> <!-- twitter grid --> | 498 | <div class="form-row mt-5"> <!-- twitter grid --> |
@@ -542,7 +545,7 @@ | |||
542 | </ng-template> | 545 | </ng-template> |
543 | </ngb-tab> | 546 | </ngb-tab> |
544 | 547 | ||
545 | <ngb-tab i18n-title title="Advanced configuration"> | 548 | <ngb-tab id="advanced-configuration" i18n-title title="Advanced configuration"> |
546 | <ng-template ngbTabContent> | 549 | <ng-template ngbTabContent> |
547 | 550 | ||
548 | <div class="form-row mt-5"> <!-- transcoding grid --> | 551 | <div class="form-row mt-5"> <!-- transcoding grid --> |
@@ -718,6 +721,7 @@ | |||
718 | 721 | ||
719 | <div class="form-row mt-4"> <!-- cache grid --> | 722 | <div class="form-row mt-4"> <!-- cache grid --> |
720 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 723 | <div class="form-group col-12 col-lg-4 col-xl-3"> |
724 | <div class="anchor" id="customizations"></div> <!-- customizations anchor --> | ||
721 | <div i18n class="inner-form-title">CUSTOMIZATIONS</div> | 725 | <div i18n class="inner-form-title">CUSTOMIZATIONS</div> |
722 | <div i18n class="inner-form-description"> | 726 | <div i18n class="inner-form-description"> |
723 | Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill. | 727 | Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill. |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index c88e81c01..c3eac68bb 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit, AfterViewChecked, ViewChild } from '@angular/core' |
2 | import { ConfigService } from '@app/+admin/config/shared/config.service' | 2 | import { ConfigService } from '@app/+admin/config/shared/config.service' |
3 | import { ServerService } from '@app/core/server/server.service' | 3 | import { ServerService } from '@app/core/server/server.service' |
4 | import { CustomConfigValidatorsService, FormReactive, UserValidatorsService } from '@app/shared' | 4 | import { CustomConfigValidatorsService, FormReactive, UserValidatorsService } from '@app/shared' |
@@ -9,13 +9,18 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val | |||
9 | import { SelectItem } from 'primeng/api' | 9 | import { SelectItem } from 'primeng/api' |
10 | import { forkJoin } from 'rxjs' | 10 | import { forkJoin } from 'rxjs' |
11 | import { ServerConfig } from '@shared/models' | 11 | import { ServerConfig } from '@shared/models' |
12 | import { ViewportScroller } from '@angular/common' | ||
13 | import { NgbTabset } from '@ng-bootstrap/ng-bootstrap' | ||
12 | 14 | ||
13 | @Component({ | 15 | @Component({ |
14 | selector: 'my-edit-custom-config', | 16 | selector: 'my-edit-custom-config', |
15 | templateUrl: './edit-custom-config.component.html', | 17 | templateUrl: './edit-custom-config.component.html', |
16 | styleUrls: [ './edit-custom-config.component.scss' ] | 18 | styleUrls: [ './edit-custom-config.component.scss' ] |
17 | }) | 19 | }) |
18 | export class EditCustomConfigComponent extends FormReactive implements OnInit { | 20 | export class EditCustomConfigComponent extends FormReactive implements OnInit, AfterViewChecked { |
21 | @ViewChild('tabs') private tabs: NgbTabset | ||
22 | |||
23 | initDone = false | ||
19 | customConfig: CustomConfig | 24 | customConfig: CustomConfig |
20 | 25 | ||
21 | resolutions: { id: string, label: string, description?: string }[] = [] | 26 | resolutions: { id: string, label: string, description?: string }[] = [] |
@@ -27,6 +32,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
27 | private serverConfig: ServerConfig | 32 | private serverConfig: ServerConfig |
28 | 33 | ||
29 | constructor ( | 34 | constructor ( |
35 | private viewportScroller: ViewportScroller, | ||
30 | protected formValidatorService: FormValidatorService, | 36 | protected formValidatorService: FormValidatorService, |
31 | private customConfigValidatorsService: CustomConfigValidatorsService, | 37 | private customConfigValidatorsService: CustomConfigValidatorsService, |
32 | private userValidatorsService: UserValidatorsService, | 38 | private userValidatorsService: UserValidatorsService, |
@@ -226,6 +232,13 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
226 | this.checkTranscodingFields() | 232 | this.checkTranscodingFields() |
227 | } | 233 | } |
228 | 234 | ||
235 | ngAfterViewChecked () { | ||
236 | if (!this.initDone) { | ||
237 | this.initDone = true | ||
238 | this.gotoAnchor() | ||
239 | } | ||
240 | } | ||
241 | |||
229 | isTranscodingEnabled () { | 242 | isTranscodingEnabled () { |
230 | return this.form.value['transcoding']['enabled'] === true | 243 | return this.form.value['transcoding']['enabled'] === true |
231 | } | 244 | } |
@@ -272,6 +285,18 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
272 | return this.i18n('No category') | 285 | return this.i18n('No category') |
273 | } | 286 | } |
274 | 287 | ||
288 | gotoAnchor () { | ||
289 | const hashToTab = { | ||
290 | 'customizations': 'advanced-configuration' | ||
291 | } | ||
292 | const hash = window.location.hash.replace('#', '') | ||
293 | |||
294 | if (hash && Object.keys(hashToTab).includes(hash)) { | ||
295 | this.tabs.select(hashToTab[hash]) | ||
296 | setTimeout(() => this.viewportScroller.scrollToAnchor(hash), 100) | ||
297 | } | ||
298 | } | ||
299 | |||
275 | private updateForm () { | 300 | private updateForm () { |
276 | this.form.patchValue(this.customConfig) | 301 | this.form.patchValue(this.customConfig) |
277 | } | 302 | } |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index 164afb4ea..87296bc19 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | <div class="form-row mt-5"> <!-- notifications grid --> | 35 | <div class="form-row mt-5"> <!-- notifications grid --> |
36 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 36 | <div class="form-group col-12 col-lg-4 col-xl-3"> |
37 | <div class="anchor" id="notifications"></div> <!-- notifications anchor --> | ||
37 | <div i18n class="account-title">NOTIFICATIONS</div> | 38 | <div i18n class="account-title">NOTIFICATIONS</div> |
38 | </div> | 39 | </div> |
39 | 40 | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts index e314cdbea..ada98401c 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts | |||
@@ -1,17 +1,18 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit, AfterViewChecked } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { BytesPipe } from 'ngx-pipes' | 3 | import { BytesPipe } from 'ngx-pipes' |
4 | import { AuthService } from '../../core' | 4 | import { AuthService } from '../../core' |
5 | import { User } from '../../shared' | 5 | import { User } from '../../shared' |
6 | import { UserService } from '../../shared/users' | 6 | import { UserService } from '../../shared/users' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { ViewportScroller } from '@angular/common' | ||
8 | 9 | ||
9 | @Component({ | 10 | @Component({ |
10 | selector: 'my-account-settings', | 11 | selector: 'my-account-settings', |
11 | templateUrl: './my-account-settings.component.html', | 12 | templateUrl: './my-account-settings.component.html', |
12 | styleUrls: [ './my-account-settings.component.scss' ] | 13 | styleUrls: [ './my-account-settings.component.scss' ] |
13 | }) | 14 | }) |
14 | export class MyAccountSettingsComponent implements OnInit { | 15 | export class MyAccountSettingsComponent implements OnInit, AfterViewChecked { |
15 | user: User = null | 16 | user: User = null |
16 | 17 | ||
17 | userVideoQuota = '0' | 18 | userVideoQuota = '0' |
@@ -21,6 +22,7 @@ export class MyAccountSettingsComponent implements OnInit { | |||
21 | userVideoQuotaUsedDaily = 0 | 22 | userVideoQuotaUsedDaily = 0 |
22 | 23 | ||
23 | constructor ( | 24 | constructor ( |
25 | private viewportScroller: ViewportScroller, | ||
24 | private userService: UserService, | 26 | private userService: UserService, |
25 | private authService: AuthService, | 27 | private authService: AuthService, |
26 | private notifier: Notifier, | 28 | private notifier: Notifier, |
@@ -57,6 +59,10 @@ export class MyAccountSettingsComponent implements OnInit { | |||
57 | }) | 59 | }) |
58 | } | 60 | } |
59 | 61 | ||
62 | ngAfterViewChecked () { | ||
63 | if (window.location.hash) this.viewportScroller.scrollToAnchor(window.location.hash.replace('#', '')) | ||
64 | } | ||
65 | |||
60 | onAvatarChange (formData: FormData) { | 66 | onAvatarChange (formData: FormData) { |
61 | this.userService.changeAvatar(formData) | 67 | this.userService.changeAvatar(formData) |
62 | .subscribe( | 68 | .subscribe( |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index f76a82243..89957704b 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -246,6 +246,11 @@ table { | |||
246 | } | 246 | } |
247 | } | 247 | } |
248 | 248 | ||
249 | .anchor { | ||
250 | position: relative; | ||
251 | top: #{-($header-height + 20px)}; | ||
252 | } | ||
253 | |||
249 | @media screen and (max-width: #{map-get($grid-breakpoints, xxl)}) { | 254 | @media screen and (max-width: #{map-get($grid-breakpoints, xxl)}) { |
250 | .main-col { | 255 | .main-col { |
251 | &.expanded { | 256 | &.expanded { |