57053: started on menu

This commit is contained in:
lotte
2018-11-05 16:34:03 +01:00
parent 2033119bd9
commit 2af1d3b042
20 changed files with 237 additions and 141 deletions

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="231.892px" height="167.458px" viewBox="0 0 231.892 167.458" enable-background="new 0 0 231.892 167.458"
xml:space="preserve">
<path fill="#6D6E71" d="M51.733,143.32c0-1.941,1.651-3.203,4.563-3.203c3.302,0,6.798,1.116,9.419,3.543l3.835-5.146
c-3.203-2.962-7.476-4.516-12.622-4.516c-7.622,0-12.284,4.468-12.284,9.856c0,12.187,18.644,8.254,18.644,13.886
c0,1.894-1.797,3.593-5.632,3.593c-4.466,0-8.011-2.039-10.292-4.419l-3.787,5.39c3.058,3.059,7.525,5.154,13.788,5.154
c8.691,0,12.964-4.474,12.964-10.397C70.329,144.971,51.733,148.418,51.733,143.32z M100.682,134.484H85.534v32.385h6.894v-11.556
h8.254c6.991,0,10.875-4.759,10.875-10.391C111.558,139.242,107.722,134.484,100.682,134.484z M99.71,149.244h-7.283v-8.69h7.283
c2.719,0,4.807,1.651,4.807,4.369C104.518,147.593,102.43,149.244,99.71,149.244z M180.759,140.067c3.301,0,6.214,2.089,7.573,4.71
l5.923-2.913c-2.281-4.078-6.408-7.914-13.496-7.914c-9.759,0-17.284,6.75-17.284,16.75c0,9.954,7.525,16.759,17.284,16.759
c7.088,0,11.215-3.94,13.496-7.97l-5.923-2.865c-1.359,2.622-4.272,4.71-7.573,4.71c-5.924,0-10.195-4.516-10.195-10.634
C170.564,144.583,174.835,140.067,180.759,140.067z M131.958,134.484l-12.486,32.385h7.824l2.04-5.486h13.886l2.039,5.486h7.816
l-12.479-32.385H131.958z M131.228,155.313l5.05-13.935l5.05,13.935H131.228z M231.892,140.553v-6.069h-22.916v32.385h22.916v-6.069
H215.87v-7.38h15.683v-6.069H215.87v-6.797H231.892z"/>
<path fill="#92C642" d="M29.956,150.652c0-9.71-7.04-16.168-17.187-16.168H0v32.385h12.817
C22.916,166.869,29.956,160.458,29.956,150.652z M12.769,160.799H6.894v-20.246h5.924c6.603,0,10.098,4.418,10.098,10.099
C22.916,156.187,19.177,160.799,12.769,160.799z"/>
<path fill="#92C642" d="M120.726,58.569l0.11-0.006l0.116-0.01l0.106-0.013l0.111-0.01l0.11-0.023l0.109-0.019l0.107-0.023
l0.106-0.029l0.106-0.023l0.106-0.033l0.103-0.034l0.096-0.035l0.104-0.04l0.101-0.042l0.099-0.042v-0.001l0.096-0.045v0
l0.095-0.044l0.096-0.049l0.091-0.056v-0.001l0.094-0.05v-0.002l0.09-0.056v-0.001l0.092-0.06l0.083-0.056v-0.001l0.085-0.063
l0.088-0.065v-0.002l0.087-0.063v-0.001c0.817-0.683,1.393-1.646,1.561-2.738l0.012-0.104v-0.009l0.014-0.101v-0.011l0.009-0.098
v-0.012l0.009-0.101V54.38l0.005-0.095v-0.016l0.002-0.105v-16.46l-0.002-0.105v-0.016l-0.005-0.095v-0.013l-0.009-0.101v-0.012
l-0.009-0.098v-0.011l-0.014-0.1v-0.01l-0.012-0.104c-0.167-1.092-0.744-2.057-1.561-2.738v-0.001l-0.087-0.063v-0.002l-0.088-0.065
l-0.085-0.063v-0.001l-0.083-0.056l-0.092-0.061v0l-0.09-0.056v-0.003l-0.094-0.05v-0.001l-0.091-0.056l-0.096-0.049l-0.095-0.043
v-0.001l-0.096-0.045v-0.001l-0.099-0.043l-0.101-0.042l-0.104-0.04l-0.096-0.035l-0.103-0.031l-0.106-0.036l-0.106-0.023
l-0.106-0.028l-0.107-0.024l-0.109-0.019l-0.11-0.023l-0.111-0.009l-0.106-0.014l-0.116-0.01l-0.11-0.006l-0.114-0.005h-7.89
c-9.715,0-15.858-7.838-15.858-17.15V6.92c0-3.812-3.102-6.915-6.914-6.915H74.085c-3.814,0-6.92,3.106-6.92,6.915v16.682
c0,3.806,3.104,6.909,6.92,6.909h8.414c9.169,0,16.906,5.95,17.146,15.403v0.04c-0.24,9.453-7.977,15.402-17.146,15.402h-8.414
c-3.816,0-6.92,3.103-6.92,6.909v16.682c0,3.809,3.106,6.915,6.92,6.915H89.95c3.812,0,6.914-3.104,6.914-6.915v-9.223
c0-9.312,6.144-17.149,15.858-17.149h7.89L120.726,58.569z M154.772,9.956C148.631,3.814,140.15,0,130.816,0h-15.024v17.424h15.024
c4.527,0,8.648,1.858,11.64,4.849c2.99,2.99,4.848,7.112,4.848,11.639v24.042c0,4.538-1.852,8.665-4.832,11.655l-0.016-0.016
c-2.991,2.991-7.113,4.849-11.64,4.849h-15.024v17.424h15.024c9.333,0,17.815-3.814,23.956-9.956v-0.033
c6.142-6.143,9.955-14.614,9.955-23.923V33.912C164.727,24.578,160.914,16.097,154.772,9.956z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1,6 +1,7 @@
<div class="outer-wrapper">
<div class="inner-wrapper">
<ds-header></ds-header>
<ds-navbar></ds-navbar>
<ds-notifications-board
[options]="config.notifications">

View File

@@ -28,7 +28,12 @@ body {
}
.main-content {
z-index: $main-z-index;
flex: 1 0 auto;
margin-top: $content-spacing;
margin-bottom: $content-spacing;
}
ds-navbar {
z-index: $nav-z-index;
}

View File

@@ -1,10 +1,9 @@
import { HeaderEffects } from './header/header.effects';
import { StoreEffects } from './store.effects';
import { NotificationsEffects } from './shared/notifications/notifications.effects';
import { NavbarEffects } from './navbar/navbar.effects';
export const appEffects = [
StoreEffects,
HeaderEffects,
NavbarEffects,
NotificationsEffects
];

View File

@@ -31,6 +31,7 @@ import { DSpaceRouterStateSerializer } from './shared/ngrx/dspace-router-state-s
import { NotificationsBoardComponent } from './shared/notifications/notifications-board/notifications-board.component';
import { NotificationComponent } from './shared/notifications/notification/notification.component';
import { SharedModule } from './shared/shared.module';
import { NavbarComponent } from './navbar/navbar.component';
export function getConfig() {
return ENV_CONFIG;
@@ -87,6 +88,7 @@ if (!ENV_CONFIG.production) {
declarations: [
AppComponent,
HeaderComponent,
NavbarComponent,
FooterComponent,
PageNotFoundComponent,
NotificationComponent,

View File

@@ -1,7 +1,5 @@
import { ActionReducerMap } from '@ngrx/store';
import * as fromRouter from '@ngrx/router-store';
import { headerReducer, HeaderState } from './header/header.reducer';
import { hostWindowReducer, HostWindowState } from './shared/host-window.reducer';
import { formReducer, FormState } from './shared/form/form.reducer';
import {
@@ -12,13 +10,17 @@ import {
filterReducer,
SearchFiltersState
} from './+search-page/search-filters/search-filter/search-filter.reducer';
import { notificationsReducer, NotificationsState } from './shared/notifications/notifications.reducers';
import {
notificationsReducer,
NotificationsState
} from './shared/notifications/notifications.reducers';
import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer';
import { navbarReducer, NavbarState } from './navbar/navbar.reducer';
export interface AppState {
router: fromRouter.RouterReducerState;
hostWindow: HostWindowState;
header: HeaderState;
navbar: NavbarState;
forms: FormState;
notifications: NotificationsState;
searchSidebar: SearchSidebarState;
@@ -29,7 +31,7 @@ export interface AppState {
export const appReducers: ActionReducerMap<AppState> = {
router: fromRouter.routerReducer,
hostWindow: hostWindowReducer,
header: headerReducer,
navbar: navbarReducer,
forms: formReducer,
notifications: notificationsReducer,
searchSidebar: sidebarReducer,

View File

@@ -1,18 +1,10 @@
<header>
<nav class="navbar navbar-dark bg-primary navbar-expand-md">
<div [ngClass]="{'clearfix': !(isNavBarCollapsed | async)}">
<a class="navbar-brand" routerLink="/home">{{ 'title' | translate }}</a>
<div class="container">
<a class="navbar-brand my-2" routerLink="/home">
<img src="assets/images/dspace-logo.svg"/>
</a>
<nav class="navbar navbar-expand-md float-right p-0">
<ds-auth-nav-menu></ds-auth-nav-menu>
</nav>
</div>
<button class="navbar-toggler" type="button" (click)="toggle()" aria-controls="collapsingNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon fa fa-bars fa-fw" aria-hidden="true"></span>
</button>
<div [ngbCollapse]="(isNavBarCollapsed | async)" class="collapse navbar-collapse" id="collapsingNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" routerLink="/home" routerLinkActive="active"><i class="fa fa-home fa-fw" aria-hidden="true"></i> {{ 'nav.home' | translate }}<span class="sr-only">(current)</span></a>
</li>
</ul>
<ds-auth-nav-menu></ds-auth-nav-menu>
</div>
</nav>
</header>

View File

@@ -1,14 +1,5 @@
@import '../../styles/variables.scss';
header nav.navbar {
border-radius: 0;
}
header nav.navbar .navbar-toggler:hover {
cursor: pointer;
}
header nav.navbar .navbar-toggler .navbar-toggler-icon {
background-image: none !important;
line-height: 1.5;
.navbar-brand img {
height: $header-logo-height;
}

View File

@@ -1,43 +1,16 @@
import { Component, OnInit } from '@angular/core';
import { createSelector, Store } from '@ngrx/store';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { RouterReducerState } from '@ngrx/router-store';
import { HeaderState } from './header.reducer';
import { HeaderToggleAction } from './header.actions';
import { AppState } from '../app.reducer';
import { HostWindowService } from '../shared/host-window.service';
const headerStateSelector = (state: AppState) => state.header;
const navCollapsedSelector = createSelector(headerStateSelector, (header: HeaderState) => header.navCollapsed);
@Component({
selector: 'ds-header',
styleUrls: ['header.component.scss'],
templateUrl: 'header.component.html',
})
export class HeaderComponent implements OnInit {
export class HeaderComponent {
/**
* Whether user is authenticated.
* @type {Observable<string>}
*/
public isAuthenticated: Observable<boolean>;
public isNavBarCollapsed: Observable<boolean>;
public showAuth = false;
constructor(
private store: Store<AppState>,
private windowService: HostWindowService
) {
}
ngOnInit(): void {
// set loading
this.isNavBarCollapsed = this.store.select(navCollapsedSelector);
}
public toggle(): void {
this.store.dispatch(new HeaderToggleAction());
}
}

View File

@@ -10,23 +10,23 @@ import { type } from '../shared/ngrx/type';
* literal types and runs a simple check to guarantee all
* action types in the application are unique.
*/
export const HeaderActionTypes = {
COLLAPSE: type('dspace/header/COLLAPSE'),
EXPAND: type('dspace/header/EXPAND'),
TOGGLE: type('dspace/header/TOGGLE')
export const NavbarActionTypes = {
COLLAPSE: type('dspace/navbar/COLLAPSE'),
EXPAND: type('dspace/navbar/EXPAND'),
TOGGLE: type('dspace/navbar/TOGGLE')
};
/* tslint:disable:max-classes-per-file */
export class HeaderCollapseAction implements Action {
type = HeaderActionTypes.COLLAPSE;
export class NavbarCollapseAction implements Action {
type = NavbarActionTypes.COLLAPSE;
}
export class HeaderExpandAction implements Action {
type = HeaderActionTypes.EXPAND;
export class NavbarExpandAction implements Action {
type = NavbarActionTypes.EXPAND;
}
export class HeaderToggleAction implements Action {
type = HeaderActionTypes.TOGGLE;
export class NavbarToggleAction implements Action {
type = NavbarActionTypes.TOGGLE;
}
/* tslint:enable:max-classes-per-file */
@@ -34,7 +34,7 @@ export class HeaderToggleAction implements Action {
* Export a type alias of all actions in this action group
* so that reducers can easily compose action types
*/
export type HeaderAction
= HeaderCollapseAction
| HeaderExpandAction
| HeaderToggleAction
export type NavbarAction
= NavbarCollapseAction
| NavbarExpandAction
| NavbarToggleAction

View File

@@ -0,0 +1,46 @@
<nav class="navbar navbar-expand-md p-0">
<div class="container">
<div class="reset-padding">
<button class="navbar-toggler" type="button" (click)="toggle()"
aria-controls="collapsingNav"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon fa fa-bars fa-fw" aria-hidden="true"></span>
</button>
<div [ngbCollapse]="(isNavBarCollapsed | async)" class="collapse navbar-collapse"
id="collapsingNav">
<ul class="navbar-nav mr-auto">
<li ngbDropdown class="nav-item">
<a href="#" ngbDropdownToggle class="nav-link" routerLinkActive="active"
id="browseDropdown" (click)="$event.preventDefault();"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{
'nav.browse.header' | translate }}</a>
<div ngbDropdownMenu aria-labelledby="browseDropdown"
class="rounded-0 m-0 border-0">
<a class="dropdown-item" href="/communitylist">Communities &
Collections</a>
<a class="dropdown-item" href="/browse?type=dateissued">By Issue
Date</a>
<a class="dropdown-item" href="/browse?type=author">Authors</a>
</div>
</li>
<li ngbDropdown class="nav-item">
<a href="#" ngbDropdownToggle class="nav-link" routerLinkActive="active"
id="scopeBrowseDropdown" (click)="$event.preventDefault();"
data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">{{ 'nav.communityBrowse.header' | translate }}</a>
<div ngbDropdownMenu aria-labelledby="scopeBrowseDropdown"
class="rounded-0 m-0 border-0">
<a class="dropdown-item" href="/browse?type=dateissued">By Issue
Date</a>
<a class="dropdown-item" href="/browse?type=author">Authors</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/home" routerLinkActive="active">{{
'nav.statistics' | translate }}</a>
</li>
</ul>
</div>
</div>
</div>
</nav>

View File

@@ -0,0 +1,18 @@
@import '../../styles/variables.scss';
nav.navbar {
border-bottom: 1px $gray-400 solid;
}
nav.navbar .navbar-toggler .navbar-toggler-icon {
background-image: none !important;
line-height: 1.5;
}
.dropdown-menu {
min-width: 100%;
}
.reset-padding {
margin-left: -$spacer/2;
margin-right: -$spacer/2;
}

View File

@@ -1,4 +1,4 @@
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
@@ -6,13 +6,7 @@ import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs/Observable';
import { HeaderComponent } from './header.component';
import { HeaderState } from './header.reducer';
import { HeaderToggleAction } from './header.actions';
import { AuthNavMenuComponent } from '../shared/auth-nav-menu/auth-nav-menu.component';
import { LogInComponent } from '../shared/log-in/log-in.component';
import { LogOutComponent } from '../shared/log-out/log-out.component';
import { LoadingComponent } from '../shared/loading/loading.component';
import { NavbarComponent } from './navbar.component';
import { ReactiveFormsModule } from '@angular/forms';
import { HostWindowService } from '../shared/host-window.service';
import { HostWindowServiceStub } from '../shared/testing/host-window-service-stub';
@@ -20,12 +14,14 @@ import { RouterStub } from '../shared/testing/router-stub';
import { Router } from '@angular/router';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NavbarState } from './navbar.reducer';
import { NavbarToggleAction } from './navbar.actions';
let comp: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
let store: Store<HeaderState>;
let comp: NavbarComponent;
let fixture: ComponentFixture<NavbarComponent>;
let store: Store<NavbarState>;
describe('HeaderComponent', () => {
describe('NavbarComponent', () => {
// async beforeEach
beforeEach(async(() => {
@@ -36,7 +32,7 @@ describe('HeaderComponent', () => {
NgbCollapseModule.forRoot(),
NoopAnimationsModule,
ReactiveFormsModule],
declarations: [HeaderComponent],
declarations: [NavbarComponent],
providers: [
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
{ provide: Router, useClass: RouterStub },
@@ -48,7 +44,7 @@ describe('HeaderComponent', () => {
// synchronous beforeEach
beforeEach(() => {
fixture = TestBed.createComponent(HeaderComponent);
fixture = TestBed.createComponent(NavbarComponent);
comp = fixture.componentInstance;
@@ -63,8 +59,8 @@ describe('HeaderComponent', () => {
navbarToggler.triggerEventHandler('click', null);
});
it('should dispatch a HeaderToggleAction', () => {
expect(store.dispatch).toHaveBeenCalledWith(new HeaderToggleAction());
it('should dispatch a NavbarToggleAction', () => {
expect(store.dispatch).toHaveBeenCalledWith(new NavbarToggleAction());
});
});

View File

@@ -0,0 +1,34 @@
import { Component, OnInit } from '@angular/core';
import { createSelector, Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { NavbarState } from './navbar.reducer';
import { NavbarToggleAction } from './navbar.actions';
import { AppState } from '../app.reducer';
const navbarStateSelector = (state: AppState) => state.navbar;
const navCollapsedSelector = createSelector(navbarStateSelector, (navbar: NavbarState) => navbar.navCollapsed);
@Component({
selector: 'ds-navbar',
styleUrls: ['navbar.component.scss'],
templateUrl: 'navbar.component.html',
})
export class NavbarComponent implements OnInit {
public isNavBarCollapsed: Observable<boolean>;
constructor(
private store: Store<AppState>,
) {
}
ngOnInit(): void {
// set loading
this.isNavBarCollapsed = this.store.select(navCollapsedSelector);
}
public toggle(): void {
this.store.dispatch(new NavbarToggleAction());
}
}

View File

@@ -1,26 +1,26 @@
import { TestBed } from '@angular/core/testing';
import { HeaderEffects } from './header.effects';
import { HeaderCollapseAction } from './header.actions';
import { NavbarEffects } from './navbar.effects';
import { NavbarCollapseAction } from './navbar.actions';
import { HostWindowResizeAction } from '../shared/host-window.actions';
import { Observable } from 'rxjs/Observable';
import { provideMockActions } from '@ngrx/effects/testing';
import { cold, hot } from 'jasmine-marbles';
import * as fromRouter from '@ngrx/router-store';
describe('HeaderEffects', () => {
let headerEffects: HeaderEffects;
describe('NavbarEffects', () => {
let navbarEffects: NavbarEffects;
let actions: Observable<any>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
HeaderEffects,
NavbarEffects,
provideMockActions(() => actions),
// other providers
],
});
headerEffects = TestBed.get(HeaderEffects);
navbarEffects = TestBed.get(NavbarEffects);
});
describe('resize$', () => {
@@ -28,9 +28,9 @@ describe('HeaderEffects', () => {
it('should return a COLLAPSE action in response to a RESIZE action', () => {
actions = hot('--a-', { a: new HostWindowResizeAction(800, 600) });
const expected = cold('--b-', { b: new HeaderCollapseAction() });
const expected = cold('--b-', { b: new NavbarCollapseAction() });
expect(headerEffects.resize$).toBeObservable(expected);
expect(navbarEffects.resize$).toBeObservable(expected);
});
});
@@ -40,9 +40,9 @@ describe('HeaderEffects', () => {
it('should return a COLLAPSE action in response to an UPDATE_LOCATION action', () => {
actions = hot('--a-', { a: { type: fromRouter.ROUTER_NAVIGATION } });
const expected = cold('--b-', { b: new HeaderCollapseAction() });
const expected = cold('--b-', { b: new NavbarCollapseAction() });
expect(headerEffects.routeChange$).toBeObservable(expected);
expect(navbarEffects.routeChange$).toBeObservable(expected);
});
});

View File

@@ -3,18 +3,18 @@ import { Effect, Actions } from '@ngrx/effects'
import * as fromRouter from '@ngrx/router-store';
import { HostWindowActionTypes } from '../shared/host-window.actions';
import { HeaderCollapseAction } from './header.actions';
import { NavbarCollapseAction } from './navbar.actions';
@Injectable()
export class HeaderEffects {
export class NavbarEffects {
@Effect() resize$ = this.actions$
.ofType(HostWindowActionTypes.RESIZE)
.map(() => new HeaderCollapseAction());
.map(() => new NavbarCollapseAction());
@Effect() routeChange$ = this.actions$
.ofType(fromRouter.ROUTER_NAVIGATION)
.map(() => new HeaderCollapseAction());
.map(() => new NavbarCollapseAction());
constructor(private actions$: Actions) {

View File

@@ -1,13 +1,9 @@
import * as deepFreeze from 'deep-freeze';
import { headerReducer } from './header.reducer';
import {
HeaderCollapseAction,
HeaderExpandAction,
HeaderToggleAction
} from './header.actions';
import { navbarReducer } from './navbar.reducer';
import { NavbarCollapseAction, NavbarExpandAction, NavbarToggleAction } from './navbar.actions';
class NullAction extends HeaderCollapseAction {
class NullAction extends NavbarCollapseAction {
type = null;
constructor() {
@@ -15,18 +11,18 @@ class NullAction extends HeaderCollapseAction {
}
}
describe('headerReducer', () => {
describe('navbarReducer', () => {
it('should return the current state when no valid actions have been made', () => {
const state = { navCollapsed: false };
const action = new NullAction();
const newState = headerReducer(state, action);
const newState = navbarReducer(state, action);
expect(newState).toEqual(state);
});
it('should start with navCollapsed = true', () => {
const action = new NullAction();
const initialState = headerReducer(undefined, action);
const initialState = navbarReducer(undefined, action);
// The navigation starts collapsed
expect(initialState.navCollapsed).toEqual(true);
@@ -34,8 +30,8 @@ describe('headerReducer', () => {
it('should set navCollapsed to true in response to the COLLAPSE action', () => {
const state = { navCollapsed: false };
const action = new HeaderCollapseAction();
const newState = headerReducer(state, action);
const action = new NavbarCollapseAction();
const newState = navbarReducer(state, action);
expect(newState.navCollapsed).toEqual(true);
});
@@ -44,8 +40,8 @@ describe('headerReducer', () => {
const state = { navCollapsed: false };
deepFreeze(state);
const action = new HeaderCollapseAction();
headerReducer(state, action);
const action = new NavbarCollapseAction();
navbarReducer(state, action);
// no expect required, deepFreeze will ensure an exception is thrown if the state
// is mutated, and any uncaught exception will cause the test to fail
@@ -53,8 +49,8 @@ describe('headerReducer', () => {
it('should set navCollapsed to false in response to the EXPAND action', () => {
const state = { navCollapsed: true };
const action = new HeaderExpandAction();
const newState = headerReducer(state, action);
const action = new NavbarExpandAction();
const newState = navbarReducer(state, action);
expect(newState.navCollapsed).toEqual(false);
});
@@ -63,16 +59,16 @@ describe('headerReducer', () => {
const state = { navCollapsed: true };
deepFreeze(state);
const action = new HeaderExpandAction();
headerReducer(state, action);
const action = new NavbarExpandAction();
navbarReducer(state, action);
});
it('should flip the value of navCollapsed in response to the TOGGLE action', () => {
const state1 = { navCollapsed: true };
const action = new HeaderToggleAction();
const action = new NavbarToggleAction();
const state2 = headerReducer(state1, action);
const state3 = headerReducer(state2, action);
const state2 = navbarReducer(state1, action);
const state3 = navbarReducer(state2, action);
expect(state2.navCollapsed).toEqual(false);
expect(state3.navCollapsed).toEqual(true);
@@ -82,8 +78,8 @@ describe('headerReducer', () => {
const state = { navCollapsed: true };
deepFreeze(state);
const action = new HeaderToggleAction();
headerReducer(state, action);
const action = new NavbarToggleAction();
navbarReducer(state, action);
});
});

View File

@@ -1,30 +1,30 @@
import { HeaderAction, HeaderActionTypes } from './header.actions';
import { NavbarAction, NavbarActionTypes } from './navbar.actions';
export interface HeaderState {
export interface NavbarState {
navCollapsed: boolean;
}
const initialState: HeaderState = {
const initialState: NavbarState = {
navCollapsed: true
};
export function headerReducer(state = initialState, action: HeaderAction): HeaderState {
export function navbarReducer(state = initialState, action: NavbarAction): NavbarState {
switch (action.type) {
case HeaderActionTypes.COLLAPSE: {
case NavbarActionTypes.COLLAPSE: {
return Object.assign({}, state, {
navCollapsed: true
});
}
case HeaderActionTypes.EXPAND: {
case NavbarActionTypes.EXPAND: {
return Object.assign({}, state, {
navCollapsed: false
});
}
case HeaderActionTypes.TOGGLE: {
case NavbarActionTypes.TOGGLE: {
return Object.assign({}, state, {
navCollapsed: !state.navCollapsed
});

View File

@@ -1,6 +1,6 @@
<ul class="navbar-nav" [ngClass]="{'mr-auto': (isXsOrSm$ | async)}">
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item dropdown" (click)="$event.stopPropagation();">
<div ngbDropdown placement="bottom-right" class="d-inline-block float-right" @fadeInOut>
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item" (click)="$event.stopPropagation();">
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
<a href="#" id="dropdownLogin" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="caret"></span></a>
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
<ds-log-in></ds-log-in>
@@ -11,7 +11,7 @@
<a id="loginLink" class="nav-link" routerLink="/login" routerLinkActive="active"><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span></a>
</li>
<li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item">
<div ngbDropdown placement="bottom-right" class="d-inline-block" [ngClass]="{'float-right': !(isXsOrSm$ | async)}" @fadeInOut>
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
<a href="#" id="dropdownUser" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fa fa-user fa-fw" aria-hidden="true"></i>Hello {{(user | async).name}}<span class="caret"></span></a>
<div id="logoutDropdownMenu" ngbDropdownMenu aria-labelledby="dropdownUser">
<ds-log-out></ds-log-out>

View File

@@ -9,3 +9,7 @@ $drop-zone-area-inner-z-index: 1021;
$login-logo-height:72px;
$login-logo-width:72px;
$main-z-index: 0;
$nav-z-index: 10;
$header-logo-height: 80px;