Skip to content

Commit

Permalink
Adds Side Navigation Module
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenUlmer authored and AlexOverbeck committed Jul 24, 2019
1 parent fe5f720 commit 82d8b7b
Show file tree
Hide file tree
Showing 23 changed files with 584 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="go-nav-group"
[ngClass]="{ 'go-nav-group--expanded': navItem.expanded }"
*ngIf="navItem.subRoutes && navItem.subRoutes.length > 0">
<div class="go-nav-group__dropdown" (click)="expand(navItem)">
<div class="go-nav-group__link">
<go-icon [icon]="navItem.routeIcon"
iconClass="go-nav-group__icon"
*ngIf="navItem.routeIcon">
</go-icon>
<span class="go-nav-group__title" *ngIf="navService.navOpen">
{{ navItem.routeTitle }}
</span>
</div>
<go-icon iconClass="go-nav-group__expand-icon"
icon="expand_more"
*ngIf="navService.navOpen"
[ngClass]="{ 'go-nav-group__expand-icon--expanded': navItem.expanded }">
</go-icon>
</div>
<div *ngIf="navItem.expanded">
<div *ngFor="let item of navItem.subRoutes">
<go-nav-group *ngIf="item.subRoutes; else subRoutesElse"
class="go-nav-group__inner-group"
[navItem]="item">
</go-nav-group>
<ng-template #subRoutesElse>
<go-nav-item *ngIf="!item.subRoutes" [navItem]="item"></go-nav-item>
</ng-template>
</div>
</div>
</div>
<go-nav-item *ngIf="!navItem.subRoutes" [navItem]="navItem"></go-nav-item>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@import '~@tangoe/gosheets/base/variables';
@import '~@tangoe/gosheets/base/mixins';
@import '../../../../styles/variables';

.go-nav-group__dropdown {
align-items: center;
display: flex;
padding-right: .5rem;
user-select: none;
@include transition(all);

&:hover {
background: $theme-dark-bg-hover;
}
}

.go-nav-group__link {
display: flex;
flex-grow: 1;
}

.go-nav-group__title {
font-weight: $weight-light;
letter-spacing: $side-nav-letter-spacing;
padding: $outer-side-nav-padding;
}

.go-nav-group__icon {
font-size: 1.2rem;
padding: 1rem;
}

.go-nav-group__expand-icon {
border-radius: 50%;
color: $theme-dark-color;
cursor: pointer;
font-size: 1.5rem;
height: 2.5rem;
padding: 0.5rem;
width: 2.5rem;

&:hover {
background: $theme-dark-bg;
}
}

.go-nav-group__expand-icon--expanded {
transform: rotate(180deg);
}

.go-nav-group__inner-group {
.go-nav-group__title {
font-size: $inner-side-nav-font-size;
padding: $inner-side-nav-padding;
}
}

.go-nav-group--expanded {
background: $theme-dark-bg-active;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Component, Input, ViewEncapsulation, Output, EventEmitter } from '@angular/core';
import { NavGroup } from '../nav-group.model';
import { NavItem } from '../nav-item.model';
import { GoSideNavService } from '../go-side-nav/go-side-nav.service';

@Component({
selector: 'go-nav-group',
templateUrl: './go-nav-group.component.html',
styleUrls: ['./go-nav-group.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class GoNavGroupComponent {
@Input() navItem: NavGroup | NavItem;
@Input() class: string;
@Output() closeNavs = new EventEmitter<NavGroup>();

constructor (public navService: GoSideNavService) { }

expand(navGroup: NavGroup): void {
navGroup.expanded = !navGroup.expanded;

if (!this.navService.navOpen) {
this.navService.toggleNav();
}

if (navGroup.expanded) {
this.closeNavs.emit(navGroup);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div class="go-nav-item"
[title]="description">
<a class="go-nav-item__link"
[routerLinkActive]="['go-nav-item__link--active']"
[routerLink]="[navItem.route]"
[routerLinkActiveOptions]="{exact:true}">
<go-icon [icon]="navItem.routeIcon"
iconClass="go-nav-group__icon"
*ngIf="navItem.routeIcon">
</go-icon>
<span [ngClass]="{ 'go-nav-item__title--with-icon': navItem.routeIcon }"
class="go-nav-item__title"
*ngIf="navService.navOpen">
{{navItem.routeTitle}}
</span>
</a>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@import '~@tangoe/gosheets/base/variables';
@import '~@tangoe/gosheets/base/mixins';
@import '../../../../styles/variables';

.go-nav-item {
align-items: center;
display: flex;
padding-right: .5rem;
@include transition(all);

&:hover {
background: $theme-dark-bg-hover;
}
}

.go-nav-item__link::before {
background: $base-primary;
border-radius: 0 $global-radius $global-radius 0;
content: " ";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
top: 0;
width: 4px;
@include transition(all);
}

.go-nav-item__link--active {
.go-nav-item__title {
font-weight: $weight-regular;
}
}

.go-nav-item__link--active::before {
opacity: 1;
}

.go-nav-item__link,
.go-nav-item__link:visited,
.go-nav-item__link:focus,
.go-nav-item__link:active {
color: $theme-dark-color;
}

.go-nav-item__link {
align-items: center;
border: none;
display: flex;
flex-grow: 1;
position: relative;
text-decoration: none;
}

.go-nav-item__title {
font-size: $inner-side-nav-font-size;
font-weight: $weight-light;
letter-spacing: $side-nav-letter-spacing;
padding: $inner-side-nav-padding;
}

.go-nav-item__title--with-icon {
font-size: 1rem;
padding: $outer-side-nav-padding;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Component, Input } from '@angular/core';
import { NavItem } from '../nav-item.model';
import { GoSideNavService } from '../go-side-nav/go-side-nav.service';

@Component({
selector: 'go-nav-item',
templateUrl: './go-nav-item.component.html',
styleUrls: ['./go-nav-item.component.scss']
})
export class GoNavItemComponent {
@Input() navItem: NavItem;

constructor (public navService: GoSideNavService) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';

import { GoIconModule } from '../go-icon/go-icon.module';

import { GoSideNavComponent } from './go-side-nav/go-side-nav.component';
import { GoNavGroupComponent } from './go-nav-group/go-nav-group.component';
import { GoNavItemComponent } from './go-nav-item/go-nav-item.component';

@NgModule({
declarations: [
GoSideNavComponent,
GoNavGroupComponent,
GoNavItemComponent
],
imports: [
CommonModule,
GoIconModule,
RouterModule
],
exports: [
GoSideNavComponent,
GoNavGroupComponent,
GoNavItemComponent
]
})

export class GoSideNavModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="go-side-nav"
[ngClass]="{ 'go-side-nav--show-mobile' : navService.navOpen, 'go-side-nav--collapsed' : !navService.navOpen }">
<go-nav-group *ngFor="let item of menuItems"
[navItem]="item"
(closeNavs)="closeNavs($event)">
</go-nav-group>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@import '~@tangoe/gosheets/base/_variables';
@import '../../../../styles/variables';

.go-side-nav {
background: $theme-dark-bg;
color: $theme-dark-color;
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
overflow-y: auto;
padding: 2rem 0;
width: $side-nav-width;

@media(max-width: $breakpoint-mobile) {
display: none;

&.go-side-nav--show-mobile {
display: flex;
width: 100vw;
}
}

&.go-side-nav--collapsed {
width: $side-nav-width--collapsed;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Component, OnInit, Input } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
import { NavGroup } from '../nav-group.model';
import { NavItem } from '../nav-item.model';
import { GoSideNavService } from './go-side-nav.service';

@Component({
selector: 'go-side-nav',
templateUrl: './go-side-nav.component.html',
styleUrls: ['./go-side-nav.component.scss']
})
export class GoSideNavComponent implements OnInit {
@Input() menuItems: Array<NavGroup | NavItem>;

constructor (private router: Router, public navService: GoSideNavService) { }

ngOnInit(): void {
this.router.events
.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
this.menuItems.forEach(item => {
(item as NavGroup).expanded = this.setExpanded(item, event.url);
});
});
}

closeNavs(navGroup: NavGroup): void {
this.menuItems.forEach(group => {
const g = group as NavGroup;
g.expanded = this.openAccordion(g, navGroup);
});
}

//#region Private Methods

private setExpanded(item: NavGroup | NavItem, url: string): boolean {
if ((item as NavGroup).subRoutes) {
return this.navGroupExpansion(item as NavGroup, url);
} else {
return url.includes((item as NavItem).route);
}
}

private navGroupExpansion(group: NavGroup, url: string): boolean {
group.expanded = group.subRoutes.some(subRoute => {
return this.setExpanded(subRoute, url);
});
return group.expanded;
}

/**
* @description this goes through and opens the accordion of the group that was clicked on and
* closes the other accordions that were previously open if they are not above the group that was
* clicked on. It uses recursion to go through nested groups to make sure that if a child group
* is open the parents of the child is also open.
* @param group this is the group we are trying to decide if it should be open.
* @param item this is the group that we are searching for that was clicked on and needs opened.
*/

private openAccordion(group: NavGroup, item: NavGroup): boolean {
if (group.subRoutes) {
if (group.routeTitle !== item.routeTitle) {
group.expanded = group.subRoutes.some(subRoute => {
return this.openAccordion((subRoute as NavGroup), item);
});
} else {
group.expanded = true;
}

return group.expanded;
}
return false;
}
//#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Observable, of as observableOf, BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root'
})

export class GoSideNavService {
public navOpen = true;

constructor() { }

toggleNav() {
this.navOpen = !this.navOpen;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NavItem } from './nav-item.model';

export interface NavGroup {
expanded?: boolean;
routeIcon?: string;
routeTitle: string;
subRoutes: Array<NavGroup | NavItem>;
}
Loading

0 comments on commit 82d8b7b

Please sign in to comment.