diff --git a/common/constants.js b/common/constants.js index f9065be7abfab8b9e81eb51fda4762a69ad6f98e..e92bdb8be98ac6aba5a3e1bb33607e348fb83e83 100644 --- a/common/constants.js +++ b/common/constants.js @@ -2,12 +2,14 @@ exports.ARIA_LABELS = { // dataset specific + SHOW_DATASET_PREVIEW: 'Show dataset preview', TOGGLE_EXPLORE_PANEL: `Toggle explore panel`, MODALITY_FILTER: `Toggle dataset modality filter`, LIST_OF_DATASETS: `List of datasets`, DOWNLOAD_PREVIEW: `Download`, DOWNLOAD_PREVIEW_CSV: `Download CSV`, DATASET_FILE_PREVIEW: `Preview of dataset`, + PIN_DATASET: 'Toggle pinning dataset', // overlay specific CONTEXT_MENU: `Viewer context menu`, diff --git a/docs/releases/v2.2.2.md b/docs/releases/v2.2.2.md index 128c1db4896b49e7ebaddd24f1b0ca304dbab342..575e922d91ea0efbd3b713f3a27f27d3290174cf 100644 --- a/docs/releases/v2.2.2.md +++ b/docs/releases/v2.2.2.md @@ -9,6 +9,8 @@ - Showing region status on region context menu (#520) - Dataset previews are now reflected in the URL state (#502) & they stagger now! - Slightly retweaked scroll dataset container condition, to make it less strict +- Fixed maximise panel on touch enabled devices (#533) +- Dynamically fit the action buttons under datasets ## Under the hood stuff diff --git a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js b/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js index 9eeb93161fa2747655248613201019fd1f54bf83..97c8fd98255902cf3bb3ee7bacbe03c467747528 100644 --- a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js +++ b/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js @@ -89,8 +89,8 @@ describe('> receptor dataset previews', () => { const receptorIndex = datasets.indexOf(receptorName) await iavPage.clickNthDataset(receptorIndex) - await iavPage.waitFor(true, true) - await iavPage.clickModalBtnByText(/preview/i) + await iavPage.wait(500) + await iavPage.click(`[aria-label="${ARIA_LABELS.SHOW_DATASET_PREVIEW}"]`) await iavPage.waitFor(true, true) }) @@ -135,7 +135,7 @@ describe('> receptor dataset previews', () => { const files = await iavPage.getBottomSheetList() const imageIndex = files.findIndex(file => /image\//i.test(file)) await iavPage.clickNthItemFromBottomSheetList(imageIndex) - await iavPage.waitFor(true, true) + await iavPage.wait(500) const modalHasImage = await iavPage.modalHasChild('div[data-img-src]') expect(modalHasImage).toEqual(true) diff --git a/e2e/src/advanced/favDatasets.prod.e2e-spec.js b/e2e/src/advanced/favDatasets.prod.e2e-spec.js index 1d3ebebe323e31e1eb0816df00330b7413eb4e71..c745200e50d1e67042f920e18b10d49b668dadbf 100644 --- a/e2e/src/advanced/favDatasets.prod.e2e-spec.js +++ b/e2e/src/advanced/favDatasets.prod.e2e-spec.js @@ -1,4 +1,5 @@ const { AtlasPage } = require('../util') +const { ARIA_LABELS } = require('../../../common/constants') const template = 'ICBM 2009c Nonlinear Asymmetric' const area = 'Area hOc1 (V1, 17, CalcS)' @@ -155,7 +156,9 @@ describe(`fav'ing dataset`, () => { const receptorIndex = datasets.indexOf(receptorName) await iavPage.clickNthDataset(receptorIndex) await iavPage.wait(500) - await iavPage.clickModalBtnByText(/pin\ this\ dataset/i) + + // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test + await iavPage.click(`mat-dialog-container [aria-label="${ARIA_LABELS.PIN_DATASET}"]`) await iavPage.wait(500) const txt = await iavPage.getSnackbarMessage() @@ -178,7 +181,9 @@ describe(`fav'ing dataset`, () => { const receptorIndex = datasets.indexOf(receptorName) await iavPage.clickNthDataset(receptorIndex) await iavPage.wait(500) - await iavPage.clickModalBtnByText(/pin\ this\ dataset/i) + + // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test + await iavPage.click(`mat-dialog-container [aria-label="${ARIA_LABELS.PIN_DATASET}"]`) await iavPage.wait(500) const numberOfFav = await iavPage.getNumberOfFavDataset() @@ -187,7 +192,8 @@ describe(`fav'ing dataset`, () => { // this wait is unfortunately necessary, as the snack bar sometimes obscures the unpin this dataset button await iavPage.wait(5000) - await iavPage.clickModalBtnByText(/unpin\ this\ dataset/i) + // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test + await iavPage.click(`mat-dialog-container [aria-label="${ARIA_LABELS.PIN_DATASET}"]`) await iavPage.wait(500) const txt = await iavPage.getSnackbarMessage() diff --git a/e2e/src/util.js b/e2e/src/util.js index 219080d5f6db8bdf3463c1e05b6cb814b9230f28..c96a61803847c02574306e31ca6f9b5dbaece2d7 100644 --- a/e2e/src/util.js +++ b/e2e/src/util.js @@ -481,7 +481,6 @@ class WdLayoutPage extends WdBase{ .isDisplayed() return isDisplayed } catch (e) { - console.warn(`modalhaschild thrown error`, e) return false } } diff --git a/src/components/components.module.ts b/src/components/components.module.ts index f6cdb091c4c747339f237e97f00a4d5c72985ae7..f3c9c22e3ae90235868d04fb125dbb98ff0984fe 100644 --- a/src/components/components.module.ts +++ b/src/components/components.module.ts @@ -32,6 +32,7 @@ import { TimerComponent } from './timer/timer.component'; import { TreeComponent } from './tree/tree.component'; import { TreeBaseDirective } from './tree/treeBase.directive'; import { IAVVerticalButton } from './vButton/vButton.component'; +import { DynamicMaterialBtn } from './dynamicMaterialBtn/dynamicMaterialBtn.component'; @NgModule({ imports : [ @@ -58,6 +59,7 @@ import { IAVVerticalButton } from './vButton/vButton.component'; DialogComponent, ConfirmDialogComponent, IAVVerticalButton, + DynamicMaterialBtn, /* directive */ HoverableBlockDirective, @@ -91,6 +93,7 @@ import { IAVVerticalButton } from './vButton/vButton.component'; DialogComponent, ConfirmDialogComponent, IAVVerticalButton, + DynamicMaterialBtn, SearchResultPaginationPipe, TreeSearchPipe, diff --git a/src/components/dynamicMaterialBtn/dynamicMaterialBtn.component.ts b/src/components/dynamicMaterialBtn/dynamicMaterialBtn.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..610ff397f77d523e92486ac9858909599995b90b --- /dev/null +++ b/src/components/dynamicMaterialBtn/dynamicMaterialBtn.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from "@angular/core"; + +type TypeMatBtnStyle = 'mat-button' | 'mat-raised-button' | 'mat-stroked-button' | 'mat-flat-button' | 'mat-icon-button' | 'mat-fab' | 'mat-mini-fab' +type TypeMatBtnColor = 'basic' | 'primary' | 'accent' | 'warn' + +@Component({ + selector: 'iav-dynamic-mat-button', + templateUrl: './dynamicMaterialBtn.template.html' +}) + +export class DynamicMaterialBtn{ + @Input('iav-dynamic-mat-button-style') + matBtnStyle: TypeMatBtnStyle = 'mat-button' + + @Input('iav-dynamic-mat-button-color') + matBtnColor: TypeMatBtnColor = 'basic' + + @Input('iav-dynamic-mat-button-aria-label') + matBtnAriaLabel: string + + @Input('iav-dynamic-mat-button-disabled') + matBtnDisabled: boolean = false +} diff --git a/src/components/dynamicMaterialBtn/dynamicMaterialBtn.template.html b/src/components/dynamicMaterialBtn/dynamicMaterialBtn.template.html new file mode 100644 index 0000000000000000000000000000000000000000..98fc139259c6fa5cbb6c78a674da81f6f41e1c1c --- /dev/null +++ b/src/components/dynamicMaterialBtn/dynamicMaterialBtn.template.html @@ -0,0 +1,84 @@ +<ng-container [ngSwitch]="matBtnStyle"> + + <!-- mat-raise-button --> + <button *ngSwitchCase="'mat-raised-button'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-raised-button + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-stroked-button --> + <button *ngSwitchCase="'mat-stroked-button'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-stroked-button + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-flat-button --> + <button *ngSwitchCase="'mat-flat-button'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-flat-button + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-icon-button --> + <button *ngSwitchCase="'mat-icon-button'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-icon-button + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-fab --> + <button *ngSwitchCase="'mat-fab'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-fab + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-mini-fab --> + <button *ngSwitchCase="'mat-mini-fab'" + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-mini-fab + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + + <!-- mat-mini-fab --> + <button *ngSwitchDefault + [attr.aria-label]="matBtnAriaLabel" + [disabled]="matBtnDisabled" + mat-button + [color]="matBtnColor"> + + <ng-container *ngTemplateOutlet="transcludedContent"> + </ng-container> + </button> + +</ng-container> + +<ng-template #transcludedContent> + <ng-content></ng-content> +</ng-template> \ No newline at end of file diff --git a/src/ui/databrowserModule/preview/previewComponentWrapper/previewCW.template.html b/src/ui/databrowserModule/preview/previewComponentWrapper/previewCW.template.html index 03f4a6d52c50d5bd6648d42c441440988fdd2fe5..71c478682921cef2df732e485c0dc69594d33099 100644 --- a/src/ui/databrowserModule/preview/previewComponentWrapper/previewCW.template.html +++ b/src/ui/databrowserModule/preview/previewComponentWrapper/previewCW.template.html @@ -30,34 +30,40 @@ </div> </h1> -<kg-dataset-previewer - class="flex-grow-1 flex-shrink-1" - [darkmode]="darktheme$ | async" - [filename]="filename" - [kgId]="kgId" - [backendUrl]="backendUrl" - #dataPreviewerStencilCmp> - -</kg-dataset-previewer> - -<div class="flex-shrink-0 flex-grow-0 d-inline-flex"> - <a *ngIf="downloadHref" - [attr.href]="downloadHref" - [attr.download]="filename" - [attr.aria-label]="DOWNLOAD_PREVIEW_ARIA_LABEL" - target="_blank" - mat-icon-button - color="primary"> - <i class="fas fa-download"></i> - </a> - - <a *ngIf="downloadCsvHref" - [attr.href]="downloadCsvHref" - [attr.download]="filename" - [attr.aria-label]="DOWNLOAD_PREVIEW_CSV_ARIA_LABEL" - target="_blank" - mat-icon-button - color="primary"> - <i class="fas fa-file-csv"></i> - </a> +<div mat-dialog-content class="h-100 d-flex flex-column"> + + <div class="h-0 flex-grow-1 flex-shrink-1"> + + <kg-dataset-previewer + class="h-100 w-100" + [darkmode]="darktheme$ | async" + [filename]="filename" + [kgId]="kgId" + [backendUrl]="backendUrl" + #dataPreviewerStencilCmp> + + </kg-dataset-previewer> + </div> + + <div class="flex-shrink-0 flex-grow-0 d-inline-flex"> + <a *ngIf="downloadHref" + [attr.href]="downloadHref" + [attr.download]="filename" + [attr.aria-label]="DOWNLOAD_PREVIEW_ARIA_LABEL" + target="_blank" + mat-icon-button + color="primary"> + <i class="fas fa-download"></i> + </a> + + <a *ngIf="downloadCsvHref" + [attr.href]="downloadCsvHref" + [attr.download]="filename" + [attr.aria-label]="DOWNLOAD_PREVIEW_CSV_ARIA_LABEL" + target="_blank" + mat-icon-button + color="primary"> + <i class="fas fa-file-csv"></i> + </a> + </div> </div> diff --git a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html index cb0f4bfacec8f35f1a6d42f1eaf6e548a0eb5a03..7d811342741964d98d03f6851e28e0da2034eb80 100644 --- a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html +++ b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html @@ -45,70 +45,79 @@ <!-- footer --> -<mat-card-actions> +<mat-card-actions iav-media-query #iavMediaQuery="iavMediaQuery"> + <ng-container *ngTemplateOutlet="actionBtns; context: { $implicit: (iavMediaQuery.mediaBreakPoint$ | async) }" > + </ng-container> +</mat-card-actions> + +<mat-card-footer></mat-card-footer> + +<ng-template #previewFilesListTemplate> + <dataset-preview-list + [kgId]="kgId"> + + </dataset-preview-list> +</ng-template> + +<!-- using ng template for context binding of media breakpoints --> +<ng-template #actionBtns let-mediaBreakPoint> <!-- explore --> <ng-container *ngIf="!strictLocal"> <a *ngFor="let kgRef of kgReference" - class="m-2" [href]="kgRef | doiParserPipe" target="_blank"> - <button - mat-raised-button - color="primary"> - Explore + <iav-dynamic-mat-button + [iav-dynamic-mat-button-style]="mediaBreakPoint < 2 ? 'mat-raised-button' : 'mat-icon-button'" + iav-dynamic-mat-button-color="primary"> + + <span *ngIf="mediaBreakPoint < 2"> + Explore + </span> <i class="fas fa-external-link-alt"></i> - </button> + </iav-dynamic-mat-button> </a> </ng-container> <!-- pin data --> <ng-container *ngIf="downloadEnabled && kgId"> - <!-- Is currently fav'ed --> - <ng-container *ngIf="favedDataentries$ | async | datasetIsFaved : dataset; else notCurrentlyFav"> - - <button mat-button - iav-stop="click mousedown" - (click)="undoableRemoveFav()" - color="primary"> - Unpin this dataset - <i class="fas fa-thumbtack"></i> - </button> + <ng-container *ngTemplateOutlet="favDatasetBtn; context: { $implicit: (favedDataentries$ | async | datasetIsFaved : dataset) }"> </ng-container> - <!-- Is NOT currently fav'ed --> - <ng-template #notCurrentlyFav> - - <button mat-button + <ng-template #favDatasetBtn let-isFav> + <iav-dynamic-mat-button + (click)="isFav ? undoableRemoveFav() : undoableAddFav()" iav-stop="click mousedown" - (click)="undoableAddFav()" - color="default"> - Pin this dataset + [iav-dynamic-mat-button-aria-label]="PIN_DATASET_ARIA_LABEL" + [iav-dynamic-mat-button-style]="mediaBreakPoint < 2 ? 'mat-button' : 'mat-icon-button'" + [iav-dynamic-mat-button-color]="isFav ? 'primary' : 'basic'"> + + <span *ngIf="mediaBreakPoint < 2"> + {{ isFav ? 'Unpin this dataset' : 'Pin this dataset' }} + </span> <i class="fas fa-thumbtack"></i> - </button> + </iav-dynamic-mat-button> </ng-template> </ng-container> - <!-- download --> <ng-container *ngIf="!strictLocal"> <a *ngIf="files && files.length > 0" [href]="dlFromKgHref" target="_blank"> - <button - [disabled]="downloadInProgress" + <iav-dynamic-mat-button [matTooltip]="tooltipText" - class="m-2" - mat-button - color="basic"> - <span> - Download as Zip + [disabled]="downloadInProgress" + [iav-dynamic-mat-button-style]="mediaBreakPoint < 2 ? 'mat-button' : 'mat-icon-button'"> + + <span *ngIf="mediaBreakPoint < 2"> + Download Zip </span> <i class="ml-1 fas" [ngClass]="!downloadInProgress? 'fa-download' :'fa-spinner fa-pulse'"></i> - </button> + </iav-dynamic-mat-button> </a> </ng-container> @@ -123,24 +132,17 @@ </kg-dataset-list> - <button mat-button - mat-dialog-close + <iav-dynamic-mat-button *ngIf="hasPreview" - (click)="showPreviewList(previewFilesListTemplate)" - color="basic"> - <span> + mat-dialog-close + [iav-dynamic-mat-button-style]="mediaBreakPoint < 2 ? 'mat-button' : 'mat-icon-button'" + [iav-dynamic-mat-button-aria-label]="SHOW_DATASET_PREVIEW_ARIA_LABEL" + (click)="showPreviewList(previewFilesListTemplate)"> + + <span *ngIf="mediaBreakPoint < 2"> Preview </span> <i class="ml-1 far fa-eye"></i> - </button> - -</mat-card-actions> - -<mat-card-footer></mat-card-footer> + </iav-dynamic-mat-button> -<ng-template #previewFilesListTemplate> - <dataset-preview-list - [kgId]="kgId"> - - </dataset-preview-list> -</ng-template> +</ng-template> \ No newline at end of file diff --git a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts index 5872a609942fc47c3d34430bda5c306f28d6277e..9b2ed686945b763819044a4bce8ca4d67fb963c7 100644 --- a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts +++ b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts @@ -1,6 +1,6 @@ import { ChangeDetectorRef, Input, OnInit, TemplateRef, OnChanges } from "@angular/core"; import { Observable } from "rxjs"; -import { IDataEntry, IFile, IPublication, ViewerPreviewFile } from 'src/services/state/dataStore.store' +import { IDataEntry, IFile, IPublication } from 'src/services/state/dataStore.store' import { HumanReadableFileSizePipe } from "src/util/pipes/humanReadableFileSize.pipe"; import { DatabrowserService } from "../databrowser.service"; import { KgSingleDatasetService } from "../kgSingleDatasetService.service"; @@ -9,6 +9,8 @@ import { DS_PREVIEW_URL } from 'src/util/constants' import { getKgSchemaIdFromFullId } from "../util/getKgSchemaIdFromFullId.pipe"; import { MatSnackBar } from "@angular/material/snack-bar"; +import { ARIA_LABELS } from 'common/constants' + export { DatabrowserService, KgSingleDatasetService, @@ -17,6 +19,9 @@ export { export class SingleDatasetBase implements OnInit, OnChanges { + public SHOW_DATASET_PREVIEW_ARIA_LABEL = ARIA_LABELS.SHOW_DATASET_PREVIEW + public PIN_DATASET_ARIA_LABEL = ARIA_LABELS.PIN_DATASET + @Input() public ripple: boolean = false /** diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html index b6ecacc3753003334269b2c610ad29a022859704..5d4fd613d2ea4e032bfba9a1deb596a81bcc3392 100644 --- a/src/ui/nehubaContainer/nehubaContainer.template.html +++ b/src/ui/nehubaContainer/nehubaContainer.template.html @@ -80,7 +80,6 @@ <!-- maximise/minimise button --> <maximise-panel-button - (touchend)="toggleMaximiseMinimise(0)" (click)="toggleMaximiseMinimise(0)" [ngClass]="{ onHover: (panelOrder$ | async | reorderPanelIndexPipe : ( hoveredPanelIndices$ | async )) === 0 }" [touch-side-class]="0" @@ -109,7 +108,6 @@ <!-- maximise/minimise button --> <maximise-panel-button - (touchend)="toggleMaximiseMinimise(1)" (click)="toggleMaximiseMinimise(1)" [ngClass]="{ onHover: (panelOrder$ | async | reorderPanelIndexPipe : ( hoveredPanelIndices$ | async )) === 1 }" [touch-side-class]="1" @@ -138,7 +136,6 @@ <!-- maximise/minimise button --> <maximise-panel-button - (touchend)="toggleMaximiseMinimise(2)" (click)="toggleMaximiseMinimise(2)" [ngClass]="{ onHover: (panelOrder$ | async | reorderPanelIndexPipe : ( hoveredPanelIndices$ | async )) === 2 }" [touch-side-class]="2" @@ -158,7 +155,6 @@ <!-- maximise/minimise button --> <maximise-panel-button - (touchend)="toggleMaximiseMinimise(3)" (click)="toggleMaximiseMinimise(3)" [ngClass]="{ onHover: (panelOrder$ | async | reorderPanelIndexPipe : ( hoveredPanelIndices$ | async )) === 3 }" [touch-side-class]="3" diff --git a/src/util/directives/mediaQuery.directive.ts b/src/util/directives/mediaQuery.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..08d77130d030ccb4bd08347e5f53a8dd527e42d9 --- /dev/null +++ b/src/util/directives/mediaQuery.directive.ts @@ -0,0 +1,54 @@ +import { Directive } from "@angular/core"; +import { BreakpointObserver } from "@angular/cdk/layout"; +import { Observable } from "rxjs"; +import { map } from "rxjs/operators"; + +const mediaBreakPoints = [ + '(min-width: 576px)', + '(min-width: 768px)', + '(min-width: 992px)', + '(min-width: 1200px)', + + // xxl, by popular demand + '(min-width: 2000px)' +] + +enum EnumMediaBreakPoints{ + s, + m, + l, + xl, + xxl, + xxxl +} + +@Directive({ + selector: '[iav-media-query]', + exportAs: 'iavMediaQuery' +}) + +export class MediaQueryDirective{ + + public mediaBreakPoint$: Observable<EnumMediaBreakPoints> + constructor( + bpObs: BreakpointObserver + ){ + this.mediaBreakPoint$ = bpObs.observe(mediaBreakPoints).pipe( + map(({ breakpoints, matches }) => { + if (!matches) return EnumMediaBreakPoints.xxxl + let tally = 0 + for (const key in breakpoints) { + if (breakpoints[key]) tally += 1 + } + switch(tally){ + case 5: return EnumMediaBreakPoints.s + case 4: return EnumMediaBreakPoints.m + case 3: return EnumMediaBreakPoints.l + case 2: return EnumMediaBreakPoints.xl + case 1: return EnumMediaBreakPoints.xxl + default: return EnumMediaBreakPoints.xl + } + }) + ) + } +} diff --git a/src/util/util.module.ts b/src/util/util.module.ts index 47d094f5f79dd9dd608ccf816afe3143d9eb49cf..1f8c3f09fb96e5ae7f842102b9f4b95353d31477 100644 --- a/src/util/util.module.ts +++ b/src/util/util.module.ts @@ -11,8 +11,13 @@ import { CaptureClickListenerDirective } from "./directives/captureClickListener import { AddUnitAndJoin } from "./pipes/addUnitAndJoin.pipe"; import { NmToMm } from "./pipes/numbers.pipe"; import { SwitchDirective } from "./directives/switch.directive"; +import { MediaQueryDirective } from './directives/mediaQuery.directive' +import { LayoutModule } from "@angular/cdk/layout"; @NgModule({ + imports:[ + LayoutModule + ], declarations: [ FilterNullPipe, FilterRowsByVisbilityPipe, @@ -28,6 +33,7 @@ import { SwitchDirective } from "./directives/switch.directive"; AddUnitAndJoin, NmToMm, SwitchDirective, + MediaQueryDirective ], exports: [ FilterNullPipe, @@ -44,6 +50,7 @@ import { SwitchDirective } from "./directives/switch.directive"; AddUnitAndJoin, NmToMm, SwitchDirective, + MediaQueryDirective ] })