src/app/app.component.ts
App component
OnDestroy
OnInit
changeDetection | ChangeDetectionStrategy.OnPush |
selector | ccf-root |
styleUrls | ./app.component.scss |
templateUrl | ./app.component.html |
Properties |
|
Methods |
HostListeners |
Accessors |
constructor(model: ModelState, page: PageState, consentService: ConsentService, snackbar: MatSnackBar, theming: ThemingService, el: ElementRef<>, injector: Injector, globalConfig: GlobalConfigState
|
||||||||||||||||||||||||||||||
Defined in src/app/app.component.ts:69
|
||||||||||||||||||||||||||||||
Parameters :
|
document:keydown | ||||||
Arguments : '$event'
|
||||||
document:keydown(target: KeyboardEvent)
|
||||||
Defined in src/app/app.component.ts:139
|
||||||
Shifts block position when certain keys are pressed
Parameters :
|
document:mousedown | ||||||
Arguments : '$event.target'
|
||||||
document:mousedown(target: HTMLElement)
|
||||||
Defined in src/app/app.component.ts:178
|
||||||
Disables block position change if an input element is clicked
Parameters :
|
handleClick | ||||||||
handleClick(target: HTMLElement)
|
||||||||
Decorators :
@HostListener('document:mousedown', ['$event.target'])
|
||||||||
Defined in src/app/app.component.ts:178
|
||||||||
Disables block position change if an input element is clicked
Parameters :
Returns :
void
|
handleKey | ||||||||
handleKey(target: KeyboardEvent)
|
||||||||
Decorators :
@HostListener('document:keydown', ['$event'])
|
||||||||
Defined in src/app/app.component.ts:139
|
||||||||
Shifts block position when certain keys are pressed
Parameters :
Returns :
void
|
registrationToggle | ||||||
registrationToggle(event: boolean)
|
||||||
Defined in src/app/app.component.ts:126
|
||||||
Parameters :
Returns :
void
|
toggleScheme |
toggleScheme()
|
Defined in src/app/app.component.ts:122
|
Toggles scheme between light and dark mode
Returns :
void
|
disablePositionChange |
Default value : false
|
Defined in src/app/app.component.ts:47
|
Disables changes in block position |
Readonly header$ |
Default value : this.globalConfig.getOption('header')
|
Defined in src/app/app.component.ts:58
|
homeUrl |
Type : string
|
Defined in src/app/app.component.ts:64
|
Readonly homeUrl$ |
Default value : this.globalConfig.getOption('homeUrl')
|
Defined in src/app/app.component.ts:59
|
logoTooltip |
Type : string
|
Defined in src/app/app.component.ts:66
|
Readonly logoTooltip$ |
Default value : this.globalConfig.getOption('logoTooltip')
|
Defined in src/app/app.component.ts:60
|
registrationExpanded |
Default value : false
|
Defined in src/app/app.component.ts:49
|
registrationStarted |
Default value : false
|
Defined in src/app/app.component.ts:44
|
False until the initial registration modal is closed |
theme |
Type : string
|
Defined in src/app/app.component.ts:62
|
Readonly theme$ |
Default value : this.globalConfig.getOption('theme')
|
Defined in src/app/app.component.ts:55
|
Readonly themeMode$ |
Default value : new ReplaySubject<'light' | 'dark'>(1)
|
Defined in src/app/app.component.ts:56
|
isLightTheme |
getisLightTheme()
|
Defined in src/app/app.component.ts:51
|
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostListener,
Injector,
OnDestroy,
OnInit,
} from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { GlobalConfigState, TrackingPopupComponent } from 'ccf-shared';
import { ConsentService } from 'ccf-shared/analytics';
import { ReplaySubject, Subscription, combineLatest } from 'rxjs';
import { GlobalConfig } from './core/services/config/config';
import { ThemingService } from './core/services/theming/theming.service';
import { ModelState } from './core/store/model/model.state';
import { PageState } from './core/store/page/page.state';
export interface User {
firstName: string;
lastName: string;
}
interface AppOptions extends GlobalConfig {
theme?: string;
header?: boolean;
homeUrl?: string;
logoTooltip?: string;
}
/**
* App component
*/
@Component({
selector: 'ccf-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnDestroy, OnInit {
/** False until the initial registration modal is closed */
registrationStarted = false;
/** Disables changes in block position */
disablePositionChange = false;
registrationExpanded = false;
get isLightTheme(): boolean {
return this.theming.getTheme().endsWith('light');
}
readonly theme$ = this.globalConfig.getOption('theme');
readonly themeMode$ = new ReplaySubject<'light' | 'dark'>(1);
readonly header$ = this.globalConfig.getOption('header');
readonly homeUrl$ = this.globalConfig.getOption('homeUrl');
readonly logoTooltip$ = this.globalConfig.getOption('logoTooltip');
theme!: string;
homeUrl!: string;
logoTooltip!: string;
/** All subscriptions managed by the container. */
private readonly subscriptions = new Subscription();
constructor(
readonly model: ModelState,
readonly page: PageState,
readonly consentService: ConsentService,
readonly snackbar: MatSnackBar,
readonly theming: ThemingService,
el: ElementRef<unknown>,
injector: Injector,
private readonly globalConfig: GlobalConfigState<AppOptions>,
cdr: ChangeDetectorRef,
) {
theming.initialize(el, injector);
this.subscriptions.add(
page.registrationStarted$.subscribe((registrationStarted) => {
this.registrationStarted = registrationStarted;
}),
);
this.theme$.subscribe((theme) => {
this.theme = theme ?? 'light';
});
this.globalConfig.getOption('homeUrl').subscribe((url) => {
this.homeUrl = url ?? '';
});
this.globalConfig.getOption('logoTooltip').subscribe((tooltip) => {
this.logoTooltip = tooltip ?? '';
});
combineLatest([this.theme$, this.themeMode$]).subscribe(([theme, mode]) => {
this.theming.setTheme(`${theme}-theme-${mode}`);
cdr.markForCheck();
});
}
ngOnInit(): void {
const snackBar = this.snackbar.openFromComponent(TrackingPopupComponent, {
data: {
preClose: () => {
snackBar.dismiss();
},
},
duration: this.consentService.consent === 'not-set' ? Infinity : 3000,
});
this.themeMode$.next('light');
this.theming.setTheme(`${this.theme}-theme-light`);
}
/**
* Toggles scheme between light and dark mode
*/
toggleScheme(): void {
this.themeMode$.next(this.isLightTheme ? 'dark' : 'light');
}
registrationToggle(event: boolean): void {
this.registrationExpanded = event;
if (!this.registrationExpanded) {
this.disablePositionChange = false;
}
}
/**
* Shifts block position when certain keys are pressed
*
* @param target The keyboard event
*/
@HostListener('document:keydown', ['$event'])
handleKey(target: KeyboardEvent): void {
const oldPosition = this.model.snapshot.position;
if (this.disablePositionChange || !this.registrationStarted) {
return;
}
target.preventDefault();
const delta = target.repeat ? 1.0 : 0.5;
let newPosition = oldPosition;
switch (target.key) {
case 'q':
newPosition = { ...oldPosition, z: oldPosition.z + delta };
break;
case 'e':
newPosition = { ...oldPosition, z: oldPosition.z - delta };
break;
case 'w':
newPosition = { ...oldPosition, y: oldPosition.y + delta };
break;
case 's':
newPosition = { ...oldPosition, y: oldPosition.y - delta };
break;
case 'a':
newPosition = { ...oldPosition, x: oldPosition.x - delta };
break;
case 'd':
newPosition = { ...oldPosition, x: oldPosition.x + delta };
break;
default:
break;
}
this.model.setPosition(newPosition);
}
/**
* Disables block position change if an input element is clicked
*
* @param target The element clicked
*/
@HostListener('document:mousedown', ['$event.target'])
handleClick(target: HTMLElement): void {
const disableWhenClicked = ['mat-mdc-input-element', 'form-input-label'];
for (const className of disableWhenClicked) {
if (typeof target.className === 'string' && target.className.includes(className)) {
this.disablePositionChange = true;
return;
}
}
this.disablePositionChange = false;
}
/**
* Cleans up all subscriptions.
*/
ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}
}
<ccf-registration-modal></ccf-registration-modal>
<ccf-header
[class.header-hidden]="(header$ | async) === false"
[logoTooltip]="(logoTooltip$ | async) ?? ''"
[homeUrl]="(homeUrl$ | async) ?? ''"
></ccf-header>
<ccf-drawer-container>
<ccf-drawer opened>
<ccf-left-sidebar [modalClosed]="registrationStarted"> </ccf-left-sidebar>
<ccf-drawer-toggle-button></ccf-drawer-toggle-button>
</ccf-drawer>
<ccf-drawer position="end" opened>
<ccf-right-sidebar
[modalClosed]="registrationStarted"
(registrationExpanded)="registrationToggle($event)"
></ccf-right-sidebar>
<ccf-drawer-toggle-button></ccf-drawer-toggle-button>
</ccf-drawer>
<ccf-drawer-content>
<ccf-content class="stage-content" [disablePositionChange]="disablePositionChange"></ccf-content>
</ccf-drawer-content>
</ccf-drawer-container>
./app.component.scss
:host {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
font-size: 1rem;
color: black;
.header-hidden {
display: none;
}
ccf-drawer-container {
height: 100%;
ccf-drawer {
width: 25.5rem;
}
ccf-drawer-content {
position: relative;
z-index: 1;
.selector-drawer {
top: 0rem;
display: flex;
flex-direction: column;
position: relative;
height: 5.688rem;
transition: all 0.5s ease-in-out;
&.expanded {
height: 15rem;
}
ccf-organ-selector {
height: 100%;
padding-top: 0.5rem;
transition: all 0.5s;
&.closed {
padding-top: 0;
}
}
.close-button-wrapper {
display: flex;
justify-content: center;
height: 0;
z-index: 2;
.close-button {
cursor: pointer;
transition: 0.6s;
.expand-collapse-icon {
width: 3rem;
height: 1.2rem;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background-color: white;
border-bottom-left-radius: 0.2rem;
border-bottom-right-radius: 0.2rem;
transition: 0.6s;
&:hover {
background-color: #ececec;
}
}
}
}
&.closed {
height: 3rem;
top: -2.9rem;
}
}
.stage-content {
border-radius: 0.5rem;
height: calc(100% - 2.5rem);
}
.expanded-stage {
height: calc(100% - 1.5rem);
padding-bottom: 1rem;
}
.retracted-stage {
height: calc(100% - 2.688rem - 14rem);
}
}
ccf-content {
// top: 0rem;
position: absolute;
transition-duration: 0.5s;
transition-timing-function: ease-in-out;
transition-property: all;
bottom: 1.5rem;
z-index: 1;
}
}
}
::ng-deep .mdc-snackbar__surface {
box-shadow: none !important;
}