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