mini sidenav variant

This commit is contained in:
Bogdan Cilibiu
2018-03-14 05:18:39 +02:00
parent a9d98fbe83
commit 4e8210b7fb
15 changed files with 291 additions and 63 deletions

View File

@@ -45,6 +45,7 @@ import { RecentFilesComponent } from './components/recent-files/recent-files.com
import { SharedFilesComponent } from './components/shared-files/shared-files.component'; import { SharedFilesComponent } from './components/shared-files/shared-files.component';
import { TrashcanComponent } from './components/trashcan/trashcan.component'; import { TrashcanComponent } from './components/trashcan/trashcan.component';
import { LayoutComponent } from './components/layout/layout.component'; import { LayoutComponent } from './components/layout/layout.component';
import { LayoutContainerComponent } from './components/layout/layout-container.component';
import { HeaderComponent } from './components/header/header.component'; import { HeaderComponent } from './components/header/header.component';
import { CurrentUserComponent } from './components/current-user/current-user.component'; import { CurrentUserComponent } from './components/current-user/current-user.component';
import { SearchComponent } from './components/search/search.component'; import { SearchComponent } from './components/search/search.component';
@@ -69,6 +70,7 @@ import { EmptyFolderComponent } from './components/empty-folder/empty-folder.com
GenericErrorComponent, GenericErrorComponent,
LoginComponent, LoginComponent,
LayoutComponent, LayoutComponent,
LayoutContainerComponent,
HeaderComponent, HeaderComponent,
CurrentUserComponent, CurrentUserComponent,
SearchComponent, SearchComponent,

View File

@@ -1,5 +1,9 @@
<adf-toolbar class="app-menu" [style.background-color]="backgroundColor"> <adf-toolbar class="app-menu" [style.background-color]="backgroundColor">
<adf-toolbar-title> <adf-toolbar-title>
<button mat-icon-button (click)="toggleMenu()">
<mat-icon>menu</mat-icon>
</button>
<a class="app-menu__title" <a class="app-menu__title"
title="{{ appName }}" title="{{ appName }}"
[routerLink]="[ '/' ]"> [routerLink]="[ '/' ]">

View File

@@ -1,6 +1,7 @@
@import 'variables'; @import 'variables';
.app-menu { .app-menu {
height: $app-menu-height;
&.adf-toolbar { &.adf-toolbar {
.mat-toolbar { .mat-toolbar {
@@ -26,12 +27,20 @@
background-color: $alfresco-white !important; background-color: $alfresco-white !important;
} }
} }
.adf-toolbar-title {
color: $alfresco-white;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
} }
.app-menu__title { .app-menu__title {
width: 100px; width: 100px;
height: 50px; height: 50px;
margin-left: 5px; margin-left: 40px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: stretch; align-items: stretch;

View File

@@ -24,7 +24,7 @@
*/ */
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { Component, ViewEncapsulation, SecurityContext } from '@angular/core'; import { Component, Output, EventEmitter, ViewEncapsulation, SecurityContext } from '@angular/core';
import { AppConfigService } from '@alfresco/adf-core'; import { AppConfigService } from '@alfresco/adf-core';
@Component({ @Component({
@@ -34,6 +34,8 @@ import { AppConfigService } from '@alfresco/adf-core';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class HeaderComponent { export class HeaderComponent {
@Output() menu: EventEmitter<any> = new EventEmitter<any>();
private defaultPath = '/assets/images/alfresco-logo-white.svg'; private defaultPath = '/assets/images/alfresco-logo-white.svg';
private defaultBackgroundColor = '#2196F3'; private defaultBackgroundColor = '#2196F3';
@@ -42,6 +44,10 @@ export class HeaderComponent {
private sanitizer: DomSanitizer private sanitizer: DomSanitizer
) {} ) {}
toggleMenu() {
this.menu.emit();
}
get appName(): string { get appName(): string {
return <string>this.appConfig.get('application.name'); return <string>this.appConfig.get('application.name');
} }

View File

@@ -0,0 +1,32 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { trigger, transition, animate, style, state } from '@angular/animations';
export const miniSidenavAnimation = trigger('miniSidenavAnimation', [
state('expanded', style({ width: '{{ width }}px' }), { params : { width: 0 } }),
state('compact', style({ width: '{{ width }}px' }), { params : { width: 0 } }),
transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)'))
]);

View File

@@ -0,0 +1,12 @@
<mat-sidenav-container>
<mat-sidenav
[@miniSidenavAnimation]="sidenavAnimationState"
[opened]="!mobileQuery.matches"
[mode]="mobileQuery.matches ? 'over' : 'side'">
<ng-content sidenav select="[app-layout-navigation]"></ng-content>
</mat-sidenav>
<mat-sidenav-content [style.marginLeft.px]="sidenavAnimationState.params.width">
<ng-content select="[app-layout-content]"></ng-content>
</mat-sidenav-content>
</mat-sidenav-container>

View File

@@ -0,0 +1,40 @@
@mixin transition($property) {
transition-property: $property !important;
transition-duration: 0.4s !important;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
}
:host {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
}
ng-content {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
}
.mat-sidenav-container {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
}
.mat-sidenav {
background: #fafafa;
border-right: 1px solid rgba(0, 0, 0, 0.07);
overflow: hidden;
}
.mat-sidenav-content {
@include transition('margin-left');
}
.mat-drawer-transition .mat-drawer-content {
@include transition('margin-left');
}

View File

@@ -0,0 +1,89 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Component, Input, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { MatSidenav } from '@angular/material';
import {MediaMatcher} from '@angular/cdk/layout';
import { miniSidenavAnimation } from './animations';
@Component({
selector: 'app-layout-container',
templateUrl: './layout-container.component.html',
styleUrls: ['./layout-container.component.scss'],
animations: [ miniSidenavAnimation ]
})
export class LayoutContainerComponent implements OnInit, OnDestroy {
static STEP_OVER = 600;
static COMPACT = true;
@Input() sidenavMin: number;
@Input() sidenavMax: number;
@Input() sidenavCompact: boolean = LayoutContainerComponent.COMPACT;
@Input() stepOver: number;
@ViewChild(MatSidenav) sidenav: MatSidenav;
sidenavAnimationState: any;
isMenuMinimized = false;
mobileQuery: MediaQueryList;
constructor(private mediaMatcher: MediaMatcher) {
this.mobileQueryListener = this.mobileQueryListener.bind(this);
}
ngOnInit() {
const stepOver = this.stepOver || LayoutContainerComponent.STEP_OVER;
this.mobileQuery = this.mediaMatcher.matchMedia(`(max-width: ${stepOver}px)`);
this.mobileQuery.addListener(this.mobileQueryListener);
this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } };
}
ngOnDestroy(): void {
this.mobileQuery.removeListener(this.mobileQueryListener);
}
toggleMenu(): void {
if (!this.mobileQuery.matches && this.sidenavCompact) {
this.isMenuMinimized = !this.isMenuMinimized;
this.sidenavAnimationState =
this.sidenavAnimationState.value === 'expanded'
? { value: 'compact', params: {width: this.sidenavMin } }
: { value: 'expanded', params: { width: this.sidenavMax } };
} else {
this.isMenuMinimized = false;
this.sidenav.toggle();
}
}
private mobileQueryListener() {
this.isMenuMinimized = false;
this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } };
}
}

View File

@@ -2,13 +2,23 @@
<adf-upload-drag-area <adf-upload-drag-area
[parentId]="node?.id" [parentId]="node?.id"
[disabled]="!canCreateContent(node)"> [disabled]="!canCreateContent(node)">
<app-header></app-header>
<div class="layout__content"> <app-header (menu)="container.toggleMenu()"></app-header>
<app-sidenav class="layout__content-side"></app-sidenav>
<router-outlet></router-outlet>
</div>
<adf-file-uploading-dialog position="left"></adf-file-uploading-dialog> <app-layout-container #container
sidenavMin="70"
sidenavMax="320"
[stepOver]="600"
class="layout__content">
<app-sidenav
app-layout-navigation
[showLabel]="!container.isMenuMinimized">
</app-sidenav>
<router-outlet app-layout-content></router-outlet>
</app-layout-container>
<adf-file-uploading-dialog position="left"></adf-file-uploading-dialog>
</adf-upload-drag-area> </adf-upload-drag-area>
</div> </div>

View File

@@ -1,10 +1,17 @@
<div class="sidenav"> <div class="sidenav">
<div class="sidenav__section sidenav__section--new"> <div class="sidenav__section sidenav__section--new" [ngClass]="{ 'section--new--mini': !showLabel }">
<button class="sidenav__section--new__button" mat-button [matMenuTriggerFor]="menu"> <button *ngIf="showLabel"
class="sidenav__section--new__button" mat-button [matMenuTriggerFor]="menu">
<span>{{ 'APP.NEW_MENU.LABEL' | translate }}</span> <span>{{ 'APP.NEW_MENU.LABEL' | translate }}</span>
<mat-icon>arrow_drop_down</mat-icon> <mat-icon>arrow_drop_down</mat-icon>
</button> </button>
<button
class="new__button--mini"
*ngIf="!showLabel" mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>add_box</mat-icon>
</button>
<mat-menu #menu="matMenu" [overlapTrigger]="false"> <mat-menu #menu="matMenu" [overlapTrigger]="false">
<button <button
mat-menu-item mat-menu-item
@@ -52,16 +59,16 @@
<ul class="sidenav-menu"> <ul class="sidenav-menu">
<li class="sidenav-menu__item" *ngFor="let item of list"> <li class="sidenav-menu__item" *ngFor="let item of list">
<a <a
class="sidenav-menu__item-link" class="sidenav-link"
[ngClass]="{ 'sidenav-menu__item-link--noicon' : !item.icon }" [ngClass]="{ 'sidenav-menu__item-link--noicon' : !item.icon }"
routerLinkActive="sidenav-menu__item-link--active" routerLinkActive="sidenav-link--active"
[routerLink]="item.disabled? null : item.route.url" [routerLink]="item.disabled? null : item.route.url"
[ngClass]="{ 'disabled': item.disabled }" [ngClass]="{ 'disabled': item.disabled }"
title="{{ item.title || '' | translate }}"> title="{{ item.title || '' | translate }}">
<mat-icon *ngIf="item.icon">{{ item.icon }}</mat-icon> <mat-icon class="sidenav-link__icon">{{ item.icon }}</mat-icon>
{{ item.label | translate }} <span class="sidenav-link__label" *ngIf="showLabel">{{ item.label | translate }}</span>
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -18,6 +18,12 @@ $sidenav-menu-item--icon-size: 24px;
border-bottom: 0; border-bottom: 0;
} }
.section--new--mini {
display: flex;
justify-content: center;
align-items: center;
}
&__section { &__section {
padding: padding:
$sidenav-section--v-padding $sidenav-section--v-padding
@@ -29,6 +35,7 @@ $sidenav-menu-item--icon-size: 24px;
&--new { &--new {
padding-top: 2 * $sidenav-section--v-padding; padding-top: 2 * $sidenav-section--v-padding;
padding-bottom: 2 * $sidenav-section--v-padding; padding-bottom: 2 * $sidenav-section--v-padding;
height: 40px;
} }
&--new__button { &--new__button {
@@ -36,50 +43,61 @@ $sidenav-menu-item--icon-size: 24px;
color: $alfresco-white; color: $alfresco-white;
background-color: $alfresco-primary-accent--default; background-color: $alfresco-primary-accent--default;
} }
.new__button--mini {
color: $alfresco-primary-accent--default;
}
} }
&-menu { &-menu {
margin: 0 -1 * $sidenav-section--h-padding; display: inline-flex;
flex-direction: column;
padding: 0; padding: 0;
margin: 0;
list-style-type: none; list-style-type: none;
&__item { &__item {
padding: $sidenav-menu-item--v-padding 0; height: 24px;
padding: 12px 0;
&-link {
padding-left: $sidenav-menu-item--h-padding + 16px + 24px;
position: relative;
display: block;
color: $alfresco-secondary-text-color;
text-decoration: none;
& > .material-icons {
position: absolute;
top: 50%;
left: $sidenav-menu-item--h-padding;
margin-top: -14px;
}
&--active {
color: $alfresco-primary-accent--default;
}
&:not(&--active):hover {
color: $alfresco-primary-text-color;
}
&.disabled {
cursor: default !important;
color: $alfresco-secondary-text-color !important;
opacity: .25;
}
&--noicon {
padding-left: 26px;
}
}
} }
} }
&-link {
flex-direction: row;
display: flex;
align-items: center;
text-decoration: none;
color: $alfresco-secondary-text-color;
text-decoration: none;
height: 24px;
&--active {
color: $alfresco-primary-accent--default;
}
&:not(&--active):hover {
color: $alfresco-primary-text-color;
}
&.disabled {
cursor: default !important;
color: $alfresco-secondary-text-color !important;
opacity: .25;
}
&--noicon {
padding-left: 26px;
}
}
&-link__icon {
width: 24px;
}
&-link__label {
opacity: 1;
width: 240px;
margin-left: 20px;
}
} }
} }

View File

@@ -24,9 +24,7 @@
*/ */
import { Subscription } from 'rxjs/Rx'; import { Subscription } from 'rxjs/Rx';
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { MinimalNodeEntryEntity } from 'alfresco-js-api'; import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { ContentService, AppConfigService } from '@alfresco/adf-core'; import { ContentService, AppConfigService } from '@alfresco/adf-core';
@@ -38,6 +36,8 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi
styleUrls: ['./sidenav.component.scss'] styleUrls: ['./sidenav.component.scss']
}) })
export class SidenavComponent implements OnInit, OnDestroy { export class SidenavComponent implements OnInit, OnDestroy {
@Input() showLabel: boolean;
node: MinimalNodeEntryEntity = null; node: MinimalNodeEntryEntity = null;
navigation = []; navigation = [];

View File

@@ -1,4 +1,4 @@
@import './_variables.scss'; @import 'variables';
$app-layout--header-height: 65px; $app-layout--header-height: 65px;
$app-layout--side-width: 320px; $app-layout--side-width: 320px;
@@ -26,12 +26,6 @@ $app-inner-layout--footer-height: 48px;
display: flex; display: flex;
flex: 1; flex: 1;
} }
&-side {
flex: 0 0 $app-layout--side-width;
background: $alfresco-gray-background;
border-right: 1px solid $alfresco-divider-color;
}
} }
.content--hide { .content--hide {
@@ -71,6 +65,7 @@ $app-inner-layout--footer-height: 48px;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
background: #fff;
} }
&__content--scroll { &__content--scroll {

View File

@@ -1,7 +1,7 @@
@import 'variables'; @import 'variables';
@import 'theme'; @import 'theme';
html, body { html, body, ng-component {
display: flex; display: flex;
font-size: 14px; font-size: 14px;
font-family: "Muli", sans-serif; font-family: "Muli", sans-serif;

View File

@@ -1,4 +1,8 @@
@import '../_variables.scss'; @import 'variables';
.upload-dialog {
z-index: 999;
}
.adf-file-uploading-row { .adf-file-uploading-row {
&__status { &__status {