diff --git a/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.scss b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.scss new file mode 100644 index 000000000..0cd40579e --- /dev/null +++ b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.scss @@ -0,0 +1,51 @@ +@import 'mixins'; + +.collapsible-sidebar { + height: inherit; + width: 220px; + position: relative; + border: 1px solid $gray-2; + border-radius: 8px; + padding: 8px; + + .content { + @include fill-container; + } + + &.collapsed { + width: 40px; + + .content { + @include center-contents; + + * { + transform: rotate(-90deg); + } + } + } + + .string-label { + @include body-1-medium($gray-7); + } + + .toggle { + position: absolute; + display: flex; + align-items: center; + bottom: clamp(10px, 10%, 72px); + right: -12px; + height: 28px; + width: 12px; + border: 1px solid $gray-2; + border-left-color: white; + border-radius: 0 6px 6px 0; + cursor: pointer; + background: white; + padding-right: 4px; + + .icon { + position: relative; + right: 6px; + } + } +} diff --git a/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.test.ts b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.test.ts new file mode 100644 index 000000000..a251c8840 --- /dev/null +++ b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.test.ts @@ -0,0 +1,31 @@ +import { fakeAsync } from '@angular/core/testing'; +import { IconType } from '@hypertrace/assets-library'; +import { createHostFactory } from '@ngneat/spectator/jest'; +import { MockComponent } from 'ng-mocks'; +import { IconComponent } from '../icon/icon.component'; +import { CollapsibleSidebarComponent } from './collapsible-sidebar.component'; + +describe('Collapsible Sidebar Component', () => { + const createHost = createHostFactory({ + component: CollapsibleSidebarComponent, + shallow: true, + declarations: [MockComponent(IconComponent)] + }); + + test('should render content correclty', fakeAsync(() => { + const spectator = createHost( + `
` + ); + + expect(spectator.query(IconComponent)?.icon).toBe(IconType.TriangleRight); + expect(spectator.query('.test-content')).not.toExist(); + expect(spectator.query('.string-label')).toHaveText('test-label'); + + spectator.click(spectator.query('.toggle') as Element); + spectator.tick(); + + expect(spectator.query(IconComponent)?.icon).toBe(IconType.TriangleLeft); + expect(spectator.query('.test-content')).toExist(); + expect(spectator.query('.string-label')).not.toExist(); + })); +}); diff --git a/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.ts b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.ts new file mode 100644 index 000000000..ee0ca4918 --- /dev/null +++ b/projects/components/src/collapsible-sidebar/collapsible-sidebar.component.ts @@ -0,0 +1,50 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges, TemplateRef } from '@angular/core'; +import { IconType } from '@hypertrace/assets-library'; +import { IconSize } from '../icon/icon-size'; + +@Component({ + selector: 'ht-collapsible-sidebar', + styleUrls: ['./collapsible-sidebar.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+
+ +
+ {{ this.label }} + +
+ +
+
+ ` +}) +export class CollapsibleSidebarComponent implements OnChanges { + @Input() + public label: string | TemplateRef = ''; + + @Input() + public expanded: boolean = false; + + public isExpanded: boolean = false; + + public ngOnChanges(): void { + this.isExpanded = this.expanded; + } + + public get isLabelATemplate(): boolean { + return typeof this.label !== 'string'; + } + + public toggleCollapseExpand(): void { + this.isExpanded = !this.isExpanded; + } +} diff --git a/projects/components/src/collapsible-sidebar/collapsible-sidebar.module.ts b/projects/components/src/collapsible-sidebar/collapsible-sidebar.module.ts new file mode 100644 index 000000000..142a125db --- /dev/null +++ b/projects/components/src/collapsible-sidebar/collapsible-sidebar.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { IconModule } from '../icon/icon.module'; +import { CollapsibleSidebarComponent } from './collapsible-sidebar.component'; + +@NgModule({ + imports: [CommonModule, IconModule], + declarations: [CollapsibleSidebarComponent], + exports: [CollapsibleSidebarComponent] +}) +export class CollapsibleSidebarModule {} diff --git a/projects/components/src/public-api.ts b/projects/components/src/public-api.ts index b1811f15a..cbdafa48e 100644 --- a/projects/components/src/public-api.ts +++ b/projects/components/src/public-api.ts @@ -20,6 +20,10 @@ export { ButtonRole, ButtonSize, ButtonStyle } from './button/button'; export * from './checkbox/checkbox.component'; export * from './checkbox/checkbox.module'; +// Collapsible sidebar +export * from './collapsible-sidebar/collapsible-sidebar.component'; +export * from './collapsible-sidebar/collapsible-sidebar.module'; + // Combo Box export * from './combo-box/combo-box.module'; export * from './combo-box/combo-box.component';