File
Implements
Metadata
| selector |
mev-root |
| styleUrls |
./app.component.scss |
| templateUrl |
./app.component.html |
Methods
|
Private
Static
isIEorEdgeOrSafari
|
isIEorEdgeOrSafari()
|
|
|
|
|
|
ngOnDestroy
|
ngOnDestroy()
|
|
|
|
|
|
onLanguageSelect
|
onLanguageSelect(undefined)
|
|
|
|
|
|
onLogoutClick
|
onLogoutClick()
|
|
|
|
|
|
envName
|
Default value : env.envName
|
|
|
|
isAuthenticated$
|
Type : Observable<boolean>
|
|
|
|
isProd
|
Default value : env.production
|
|
|
|
language$
|
Type : Observable<string>
|
|
|
|
languages
|
Type : []
|
Default value : ['en']
|
|
|
|
logo
|
Default value : require('../../assets/logo.png').default
|
|
|
|
navigation
|
Type : []
|
Default value : [
{ link: 'about', label: 'mev.menu.main' },
{ link: 'tutorial', label: 'mev.menu.tutorial' },
{ link: 'workarea', label: 'Get Started' }
]
|
|
|
|
navigationSideMenu
|
Type : []
|
Default value : [
...this.navigation,
{ link: 'settings', label: 'mev.menu.settings' }
]
|
|
|
|
Private
sessionSubscription$
|
Type : Subscription
|
|
|
|
sessionTimeout
|
Default value : 60 * 15
|
|
|
|
stickyHeader$
|
Type : Observable<boolean>
|
|
|
|
theme$
|
Type : Observable<string>
|
|
|
|
version
|
Default value : env.versions.app
|
|
|
|
year
|
Default value : new Date().getFullYear()
|
|
|
import browser from 'browser-detect';
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Observable, Subscription } from 'rxjs';
import { Router } from '@angular/router';
import { BnNgIdleService } from 'bn-ng-idle';
import { AuthenticationService } from '@app/core/authentication/authentication.service';
import { User } from '@app/_models/user';
import { environment as env } from '../../environments/environment';
import {
routeAnimations,
LocalStorageService,
selectIsAuthenticated,
selectSettingsStickyHeader,
selectSettingsLanguage,
selectEffectiveTheme
} from '../core/core.module';
import {
actionSettingsChangeAnimationsPageDisabled,
actionSettingsChangeLanguage
} from '../core/settings/settings.actions';
@Component({
selector: 'mev-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
animations: [routeAnimations]
})
export class AppComponent implements OnInit {
currentUser: User;
socialUser;
isAuthenticated: boolean;
isProd = env.production;
envName = env.envName;
version = env.versions.app;
year = new Date().getFullYear();
logo = require('../../assets/logo.png').default;
languages = ['en'];
sessionTimeout = 60 * 15; // 15 minutes
navigation = [
{ link: 'about', label: 'mev.menu.main' },
{ link: 'tutorial', label: 'mev.menu.tutorial' },
{ link: 'workarea', label: 'Get Started' }
];
navigationSideMenu = [
...this.navigation,
{ link: 'settings', label: 'mev.menu.settings' }
];
isAuthenticated$: Observable<boolean>;
stickyHeader$: Observable<boolean>;
language$: Observable<string>;
theme$: Observable<string>;
private sessionSubscription$: Subscription;
constructor(
private store: Store,
private storageService: LocalStorageService,
private router: Router,
private bnIdle: BnNgIdleService,
private authenticationService: AuthenticationService
) {
this.authenticationService.currentUser.subscribe(x => {
this.isAuthenticated = x !== null;
this.currentUser = x;
});
}
private static isIEorEdgeOrSafari() {
return ['ie', 'edge', 'safari'].includes(browser().name);
}
onLogoutClick() {
this.authenticationService.logout();
this.router.navigate(['/login']);
}
ngOnInit(): void {
this.socialUser = JSON.parse(localStorage.getItem('socialUser'));
// listen for the user’s idleness
this.sessionSubscription$ = this.bnIdle
.startWatching(this.sessionTimeout)
.subscribe((isTimedOut: boolean) => {
if (isTimedOut) {
this.onLogoutClick();
}
});
this.storageService.testLocalStorage();
if (AppComponent.isIEorEdgeOrSafari()) {
this.store.dispatch(
actionSettingsChangeAnimationsPageDisabled({
pageAnimationsDisabled: true
})
);
}
this.isAuthenticated$ = this.store.pipe(select(selectIsAuthenticated));
this.stickyHeader$ = this.store.pipe(select(selectSettingsStickyHeader));
this.language$ = this.store.pipe(select(selectSettingsLanguage));
this.theme$ = this.store.pipe(select(selectEffectiveTheme));
}
ngOnDestroy(): void {
if (this.sessionSubscription$) {
this.sessionSubscription$.unsubscribe();
}
}
onLanguageSelect({ value: language }) {
this.store.dispatch(actionSettingsChangeLanguage({ language }));
}
}
<div [class]="'theme-wrapper ' + (theme$ | async)">
<mat-sidenav-container>
<mat-sidenav #sidenav mode="push">
<div class="branding"><img [src]="logo" [alt]="logo"/>
<span>{{ 'mev.title.short' | translate}}</span></div>
<mat-nav-list>
<a mat-list-item *ngFor="let item of navigationSideMenu" (click)="sidenav.close()" [routerLink]="[item.link]"
routerLinkActive="active">
{{item.label | translate}}
</a>
<a mat-list-item href="https://github.com/dfci-cccb/mev/issues" target="_blank" rel="noopener noreferrer">
Github
</a>
</mat-nav-list>
</mat-sidenav>
<div class="wrapper">
<div class="toolbar" [style.position]="(stickyHeader$ | async) ? 'fixed' : 'inherit'"
[class.mat-elevation-z4]="(stickyHeader$ | async)">
<mat-toolbar color="primary">
<button mat-icon-button class="d-md-none" (click)="sidenav.open()">
<fa-icon icon="bars"></fa-icon>
</button>
<span routerLink="" class="branding spacer center d-inline d-sm-none">
<img [src]="logo" [alt]="logo"/></span>
<span routerLink="" class="branding spacer center d-none d-sm-inline d-md-none"><img [src]="logo"
[alt]="logo"/> {{
'mev.title.short' | translate }}</span>
<span routerLink="" class="branding spacer d-none d-md-inline"><img [src]="logo" [alt]="logo"/>Web MeV</span>
<span class="d-none d-md-inline">
<button mat-button class="nav-button" *ngFor="let item of navigation" [routerLink]="[item.link]"
routerLinkActive="active">
{{item.label | translate}}
</button>
</span>
<!--button mat-button mat-stroked-button color="accent" *ngIf="!(isAuthenticated$ | async)" (click)="onLoginClick()">
{{ 'mev.menu.login' | translate }}
</button-->
<!--button *ngIf="(isAuthenticated$ | async)"
mat-icon-button
[matMenuTriggerFor]="toolbarUserMenu">
<fa-icon icon="user-circle"></fa-icon>
</button-->
<!--mat-menu #toolbarUserMenu="matMenu">
<button mat-menu-item (click)="onLogoutClick()">
<mat-icon><fa-icon icon="power-off"></fa-icon></mat-icon>
<span>{{ 'mev.menu.logout' | translate }}</span>
</button>
</mat-menu-->
<button mat-button mat-stroked-button color="accent" *ngIf="!isAuthenticated" routerLink="/login">
{{ 'mev.menu.login' | translate }}
</button>
<button *ngIf="isAuthenticated"
mat-icon-button
[matMenuTriggerFor]="toolbarUserMenu">
<fa-icon icon="user-circle"></fa-icon>
</button>
<mat-menu #toolbarUserMenu="matMenu">
<button mat-menu-item routerLink="/change-password">
<span *ngIf="socialUser" class="social-user-info">
<span class="social-user-info__name">
{{ socialUser.name }}
</span>
<span class="social-user-info__email">
{{ socialUser.email }}
</span>
</span>
<mat-icon>
<fa-icon icon="lock"></fa-icon>
</mat-icon>
<span>Account security</span>
</button>
<button mat-menu-item (click)="onLogoutClick()">
<mat-icon>
<fa-icon icon="power-off"></fa-icon>
</mat-icon>
<span>{{ 'mev.menu.logout' | translate }}</span>
</button>
</mat-menu>
<!-- <button mat-icon-button routerLink="settings" class="d-none d-sm-inline">
<fa-icon icon="cog"></fa-icon>
</button> -->
<a [matTooltip]="'mev.header.github' | translate"
matTooltipPosition="before"
mat-icon-button
class="link d-none d-sm-inline"
href="https://github.com/dfci-cccb/mev"
target="_blank" rel="noopener noreferrer">
<fa-icon [icon]="['fab','github']"></fa-icon>
</a>
<span *ngIf="language$ | async as language">
<mat-select [ngModel]="language" (selectionChange)="onLanguageSelect($event)">
<mat-option *ngFor="let l of languages" [value]="l">
{{ l.toUpperCase() }}
</mat-option>
</mat-select>
</span>
</mat-toolbar>
</div>
<div class="content"
[@routeAnimations]="o.isActivated && o.activatedRoute.routeConfig.data && o.activatedRoute.routeConfig.data.title">
<router-outlet #o="outlet"></router-outlet>
<router-outlet></router-outlet>
</div>
<div class="footer">
<div class="row">
<div class="col-sm-12 links">
<a href="https://github.com/dfci-cccb/mev" target="_blank" rel="noopener noreferrer">
<fa-icon [icon]="['fab','github']"></fa-icon>
<span>Github</span>
</a>
<a href="https://twitter.com/webmev" target="_blank" rel="noopener noreferrer">
<fa-icon [icon]="['fab','twitter']"></fa-icon>
<span>Twitter</span>
</a>
<a href="https://www.youtube.com/channel/UCFrvYZDDiJ-Z-ZVKCH2pY9A"
target="_blank" rel="noopener noreferrer">
<fa-icon [icon]="['fab','youtube']"></fa-icon>
<span>Youtube</span>
</a>
</div>
</div>
</div>
</div>
</mat-sidenav-container>
</div>
@import '../../styles-variables';
.theme-wrapper {
height: 100%;
width: 100%;
}
mat-sidenav-container {
height: 100%;
width: 100%;
.toolbar {
position: fixed;
width: 100%;
display: flex;
z-index: 10;
.nav-button {
margin: 0 10px 0 0;
}
fa-icon {
font-size: 24px;
}
.branding {
cursor: pointer;
overflow: hidden;
padding-top: 4px;
text-overflow: ellipsis;
&.center {
text-align: center;
}
img {
position: relative;
top: -2px;
width: 48px;
height: 48px;
}
}
.mat-stroked-button {
margin-right: 10px;
}
.spacer {
flex: 1 1 auto;
}
mat-select {
margin: 0 0 0 20px;
width: 40px;
font-size: 14px;
}
@media (max-width: map-get($grid-breakpoints, lg)) {
.nav-button {
min-width: 0;
padding: 0 10px;
}
}
}
.wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
.content {
flex: 1 0 auto;
margin-top: 64px;
overflow: hidden;
}
.footer {
flex: 0 0 auto;
padding: 0 15px;
text-align: center;
.row {
padding: 10px 0;
.links {
a {
transition: padding 0.5s;
display: inline-block;
padding: 0 5px !important;
line-height: 35px;
&:hover {
text-decoration: none;
}
fa-icon {
font-size: 35px;
vertical-align: top;
}
span {
display: inline-block;
width: 75px;
padding: 0 0 0 3px;
overflow: hidden;
text-align: left;
white-space: nowrap;
transition: width 0.5s;
}
}
@media (min-width: map-get($grid-breakpoints, lg)) {
a {
padding: 20px 10px;
}
}
@media (max-width: map-get($grid-breakpoints, md)) {
a {
padding: 20px;
span {
width: 0;
padding: 0;
}
}
}
@media (max-width: map-get($grid-breakpoints, sm)) {
a {
padding: 20px 5px;
}
}
}
@media (min-width: map-get($grid-breakpoints, sm)) {
.signature {
position: relative;
a {
position: absolute;
right: 15px;
}
}
}
}
}
}
@media (max-width: $toolbar-breakpoint) {
.content {
margin-top: 56px !important;
}
}
}
mat-sidenav {
width: 250px;
.branding {
height: 64px;
padding: 8px 10px;
font-size: 20px;
font-weight: 500;
img {
height: 48px;
margin: 2px 10px 0 0;
}
span {
position: relative;
top: 3px;
}
}
.mat-nav-list {
padding-top: 0;
}
}
.mat-menu-item {
height: auto;
}
.social-user-info {
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
color: #202124;
display: block;
}
.social-user-info__name {
font-weight: bold;
font-size: 16px;
line-height: 22px;
font-family: 'Google Sans', Roboto, RobotoDraft, Helvetica, Arial, sans-serif;
display: block;
}
.social-user-info__email {
font-weight: 400;
font-size: 14px;
font-family: Roboto, RobotoDraft, Helvetica, Arial, sans-serif;
display: block;
}
Legend
Html element with directive