Add sidebar navigation

pull/57/head
HardiReady 2019-02-24 02:08:56 +01:00
parent 430d4ce7da
commit e9ca404f85
12 changed files with 269 additions and 177 deletions

View File

@ -2,10 +2,14 @@
<mat-sidenav-container> <mat-sidenav-container>
<mat-sidenav-content> <mat-sidenav-content>
<app-header (sidenavToggle)="sidenav.toggle()"></app-header> <app-header (sidenavToggle)="sidenav.toggle()"></app-header>
<main> </mat-sidenav-content>
<div> <mat-sidenav #sidenav role="navigation">
<router-outlet></router-outlet> <app-sidenav-list (sidenavClose)="sidenav.close()"></app-sidenav-list>
</mat-sidenav>
</mat-sidenav-container>
<div (click)="sidenav.close()">
<router-outlet></router-outlet>
<div id="left"> <div id="left">
<router-outlet name="left"></router-outlet> <router-outlet name="left"></router-outlet>
</div> </div>
@ -14,12 +18,6 @@
<router-outlet name="right"></router-outlet> <router-outlet name="right"></router-outlet>
</div> </div>
</div> </div>
</main>
</mat-sidenav-content>
<mat-sidenav #sidenav role="navigation">
<app-sidenav-list (sidenavClose)="sidenav.close()"></app-sidenav-list>
</mat-sidenav>
</mat-sidenav-container>
<div *ngIf="loading" class="load-indicator"> <div *ngIf="loading" class="load-indicator">
<div class="opt-loader"></div> <div class="opt-loader"></div>

View File

@ -1,73 +1,24 @@
@import "style/load-indicator.scss"; @import "style/load-indicator.scss";
mat-sidenav-container, mat-sidenav-content, mat-sidenav { mat-sidenav-container, mat-sidenav-content, mat-sidenav {
height: 100%; height: 100vh;
display: inline;
background: #fdfdfd;
} }
mat-sidenav { mat-sidenav {
top: 50px;
width: 250px; width: 250px;
} }
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
display: inline;
}
.content {
padding-left: 15px;
padding-right: 15px;
}
.scrollable-menu {
height: auto;
max-height: 200px;
overflow-x: hidden;
}
#scrollTopBtn { #scrollTopBtn {
position: fixed; position: fixed;
bottom: 20px; bottom: 20px;
right: 30px; right: 30px;
z-index: 99; z-index: 99;
background: rgba(16, 16, 16, 0.8); background: rgba(16, 16, 16, 0.8);
}
#scrollTopBtn:hover { &:hover {
background: #101010; background: #101010;
} }
.unprocessed {
-webkit-animation-name: color-blink; /* Safari 4.0 - 8.0 */
-webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */
animation-name: color-blink;
animation-duration: 4s;
animation-iteration-count: infinite;
}
.unprocessed-child {
background-color: orange;
}
/* Safari 4.0 - 8.0 */
@-webkit-keyframes color-blink {
from {
background-color: #222222;
}
to {
background-color: orange;
}
}
@keyframes color-blink {
from {
background-color: #222222;
}
to {
background-color: orange;
}
} }

View File

@ -22,7 +22,7 @@ import {HttpClientModule} from '@angular/common/http';
import {SpinnerService} from './services/user-interface/spinner/spinner.service'; import {SpinnerService} from './services/user-interface/spinner/spinner.service';
import {SettingsService} from './services/settings.service'; import {SettingsService} from './services/settings.service';
import {HttpGateway} from './services/http-gateway'; import {HttpGateway} from './services/http-gateway';
import {MatListModule, MatSidenavModule, MatToolbarModule} from '@angular/material'; import {MatListModule, MatMenuModule, MatSidenavModule, MatToolbarModule} from '@angular/material';
import {FlexLayoutModule} from '@angular/flex-layout'; import {FlexLayoutModule} from '@angular/flex-layout';
@NgModule({ @NgModule({
@ -37,6 +37,7 @@ import {FlexLayoutModule} from '@angular/flex-layout';
MatSidenavModule, MatSidenavModule,
MatToolbarModule, MatToolbarModule,
MatListModule, MatListModule,
MatMenuModule,
FlexLayoutModule, FlexLayoutModule,
], ],

View File

@ -29,85 +29,82 @@
<li routerLinkActive="active"> <li routerLinkActive="active">
<a routerLink='{{config.statsPath}}' class="link">{{'navigation.top.statistics' | translate}}</a> <a routerLink='{{config.statsPath}}' class="link">{{'navigation.top.statistics' | translate}}</a>
</li> </li>
<li *ngIf="loginService.hasPermission(2)" <li *ngIf="loginService.hasPermission(2)">
class="dropdown"> <mat-list-item [matMenuTriggerFor]="menuManagement">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a matline>
aria-expanded="false">
{{'navigation.top.management' | translate}} {{'navigation.top.management' | translate}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> </mat-list-item>
<li routerLinkActive="active"> <mat-menu #menuManagement="matMenu">
<a routerLink='{{config.manageUserPath}}' class="link">{{'navigation.top.management.users' | translate}}</a> <button routerLink='{{config.manageUserPath}}' mat-menu-item>
{{'navigation.top.management.users' | translate}}
</button>
<button routerLink='{{config.manageSquadPath}}' mat-menu-item>
{{'navigation.top.management.squads' | translate}}
</button>
<button routerLink='{{config.manageDecorationPath}}' mat-menu-item>
{{'navigation.top.management.decorations' | translate}}
</button>
<button routerLink='{{config.manageRankPath}}' mat-menu-item>
{{'navigation.top.management.ranks' | translate}}
</button>
</mat-menu>
</li> </li>
<li routerLinkActive="active"> <li *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2) && loginService.hasSquad()">
<a routerLink='{{config.manageSquadPath}}' <mat-list-item [matMenuTriggerFor]="menuSqlRequest">
class="link">{{'navigation.top.management.squads' | translate}}</a> <a matline>
</li>
<li routerLinkActive="active">
<a routerLink='{{config.manageDecorationPath}}'
class="link">{{'navigation.top.management.decorations' | translate}}</a>
</li>
<li routerLinkActive="active">
<a routerLink='{{config.manageRankPath}}' class="link">{{'navigation.top.management.ranks' | translate}}</a>
</li>
</ul>
</li>
<li *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2) && loginService.hasSquad()"
class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
{{'navigation.top.request' | translate}} {{'navigation.top.request' | translate}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> </mat-list-item>
<li> <mat-menu #menuSqlRequest="matMenu">
<a routerLink="{{config.request}}/{{config.sqlDashboardPath}}">{{'navigation.top.request.open' | translate}}</a> <button routerLink="{{config.request}}/{{config.sqlDashboardPath}}" mat-menu-item>
{{'navigation.top.request.open' | translate}}
</button>
<button routerLink="{{config.request}}/{{config.requestPromotionPath}}" mat-menu-item>
{{'navigation.top.request.promotion' | translate}}
</button>
<button routerLink="{{config.request}}/{{config.requestAwardPath}}" mat-menu-item>
{{'navigation.top.request.award' | translate}}
</button>
</mat-menu>
</li> </li>
<li> <li *ngIf="loginService.hasPermission(2) && loginService.hasSquad()">
<a routerLink="{{config.request}}/{{config.requestPromotionPath}}">{{'navigation.top.request.promotion' | translate}}</a> <mat-list-item [matMenuTriggerFor]="menuRequests">
</li> <a [ngClass]="{'unprocessed': promotionService.hasUnprocessedPromotion || awardingService.hasUnprocessedAwards}"
<li> matline>
<a routerLink="{{config.request}}/{{config.requestAwardPath}}">{{'navigation.top.request.award' | translate}}</a>
</li>
</ul>
</li>
<li *ngIf="loginService.hasPermission(2) && loginService.hasSquad()" class="dropdown">
<a href="#"
[ngClass]="{'unprocessed': promotionService.hasUnprocessedPromotion || awardingService.hasUnprocessedAwards}"
class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
{{'navigation.top.request.manage' | translate}} {{'navigation.top.request.manage' | translate}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> </mat-list-item>
<li> <mat-menu #menuRequests="matMenu">
<a [ngClass]="{'unprocessed-child': promotionService.hasUnprocessedPromotion}" <button [ngClass]="{'unprocessed-child': promotionService.hasUnprocessedPromotion}"
routerLink="{{config.request}}/{{config.confirmPromotionPath}}">{{'navigation.top.request.promotion' | translate}}</a> routerLink="{{config.request}}/{{config.confirmPromotionPath}}" mat-menu-item>
</li> {{'navigation.top.request.promotion' | translate}}
<li> </button>
<a [ngClass]="{'unprocessed-child': awardingService.hasUnprocessedAwards}" <button [ngClass]="{'unprocessed-child': awardingService.hasUnprocessedAwards}"
routerLink="{{config.request}}/{{config.confirmAwardPath}}">{{'navigation.top.request.award' | translate}}</a> routerLink="{{config.request}}/{{config.confirmAwardPath}}" mat-menu-item>
</li> {{'navigation.top.request.award' | translate}}
</ul> </button>
</mat-menu>
</li> </li>
</ul> </ul>
</div> </div>
<div fxFlex fxLayout fxLayoutAlign="end" fxHide.lt-lg> <div fxFlex fxLayout fxLayoutAlign="end" fxHide.lt-lg>
<ul fxLayout fxLayoutGap="15px" class="navigation-items"> <ul fxLayout fxLayoutGap="15px" class="navigation-items">
<li *ngIf="loginService.hasPermission(4)" <li *ngIf="loginService.hasPermission(4)">
class="dropdown"> <mat-list-item [matMenuTriggerFor]="menuAdmin">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a matline>
aria-expanded="false">
{{'navigation.top.admin' | translate}} {{'navigation.top.admin' | translate}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> </mat-list-item>
<li routerLinkActive="active"> <mat-menu #menuAdmin="matMenu">
<a routerLink='{{config.adminPanelAppUsersPath}}' <button routerLink='{{config.adminPanelAppUsersPath}}' mat-menu-item>
class="link">{{'navigation.top.management.users' | translate}}</a> {{'navigation.top.management.users' | translate}}
</li> </button>
</ul> </mat-menu>
</li> </li>
<li *ngIf="loginService.isLoggedIn()" class="link" style="cursor: pointer"> <li *ngIf="loginService.isLoggedIn()" class="link" style="cursor: pointer">
<a (click)="logout()">{{'navigation.top.logout' | translate}}</a> <a (click)="logout()">{{'navigation.top.logout' | translate}}</a>
@ -115,19 +112,23 @@
<li *ngIf="!loginService.isLoggedIn()" routerLinkActive="active"> <li *ngIf="!loginService.isLoggedIn()" routerLinkActive="active">
<a routerLink='{{config.loginPath}}' class="link">{{'navigation.top.login' | translate}}</a> <a routerLink='{{config.loginPath}}' class="link">{{'navigation.top.login' | translate}}</a>
</li> </li>
<li class="dropdown" *ngIf="features.localization"> <li *ngIf="features.localization">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <mat-list-item [matMenuTriggerFor]="menuLanguage">
aria-expanded="false"> <a class="text-uppercase" matline>
<span class="text-uppercase">{{language}}</span> {{language}}
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> </mat-list-item>
<li *ngFor="let lang of languages" style="cursor: pointer"> <mat-menu #menuLanguage="matMenu">
<a (click)="setLanguage(lang)"> <button mat-menu-item (click)="setLanguage(languages[0])">
<mat-icon svgIcon="flag-{{lang}}"></mat-icon> <mat-icon svgIcon="flag-{{languages[0]}}"></mat-icon>
</a> <span class="text-uppercase">{{languages[0]}}</span>
</li> </button>
</ul> <button mat-menu-item (click)="setLanguage(languages[1])">
<mat-icon svgIcon="flag-{{languages[1]}}"></mat-icon>
<span class="text-uppercase">{{languages[1]}}</span>
</button>
</mat-menu>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -3,15 +3,19 @@ li {
line-height: 46px; line-height: 46px;
} }
li > a { li a {
font-size: 16px; font-size: 16px;
text-decoration: none; text-decoration: none;
color: #9d9d9d; color: #9d9d9d;
padding: 16px 5px; padding: 16px 5px;
} }
li mat-list-item {
cursor: pointer;
}
li:hover, li.active { li:hover, li.active {
> a { a {
color: white; color: white;
} }
} }
@ -55,3 +59,34 @@ mat-toolbar{
margin: auto; margin: auto;
} }
} }
.unprocessed {
-webkit-animation-name: color-blink; /* Safari 4.0 - 8.0 */
-webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */
animation-name: color-blink;
animation-duration: 4s;
animation-iteration-count: infinite;
}
.unprocessed-child {
background-color: orange;
}
/* Safari 4.0 - 8.0 */
@-webkit-keyframes color-blink {
from {
background-color: #222222;
}
to {
background-color: orange;
}
}
@keyframes color-blink {
from {
background-color: #222222;
}
to {
background-color: orange;
}
}

View File

@ -1,11 +1,104 @@
<mat-nav-list> <mat-nav-list>
<a mat-list-item routerLink="/home" (click)="onSidenavClose()"> <a mat-list-item routerLink='{{config.overviewPath}}' (click)="onSidenavClose()">
<mat-icon>home</mat-icon> <span class="nav-caption">Home</span> <span class="nav-caption">{{'navigation.top.overview' | translate}}</span>
</a> </a>
<a mat-list-item routerLink="/owner" (click)="onSidenavClose()"> <a mat-list-item [routerLink]="[config.publicPath.concat('/').concat(config.rankPath)]"
<mat-icon>assignment_ind</mat-icon> <span class="nav-caption">Owner Actions</span> (click)="onSidenavClose()">
<span class="nav-caption">{{'navigation.top.ranks' | translate}}</span>
</a> </a>
<a mat-list-item routerLink="#" (click)="onSidenavClose()"> <a mat-list-item [routerLink]="[config.publicPath.concat('/').concat(config.decorationPath)]"
<mat-icon>account_balance</mat-icon><span class="nav-caption">Account Actions</span> (click)="onSidenavClose()">
<span class="nav-caption">{{'navigation.top.decorations' | translate}}</span>
</a>
<a mat-list-item routerLink='{{config.statsPath}}' (click)="onSidenavClose()">
<span class="nav-caption">{{'navigation.top.statistics' | translate}}</span>
</a>
<mat-list-item *ngIf="loginService.hasPermission(2)"
[matMenuTriggerFor]="menuManagement">
<a matline>
<span class="nav-caption">{{'navigation.top.management' | translate}}</span>
<span class="caret"></span>
</a>
</mat-list-item>
<mat-menu #menuManagement="matMenu">
<button routerLink='{{config.manageUserPath}}' mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.management.users' | translate}}
</button>
<button routerLink='{{config.manageSquadPath}}' mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.management.squads' | translate}}
</button>
<button routerLink='{{config.manageDecorationPath}}' mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.management.decorations' | translate}}
</button>
<button routerLink='{{config.manageRankPath}}' mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.management.ranks' | translate}}
</button>
</mat-menu>
<mat-list-item *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2) && loginService.hasSquad()"
[matMenuTriggerFor]="menuSqlRequest">
<a matline>
<span class="nav-caption">{{'navigation.top.request' | translate}}</span>
<span class="caret"></span>
</a>
</mat-list-item>
<mat-menu #menuSqlRequest="matMenu">
<button routerLink="{{config.request}}/{{config.sqlDashboardPath}}" mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.request.open' | translate}}
</button>
<button routerLink="{{config.request}}/{{config.requestPromotionPath}}" mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.request.promotion' | translate}}
</button>
<button routerLink="{{config.request}}/{{config.requestAwardPath}}" mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.request.award' | translate}}
</button>
</mat-menu>
<mat-list-item *ngIf="loginService.hasPermission(2) && loginService.hasSquad()"
[matMenuTriggerFor]="menuRequests">
<a [ngClass]="{'unprocessed': promotionService.hasUnprocessedPromotion || awardingService.hasUnprocessedAwards}"
matline>
<span class="nav-caption">{{'navigation.top.request.manage' | translate}}</span>
<span class="caret"></span>
</a>
</mat-list-item>
<mat-menu #menuRequests="matMenu">
<button [ngClass]="{'unprocessed-child': promotionService.hasUnprocessedPromotion}"
routerLink="{{config.request}}/{{config.confirmPromotionPath}}" mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.request.promotion' | translate}}
</button>
<button [ngClass]="{'unprocessed-child': awardingService.hasUnprocessedAwards}"
routerLink="{{config.request}}/{{config.confirmAwardPath}}" mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.request.award' | translate}}
</button>
</mat-menu>
<mat-divider style="margin-bottom: 50%;"></mat-divider>
<mat-list-item *ngIf="loginService.hasPermission(4)" [matMenuTriggerFor]="menuAdmin">
<a matline>
<span class="nav-caption">{{'navigation.top.admin' | translate}}</span>
<span class="caret"></span>
</a>
</mat-list-item>
<mat-menu #menuAdmin="matMenu">
<button routerLink='{{config.adminPanelAppUsersPath}}' mat-menu-item (click)="onSidenavClose()">
{{'navigation.top.management.users' | translate}}
</button>
</mat-menu>
<a mat-list-item *ngIf="loginService.isLoggedIn()"
(click)="logout(); onSidenavClose()">
<span class="nav-caption">{{'navigation.top.logout' | translate}}</span>
</a>
<a mat-list-item *ngIf="!loginService.isLoggedIn()"
routerLink='{{config.loginPath}}' (click)="onSidenavClose()">
<span class="nav-caption">{{'navigation.top.login' | translate}}</span>
</a>
<a mat-list-item href="https://www.opt4.net/dashboard">
<span class="nav-caption">{{'navigation.top.board' | translate}}</span>
</a> </a>
</mat-nav-list> </mat-nav-list>

View File

@ -1,4 +1,8 @@
import {Component, EventEmitter, OnInit, Output} from '@angular/core'; import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {RouteConfig} from '../../app.config';
import {LoginService} from '../../services/app-user-service/login-service';
import {PromotionService} from '../../services/army-management/promotion.service';
import {AwardingService} from '../../services/army-management/awarding.service';
@Component({ @Component({
selector: 'app-sidenav-list', selector: 'app-sidenav-list',
@ -9,7 +13,12 @@ export class SidenavListComponent implements OnInit {
@Output() sidenavClose = new EventEmitter(); @Output() sidenavClose = new EventEmitter();
constructor() { } config = RouteConfig;
constructor(public loginService: LoginService,
private promotionService: PromotionService,
private awardingService: AwardingService) {
}
ngOnInit() { ngOnInit() {
} }

View File

@ -2,3 +2,7 @@
width: 100%; width: 100%;
padding-bottom: 20px; padding-bottom: 20px;
} }
input.form-control {
z-index: 0;
}

View File

@ -47,8 +47,7 @@
[selected]="war._id == selectedWarId"> [selected]="war._id == selectedWarId">
</cc-war-item> </cc-war-item>
</div> </div>
</div>
<div class="fill-vertical-border" <div class="fill-vertical-border"
[ngClass]="{collapsed: collapsed}"> [ngClass]="{collapsed: collapsed}">
</div> </div>
</div>

View File

@ -88,9 +88,6 @@
} }
.fill-vertical-border { .fill-vertical-border {
width: 20%;
top: 0;
z-index: -20;
position: fixed; position: fixed;
border-right: 1px solid #dadada; border-right: 1px solid #dadada;
height: 100vh; height: 100vh;

View File

@ -48,12 +48,16 @@ form {
#left { #left {
max-width: 20%; max-width: 20%;
min-width: min-content; min-width: 345px;
margin: 0; margin: 0;
position: static; position: static;
float: left; float: left;
border-right: thin solid #dadada; border-right: thin solid #dadada;
box-shadow: #dadada 1px 1px 6px; box-shadow: #dadada 1px 1px 6px;
@media all and (max-width: 599px) {
// TODO
}
} }
#right { #right {