diff --git a/packages/stark-build/config/tslint.json b/packages/stark-build/config/tslint.json index f552ee820b..dde0b96445 100644 --- a/packages/stark-build/config/tslint.json +++ b/packages/stark-build/config/tslint.json @@ -34,7 +34,7 @@ "use-view-encapsulation": false, "trackBy-function": true, "no-unused-css": true, - "template-cyclomatic-complexity": [true, 5], + "template-cyclomatic-complexity": [true, 10], "template-conditional-complexity": [true, 4], // TSlint rules diff --git a/packages/stark-core/src/common/translations/translations/en.ts b/packages/stark-core/src/common/translations/translations/en.ts index b5126abc35..8b9465e74e 100644 --- a/packages/stark-core/src/common/translations/translations/en.ts +++ b/packages/stark-core/src/common/translations/translations/en.ts @@ -12,6 +12,21 @@ export const translationsEn: object = { SORTING: { ASC: "Ascending", DESC: "Descending" + }, + ICONS: { + ADD_ITEM: "Add", + EDIT_ITEM: "Edit", + DELETE_ITEM: "Delete", + APPROVE_ITEM: "Approve", + REJECT_ITEM: "Reject", + RELOAD_PAGE: "Reload page", + OPEN_SELECTION: "Open selection", + SAVE_ITEM: "Save", + CLOSE_ITEM: "Close", + RESET: "Reset", + SEARCH: "Search", + NEW_ITEM: "New", + SAVE_AND_NEXT: "Save And Next" } } }; diff --git a/packages/stark-core/src/common/translations/translations/fr.ts b/packages/stark-core/src/common/translations/translations/fr.ts index af7cd26f36..22aa4fa42f 100644 --- a/packages/stark-core/src/common/translations/translations/fr.ts +++ b/packages/stark-core/src/common/translations/translations/fr.ts @@ -12,6 +12,21 @@ export const translationsFr: object = { SORTING: { ASC: "Ascendant", DESC: "Descendant" + }, + ICONS: { + ADD_ITEM: "Ajouter", + EDIT_ITEM: "Modifier", + DELETE_ITEM: "Supprimer", + APPROVE_ITEM: "Approuver", + REJECT_ITEM: "Rejeter", + RELOAD_PAGE: "Recharger la page", + OPEN_SELECTION: "Ouvrir la sélection", + SAVE_ITEM: "Sauver", + CLOSE_ITEM: "Fermer", + RESET: "Réinitialiser", + SEARCH: "Chercher", + NEW_ITEM: "Nouveau", + SAVE_AND_NEXT: "Sauver et Suivant" } } }; diff --git a/packages/stark-core/src/common/translations/translations/nl.ts b/packages/stark-core/src/common/translations/translations/nl.ts index afdff31cdf..515cf6cc71 100644 --- a/packages/stark-core/src/common/translations/translations/nl.ts +++ b/packages/stark-core/src/common/translations/translations/nl.ts @@ -12,6 +12,21 @@ export const translationsNl: object = { SORTING: { ASC: "Oplopend", DESC: "Aflopend" + }, + ICONS: { + ADD_ITEM: "Toevoegen", + EDIT_ITEM: "Wijzig", + DELETE_ITEM: "Verwijder", + APPROVE_ITEM: "Goedkeuren", + REJECT_ITEM: "Afkeuren", + RELOAD_PAGE: "Pagina vernieuwen", + OPEN_SELECTION: "Open selectie", + SAVE_ITEM: "Bewaren", + CLOSE_ITEM: "Sluiten", + RESET: "Reset", + SEARCH: "Zoeken", + NEW_ITEM: "Nieuw", + SAVE_AND_NEXT: "Bewaar en volgende" } } }; diff --git a/packages/stark-ui/assets/styles/_base.scss b/packages/stark-ui/assets/styles/_base.scss index acb8adff8b..a0ac789468 100644 --- a/packages/stark-ui/assets/styles/_base.scss +++ b/packages/stark-ui/assets/styles/_base.scss @@ -27,11 +27,6 @@ } @media screen { - html, - body { - overflow: hidden; - } - .stark-app { display: flex; flex-direction: column; @@ -68,6 +63,7 @@ body { /* system sans-serif font stack */ font-family: mat-font-family($typography-config); font-size: mat-font-size($typography-config, body-1); + line-height: mat-line-height($typography-config, body-1); } h1, diff --git a/packages/stark-ui/assets/styles/_colors.scss b/packages/stark-ui/assets/styles/_colors.scss index 55985ccbb3..4e4c9a65dd 100644 --- a/packages/stark-ui/assets/styles/_colors.scss +++ b/packages/stark-ui/assets/styles/_colors.scss @@ -1,10 +1,16 @@ $mat-light-theme-background: $backgrounds; +$mat-light-theme-foreground: $foregrounds; @if variable-exists(stark-base-theme) { $base-theme: map-merge($base-theme, $stark-base-theme); + @if map-has-key($stark-base-theme, backgrounds) { $mat-light-theme-background: map-merge($backgrounds, map-get($stark-base-theme, backgrounds)); } + + @if map-has-key($stark-base-theme, foregrounds) { + $mat-light-theme-foreground: map-merge($foregrounds, map-get($stark-base-theme, foregrounds)); + } } $stark-color-theme: mat-light-theme( diff --git a/packages/stark-ui/assets/styles/_media-queries.scss b/packages/stark-ui/assets/styles/_media-queries.scss new file mode 100644 index 0000000000..d873cb087b --- /dev/null +++ b/packages/stark-ui/assets/styles/_media-queries.scss @@ -0,0 +1,8 @@ +$tablet-query: "(min-width: 600px)"; +$tablet-screen-query: "screen and (min-width: 600px)"; +$desktop-query: "(min-width: 960px)"; +$desktop-screen-query: "screen and (min-width: 960px)"; +$mobile-only-query: "(max-width: 599px)"; +$mobile-only-screen-query: "screen and (max-width: 599px)"; +$tablet-only-query: "(min-width: 600px) and (max-width: 959px)"; +$tablet-only-screen-query: "screen and (min-width: 600px) and (max-width: 959px)"; diff --git a/packages/stark-ui/assets/styles/_old-variables.scss b/packages/stark-ui/assets/styles/_old-variables.scss index 6f255401ed..8aa7c5c32d 100644 --- a/packages/stark-ui/assets/styles/_old-variables.scss +++ b/packages/stark-ui/assets/styles/_old-variables.scss @@ -1,13 +1,3 @@ -// Old Stark vars -$tablet-query: "(min-width: 600px)"; -$tablet-screen-query: "screen and (min-width: 600px)"; -$desktop-query: "(min-width: 960px)"; -$desktop-screen-query: "screen and (min-width: 960px)"; -$mobile-only-query: "(max-width: 599px)"; -$mobile-only-screen-query: "screen and (max-width: 599px)"; -$tablet-only-query: "(min-width: 600px) and (max-width: 959px)"; -$tablet-only-screen-query: "screen and (min-width: 600px) and (max-width: 959px)"; - $elevation-1: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); $elevation-2: 0 1px 5px 0 rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12); $elevation-3: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12); diff --git a/packages/stark-ui/assets/styles/_typography.scss b/packages/stark-ui/assets/styles/_typography.scss index 7d3ca25b3e..c41a41273d 100644 --- a/packages/stark-ui/assets/styles/_typography.scss +++ b/packages/stark-ui/assets/styles/_typography.scss @@ -15,7 +15,7 @@ $typography-config: mat-typography-config( $display-1: mat-typography-level-create(map-get($typography-theme, display-1)), $headline: mat-typography-level-create(map-get($typography-theme, headline)), $title: mat-typography-level-create(map-get($typography-theme, title)), - $subheading-2: mat-typography-level-create(map-get($typography-theme, subheading-2)), + $subheading-2: mat-typography-level-create(map-get($typography-theme, subheading-2)), /*Menu, List, Option*/ $subheading-1: mat-typography-level-create(map-get($typography-theme, subheading-1)), $body-2: mat-typography-level-create(map-get($typography-theme, body-2)), $body-1: mat-typography-level-create(map-get($typography-theme, body-1)), diff --git a/packages/stark-ui/assets/styles/_variables.scss b/packages/stark-ui/assets/styles/_variables.scss index bade1756f1..350d518358 100644 --- a/packages/stark-ui/assets/styles/_variables.scss +++ b/packages/stark-ui/assets/styles/_variables.scss @@ -200,9 +200,9 @@ $typography-theme: ( 500 ), subheading-2: ( + 13px, 16px, - 28px, - 400 + 500 ), subheading-1: ( 15px, diff --git a/packages/stark-ui/assets/themes/_button-theme.scss b/packages/stark-ui/assets/themes/_button-theme.scss index 395cdb19de..5b69bbb690 100644 --- a/packages/stark-ui/assets/themes/_button-theme.scss +++ b/packages/stark-ui/assets/themes/_button-theme.scss @@ -1,3 +1,13 @@ +@mixin stark-button-color($color) { + color: $color; + .mat-button-focus-overlay { + background-color: rgba($color: $color, $alpha: 0.12); + } + .mat-ripple-element { + background-color: rgba($color: $color, $alpha: 0.1); + } +} + @if variable-exists(stark-button-theme) { $button-theme: map-merge($button-theme, $stark-button-theme); } diff --git a/packages/stark-ui/assets/themes/_menu-theme.scss b/packages/stark-ui/assets/themes/_menu-theme.scss new file mode 100644 index 0000000000..92a70a47f2 --- /dev/null +++ b/packages/stark-ui/assets/themes/_menu-theme.scss @@ -0,0 +1,13 @@ +.mat-menu-content .mat-menu-item { + color: mat-color(map-get($base-theme, primary-palette)); + .mat-icon { + color: inherit; + svg { + height: 20px; + width: 20px; + } + } + &[disabled] { + color: map-get($mat-light-theme-foreground, disabled-button); + } +} diff --git a/packages/stark-ui/assets/themes/_theming.scss b/packages/stark-ui/assets/themes/_theming.scss index 8367343cbc..cb901bf3a0 100644 --- a/packages/stark-ui/assets/themes/_theming.scss +++ b/packages/stark-ui/assets/themes/_theming.scss @@ -4,5 +4,6 @@ @import "../styles/variables"; @import "../styles/colors"; @import "../styles/typography"; +@import "../styles/media-queries"; @import "../styles/old-variables"; @import "../styles/base"; diff --git a/packages/stark-ui/src/modules.ts b/packages/stark-ui/src/modules.ts index 597277f3c7..d191c9ebfa 100644 --- a/packages/stark-ui/src/modules.ts +++ b/packages/stark-ui/src/modules.ts @@ -1,3 +1,4 @@ +export * from "./modules/action-bar"; export * from "./modules/app-logo"; export * from "./modules/slider"; export * from "./modules/svg-view-box"; diff --git a/packages/stark-ui/src/modules/action-bar.ts b/packages/stark-ui/src/modules/action-bar.ts new file mode 100644 index 0000000000..01c7f68707 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar.ts @@ -0,0 +1,2 @@ +export * from "./action-bar/action-bar.module"; +export * from "./action-bar/components"; diff --git a/packages/stark-ui/src/modules/action-bar/action-bar.module.ts b/packages/stark-ui/src/modules/action-bar/action-bar.module.ts new file mode 100644 index 0000000000..2df8152ed7 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/action-bar.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { MatButtonModule, MatIconModule, MatMenuModule, MatTooltipModule } from "@angular/material"; +import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; +import { StarkActionBarComponent } from "./components"; +import { TranslateModule } from "@ngx-translate/core"; + +@NgModule({ + declarations: [StarkActionBarComponent], + imports: [BrowserModule, StarkSvgViewBoxModule, MatButtonModule, MatIconModule, MatMenuModule, MatTooltipModule, TranslateModule], + exports: [StarkActionBarComponent] +}) +export class StarkActionBarModule {} diff --git a/packages/stark-ui/src/modules/action-bar/components.ts b/packages/stark-ui/src/modules/action-bar/components.ts new file mode 100644 index 0000000000..0e897e2847 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components.ts @@ -0,0 +1,3 @@ +export * from "./components/action-bar.component"; +export * from "./components/action.intf"; +export * from "./components/action-bar-config.intf"; diff --git a/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss b/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss new file mode 100644 index 0000000000..632674297f --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/_action-bar-theme.scss @@ -0,0 +1,38 @@ +.stark-action-bar { + .mat-icon-button { + @include stark-button-color(mat-color(map-get($base-theme, primary-palette))); + } + &.stark-action-bar-full { + background-color: rgba(0, 0, 0, 0.85); + color: rgba(255, 255, 255, 0.8); + .mat-icon-button { + @include stark-button-color(rgba($color: #fff, $alpha: 0.8)); + } + .action-label { + &.disabled { + color: rgba($color: #fff, $alpha: 0.25); + } + } + } +} + +@media #{$tablet-query} { + .stark-action-bar { + color: $md-primary; + &.stark-action-bar-full { + background: none; + color: mat-color(map-get($base-theme, primary-palette)); + .mat-icon-button:not([disabled]) { + @include stark-button-color(mat-color(map-get($base-theme, primary-palette))); + } + [disabled].mat-icon-button { + @include stark-button-color(map-get($mat-light-theme-foreground, disabled-button)); + } + .action-label { + &.disabled { + color: map-get($mat-light-theme-foreground, disabled-button); + } + } + } + } +} diff --git a/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss b/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss new file mode 100644 index 0000000000..ba878ad4e2 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/_action-bar.component.scss @@ -0,0 +1,62 @@ +.stark-action-bar { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + max-height: 40px; + overflow: hidden; + transform-origin: bottom; + .action-bar-wrapper { + display: flex; + align-items: center; + flex-wrap: wrap; + } + .mat-icon-button { + .mat-icon svg { + height: 20px; + width: 20px; + } + } + &.stark-action-bar-full { + bottom: 0; + left: 0; + margin-bottom: 0; + padding: 4px 0; + position: fixed; + right: 0; + z-index: 4; + &.extended { + transition: 0.3s ease; + height: auto; + max-height: 280px; + overflow-y: scroll; + .action-bar-wrapper { + display: flex; + align-items: flex-start; + flex-direction: column; + flex-wrap: nowrap; + } + } + .action-label { + font-size: 13px; + padding-left: 15px; + } + } +} + +@media #{$tablet-query} { + .stark-action-bar { + position: relative; + height: auto; + transition: 0.7s ease; + &.stark-action-bar-full { + position: relative; + &.extended { + max-height: 900px; + } + } + } + .stark-action-bar-compact { + flex-wrap: nowrap; + padding: 0; + } +} diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts new file mode 100644 index 0000000000..42bcbc4de0 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/action-bar-config.intf.ts @@ -0,0 +1,16 @@ +import { StarkAction } from "./action.intf"; + +/** + * Stark Action interface + */ +export interface StarkActionBarConfig { + /** + * Array of actions (StarkAction config objects) to be included in the action bar + */ + actions: StarkAction[]; + + /** + * If false, then action bar will not be present on the page (optional) + */ + isPresent?: boolean; +} diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html new file mode 100644 index 0000000000..302a86080e --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.html @@ -0,0 +1,34 @@ +
+
+
+ + + + +
+
+ +
+ + + +
+ +
+ + {{ action.label }} +
+
+
+
+
+
diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts new file mode 100644 index 0000000000..1e4834e0cc --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.spec.ts @@ -0,0 +1,131 @@ +import { NO_ERRORS_SCHEMA } from "@angular/core"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { MatButtonModule, MatMenuModule, MatTooltipModule } from "@angular/material"; +import { STARK_LOGGING_SERVICE, STARK_ROUTING_SERVICE } from "@nationalbankbelgium/stark-core"; +import { MockStarkLoggingService, MockStarkRoutingService } from "@nationalbankbelgium/stark-core/testing"; +import { StarkSvgViewBoxModule } from "../../svg-view-box/svg-view-box.module"; +import { StarkActionBarComponent } from "./action-bar.component"; +import { StarkActionBarConfig } from "./action-bar-config.intf"; +import { StarkAction } from "./action.intf"; +import { TranslateModule, TranslateService } from "@ngx-translate/core"; +import createSpy = jasmine.createSpy; + +describe("ActionBarComponent", () => { + let fixture: ComponentFixture; + let component: StarkActionBarComponent; + const buttonToggleSelector: string = ".extend-action-bar"; + + beforeEach(async(() => { + return TestBed.configureTestingModule({ + declarations: [StarkActionBarComponent], + imports: [StarkSvgViewBoxModule, MatButtonModule, MatMenuModule, MatTooltipModule, TranslateModule.forRoot()], + providers: [ + { provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }, + { provide: STARK_ROUTING_SERVICE, useClass: MockStarkRoutingService }, + TranslateService + ], + schemas: [NO_ERRORS_SCHEMA] // tells the Angular compiler to ignore unrecognized elements and attributes (svgIcon) + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StarkActionBarComponent); + component = fixture.componentInstance; + const demoActions: StarkAction[] = [ + { + id: "userDetailValidate", + label: "Validate", + icon: "check", + actionCall: createSpy("actionCallSpy"), + isEnabled: false, + isVisible: true + }, + { + id: "userDetailSave", + label: "Save", + icon: "content-save", + actionCall: createSpy("actionCallSpy"), + isEnabled: true, + isVisible: true + } + ]; + + const demoActionBarConfig: StarkActionBarConfig = { + actions: demoActions, + isPresent: true + }; + + component.actionBarConfig = demoActionBarConfig; + fixture.detectChanges(); + }); + + describe("@Input() mode", () => { + it("should have the toggle action bar button visible in full mode", () => { + component.mode = "full"; + fixture.detectChanges(); + const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector); + expect(buttonToggleExtend).toBeDefined(); + }); + + it("should not have the toggle action bar button visible in compact mode", () => { + component.mode = "compact"; + fixture.detectChanges(); + const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector); + expect(buttonToggleExtend).toBeNull(); + }); + }); + + describe("@Input() actionBarId", () => { + it("should have set the id of the action bar", () => { + component.actionBarId = "action-bar-id"; + fixture.detectChanges(); + const actionBar: HTMLElement = fixture.nativeElement.querySelector("#" + component.actionBarId); + expect(actionBar).toBeDefined(); + }); + }); + + describe("@Input() actionBarConfig", () => { + it("should not call the defined action when disabled", () => { + const menuItem: HTMLElement = fixture.nativeElement.querySelector( + "#" + component.actionBarId + "-" + component.actionBarConfig.actions[0].id + ); + menuItem.click(); + expect(component.actionBarConfig.actions[0].actionCall).not.toHaveBeenCalled(); + }); + + it("should call the defined action when enabled", () => { + const menuItem: HTMLElement = fixture.nativeElement.querySelector( + "#" + component.actionBarId + "-" + component.actionBarConfig.actions[1].id + ); + menuItem.click(); + expect(component.actionBarConfig.actions[1].actionCall).toHaveBeenCalledTimes(1); + }); + }); + + describe("@Input() alternativeActions", () => { + beforeEach(() => { + component.alternativeActions = component.actionBarConfig.actions; + fixture.detectChanges(); + }); + + it("should display", () => { + const actionBar: HTMLElement = fixture.nativeElement.querySelector(".open-alt-actions"); + expect(actionBar).toBeDefined(); + }); + }); + + describe("toggle extended action bar", () => { + it("should toggle the action bar extension", () => { + const buttonToggleExtend: HTMLElement = fixture.nativeElement.querySelector(buttonToggleSelector); + spyOn(component, "toggleExtendedActionBar").and.callThrough(); + buttonToggleExtend.click(); + fixture.detectChanges(); + expect(component.toggleExtendedActionBar).toHaveBeenCalledTimes(1); + expect(component.isExtended).toBe(true); + buttonToggleExtend.click(); + fixture.detectChanges(); + expect(component.toggleExtendedActionBar).toHaveBeenCalledTimes(2); + expect(component.isExtended).toBe(false); + }); + }); +}); diff --git a/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts new file mode 100644 index 0000000000..cfb7d1dcd3 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/action-bar.component.ts @@ -0,0 +1,74 @@ +import { Component, ViewEncapsulation, Input } from "@angular/core"; +import { StarkActionBarConfig } from "./action-bar-config.intf"; +import { StarkAction } from "./action.intf"; + +export type StarkActionBarComponentMode = "full" | "compact"; + +/** + * Component to display the application's action bars + */ +@Component({ + selector: "stark-action-bar", + templateUrl: "./action-bar.component.html", + encapsulation: ViewEncapsulation.None +}) +export class StarkActionBarComponent { + /** + * HTML id of action bar component. + */ + @Input() public actionBarId: string = ""; + + /** + * StarkActionBarConfig object. + */ + @Input() public actionBarConfig: StarkActionBarConfig; + + /** + * HTML id of action bar component. + */ + @Input() public actionBarScope: any; + + /** + * Alternative actions + */ + @Input() public alternativeActions: StarkAction[]; + + /** + * Desired layout or flavour: + * - full: full featured action bar with labels, expanded view, etc... + * - compact: minimalistic layout with icons only. + */ + @Input() public mode: StarkActionBarComponentMode = "full"; + + /** + * status of the extended action in full mode + */ + public isExtended: boolean = false; + + /** + * toggle the extended action in full mode + */ + public toggleExtendedActionBar(): void { + this.isExtended = !this.isExtended; + } + + /** + * Action onClick handler + */ + public onClick(action: StarkAction, $event: Event): void { + if (action.isEnabled) { + let scope: any = {}; + if (this.actionBarScope) { + scope = this.actionBarScope; + } + action.actionCall($event, scope); + } + } + + /** + * @ignore + */ + public trackAction(_index: number, action: StarkAction): string { + return action.id; + } +} diff --git a/packages/stark-ui/src/modules/action-bar/components/action.intf.ts b/packages/stark-ui/src/modules/action-bar/components/action.intf.ts new file mode 100644 index 0000000000..fd7593e1c5 --- /dev/null +++ b/packages/stark-ui/src/modules/action-bar/components/action.intf.ts @@ -0,0 +1,94 @@ +/** + * Stark Action Base interface + */ +export interface StarkActionBase { + /** + * Path to SVG icon from iconSets to display inside the action button. Ex: "pencil" (optional) + */ + icon?: string; + + /** + * Text to be displayed as label of the action button (optional) + */ + label?: string; + + /** + * The second label if this action has two possible states: activated and deactivated (optional) + */ + labelActivated?: string; + + /** + * In case of two label states, this function will hide one of them or show another (optional) + */ + labelSwitchFunction?: () => boolean; + + /** + * Whether the action button should be enabled for user interaction or not (optional) + */ + isEnabled?: boolean; + + /** + * The second icon if this action has two possible states: activated and deactivated (optional) + */ + iconActivated?: string; + + /** + * In case of two icon states, this function will hide one of them or show another (optional) + */ + iconSwitchFunction?: () => boolean; + + /** + * Custom CSS class to be set to the action button (optional) + */ + className?: string; +} + +/** + * Definition of an action to be used in an Stark Action Bar + */ +export interface StarkAction extends StarkActionBase { + /** + * The HTML id to be set to the action button + */ + id: string; + + /** + * Text to be displayed as label of the action button + */ + label: string; + + /** + * Path to SVG icon from iconSets to display inside the action button. Ex: "pencil" + */ + icon: string; + + /** + * Function to be fired when action button is clicked + */ + actionCall: Function; + + /** + * Whether the action button should be enabled for user interaction or not + */ + isEnabled: boolean; + + /** + * Whether the action button will be visible or not (optional) + */ + isVisible?: boolean; +} + +/** + * Definition of a action bar's default action to be used in an Stark generic form + */ +export interface StarkDefaultPredefinedAction extends StarkActionBase {} + +/** + * Definition of a action bar's normal action to be used in an Stark generic form + */ +export interface StarkCustomizablePredefinedAction extends StarkActionBase { + /** + * Whether the action button will be visible or not (optional) + */ + isVisible?: boolean; +} diff --git a/packages/stark-ui/tsconfig.spec.json b/packages/stark-ui/tsconfig.spec.json index b4cfe9bba6..ce781fb602 100644 --- a/packages/stark-ui/tsconfig.spec.json +++ b/packages/stark-ui/tsconfig.spec.json @@ -3,6 +3,7 @@ "compilerOptions": { "module": "commonjs", "paths": { + "@ngx-translate/*": ["../stark-core/node_modules/@ngx-translate/*"], "@nationalbankbelgium/stark-core/testing": ["../../dist/packages/stark-core/testing"], "@nationalbankbelgium/stark-core": ["../../dist/packages/stark-core"], "@nationalbankbelgium/stark-ui": ["."] diff --git a/packages/tsconfig.json b/packages/tsconfig.json index e4a87d4c51..e782e35c83 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -10,6 +10,7 @@ "paths": { "rxjs/*": ["../node_modules/rxjs/*"], "@angular/*": ["../node_modules/@angular/*"], + "@ngx-translate/*": ["./stark-core/node_modules/@ngx-translate/*"], "environments/environment": ["./stark-core/src/common/environment"], "@nationalbankbelgium/stark-*": ["./stark-*"] }, diff --git a/showcase/karma.conf.js b/showcase/karma.conf.js index 12eba512ad..67aabf76fe 100644 --- a/showcase/karma.conf.js +++ b/showcase/karma.conf.js @@ -9,7 +9,7 @@ const helpers = require("./node_modules/@nationalbankbelgium/stark-testing/helpe const defaultKarmaConfig = require("./node_modules/@nationalbankbelgium/stark-testing/karma.conf.js").rawKarmaConfig; // entry files of the "@nationalbankbelgium/stark-ui" module imported in mock files -const karmaTypescriptExclusions = [...defaultKarmaConfig.exclude, "src/assets/examples/*"]; +const karmaTypescriptExclusions = [...defaultKarmaConfig.exclude, "src/assets/examples/**"]; // start customizing the KarmaCI configuration from stark-testing const starkShowcaseSpecificConfiguration = Object.assign({}, defaultKarmaConfig, { diff --git a/showcase/src/app/app.component.html b/showcase/src/app/app.component.html index 940f3d5304..cb53f2f1a6 100644 --- a/showcase/src/app/app.component.html +++ b/showcase/src/app/app.component.html @@ -20,6 +20,9 @@ Home + + Action Bar + Example Viewer diff --git a/showcase/src/app/app.module.ts b/showcase/src/app/app.module.ts index b8acdcf651..c4169ddfe7 100644 --- a/showcase/src/app/app.module.ts +++ b/showcase/src/app/app.module.ts @@ -36,7 +36,7 @@ import { StarkUser } from "@nationalbankbelgium/stark-core"; -import { StarkAppLogoModule, StarkSliderModule } from "@nationalbankbelgium/stark-ui"; +import { StarkActionBarModule, StarkAppLogoModule, StarkSliderModule } from "@nationalbankbelgium/stark-ui"; import { routerConfigFn } from "./router.config"; import { registerMaterialIconSet } from "./material-icons.config"; import { Deserialize } from "cerialize"; @@ -55,12 +55,13 @@ import { AppComponent } from "./app.component"; import { AppState } from "./app.service"; import { HomeComponent } from "./home"; import { NoContentComponent } from "./no-content"; +import { ActionBarComponent, ExampleViewerComponent } from "./demo"; + /* tslint:disable:no-import-side-effect */ // load PostCSS styles import "../styles/styles.pcss"; // load SASS styles import "../styles/styles.scss"; -import { DemoComponent } from "./demo/demo.component"; /* tslint:enable */ // Application wide providers @@ -119,7 +120,7 @@ export const metaReducers: MetaReducer[] = ENV !== "production" ? [logger */ @NgModule({ bootstrap: [AppComponent], - declarations: [AppComponent, HomeComponent, NoContentComponent, DemoComponent], + declarations: [AppComponent, HomeComponent, NoContentComponent, ActionBarComponent, ExampleViewerComponent], /** * Import Angular's modules. */ @@ -152,7 +153,9 @@ export const metaReducers: MetaReducer[] = ENV !== "production" ? [logger StarkSessionModule.forRoot(), StarkRoutingModule.forRoot(), StarkAppLogoModule, - StarkSliderModule + StarkSliderModule, + StarkActionBarModule, + StarkAppLogoModule ], /** * Expose our Services and Providers into Angular's dependency injection. diff --git a/showcase/src/app/app.routes.ts b/showcase/src/app/app.routes.ts index c7efe82a98..c2e5cdd8f1 100644 --- a/showcase/src/app/app.routes.ts +++ b/showcase/src/app/app.routes.ts @@ -1,10 +1,11 @@ -import { DemoComponent } from "./demo"; +import { ActionBarComponent, ExampleViewerComponent } from "./demo"; import { HomeComponent } from "./home"; import { NoContentComponent } from "./no-content"; import { Ng2StateDeclaration } from "@uirouter/angular"; export const APP_STATES: Ng2StateDeclaration[] = [ { name: "home", url: "/", component: HomeComponent }, - { name: "demo-example-viewer", url: "/demo-example-viewer", component: DemoComponent }, + { name: "demo-action-bar", url: "/demo/action-bar", component: ActionBarComponent }, + { name: "demo-example-viewer", url: "/demo/example-viewer", component: ExampleViewerComponent }, { name: "otherwise", url: "/otherwise", component: NoContentComponent } ]; diff --git a/showcase/src/app/demo/action-bar/action-bar.component.html b/showcase/src/app/demo/action-bar/action-bar.component.html new file mode 100644 index 0000000000..38afe80414 --- /dev/null +++ b/showcase/src/app/demo/action-bar/action-bar.component.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/showcase/src/app/demo/action-bar/action-bar.component.ts b/showcase/src/app/demo/action-bar/action-bar.component.ts new file mode 100644 index 0000000000..4c50dc3958 --- /dev/null +++ b/showcase/src/app/demo/action-bar/action-bar.component.ts @@ -0,0 +1,105 @@ +import { Component, OnInit, Inject } from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkAction, StarkActionBarConfig } from "@nationalbankbelgium/stark-ui"; + +@Component({ + selector: "showcase-demo-action-bar", + templateUrl: "./action-bar.component.html" +}) +export class ActionBarComponent implements OnInit { + public actions: StarkAction[]; + public actionBarConfig: StarkActionBarConfig; + public alternativeActions: StarkAction[]; + + public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {} + + public ngOnInit(): void { + this.actions = [ + { + id: "actionValidate", + label: "STARK.ICONS.APPROVE_ITEM", + icon: "check", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: false, + isVisible: true + }, + { + id: "actionSave", + label: "STARK.ICONS.SAVE_ITEM", + icon: "content-save", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: true, + isVisible: true + }, + { + id: "actionDelete", + label: "STARK.ICONS.DELETE_ITEM", + icon: "delete", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: false, + isVisible: true + }, + { + id: "actionClose", + label: "STARK.ICONS.CLOSE_ITEM", + icon: "close", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: true, + isVisible: true + } + ]; + + this.actionBarConfig = { + actions: this.actions, + isPresent: true + }; + + this.alternativeActions = [ + { + id: "actionAdd", + label: "STARK.ICONS.ADD_ITEM", + icon: "account-plus", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: true, + isVisible: true + }, + { + id: "actionMinus", + label: "STARK.ICONS.DELETE_ITEM", + icon: "account-minus", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: false, + isVisible: true + }, + { + id: "actionEdit", + label: "STARK.ICONS.EDIT_ITEM", + icon: "pencil", + actionCall: ($event: Event, data: any): void => { + this.logger.debug($event); + this.logger.debug(data); + }, + isEnabled: true, + isVisible: true + } + ]; + } +} diff --git a/showcase/src/app/demo/demo.component.scss b/showcase/src/app/demo/demo.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/showcase/src/app/demo/demo.component.spec.ts b/showcase/src/app/demo/demo.component.spec.ts deleted file mode 100644 index aeafc5c4ac..0000000000 --- a/showcase/src/app/demo/demo.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { HttpClientModule } from "@angular/common/http"; -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { DemoComponent } from "./demo.component"; -import { SharedModule } from "../shared/shared.module"; -import { MockStarkLoggingService } from "@nationalbankbelgium/stark-core/testing"; -import { STARK_LOGGING_SERVICE } from "@nationalbankbelgium/stark-core"; - -describe("DemoComponent", () => { - let component: DemoComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - return TestBed.configureTestingModule({ - declarations: [DemoComponent], - imports: [HttpClientModule, SharedModule], - providers: [{ provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DemoComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/showcase/src/app/demo/demo.component.ts b/showcase/src/app/demo/demo.component.ts deleted file mode 100644 index 16f284c7f6..0000000000 --- a/showcase/src/app/demo/demo.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component, Inject } from "@angular/core"; -import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; - -@Component({ - selector: "showcase-demo", - templateUrl: "./demo.component.html", - styleUrls: ["./demo.component.scss"] -}) -export class DemoComponent { - public constructor(@Inject(STARK_LOGGING_SERVICE) public loggingService: StarkLoggingService) {} -} diff --git a/showcase/src/app/demo/demo.component.html b/showcase/src/app/demo/example-viewer/example-viewer.component.html similarity index 100% rename from showcase/src/app/demo/demo.component.html rename to showcase/src/app/demo/example-viewer/example-viewer.component.html diff --git a/showcase/src/app/demo/example-viewer/example-viewer.component.ts b/showcase/src/app/demo/example-viewer/example-viewer.component.ts new file mode 100644 index 0000000000..799d49aa8b --- /dev/null +++ b/showcase/src/app/demo/example-viewer/example-viewer.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "showcase-demo-example-viewer", + templateUrl: "./example-viewer.component.html" +}) +export class ExampleViewerComponent {} diff --git a/showcase/src/app/demo/index.ts b/showcase/src/app/demo/index.ts index ced8212a57..15776ea93e 100644 --- a/showcase/src/app/demo/index.ts +++ b/showcase/src/app/demo/index.ts @@ -1 +1,2 @@ -export * from "./demo.component"; +export * from "./action-bar/action-bar.component"; +export * from "./example-viewer/example-viewer.component"; diff --git a/showcase/src/app/shared/example-viewer/example-viewer.component.html b/showcase/src/app/shared/example-viewer/example-viewer.component.html index 0b27a57b02..9c12c5f42d 100644 --- a/showcase/src/app/shared/example-viewer/example-viewer.component.html +++ b/showcase/src/app/shared/example-viewer/example-viewer.component.html @@ -1,6 +1,6 @@
-

{{ title }}

+

{{ title }}