<!DOCTYPE html>
<html>

  <head>
    <base href="." />
    
    <title>NgxAside simple Angular sidebar component - demo</title>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">



    <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
    <script src="https://unpkg.com/zone.js/dist/zone.js"></script>
    <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
    <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
    <script src="config.js"></script>
    <script>
    System.import('app')
      .catch(console.error.bind(console));
  </script>
  </head>

  <body>
    <my-app>
    Loading ...
  </my-app>
  </body>

</html>
/* Styles go here */

.demo{
    display: flex;
    height: 100vh;
    width: 100%;
    align-items: center;
    justify-content: center;
}
### Angular Starter Plunker - Typescript
System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  paths: {
    'npm:': 'https://unpkg.com/'
  },
  //map tells the System loader where to look for things
  map: {
    
    'app': './src',
    
    '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
    '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
    '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
    '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
    '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
    '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
    '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
    '@angular/animations':'npm:@angular/platform-browser@4.0.0/bundles/platform-browser-animations.umd.js',
    '@angular/platform-browser/animations':'npm:@angular/platform-browser@4.0.0/@angular/platform-browser/animations.es5.js',
    
    '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
    '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
    '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
    '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
    '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
    '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
    '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
    
    'rxjs': 'npm:rxjs',
    'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    },
    rxjs: {
      defaultExtension: 'js'
    }
  }
});
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';

platformBrowserDynamic().bootstrapModule(AppModule)
//our root app component
import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

import { NgxAsideModule } from '../lib/aside/index.ts';

@Component({
  selector: 'my-app',
  template: `
  
  <div class="demo">
  <div class="btn-group" role="group">
    <button class="btn btn-default" (click)="NgxAsidePanelLeft.show()">Show aside from the left side</button>
    <button class="btn btn-default"  (click)="NgxAsidePanelRight.show()">Show aside from the right side</button>
    </div>
</div>
<ngx-aside #NgxAsidePanelLeft 
[position]="'left'"
[title]="'Aside title'"
>


    <h1> Test aside left panel</h1>

    <code>Default configuration</code>
    <code>

    </code>
</ngx-aside>


<ngx-aside #NgxAsidePanelRight
           (cancel)="onCancel()"
           (submit)="onSave()"
           
           [closeOnEscape]="false"
           [showOverlay]="false"
           [showDefaultFooter]="false"
           [showDefaultHeader]="false"> 

    <header style="padding: 10px; background-color:#607d8b; color: #fafafa ">My own header with own styles</header>

    <h1>Sidebar content</h1>

Configuration<br/>
  <code>
           [closeOnEscape]="false" <br/>
           [showOverlay]="false" <br/>
           [showDefaultFooter]="false" <br/>
           [showDefaultHeader]="false" <br/>
  </code>

    <footer style="padding: 20px; background-color: #009688;">
        My own footer, with custom buttons <br/><br/>
        <button class="btn btn-default" (click)="NgxAsidePanelRight.hide()">
            Close
        </button>
    </footer>

</ngx-aside>

  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

@NgModule({
  imports: [ BrowserModule, NgxAsideModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}
export  { NgxAsideModule } from './aside.module.ts';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {NgxOverlayComponent} from './overlay.component';
import {NgxAsideComponent} from './aside.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

@NgModule({
    imports: [CommonModule, BrowserAnimationsModule],
    exports: [NgxAsideComponent],
    declarations: [
        NgxAsideComponent,
        NgxOverlayComponent,
    ],
    entryComponents: [NgxOverlayComponent]
})

export class NgxAsideModule {

}
import {
    Component,
    Input,
    ViewContainerRef,
    Output,
    EventEmitter,
    ComponentRef,
    HostBinding,
    OnInit,
    HostListener,
    ComponentFactoryResolver
}
    from
    "@angular/core";

import { NgxOverlayComponent } from './overlay.component.ts';
import { slideAnimations } from './aside.animations.ts';

@Component({
    selector: 'ngx-aside',
    templateUrl: './lib/aside/aside.component.html',
    styleUrls: ['./lib/aside/aside.component.scss'],
    animations: [slideAnimations]
})

/*

 TODO: Configurable parameters
 width
 max-width


 TODO: @OutputEvents
 @OutputFunctions ?

 ----

 */

export class NgxAsideComponent implements OnInit {


    @Output() cancel: EventEmitter<any> = new EventEmitter();
    @Output() submit: EventEmitter<any> = new EventEmitter();


    @Input() position = 'right';
    @Input() showDefaultFooter = true;
    @Input() showDefaultHeader = true;
    @Input() showOverlay = true;
    @Input() closeOnEscape = true;
    @Input() title = '';


    @HostBinding('class') cssClasses: HostBinding;


    private backdrop: ComponentRef<{}>;
    private visibleStatus: boolean = false;
    private rootViewContainerRef: ViewContainerRef;


    constructor(private _resolver: ComponentFactoryResolver, private vcRef: ViewContainerRef) {
        this.rootViewContainerRef = vcRef;
    }

    ngOnInit() {
        this.cssClasses = this.position;
    }

    private addOverlay() {
        if (!this.backdrop && this.showOverlay) {
            const OverlayComponentFactory = this._resolver.resolveComponentFactory(NgxOverlayComponent);
            this.backdrop = this.rootViewContainerRef.createComponent(OverlayComponentFactory, 0);
        }
    }


    hideAside(event) {
        if (this.cancel.observers.length > 0) {
            this.cancel.emit(event);
        } else { // If we don`t have any subscribers
            this.hide();
        }

    }


    submitAside() {
        if (this.cancel.observers.length > 0) {
            this.submit.emit();
        } else {  // If we don`t have any subscribers
            this.hide();

        }
    }

    @HostListener('document:keydown.esc', ['$event'])
    handleEscape(event) {

        if (this.closeOnEscape) {
            event.preventDefault();
            this.hideAside(event);
        }


        return false;
    }

    hide() {


        this.visibleStatus = false;

        if (!this.backdrop) {
            return;
        }

        this.backdrop.destroy();
        this.backdrop = void 0;

    }

    show() {
        this.visibleStatus = true;
        this.addOverlay();
    }
}
:host * {
  box-sizing: border-box;
}
:host.right aside {
  right: 0;
  top: 0;
  bottom: 0;
}
:host.left aside {
  left: 0;
  top: 0;
  bottom: 0;
}

aside {
  will-change: opacity;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  position: fixed;
  width: auto;
  max-width: 50%;
  background-color: white;
  z-index: 2;
  box-shadow: -6px 3px 11px 0px rgba(0, 0, 0, 0.23);
  padding: 0 16px;
}

section {
  height: 100vh;
  overflow: auto;
}

header {
  font-size: 20px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 64px;
}
header .aside-button-close {
  width: 20px;
  text-align: center;
  opacity: .8;
}
header .aside-button-close:hover {
  cursor: pointer;
  opacity: 1;
}

footer {
  border-top: 1px solid #e5e5e5;
  display: flex;
  align-items: flex-start;
  padding: 16px 0 16px 0;
}
footer button {
  margin-right: 6px;
}

:host.left aside {
  box-shadow: 6px -1px 11px 0px rgba(0, 0, 0, 0.23);
}
:host.left.footer {
  justify-content: flex-end;
}
import {
    Component
} from '@angular/core';


import {
    trigger,
    transition,
    style,
    animate
} from '@angular/animations';

@Component({
    selector: 'ngx-aside-overlay',
    template: `
        <div class="overlay" [@show]="showStatus"></div>`,
    styles: [`.overlay {
        z-index: 1;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: currentColor;
        opacity: .6;
    }`],
    animations: [
        trigger('show', [
            transition('void => *', [
                style([{opacity: 0}]),
                animate(100,
                    style([{opacity: .6}])
                )
            ])
        ])
    ]
})

export class NgxOverlayComponent {
    showStatus: boolean;
    // @HostBinding('style.opacity') opacity;

    constructor() {
        this.showStatus = true;
    }

    ngAfterContentInit() {


    }
}
import {
    animate,
    AnimationEntryMetadata,
    style,
    transition,
    trigger
} from '@angular/core';

export const slideAnimations: AnimationEntryMetadata = trigger('slide', [

    transition('void => left', [
        style({
            opacity: .6,
            transform: 'translate3d(-100%,0,0)'
        }),
        animate('.2s cubic-bezier(0.215, 0.610, 0.355, 1)',
            style({
                opacity: 1,
                transform: 'translateZ(0)'
            }))
    ]),

    transition('void => right', [
        style({
            opacity: .6,
            transform: 'translate3d(100%,0,0)'
        }),
        animate('.2s cubic-bezier(0.215, 0.610, 0.355, 1)',
            style({
                opacity: 1,
                transform: 'translateZ(0)'
            }))
    ]),

    transition('left => void', [
        animate('.2s cubic-bezier(0.165, 0.84, 0.44, 1)', style({
                opacity: 0,
                transform: 'translate3d(-50%,0,0)'
            }
        ))
    ]),

    transition('right => void', [
        animate('.2s cubic-bezier(0.165, 0.84, 0.44, 1)', style({
                opacity: 0,
                transform: 'translate3d(50%,0,0)'
            }
        ))
    ])
])
<aside [@slide]="position" *ngIf="visibleStatus">

    <!-- Custom Header -->
    <ng-content *ngIf="!showDefaultHeader" class="aside-title-huj" select="header">


    </ng-content>
    <!-- End Custom Header -->


    <!-- Default Header -->
    <header *ngIf="showDefaultHeader">
        <div class="aside-title">
            {{title}}
        </div>

        <div (click)="hideAside()" class="aside-button-close">
            &times;
        </div>

    </header>
    <!-- End Custom Header -->


    <section>
        <div class="aside-container">
            <ng-content></ng-content>
        </div>
    </section>

    <!-- Custom Footer -->
    <ng-content *ngIf="!showDefaultFooter" select="footer"></ng-content>
    <!-- End Custom Footer -->

    <!-- Default Footer -->
    <footer *ngIf="showDefaultFooter">

        <button (click)="hideAside($event)" type="button" class="btn btn-secondary">Close</button>
        <button (click)="submitAside($event)" type="button" class="btn btn-primary">Save</button>


    </footer>
    <!--End  Default Footer -->

</aside>