57053: horizontal menu

This commit is contained in:
lotte
2018-11-09 10:18:17 +01:00
parent 2af1d3b042
commit b0fe14d015
15 changed files with 194 additions and 53 deletions

View File

@@ -46,7 +46,15 @@
}
},
"nav": {
"home": "Home",
"browse": {
"header": "All of DSpace"
},
"community-browse": {
"header": "By Community"
},
"statistics": {
"header": "Statistics"
},
"login": "Log In",
"logout": "Log Out"
},

View File

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

View File

@@ -34,6 +34,6 @@ body {
margin-bottom: $content-spacing;
}
ds-navbar {
ds-header-navbar-wrapper {
z-index: $nav-z-index;
}

View File

@@ -32,6 +32,7 @@ import { NotificationsBoardComponent } from './shared/notifications/notification
import { NotificationComponent } from './shared/notifications/notification/notification.component';
import { SharedModule } from './shared/shared.module';
import { NavbarComponent } from './navbar/navbar.component';
import { HeaderNavbarWrapperComponent } from './header-nav-wrapper/header-navbar-wrapper.component';
export function getConfig() {
return ENV_CONFIG;
@@ -89,6 +90,7 @@ if (!ENV_CONFIG.production) {
AppComponent,
HeaderComponent,
NavbarComponent,
HeaderNavbarWrapperComponent,
FooterComponent,
PageNotFoundComponent,
NotificationComponent,

View File

@@ -0,0 +1,4 @@
<div [ngClass]="{'open': !(isNavBarCollapsed | async)}">
<ds-header></ds-header>
<ds-navbar [isNavBarCollapsed]="isNavBarCollapsed"></ds-navbar>
</div>

View File

@@ -0,0 +1,9 @@
@import '../../styles/variables.scss';
@media screen and (max-width: map-get($grid-breakpoints, md)) {
:host.open {
background-color: $white;
top: 0;
position: sticky;
}
}

View File

@@ -0,0 +1,36 @@
import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core';
import { createSelector, Store } from '@ngrx/store';
import { AppState } from '../app.reducer';
import { Observable } from 'rxjs/Observable';
import { NavbarState } from '../navbar/navbar.reducer';
import { Subscription } from 'rxjs/Subscription';
import { hasValue } from '../shared/empty.util';
const navbarStateSelector = (state: AppState) => state.navbar;
const navCollapsedSelector = createSelector(navbarStateSelector, (navbar: NavbarState) => navbar.navCollapsed);
@Component({
selector: 'ds-header-navbar-wrapper',
styleUrls: ['header-navbar-wrapper.component.scss'],
templateUrl: 'header-navbar-wrapper.component.html',
})
export class HeaderNavbarWrapperComponent implements OnInit, OnDestroy {
@HostBinding('class.open') isOpen = false;
private sub: Subscription;
public isNavBarCollapsed: Observable<boolean>;
constructor(
private store: Store<AppState>
) {
}
ngOnInit(): void {
this.isNavBarCollapsed = this.store.select(navCollapsedSelector);
this.sub = this.isNavBarCollapsed.subscribe((isCollapsed) => this.isOpen = !isCollapsed)
}
ngOnDestroy() {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
}

View File

@@ -3,8 +3,16 @@
<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">
<nav class="navbar navbar-light navbar-expand-md float-right px-0">
<ds-auth-nav-menu></ds-auth-nav-menu>
<div class="pl-2">
<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>
</nav>
</div>
</header>

View File

@@ -3,3 +3,7 @@
.navbar-brand img {
height: $header-logo-height;
}
.navbar-toggler .navbar-toggler-icon {
background-image: none !important;
line-height: 1.5;
}

View File

@@ -1,5 +1,8 @@
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { NavbarToggleAction } from '../navbar/navbar.actions';
import { Store } from '@ngrx/store';
import { AppState } from '../app.reducer';
@Component({
selector: 'ds-header',
@@ -13,4 +16,13 @@ export class HeaderComponent {
*/
public isAuthenticated: Observable<boolean>;
public showAuth = false;
constructor(
private store: Store<AppState>,
) {
}
public toggle(): void {
this.store.dispatch(new NavbarToggleAction());
}
}

View File

@@ -1,43 +1,43 @@
<nav class="navbar navbar-expand-md p-0">
<nav [ngClass]="{'open': !(isNavBarCollapsed | async)}"
[@slideMobileNav]="!(windowService.isXsOrSm() | async) ? 'default' : ((isNavBarCollapsed | async) ? 'collapsed' : 'expanded')"
class="navbar navbar-light navbar-expand-md p-md-0 navbar-container"> <!-- TODO remove navbar-container class when https://github.com/twbs/bootstrap/issues/24726 is fixed -->
<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">
<div class="reset-padding-md w-100">
<div id="collapsingNav">
<ul class="navbar-nav mr-auto shadow-none">
<li ngbDropdown class="nav-item" #dropdown1="ngbDropdown"
(mouseenter)="openDropdownOnHover(dropdown1)"
(mouseleave)="closeDropdownOnHover(dropdown1)">
<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">
class="rounded-bottom m-0 shadow-none border-top-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>
<a class="dropdown-item" href="/browse?type=author">By Author</a>
</div>
</li>
<li ngbDropdown class="nav-item">
<li ngbDropdown class="nav-item" #dropdown2="ngbDropdown"
(mouseenter)="openDropdownOnHover(dropdown2)"
(mouseleave)="closeDropdownOnHover(dropdown2)">
<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>
aria-expanded="false">{{ 'nav.community-browse.header' | translate }}</a>
<div ngbDropdownMenu aria-labelledby="scopeBrowseDropdown"
class="rounded-0 m-0 border-0">
class="rounded-bottom m-0 shadow-none border-top-0">
<a class="dropdown-item" href="/browse?type=dateissued">By Issue
Date</a>
<a class="dropdown-item" href="/browse?type=author">Authors</a>
<a class="dropdown-item" href="/browse?type=author">By Author</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/home" routerLinkActive="active">{{
'nav.statistics' | translate }}</a>
<a class="nav-link" routerLink="/statistics" routerLinkActive="active">{{
'nav.statistics.header' | translate }}</a>
</li>
</ul>
</div>

View File

@@ -1,18 +1,56 @@
@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;
border-bottom: 1px $gray-400 solid;
align-items: baseline;
}
.dropdown-menu {
min-width: 100%;
min-width: 100%;
}
.reset-padding {
margin-left: -$spacer/2;
margin-right: -$spacer/2;
/** Mobile menu styling **/
@media screen and (max-width: map-get($grid-breakpoints, md)) {
.navbar {
width: 100%;
left: 0;
background-color: $white;
position: absolute;
overflow: hidden;
height: 0;
&.open {
height: 100vh; //doesn't matter because wrapper is sticky
}
.dropdown-toggle {
&:after {
float: right;
margin-top: $spacer/2;
}
}
.dropdown-menu {
border: 0;
}
}
}
@media screen and (min-width: map-get($grid-breakpoints, md)) {
.reset-padding-md {
margin-left: -$spacer/2;
margin-right: -$spacer/2;
}
}
/* TODO remove when https://github.com/twbs/bootstrap/issues/24726 is fixed */
.navbar-expand-md.navbar-container {
@media screen and (max-width: map-get($grid-breakpoints, md)) {
> .container {
padding-left: $spacer;
padding-right: $spacer;
}
padding-left: 0;
padding-right: 0;
}
}

View File

@@ -1,34 +1,45 @@
import { Component, OnInit } from '@angular/core';
import { createSelector, Store } from '@ngrx/store';
import { Component, Input } from '@angular/core';
import { 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);
import { slideMobileNav } from '../shared/animations/slide';
import { HostWindowService } from '../shared/host-window.service';
import { first } from 'rxjs/operators';
@Component({
selector: 'ds-navbar',
styleUrls: ['navbar.component.scss'],
templateUrl: 'navbar.component.html',
animations: [slideMobileNav]
})
export class NavbarComponent implements OnInit {
public isNavBarCollapsed: Observable<boolean>;
export class NavbarComponent {
@Input() isNavBarCollapsed: Observable<boolean>;
constructor(
private store: Store<AppState>,
protected windowService: HostWindowService
) {
}
ngOnInit(): void {
// set loading
this.isNavBarCollapsed = this.store.select(navCollapsedSelector);
openDropdownOnHover(dropdown: any): void {
this.windowService.isXsOrSm().pipe(
first()
).subscribe((isMobile) => {
if (!isMobile) {
dropdown.open();
}
});
}
public toggle(): void {
this.store.dispatch(new NavbarToggleAction());
closeDropdownOnHover(dropdown: any): void {
this.windowService.isXsOrSm().pipe(
first()
).subscribe((isMobile) => {
if (!isMobile) {
dropdown.close();
}
});
}
}

View File

@@ -1,4 +1,4 @@
import { animate, state, transition, trigger, style, stagger, query } from '@angular/animations';
import { animate, state, style, transition, trigger } from '@angular/animations';
export const slide = trigger('slide', [
@@ -8,3 +8,12 @@ export const slide = trigger('slide', [
transition('expanded <=> collapsed', animate(250))
]);
export const slideMobileNav = trigger('slideMobileNav', [
state('expanded', style({ height: '100vh' })),
state('collapsed', style({ height: 0 })),
transition('expanded <=> collapsed', animate(300))
]);

View File

@@ -33,5 +33,6 @@ $navbar-dark-color: rgba(white, .5) !default;
$navbar-light-color: rgba(black, .5) !default;
$navbar-dark-toggler-icon-bg: url("data%3Aimage%2Fsvg+xml%3Bcharset%3Dutf8%2C%3Csvg+viewBox%3D%270+0+30+30%27+xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath+stroke%3D%27#{$navbar-dark-color}%27+stroke-width%3D%272%27+stroke-linecap%3D%27round%27+stroke-miterlimit%3D%2710%27+d%3D%27M4+7h22M4+15h22M4+23h22%27%2F%3E%3C%2Fsvg%3E");
$navbar-light-toggler-icon-bg: url("data%3Aimage%2Fsvg+xml%3Bcharset%3Dutf8%2C%3Csvg+viewBox%3D%270+0+30+30%27+xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath+stroke%3D%27#{$navbar-light-color}%27+stroke-width%3D%272%27+stroke-linecap%3D%27round%27+stroke-miterlimit%3D%2710%27+d%3D%27M4+7h22M4+15h22M4+23h22%27%2F%3E%3C%2Fsvg%3E");
$dropdown-border-radius: 0px;
$enable-shadows: true !default;