mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
@@ -62,6 +62,11 @@
|
|||||||
"@angularclass/bootloader": "1.0.1",
|
"@angularclass/bootloader": "1.0.1",
|
||||||
"@angularclass/idle-preload": "1.0.4",
|
"@angularclass/idle-preload": "1.0.4",
|
||||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.14",
|
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.14",
|
||||||
|
"@ngrx/core": "^1.2.0",
|
||||||
|
"@ngrx/effects": "^2.0.0",
|
||||||
|
"@ngrx/router-store": "^1.2.5",
|
||||||
|
"@ngrx/store": "^2.2.1",
|
||||||
|
"@ngrx/store-devtools": "^3.2.2",
|
||||||
"angular2-express-engine": "2.1.0-rc.1",
|
"angular2-express-engine": "2.1.0-rc.1",
|
||||||
"angular2-platform-node": "2.1.0-rc.1",
|
"angular2-platform-node": "2.1.0-rc.1",
|
||||||
"angular2-universal": "2.1.0-rc.1",
|
"angular2-universal": "2.1.0-rc.1",
|
||||||
|
@@ -1,21 +1,4 @@
|
|||||||
<header>
|
<ds-header></ds-header>
|
||||||
<nav class="navbar navbar-dark bg-inverse">
|
|
||||||
<button class="navbar-toggler hidden-sm-up" type="button" (click)="toggle()" aria-controls="collapsingNav" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<i class="fa fa-bars fa-fw" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<div [ngClass]="{'clearfix': !isNavBarCollaped()}">
|
|
||||||
<a class="navbar-brand" routerLink="/home">
|
|
||||||
<!-- TODO: add logo here -->{{ 'title' | translate }}</a>
|
|
||||||
</div>
|
|
||||||
<div [ngbCollapse]="isNavBarCollaped()" class="collapse navbar-toggleable-xs" id="collapsingNav">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<main>
|
<main>
|
||||||
|
@@ -1,13 +1 @@
|
|||||||
@import '../styles/variables.scss';
|
|
||||||
|
|
||||||
header nav.navbar {
|
|
||||||
border-radius: 0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
header nav.navbar .navbar-toggler {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
header nav.navbar .navbar-toggler:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
@@ -1,7 +1,14 @@
|
|||||||
import { Component, HostListener, Input, ChangeDetectionStrategy, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core';
|
import {
|
||||||
import { Event, NavigationEnd, Router } from '@angular/router';
|
Component,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
import { TranslateService } from 'ng2-translate';
|
ViewEncapsulation,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit, HostListener
|
||||||
|
} from "@angular/core";
|
||||||
|
import { TranslateService } from "ng2-translate";
|
||||||
|
import { HostWindowState } from "./shared/host-window.reducer";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { HostWindowActions } from "./shared/host-window.actions";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
changeDetection: ChangeDetectionStrategy.Default,
|
changeDetection: ChangeDetectionStrategy.Default,
|
||||||
@@ -11,14 +18,6 @@ import { TranslateService } from 'ng2-translate';
|
|||||||
styleUrls: ['./app.component.css']
|
styleUrls: ['./app.component.css']
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnDestroy, OnInit {
|
export class AppComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
// TODO: move header and all related properties into its own component
|
|
||||||
|
|
||||||
private navCollapsed: boolean;
|
|
||||||
|
|
||||||
private routerSubscription: any;
|
|
||||||
|
|
||||||
|
|
||||||
private translateSubscription: any;
|
private translateSubscription: any;
|
||||||
|
|
||||||
example: string;
|
example: string;
|
||||||
@@ -26,32 +25,25 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
data: any = {
|
data: any = {
|
||||||
greeting: 'Hello',
|
greeting: 'Hello',
|
||||||
recipient: 'World'
|
recipient: 'World'
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(public translate: TranslateService, private router: Router) {
|
constructor(
|
||||||
|
private translate: TranslateService,
|
||||||
|
private store: Store<HostWindowState>
|
||||||
|
) {
|
||||||
// this language will be used as a fallback when a translation isn't found in the current language
|
// this language will be used as a fallback when a translation isn't found in the current language
|
||||||
translate.setDefaultLang('en');
|
translate.setDefaultLang('en');
|
||||||
// the lang to use, if the lang isn't available, it will use the current loader to get them
|
// the lang to use, if the lang isn't available, it will use the current loader to get them
|
||||||
translate.use('en');
|
translate.use('en');
|
||||||
|
|
||||||
this.collapse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.routerSubscription = this.router.events.subscribe((event: Event) => {
|
|
||||||
if (event instanceof NavigationEnd) {
|
|
||||||
this.collapse();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.translateSubscription = this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((translation: string) => {
|
this.translateSubscription = this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((translation: string) => {
|
||||||
this.example = translation;
|
this.example = translation;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.routerSubscription) {
|
|
||||||
this.routerSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
if (this.translateSubscription) {
|
if (this.translateSubscription) {
|
||||||
this.translateSubscription.unsubscribe();
|
this.translateSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
@@ -59,23 +51,9 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
private onResize(event): void {
|
private onResize(event): void {
|
||||||
this.collapse();
|
this.store.dispatch(
|
||||||
}
|
HostWindowActions.resize(event.target.innerWidth, event.target.innerHeight)
|
||||||
|
);
|
||||||
private collapse(): void {
|
|
||||||
this.navCollapsed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private expand(): void {
|
|
||||||
this.navCollapsed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggle(): void {
|
|
||||||
this.navCollapsed ? this.expand() : this.collapse();
|
|
||||||
}
|
|
||||||
|
|
||||||
public isNavBarCollaped(): boolean {
|
|
||||||
return this.navCollapsed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
6
src/app/app.effects.ts
Normal file
6
src/app/app.effects.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { EffectsModule } from "@ngrx/effects";
|
||||||
|
import { HeaderEffects } from "./header/header.effects";
|
||||||
|
|
||||||
|
export const effects = [
|
||||||
|
EffectsModule.run(HeaderEffects)
|
||||||
|
];
|
@@ -5,14 +5,54 @@ import { SharedModule } from './shared/shared.module';
|
|||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
import { HeaderComponent } from './header/header.component';
|
||||||
|
|
||||||
|
import { StoreModule } from "@ngrx/store";
|
||||||
|
import { RouterStoreModule } from "@ngrx/router-store";
|
||||||
|
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
|
||||||
|
|
||||||
|
import { rootReducer } from './app.reducers';
|
||||||
|
import { effects } from './app.effects';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
HeaderComponent
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
SharedModule,
|
SharedModule,
|
||||||
HomeModule,
|
HomeModule,
|
||||||
AppRoutingModule
|
AppRoutingModule,
|
||||||
|
/**
|
||||||
|
* StoreModule.provideStore is imported once in the root module, accepting a reducer
|
||||||
|
* function or object map of reducer functions. If passed an object of
|
||||||
|
* reducers, combineReducers will be run creating your application
|
||||||
|
* meta-reducer. This returns all providers for an @ngrx/store
|
||||||
|
* based application.
|
||||||
|
*/
|
||||||
|
StoreModule.provideStore(rootReducer),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngrx/router-store keeps router state up-to-date in the store and uses
|
||||||
|
* the store as the single source of truth for the router's state.
|
||||||
|
*/
|
||||||
|
RouterStoreModule.connectRouter(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store devtools instrument the store retaining past versions of state
|
||||||
|
* and recalculating new states. This enables powerful time-travel
|
||||||
|
* debugging.
|
||||||
|
*
|
||||||
|
* To use the debugger, install the Redux Devtools extension for either
|
||||||
|
* Chrome or Firefox
|
||||||
|
*
|
||||||
|
* See: https://github.com/zalmoxisus/redux-devtools-extension
|
||||||
|
*/
|
||||||
|
StoreDevtoolsModule.instrumentOnlyWithExtension(),
|
||||||
|
|
||||||
|
effects
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
20
src/app/app.reducers.ts
Normal file
20
src/app/app.reducers.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { combineReducers } from "@ngrx/store";
|
||||||
|
import { routerReducer, RouterState } from "@ngrx/router-store";
|
||||||
|
import { headerReducer, HeaderState } from './header/header.reducer';
|
||||||
|
import { hostWindowReducer, HostWindowState } from "./shared/host-window.reducer";
|
||||||
|
|
||||||
|
export interface AppState {
|
||||||
|
router: RouterState;
|
||||||
|
hostWindow: HostWindowState;
|
||||||
|
header: HeaderState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reducers = {
|
||||||
|
router: routerReducer,
|
||||||
|
hostWindow: hostWindowReducer,
|
||||||
|
header: headerReducer
|
||||||
|
};
|
||||||
|
|
||||||
|
export function rootReducer(state: any, action: any) {
|
||||||
|
return combineReducers(reducers)(state, action);
|
||||||
|
}
|
24
src/app/header/header.actions.ts
Normal file
24
src/app/header/header.actions.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Action } from "@ngrx/store";
|
||||||
|
|
||||||
|
export class HeaderActions {
|
||||||
|
static COLLAPSE = 'dspace/header/COLLAPSE';
|
||||||
|
static collapse(): Action {
|
||||||
|
return {
|
||||||
|
type: HeaderActions.COLLAPSE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static EXPAND = 'dspace/header/EXPAND';
|
||||||
|
static expand(): Action {
|
||||||
|
return {
|
||||||
|
type: HeaderActions.EXPAND
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TOGGLE = 'dspace/header/TOGGLE';
|
||||||
|
static toggle(): Action {
|
||||||
|
return {
|
||||||
|
type: HeaderActions.TOGGLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/app/header/header.component.html
Normal file
18
src/app/header/header.component.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<header>
|
||||||
|
<nav class="navbar navbar-dark bg-inverse">
|
||||||
|
<button class="navbar-toggler hidden-sm-up" type="button" (click)="toggle()" aria-controls="collapsingNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<i class="fa fa-bars fa-fw" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<div [ngClass]="{'clearfix': !(isNavBarCollapsed | async)}">
|
||||||
|
<a class="navbar-brand" routerLink="/home">
|
||||||
|
<!-- TODO: add logo here -->{{ 'title' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
<div [ngbCollapse]="(isNavBarCollapsed | async)" class="collapse navbar-toggleable-xs" id="collapsingNav">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
13
src/app/header/header.component.scss
Normal file
13
src/app/header/header.component.scss
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
@import '../../styles/variables.scss';
|
||||||
|
|
||||||
|
header nav.navbar {
|
||||||
|
border-radius: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header nav.navbar .navbar-toggler {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
header nav.navbar .navbar-toggler:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
39
src/app/header/header.component.ts
Normal file
39
src/app/header/header.component.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Store } from "@ngrx/store";
|
||||||
|
import { HeaderState } from "./header.reducer";
|
||||||
|
import { HeaderActions } from "./header.actions";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
import 'rxjs/add/operator/filter';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-header',
|
||||||
|
styleUrls: ['header.component.css'],
|
||||||
|
templateUrl: 'header.component.html'
|
||||||
|
})
|
||||||
|
export class HeaderComponent implements OnInit {
|
||||||
|
public isNavBarCollapsed: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<HeaderState>
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.isNavBarCollapsed = this.store.select('header')
|
||||||
|
//unwrap navCollapsed
|
||||||
|
.map(({ navCollapsed }: HeaderState) => navCollapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private collapse(): void {
|
||||||
|
this.store.dispatch(HeaderActions.collapse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private expand(): void {
|
||||||
|
this.store.dispatch(HeaderActions.expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggle(): void {
|
||||||
|
this.store.dispatch(HeaderActions.toggle());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
src/app/header/header.effects.ts
Normal file
21
src/app/header/header.effects.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { Effect, Actions } from '@ngrx/effects'
|
||||||
|
import { HeaderActions } from "./header.actions";
|
||||||
|
import { HostWindowActions } from "../shared/host-window.actions";
|
||||||
|
import { routerActions } from "@ngrx/router-store";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HeaderEffects {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private actions$: Actions
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@Effect() resize$ = this.actions$
|
||||||
|
.ofType(HostWindowActions.RESIZE)
|
||||||
|
.map(() => HeaderActions.collapse());
|
||||||
|
|
||||||
|
@Effect() routeChange$ = this.actions$
|
||||||
|
.ofType(routerActions.UPDATE_LOCATION)
|
||||||
|
.map(() => HeaderActions.collapse());
|
||||||
|
}
|
39
src/app/header/header.reducer.ts
Normal file
39
src/app/header/header.reducer.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Action } from "@ngrx/store";
|
||||||
|
import { HeaderActions } from "./header.actions";
|
||||||
|
|
||||||
|
export interface HeaderState {
|
||||||
|
navCollapsed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: HeaderState = {
|
||||||
|
navCollapsed: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export const headerReducer = (state = initialState, action: Action): HeaderState => {
|
||||||
|
switch (action.type) {
|
||||||
|
|
||||||
|
case HeaderActions.COLLAPSE: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
navCollapsed: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case HeaderActions.EXPAND: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
navCollapsed: false
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case HeaderActions.TOGGLE: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
navCollapsed: !state.navCollapsed
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
14
src/app/shared/host-window.actions.ts
Normal file
14
src/app/shared/host-window.actions.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Action } from "@ngrx/store";
|
||||||
|
|
||||||
|
export class HostWindowActions {
|
||||||
|
static RESIZE = 'dspace/host-window/RESIZE';
|
||||||
|
static resize(newWidth: number, newHeight: number): Action {
|
||||||
|
return {
|
||||||
|
type: HostWindowActions.RESIZE,
|
||||||
|
payload: {
|
||||||
|
width: newWidth,
|
||||||
|
height: newHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/app/shared/host-window.reducer.ts
Normal file
25
src/app/shared/host-window.reducer.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Action } from "@ngrx/store";
|
||||||
|
import { HostWindowActions } from "./host-window.actions";
|
||||||
|
|
||||||
|
export interface HostWindowState {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: HostWindowState = {
|
||||||
|
width: null,
|
||||||
|
height: null
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hostWindowReducer = (state = initialState, action: Action): HostWindowState => {
|
||||||
|
switch (action.type) {
|
||||||
|
|
||||||
|
case HostWindowActions.RESIZE: {
|
||||||
|
return Object.assign({}, state, action.payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Reference in New Issue
Block a user