Skip to content

Commit

Permalink
feat(sidepanel): add component (#41)
Browse files Browse the repository at this point in the history
* feat(sidepanel): add component

* feat(sidepanel): add close button

* docs: comment about not recommended mobile usage
  • Loading branch information
snoopy-cat authored and GitHub Enterprise committed Sep 24, 2020
1 parent 8580b4a commit a050365
Show file tree
Hide file tree
Showing 24 changed files with 780 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { NxFileUploaderModule } from '@aposin/ng-aquila/file-uploader';
import { TextFieldModule } from '@angular/cdk/text-field';
import { NxToolbarModule } from '@aposin/ng-aquila/toolbar';
import { NxTimefieldModule } from '@aposin/ng-aquila/timefield';
import { NxSidepanelModule } from '@aposin/ng-aquila/sidepanel';

// Collect all imports and exports here
// Note: when you have to call .forRoot() or .forChild() in imports you have to add it separately from
Expand Down Expand Up @@ -122,6 +123,7 @@ const EXPORTED_MODULES = [
NxHeaderModule,
NxInputModule,
NxSidebarModule,
NxSidepanelModule,
NxBadgeModule,
NxTreeModule,
NxActionModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.my-sidepanel {
top: 60px;
height: calc(100% - 60px);
width: 240px;
}

@media only screen and (max-width: 785px) {
.my-sidepanel {
top: 120px;
height: calc(100% - 120px);
}
}

.my-sidepanel-header {
display: flex;
justify-content: space-between;
padding: 32px 32px 24px 32px;
}

.my-sidepanel-content {
padding: 0 32px 32px 32px;
}

.example-hint nx-icon {
vertical-align: bottom;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<nx-radio-toggle nxStyle="small" [(ngModel)]="opened">
<nx-radio-toggle-button [nxValue]="true">Open</nx-radio-toggle-button>
<nx-radio-toggle-button [nxValue]="false">Close</nx-radio-toggle-button>
</nx-radio-toggle>

<p>Opened: {{ opened }}</p>

<p class="example-hint">Watch the sidepanel appearing on the right side of the screen <nx-icon name="arrow-right" size="s"></nx-icon></p>

<nx-sidepanel class="my-sidepanel" [(opened)]="opened">
<nx-sidepanel-header>
<div class="my-sidepanel-header">
Sidepanel
<button nxSidepanelCloseButton aria-label="Close Sidepanel"></button>
</div>
</nx-sidepanel-header>

<nx-sidepanel-content>
<div class="my-sidepanel-content">
<p class="nx-margin-top-0">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
<p>Aliquam tincidunt mauris eu risus.</p>
<p>Vestibulum auctor dapibus neque.</p>
<p>Nunc dignissim risus id metus.</p>
<p>Cras ornare tristique elit.</p>
<p>Vivamus vestibulum ntulla nec ante.</p>
<p>Praesent placerat risus quis eros.</p>
<p>Fusce pellentesque suscipit nibh.</p>
<p>Integer vitae libero ac risus egestas placerat.</p>
<p>Vestibulum commodo felis quis tortor.</p>
<p>Ut aliquam sollicitudin leo.</p>
<p>Cras iaculis ultricies nulla.</p>
<p>Donec quis dui at dolor tempor interdum.</p>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
<p>Aliquam tincidunt mauris eu risus.</p>
<p>Vestibulum auctor dapibus neque.</p>
<p>Nunc dignissim risus id metus.</p>
<p>Cras ornare tristique elit.</p>
<p>Vivamus vestibulum ntulla nec ante.</p>
<p>Praesent placerat risus quis eros.</p>
<p>Fusce pellentesque suscipit nibh.</p>
<p>Integer vitae libero ac risus egestas placerat.</p>
<p>Vestibulum commodo felis quis tortor.</p>
<p>Ut aliquam sollicitudin leo.</p>
<p>Cras iaculis ultricies nulla.</p>
<p>Donec quis dui at dolor tempor interdum.</p>
</div>
</nx-sidepanel-content>

</nx-sidepanel>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component } from '@angular/core';
import { NxBreakpoints, NxViewportService } from '@aposin/ng-aquila/utils';
import { Subscription } from 'rxjs';

/**
* @title Floating sidepanel example
*/
@Component({
selector: 'nx-sidepanel-floating-example',
styleUrls: ['sidepanel-floating-example.css'],
templateUrl: './sidepanel-floating-example.html'
})
export class SidepanelFloatingExampleComponent {
opened: boolean = true;
isGreaterThanSmall: boolean = true;

viewportServiceSubscription: Subscription;

constructor(public viewportService: NxViewportService) {
this.viewportServiceSubscription = this.viewportService.min(NxBreakpoints.BREAKPOINT_SMALL)
.subscribe(isGreaterThanSmall => {
// only do something if the width has changed between small and bigger
if (isGreaterThanSmall !== this.isGreaterThanSmall) {
this.isGreaterThanSmall = isGreaterThanSmall;
if (isGreaterThanSmall && !this.opened) {
this.opened = true;
} else if (!isGreaterThanSmall && this.opened) {
this.opened = false;
}
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
:host {
display: flex;
height: 400px;
}

.content {
flex: 1;
height: 100%;
overflow-y: auto;
padding-right: 24px;
}

.my-sidepanel {
width: 240px;
}

.my-sidepanel-header {
display: flex;
justify-content: space-between;
padding: 32px 32px 24px 32px;
}

.my-sidepanel-content {
padding: 0 32px 32px 32px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<div class="content">
<nx-radio-toggle nxStyle="small" [(ngModel)]="opened">
<nx-radio-toggle-button [nxValue]="true">Open</nx-radio-toggle-button>
<nx-radio-toggle-button [nxValue]="false">Close</nx-radio-toggle-button>
</nx-radio-toggle>

<p>Opened: {{ opened }}</p>

<p><i>Here is some example content that can be scrolled.</i></p>
<p><i>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</i></p>
<p><i>Aliquam tincidunt mauris eu risus. Aliquam tincidunt mauris eu risus. Aliquam tincidunt mauris eu risus. Aliquam tincidunt mauris eu risus.</i></p>
<p><i>Vestibulum auctor dapibus neque. Vestibulum auctor dapibus neque.</i></p>
<p><i>Vivamus vestibulum ntulla nec ante. Vivamus vestibulum ntulla nec ante.</i></p>
<p><i>Praesent placerat risus quis eros. Praesent placerat risus quis eros.</i></p>
<p><i>Fusce pellentesque suscipit nibh. Fusce pellentesque suscipit nibh.</i></p>
<p><i>Integer vitae libero ac risus egestas placerat. Integer vitae libero ac risus egestas placerat.</i></p>
</div>

<nx-sidepanel class="my-sidepanel" [(opened)]="opened" position="static">
<nx-sidepanel-header>
<div class="my-sidepanel-header">
Sidepanel
<button nxSidepanelCloseButton aria-label="Close Sidepanel"></button>
</div>
</nx-sidepanel-header>

<nx-sidepanel-content>
<div class="my-sidepanel-content">
<p class="nx-margin-top-0">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
<p>Aliquam tincidunt mauris eu risus.</p>
<p>Vestibulum auctor dapibus neque.</p>
<p>Nunc dignissim risus id metus.</p>
<p>Cras ornare tristique elit.</p>
<p>Vivamus vestibulum ntulla nec ante.</p>
<p>Praesent placerat risus quis eros.</p>
<p>Fusce pellentesque suscipit nibh.</p>
<p>Integer vitae libero ac risus egestas placerat.</p>
<p>Vestibulum commodo felis quis tortor.</p>
<p>Ut aliquam sollicitudin leo.</p>
<p>Cras iaculis ultricies nulla.</p>
<p>Donec quis dui at dolor tempor interdum.</p>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
<p>Aliquam tincidunt mauris eu risus.</p>
<p>Vestibulum auctor dapibus neque.</p>
<p>Nunc dignissim risus id metus.</p>
<p>Cras ornare tristique elit.</p>
</div>
</nx-sidepanel-content>

</nx-sidepanel>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Component } from '@angular/core';

/**
* @title Static sidepanel example
*/
@Component({
selector: 'nx-sidepanel-static-example',
styleUrls: ['sidepanel-static-example.css'],
templateUrl: './sidepanel-static-example.html'
})
export class SidepanelStaticExampleComponent {
opened: boolean = true;
}
9 changes: 9 additions & 0 deletions projects/ng-aquila/src/shared-styles/theming/tokens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,15 @@ $nx-theme: (
sidebar-handle-color: ui-04,
sidebar-footer-button-color: text-01,

sidepanel-background-color: ui-02,
sidepanel-close-icon-color: text-01,
sidepanel-floating-shadow: none,

sidepanel-header-font-size: heading-05-font-size,
sidepanel-header-line-height: heading-05-line-height,
sidepanel-header-font-weight: heading-05-font-weight,
sidepanel-header-letter-spacing: 0,

file-uploader-file-row-text-color: text-01,
file-uploader-file-row-border-bottom-color: ui-04,
file-uploader-file-row-hover-background-color: ui-02,
Expand Down
7 changes: 7 additions & 0 deletions projects/ng-aquila/src/sidepanel/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ngPackage": {
"lib": {
"entryFile": "public-api.ts"
}
}
}
5 changes: 5 additions & 0 deletions projects/ng-aquila/src/sidepanel/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './sidepanel';
export * from './sidepanel-header';
export * from './sidepanel-content';
export * from './sidepanel-close-button';
export * from './sidepanel.module';
24 changes: 24 additions & 0 deletions projects/ng-aquila/src/sidepanel/sidepanel-close-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@import '../shared-styles/index';

:host {
cursor: pointer;
background-color: transparent;
border: none;
outline: none;
padding: 0;
display: flex;
align-items: center;

nx-icon {
@include var(color, sidepanel-close-icon-color);

@media screen and (-ms-high-contrast: active) {
color: buttonText;
}
}
}

:host-context([data-whatinput="keyboard"]):focus nx-icon {
@include focus-style;
border-radius: nx-border-radius(s);
}
90 changes: 90 additions & 0 deletions projects/ng-aquila/src/sidepanel/sidepanel-close-button.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Component, Type, ViewChild, DebugElement, Directive } from '@angular/core';
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
import * as axe from 'axe-core';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NxSidepanelModule } from './sidepanel.module';
import { NxSidepanelComponent, PositionType } from './sidepanel';
import { NxSidepanelCloseButtonComponent } from './sidepanel-close-button';

// For better readablity here, We can safely ignore some conventions in our specs
// tslint:disable:component-class-suffix

@Directive()
abstract class SidepanelCloseButtonTest {
@ViewChild(NxSidepanelComponent) sidebarInstance: NxSidepanelComponent;
@ViewChild(NxSidepanelCloseButtonComponent) buttonInstance: NxSidepanelCloseButtonComponent;
}

describe('NxSidepanelCloseButtonComponent', () => {
let fixture: ComponentFixture<SidepanelCloseButtonTest>;
let testInstance: SidepanelCloseButtonTest;
let sidepanelInstance: NxSidepanelComponent;
let sidepanelElement: DebugElement;
let buttonElement: HTMLButtonElement;

function createTestComponent(component: Type<SidepanelCloseButtonTest>) {
fixture = TestBed.createComponent(component);
fixture.detectChanges();
testInstance = fixture.componentInstance;
sidepanelInstance = testInstance.sidebarInstance;
sidepanelElement = fixture.debugElement.query(By.css('nx-sidepanel'));
buttonElement = fixture.nativeElement.querySelector('button') as HTMLButtonElement;
}

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
BasicSidepanel
],
imports: [
BrowserAnimationsModule,
NxSidepanelModule
]
}).compileComponents();
}));

describe('basic', () => {
beforeEach(() => {
createTestComponent(BasicSidepanel);
});

it('creates the sidepanel', () => {
expect(sidepanelInstance).toBeTruthy();
});

it('closes the panel on button click', () => {
buttonElement.click();
fixture.detectChanges();
expect(sidepanelInstance.opened).toBe(false);
expect(sidepanelElement.nativeElement.classList).toContain('is-closed');
});
});

describe('a11y', () => {
beforeEach(() => {
createTestComponent(BasicSidepanel);
});

it('has no accessibility violations', function(done) {
axe.run(fixture.nativeElement, {}, (error: Error, results: axe.AxeResults) => {
expect(results.violations.length).toBe(0);
const violationMessages = results.violations.map(item => item.description);
if (violationMessages.length) {
console.log(violationMessages);
}
done();
});
});
});
});

@Component({
template: `
<nx-sidepanel>
Hello Sidepanel
<button nxSidepanelCloseButton aria-label="Close Sidepanel"></button>
</nx-sidepanel>
`
})
class BasicSidepanel extends SidepanelCloseButtonTest {}
21 changes: 21 additions & 0 deletions projects/ng-aquila/src/sidepanel/sidepanel-close-button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { NxSidepanelComponent } from './sidepanel';

@Component({
// tslint:disable-next-line:component-selector
selector: 'button[nxSidepanelCloseButton]',
template: `<nx-icon name="close" size="s" aria-hidden="true"></nx-icon>`,
styleUrls: ['./sidepanel-close-button.scss'],
host: {
'(click)': '_toggle()'
},
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NxSidepanelCloseButtonComponent {

_toggle() {
this._sidepanel.toggle();
}

constructor(private _sidepanel: NxSidepanelComponent) {}
}
6 changes: 6 additions & 0 deletions projects/ng-aquila/src/sidepanel/sidepanel-content.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import '../shared-styles/index';

:host {
display: block;
overflow-y: auto; // height is set in js so that overflow: auto works correctly
}
Loading

0 comments on commit a050365

Please sign in to comment.