diff options
Diffstat (limited to 'overlays/spm/frontend/src/app/app.component.ts')
-rw-r--r-- | overlays/spm/frontend/src/app/app.component.ts | 89 |
1 files changed, 84 insertions, 5 deletions
diff --git a/overlays/spm/frontend/src/app/app.component.ts b/overlays/spm/frontend/src/app/app.component.ts index 7c231203..11c0f772 100644 --- a/overlays/spm/frontend/src/app/app.component.ts +++ b/overlays/spm/frontend/src/app/app.component.ts | |||
@@ -1,6 +1,18 @@ | |||
1 | import { Component, OnInit, OnDestroy } from '@angular/core'; | 1 | import { Component, OnInit, OnDestroy, Inject, Renderer2, RendererFactory2 } from '@angular/core'; |
2 | import { DOCUMENT } from '@angular/common'; | ||
3 | import { MediaMatcher } from '@angular/cdk/layout'; | ||
4 | import { LocalStorage } from 'ngx-webstorage'; | ||
5 | import { BehaviorSubject, Subscription, Subject } from 'rxjs'; | ||
6 | import { Router, RouterEvent, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router'; | ||
7 | import { HttpClient, HttpHeaders } from '@angular/common/http'; | ||
2 | 8 | ||
3 | import { ColorSchemeService } from './color-scheme.service'; | 9 | import { map, filter } from 'rxjs/operators'; |
10 | |||
11 | type ColorScheme = 'dark' | 'light'; | ||
12 | |||
13 | export interface DomainResponse { | ||
14 | domain: string; | ||
15 | } | ||
4 | 16 | ||
5 | @Component({ | 17 | @Component({ |
6 | selector: 'app-root', | 18 | selector: 'app-root', |
@@ -8,14 +20,81 @@ import { ColorSchemeService } from './color-scheme.service'; | |||
8 | styleUrls: ['./app.component.sass'] | 20 | styleUrls: ['./app.component.sass'] |
9 | }) | 21 | }) |
10 | export class AppComponent implements OnInit, OnDestroy { | 22 | export class AppComponent implements OnInit, OnDestroy { |
23 | private renderer: Renderer2; | ||
24 | colorSchemeMatcher: MediaQueryList; | ||
25 | |||
11 | title = 'spm-frontend'; | 26 | title = 'spm-frontend'; |
12 | 27 | ||
13 | constructor(private colorSchemeService: ColorSchemeService) {} | 28 | public activeColorScheme$: BehaviorSubject<ColorScheme> = new BehaviorSubject<ColorScheme>('dark'); |
29 | |||
30 | @LocalStorage('prefers-color-scheme') | ||
31 | public colorSchemeOverride?: ColorScheme; | ||
32 | |||
33 | colorSchemeSubscription?: Subscription; | ||
34 | |||
35 | router: Router; | ||
36 | public routerLoading$: Subject<boolean> = new Subject<boolean>(); | ||
37 | routerEventSubscription?: Subscription; | ||
38 | |||
39 | http: HttpClient; | ||
40 | apiDomain$: Subject<string> = new Subject<string>(); | ||
41 | |||
42 | constructor( rendererFactory: RendererFactory2, | ||
43 | mediaMatcher: MediaMatcher, | ||
44 | @Inject(DOCUMENT) private document: Document, | ||
45 | router: Router, | ||
46 | http: HttpClient, | ||
47 | ) { | ||
48 | this.renderer = rendererFactory.createRenderer(null, null); | ||
49 | this.colorSchemeMatcher = mediaMatcher.matchMedia('(prefers-color-scheme: dark)'); | ||
50 | this.document = document; | ||
51 | |||
52 | this.colorSchemeListener = this.colorSchemeListener.bind(this); | ||
53 | this.colorSchemeMatcher.addEventListener('change', this.colorSchemeListener); | ||
54 | this.activeColorScheme$.next(this.getColorScheme()); | ||
55 | |||
56 | this.router = router; | ||
57 | this.http = http; | ||
58 | } | ||
59 | |||
60 | private colorSchemeListener(event: { matches: boolean; }) { | ||
61 | this.activeColorScheme$.next(this.getColorScheme(event)); | ||
62 | } | ||
63 | |||
64 | private getColorScheme(event?: { matches: boolean; }): ColorScheme { | ||
65 | if (this.colorSchemeOverride) { | ||
66 | return this.colorSchemeOverride; | ||
67 | } else if (event) { | ||
68 | return event.matches ? 'dark' : 'light'; | ||
69 | } else { | ||
70 | return this.colorSchemeMatcher.matches ? 'dark' : 'light'; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | updateColorScheme(scheme: ColorScheme) { | ||
75 | this.colorSchemeOverride = scheme; | ||
76 | this.activeColorScheme$.next(scheme); | ||
77 | } | ||
14 | 78 | ||
15 | ngOnInit() { | 79 | ngOnInit() { |
16 | this.colorSchemeService.init(); | 80 | this.colorSchemeSubscription = this.activeColorScheme$.subscribe(scheme => { this.renderer.setAttribute(this.document.body, 'data-color-scheme', scheme); }); |
81 | |||
82 | this.routerEventSubscription = this.router.events.pipe( | ||
83 | filter(event => | ||
84 | event instanceof NavigationStart || | ||
85 | event instanceof NavigationEnd || | ||
86 | event instanceof NavigationCancel || | ||
87 | event instanceof NavigationError | ||
88 | ), | ||
89 | map(event => event instanceof NavigationStart) | ||
90 | ).subscribe(this.routerLoading$); | ||
91 | |||
92 | this.http.get<DomainResponse>('/domain', { headers: new HttpHeaders({ 'Accept': 'application/json' }) }).pipe(map((resp: DomainResponse) => resp.domain)).subscribe(this.apiDomain$); | ||
17 | } | 93 | } |
18 | ngOnDestroy() { | 94 | ngOnDestroy() { |
19 | this.colorSchemeService.destroy(); | 95 | this.colorSchemeMatcher.removeEventListener('change', this.colorSchemeListener); |
96 | |||
97 | this.colorSchemeSubscription?.unsubscribe(); | ||
98 | this.routerEventSubscription?.unsubscribe(); | ||
20 | } | 99 | } |
21 | } | 100 | } |