finished look of sidebar

This commit is contained in:
lotte
2018-11-21 09:13:02 +01:00
parent cd5c7b72c2
commit ea3a2076c7
10 changed files with 110 additions and 52 deletions

View File

@@ -25,7 +25,7 @@
"prebuild:prod": "yarn run prebuild", "prebuild:prod": "yarn run prebuild",
"build": "webpack --progress --mode development", "build": "webpack --progress --mode development",
"build:aot": "webpack --env.aot --env.server --mode development && webpack --env.aot --env.client --mode development", "build:aot": "webpack --env.aot --env.server --mode development && webpack --env.aot --env.client --mode development",
"build:prod": "webpack --env.aot --env.server --env.production && webpack --env.aot --env.client --env.production", "build:prod": "webpack --env.aot --env.server --mode production && webpack --env.aot --env.client --mode production",
"postbuild:prod": "yarn run rollup", "postbuild:prod": "yarn run rollup",
"rollup": "rollup -c rollup.config.js", "rollup": "rollup -c rollup.config.js",
"prestart": "yarn run build:prod", "prestart": "yarn run build:prod",

View File

@@ -12,6 +12,7 @@ import { type } from '../../shared/ngrx/type';
*/ */
export const AdminSidebarActionTypes = { export const AdminSidebarActionTypes = {
SECTION_COLLAPSE: type('dspace/admin-sidebar/SECTION_COLLAPSE'), SECTION_COLLAPSE: type('dspace/admin-sidebar/SECTION_COLLAPSE'),
SECTION_COLLAPSE_ALL: type('dspace/admin-sidebar/SECTION_COLLAPSE_ALL'),
SECTION_EXPAND: type('dspace/admin-sidebar/SECTION_EXPAND'), SECTION_EXPAND: type('dspace/admin-sidebar/SECTION_EXPAND'),
SECTION_TOGGLE: type('dspace/admin-sidebar/SECTION_TOGGLE'), SECTION_TOGGLE: type('dspace/admin-sidebar/SECTION_TOGGLE'),
COLLAPSE: type('dspace/admin-sidebar/COLLAPSE'), COLLAPSE: type('dspace/admin-sidebar/COLLAPSE'),
@@ -73,6 +74,13 @@ export class AdminSidebarSectionCollapseAction extends AdminSidebarSectionAction
type = AdminSidebarActionTypes.SECTION_COLLAPSE; type = AdminSidebarActionTypes.SECTION_COLLAPSE;
} }
/**
* Used to collapse a section
*/
export class AdminSidebarSectionCollapseAllAction extends AdminSidebarAction {
type = AdminSidebarActionTypes.SECTION_COLLAPSE_ALL;
}
/** /**
* Used to expand a section * Used to expand a section
*/ */

View File

@@ -1,13 +1,16 @@
<nav class="navbar navbar-dark bg-dark p-0" [ngClass]="{'active': (sidebarCollapsed | async)}" <nav class="navbar navbar-dark bg-dark p-0" [ngClass]="{'active': sidebarActive}"
[@slideSidebar]="{ [@slideSidebar]="{
value: ((sidebarCollapsed | async) ? 'collapsed' : 'expanded'), value: ((sidebarCollapsed | async) ? 'collapsed' : 'expanded'),
params: {sidebarWidth: (sidebarWidth | async)} params: {sidebarWidth: (sidebarWidth | async)}
}"> }" (@slideSidebar.done)="finishSlide($event)">
<div class="sidebar-top-level-items"> <div class="sidebar-top-level-items">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="admin-menu-header"> <li class="admin-menu-header">
<a class="shortcuts-tree navbar-brand" href="#"> <a class="shortcuts-tree navbar-brand mr-0" href="#">
<img class="admin-logo mr-2" src="assets/images/dspace-logo-mini.svg"> <span class="logo-wrapper">
<img class="admin-logo" src="assets/images/dspace-logo-mini.svg">
</span>
<h4 class="section-header-text">Admin</h4> <h4 class="section-header-text">Admin</h4>
</a> </a>
</li> </li>
@@ -17,7 +20,7 @@
<i class="fas fa-plus-circle fa-fw"></i> <i class="fas fa-plus-circle fa-fw"></i>
<span class="section-header-text">New</span> <span class="section-header-text">New</span>
<i class="fas fa-chevron-right fa-pull-right fa-xxs" <i class="fas fa-chevron-right fa-pull-right fa-xxs"
[ngClass]="{'fa-rotate-90': (active('new') | async)}"></i> [@rotateInOut]="(active('new') | async) ? 'rotateOut': 'rotateIn'"></i>
</a> </a>
<ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('new') | async)"> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('new') | async)">
<li><a class="nav-item nav-link" href="#">Community</a></li> <li><a class="nav-item nav-link" href="#">Community</a></li>

View File

@@ -16,9 +16,9 @@
overflow: auto; overflow: auto;
} }
} }
.section-header-text, .fa-chevron-right {
.section-header-text { display: none;
display: inline; padding-left: $spacer/2;
} }
.navbar-nav { .navbar-nav {
@@ -27,11 +27,9 @@
&.active { &.active {
background-color: $admin-sidebar-dark; background-color: $admin-sidebar-dark;
} }
.fa-fw {
text-align: left;
width: 1.75em;
}
} }
.sidebar-sub-level-items { .sidebar-sub-level-items {
list-style: disc; list-style: disc;
color: $navbar-dark-color; color: $navbar-dark-color;
@@ -42,16 +40,25 @@
} }
.admin-menu-header { .admin-menu-header {
background-color: $admin-sidebar-dark; background-color: $admin-sidebar-dark;
img { .logo-wrapper {
height: 1em; text-align: center;
vertical-align: baseline; display: inline-block;
width: 1.25em;
img {
height: 1em;
vertical-align: text-bottom;
}
} }
.section-header-text {
vertical-align: bottom;
}
} }
} }
&.active { &.active {
.section-header-text, .fa-chevron-right { .section-header-text, .fa-chevron-right {
display: none; display: inline;
} }
} }
} }

View File

@@ -4,10 +4,15 @@ import { MemoizedSelector, select, Store } from '@ngrx/store';
import { AdminSidebarSectionState, AdminSidebarState, } from './admin-sidebar.reducer'; import { AdminSidebarSectionState, AdminSidebarState, } from './admin-sidebar.reducer';
import { hasValue } from '../../shared/empty.util'; import { hasValue } from '../../shared/empty.util';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { AdminSidebarSectionToggleAction, AdminSidebarToggleAction } from './admin-sidebar.actions'; import {
AdminSidebarSectionCollapseAllAction,
AdminSidebarSectionToggleAction,
AdminSidebarToggleAction
} from './admin-sidebar.actions';
import { AppState, keySelector } from '../../app.reducer'; import { AppState, keySelector } from '../../app.reducer';
import { slideSidebar } from '../../shared/animations/slide'; import { slideSidebar } from '../../shared/animations/slide';
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service'; import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
import { rotateInOut } from '../../shared/animations/rotate';
const sidebarSectionStateSelector = (state: AppState) => state.adminSidebar.sections; const sidebarSectionStateSelector = (state: AppState) => state.adminSidebar.sections;
const sidebarStateSelector = (state) => state.adminSidebar; const sidebarStateSelector = (state) => state.adminSidebar;
@@ -20,11 +25,12 @@ const sectionByNameSelector = (name: string): MemoizedSelector<AppState, AdminSi
selector: 'ds-admin-sidebar', selector: 'ds-admin-sidebar',
templateUrl: './admin-sidebar.component.html', templateUrl: './admin-sidebar.component.html',
styleUrls: ['./admin-sidebar.component.scss'], styleUrls: ['./admin-sidebar.component.scss'],
animations: [slideSidebar] animations: [slideSidebar, rotateInOut]
}) })
export class AdminSidebarComponent implements OnInit { export class AdminSidebarComponent implements OnInit {
sidebarCollapsed: Observable<boolean>; sidebarCollapsed: Observable<boolean>;
sidebarWidth: Observable<string>; sidebarWidth: Observable<string>;
sidebarActive = true;
constructor(private store: Store<AdminSidebarState>, constructor(private store: Store<AdminSidebarState>,
private variableService: CSSVariableService) { private variableService: CSSVariableService) {
@@ -52,6 +58,21 @@ export class AdminSidebarComponent implements OnInit {
toggle(event: Event) { toggle(event: Event) {
event.preventDefault(); event.preventDefault();
// Is sidebar closing?
if (this.sidebarActive) {
this.sidebarActive = false;
this.store.dispatch(new AdminSidebarSectionCollapseAllAction());
}
this.store.dispatch(new AdminSidebarToggleAction()); this.store.dispatch(new AdminSidebarToggleAction());
} }
/**
* Method to change this.collapsed to false when the slide animation ends and is sliding open
* @param event The animation event
*/
finishSlide(event: any): void {
if (event.fromState === 'collapsed') {
this.sidebarActive = true;
}
}
} }

View File

@@ -59,6 +59,16 @@ export function adminSidebarReducer(state = initialState, action: AdminSidebarAc
collapsed: !collapsed collapsed: !collapsed
}); });
} }
case AdminSidebarActionTypes.SECTION_COLLAPSE_ALL: {
const newSectionState: AdminSidebarSectionState = Object.create(null);
if (hasValue(state.sections)) {
Object.keys(state.sections).forEach((section) =>
newSectionState[section] = {
sectionCollapsed: true
});
}
return Object.assign({}, state, { sections: newSectionState });
}
default: { default: {
return state; return state;
} }

View File

@@ -12,6 +12,10 @@ export const rotateLeave = transition('rotateIn => rotateOut', [
animate('400ms ease-in-out') animate('400ms ease-in-out')
]); ]);
export const rotate = state('rotate', style({opacity: 0, transform: 'rotate(90deg)'}));
export const rotateIn = trigger('rotateIn', [ export const rotateIn = trigger('rotateIn', [
rotateEnter rotateEnter
]); ]);

View File

@@ -2,7 +2,11 @@ import { Store, StoreModule } from '@ngrx/store';
import { async, inject, TestBed } from '@angular/core/testing'; import { async, inject, TestBed } from '@angular/core/testing';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { DynamicFormControlModel, DynamicInputModel } from '@ng-dynamic-forms/core'; import {
DynamicFormControlModel,
DynamicFormGroupModel,
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { FormService } from './form.service'; import { FormService } from './form.service';
import { FormBuilderService } from './builder/form-builder.service'; import { FormBuilderService } from './builder/form-builder.service';
@@ -10,7 +14,7 @@ import { AppState } from '../../app.reducer';
import { formReducer } from './form.reducer'; import { formReducer } from './form.reducer';
import { getMockFormBuilderService } from '../mocks/mock-form-builder-service'; import { getMockFormBuilderService } from '../mocks/mock-form-builder-service';
describe('FormService test suite', () => { fdescribe('FormService test suite', () => {
const config = { const config = {
form: { form: {
validatorMap: { validatorMap: {
@@ -37,30 +41,30 @@ describe('FormService test suite', () => {
}), }),
new DynamicInputModel({ id: 'date' }), new DynamicInputModel({ id: 'date' }),
new DynamicInputModel({ id: 'description' }), new DynamicInputModel({ id: 'description' }),
// new DynamicFormGroupModel({ new DynamicFormGroupModel({
//
// id: 'addressLocation', id: 'addressLocation',
// group: [ group: [
// new DynamicInputModel({ new DynamicInputModel({
//
// id: 'zipCode', id: 'zipCode',
// label: 'Zip Code', label: 'Zip Code',
// placeholder: 'ZIP' placeholder: 'ZIP'
// }), }),
// new DynamicInputModel({ new DynamicInputModel({
//
// id: 'state', id: 'state',
// label: 'State', label: 'State',
// placeholder: 'State' placeholder: 'State'
// }), }),
// new DynamicInputModel({ new DynamicInputModel({
//
// id: 'city', id: 'city',
// label: 'City', label: 'City',
// placeholder: 'City' placeholder: 'City'
// }) })
// ] ]
// }), }),
]; ];
let controls; let controls;

View File

@@ -19,7 +19,7 @@ describe('HostWindowService', () => {
beforeEach(() => { beforeEach(() => {
const _initialState = { hostWindow: { width: 1600, height: 770 } }; const _initialState = { hostWindow: { width: 1600, height: 770 } };
store = new Store<AppState>(observableOf(_initialState), undefined, undefined); store = new Store<AppState>(observableOf(_initialState), undefined, undefined);
service = new HostWindowService(store); service = new HostWindowService(store, null);
}); });
it('isXs() should return false with width = 1600', () => { it('isXs() should return false with width = 1600', () => {
@@ -55,7 +55,7 @@ describe('HostWindowService', () => {
beforeEach(() => { beforeEach(() => {
const _initialState = { hostWindow: { width: 1100, height: 770 } }; const _initialState = { hostWindow: { width: 1100, height: 770 } };
store = new Store<AppState>(observableOf(_initialState), undefined, undefined); store = new Store<AppState>(observableOf(_initialState), undefined, undefined);
service = new HostWindowService(store); service = new HostWindowService(store, null);
}); });
it('isXs() should return false with width = 1100', () => { it('isXs() should return false with width = 1100', () => {
@@ -91,7 +91,7 @@ describe('HostWindowService', () => {
beforeEach(() => { beforeEach(() => {
const _initialState = { hostWindow: { width: 800, height: 770 } }; const _initialState = { hostWindow: { width: 800, height: 770 } };
store = new Store<AppState>(observableOf(_initialState), undefined, undefined); store = new Store<AppState>(observableOf(_initialState), undefined, undefined);
service = new HostWindowService(store); service = new HostWindowService(store, null);
}); });
it('isXs() should return false with width = 800', () => { it('isXs() should return false with width = 800', () => {
@@ -127,7 +127,7 @@ describe('HostWindowService', () => {
beforeEach(() => { beforeEach(() => {
const _initialState = { hostWindow: { width: 600, height: 770 } }; const _initialState = { hostWindow: { width: 600, height: 770 } };
store = new Store<AppState>(observableOf(_initialState), undefined, undefined); store = new Store<AppState>(observableOf(_initialState), undefined, undefined);
service = new HostWindowService(store); service = new HostWindowService(store, null);
}); });
it('isXs() should return false with width = 600', () => { it('isXs() should return false with width = 600', () => {
@@ -163,7 +163,7 @@ describe('HostWindowService', () => {
beforeEach(() => { beforeEach(() => {
const _initialState = { hostWindow: { width: 400, height: 770 } }; const _initialState = { hostWindow: { width: 400, height: 770 } };
store = new Store<AppState>(observableOf(_initialState), undefined, undefined); store = new Store<AppState>(observableOf(_initialState), undefined, undefined);
service = new HostWindowService(store); service = new HostWindowService(store, null);
}); });
it('isXs() should return true with width = 400', () => { it('isXs() should return true with width = 400', () => {
@@ -197,7 +197,7 @@ describe('HostWindowService', () => {
describe('widthCategory', () => { describe('widthCategory', () => {
beforeEach(() => { beforeEach(() => {
service = new HostWindowService({} as Store<AppState>); service = new HostWindowService({} as Store<AppState>, null);
}); });
it('should call getWithObs to get the current width', () => { it('should call getWithObs to get the current width', () => {

View File

@@ -27,7 +27,8 @@ module.exports = function(env, options) {
getAotPlugin('client', !!env.aot) getAotPlugin('client', !!env.aot)
] ]
}); });
if (env.production) { console.log(options.mode);
if (options.mode === 'production') {
serverConfig = webpackMerge({}, serverConfig, prodPartial); serverConfig = webpackMerge({}, serverConfig, prodPartial);
clientConfig = webpackMerge({}, clientConfig, prodPartial); clientConfig = webpackMerge({}, clientConfig, prodPartial);
} }