@quadrel-enterprise-ui/qdc-cards 19.1.0 → 20.0.0-beta.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.js +3 -0
- package/esm2022/index.js.map +1 -0
- package/esm2022/lib/card/card.component.js +53 -0
- package/esm2022/lib/card/card.component.js.map +1 -0
- package/esm2022/lib/card/card.model.js +2 -0
- package/esm2022/lib/card/card.model.js.map +1 -0
- package/esm2022/lib/card/card.module.js +23 -0
- package/esm2022/lib/card/card.module.js.map +1 -0
- package/esm2022/lib/card/menu/card-menu.component.js +37 -0
- package/esm2022/lib/card/menu/card-menu.component.js.map +1 -0
- package/esm2022/lib/card/model/card-actions-config.interface.js +2 -0
- package/esm2022/lib/card/model/card-actions-config.interface.js.map +1 -0
- package/esm2022/lib/card-layout/card-layout.component.js +117 -0
- package/esm2022/lib/card-layout/card-layout.component.js.map +1 -0
- package/esm2022/lib/card-layout/card-layout.model.js +2 -0
- package/esm2022/lib/card-layout/card-layout.model.js.map +1 -0
- package/esm2022/lib/card-layout/card-layout.module.js +25 -0
- package/esm2022/lib/card-layout/card-layout.module.js.map +1 -0
- package/esm2022/lib/card-layout/card-status/card-status-height.directive.js +51 -0
- package/esm2022/lib/card-layout/card-status/card-status-height.directive.js.map +1 -0
- package/esm2022/lib/card-layout/card-status/card-status.component.js +112 -0
- package/esm2022/lib/card-layout/card-status/card-status.component.js.map +1 -0
- package/esm2022/lib/card-layout/card-status/card-status.model.js +2 -0
- package/esm2022/lib/card-layout/card-status/card-status.model.js.map +1 -0
- package/esm2022/lib/card-layout/card-status/pagination/pagination.model.js +2 -0
- package/esm2022/lib/card-layout/card-status/pagination/pagination.model.js.map +1 -0
- package/esm2022/lib/shared/popover/cards-popover.module.js +19 -0
- package/esm2022/lib/shared/popover/cards-popover.module.js.map +1 -0
- package/esm2022/lib/shared/popover/cards-popover.service.js +23 -0
- package/esm2022/lib/shared/popover/cards-popover.service.js.map +1 -0
- package/esm2022/lib/shared/popover/popover/cards-popover.component.js +14 -0
- package/esm2022/lib/shared/popover/popover/cards-popover.component.js.map +1 -0
- package/esm2022/lib/shared/popover/popover-on-click/cards-popover-on-click.directive.js +100 -0
- package/esm2022/lib/shared/popover/popover-on-click/cards-popover-on-click.directive.js.map +1 -0
- package/esm2022/quadrel-enterprise-ui-qdc-cards.js +5 -0
- package/esm2022/quadrel-enterprise-ui-qdc-cards.js.map +1 -0
- package/lib/card/card.component.d.ts +2 -3
- package/lib/card/model/card-actions-config.interface.d.ts +13 -6
- package/lib/card-layout/card-layout.component.d.ts +2 -3
- package/lib/card-layout/card-status/card-status-height.directive.d.ts +1 -2
- package/lib/shared/popover/popover-on-click/cards-popover-on-click.directive.d.ts +2 -4
- package/package.json +10 -10
- package/quadrel-enterprise-ui-qdc-cards.d.ts +5 -0
- package/esm2022/index.mjs +0 -3
- package/esm2022/lib/card/card.component.mjs +0 -53
- package/esm2022/lib/card/card.model.mjs +0 -2
- package/esm2022/lib/card/card.module.mjs +0 -23
- package/esm2022/lib/card/menu/card-menu.component.mjs +0 -37
- package/esm2022/lib/card/model/card-actions-config.interface.mjs +0 -2
- package/esm2022/lib/card-layout/card-layout.component.mjs +0 -117
- package/esm2022/lib/card-layout/card-layout.model.mjs +0 -2
- package/esm2022/lib/card-layout/card-layout.module.mjs +0 -25
- package/esm2022/lib/card-layout/card-status/card-status-height.directive.mjs +0 -51
- package/esm2022/lib/card-layout/card-status/card-status.component.mjs +0 -112
- package/esm2022/lib/card-layout/card-status/card-status.model.mjs +0 -2
- package/esm2022/lib/card-layout/card-status/pagination/pagination.model.mjs +0 -2
- package/esm2022/lib/shared/popover/cards-popover.module.mjs +0 -19
- package/esm2022/lib/shared/popover/cards-popover.service.mjs +0 -23
- package/esm2022/lib/shared/popover/popover/cards-popover.component.mjs +0 -14
- package/esm2022/lib/shared/popover/popover-on-click/cards-popover-on-click.directive.mjs +0 -100
- package/esm2022/quadrel-enterprise-ui-qdc-cards.mjs +0 -5
package/esm2022/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/qdc-cards/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,wBAAwB,CAAC","sourcesContent":["export * from './lib/card-layout/card-layout.module';\nexport * from './lib/card/card.module';\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, inject, Input, TemplateRef, ViewEncapsulation } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import * as i1 from "@quadrel-enterprise-ui/framework";
|
|
4
|
+
import * as i2 from "./menu/card-menu.component";
|
|
5
|
+
import * as i3 from "@ngx-translate/core";
|
|
6
|
+
export class QdcCardComponent {
|
|
7
|
+
constructor() {
|
|
8
|
+
/** JSON configuration driving the visual appearance of the card. */
|
|
9
|
+
this.cardConfig = {};
|
|
10
|
+
/** Optional test-id for E2E / integration tests. */
|
|
11
|
+
this.testId = 'card';
|
|
12
|
+
this.hasHeader = false;
|
|
13
|
+
this.hasFooter = false;
|
|
14
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
15
|
+
}
|
|
16
|
+
get isMobile() {
|
|
17
|
+
if (typeof window !== 'undefined') {
|
|
18
|
+
return window.matchMedia('(max-width: 599px)').matches;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
ngAfterContentInit() {
|
|
23
|
+
this.evaluateVisibility();
|
|
24
|
+
}
|
|
25
|
+
ngOnChanges() {
|
|
26
|
+
this.evaluateVisibility();
|
|
27
|
+
}
|
|
28
|
+
evaluateVisibility() {
|
|
29
|
+
this.hasHeader = !!(this.cardConfig?.icon || this.cardConfig?.title || this.cardConfig?.subTitle);
|
|
30
|
+
this.cdr.markForCheck();
|
|
31
|
+
}
|
|
32
|
+
isTemplate(value) {
|
|
33
|
+
return value instanceof TemplateRef;
|
|
34
|
+
}
|
|
35
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
36
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: QdcCardComponent, isStandalone: false, selector: "qdc-card", inputs: { cardConfig: "cardConfig", testId: ["data-test-id", "testId"] }, host: { properties: { "attr.data-test-id": "testId", "class.mobile": "this.isMobile" }, classAttribute: "qdc-card" }, usesOnChanges: true, ngImport: i0, template: "<article class=\"qdc-card\" (click)=\"cardConfig?.onCardClick()\">\n @if (cardConfig) {\n <!-- Header -->\n @if (cardConfig.icon || cardConfig.title || cardConfig.subTitle || cardConfig.chip) {\n <header class=\"qdc-card__header\">\n <div class=\"qdc-card__header-left\">\n @if (cardConfig.icon) {\n <qd-icon class=\"qdc-card__icon\" [icon]=\"cardConfig.icon\"></qd-icon>\n }\n <div class=\"qdc-card__header-main\">\n @if (cardConfig.title) {\n <span class=\"qdc-card__title\">{{ cardConfig.title }}</span>\n } @if (cardConfig.subTitle) {\n <span class=\"qdc-card__subtitle\">{{ cardConfig.subTitle }}</span>\n }\n </div>\n </div>\n\n <div class=\"qdc-card__header-right\">\n @if (cardConfig.chip) {\n <qd-chip [state]=\"cardConfig.chip!.state\" data-test-id=\"test-chip\">\n {{ cardConfig.chip!.label.i18n | translate }}\n </qd-chip>\n } @if (cardConfig.menuActions) {\n <div class=\"qdc-card__header-actions\">\n <qdc-card-menu [actions]=\"cardConfig.menuActions\"></qdc-card-menu>\n </div>\n }\n </div>\n </header>\n }\n\n <!-- Body -->\n @if (cardConfig.bodyPairs) {\n <div class=\"qdc-card__body\">\n <div class=\"qdc-card__body-grid\">\n @for (item of cardConfig.bodyPairs; track $index) {\n <div class=\"qdc-card__body-row\">\n <div class=\"qdc-card__body-label\">\n <span>{{ item.i18n | translate }}</span>\n </div>\n <div class=\"qdc-card__body-content\">\n @if (item.value) {\n <span class=\"qdc-card__body-value\">{{ item.value }}</span>\n } @if (item.status) {\n <qd-status-indicator [type]=\"item.status.type\" [level]=\"item.status.level\"></qd-status-indicator>\n } @if (item.icon) {\n <qd-icon [icon]=\"item.icon\"></qd-icon>\n } @if (item.chips) {\n <div class=\"qdc-card__body-chips\">\n @for (chip of item.chips; track $index) {\n <qd-chip [state]=\"chip.state\" class=\"qdc-card__body-chip\">\n {{ chip.label.i18n | translate }}\n </qd-chip>\n }\n </div>\n } @if (item.booleanValue !== undefined) {\n <qd-icon [icon]=\"item.booleanValue ? 'checkmark' : 'timesLarge'\"></qd-icon>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer -->\n @if (cardConfig.footer) {\n <footer class=\"qdc-card__footer\">\n @if (cardConfig.footer.icon || cardConfig.footer.text) {\n <div class=\"qdc-card__footer-start\">\n <qd-icon class=\"qdc-card__footer-icon\" [icon]=\"cardConfig.footer.icon?.icon\" [status]=\"cardConfig.footer.icon?.status\"></qd-icon>\n <span class=\"qdc-card__footer-text\">{{ cardConfig.footer.text | translate }}</span>\n </div>\n } @if (cardConfig.footer.action) {\n <div class=\"qdc-card__footer-end\">\n <button\n qdButton\n qdButtonGhost\n [disabled]=\"cardConfig.footer.action?.isDisabled\"\n (click)=\"cardConfig.footer.action?.handler()\"\n [icon]=\"cardConfig.footer.action?.icon\"\n data-test-id=\"test-footer-button\"\n >\n {{ cardConfig.footer.action?.label.i18n | translate }}\n </button>\n </div>\n }\n </footer>\n } } @else {\n <div class=\"qdc-card__empty\">\n <span class=\"qdc-card__empty-text\">No card configuration provided.</span>\n </div>\n }\n</article>\n", styles: ["@charset \"UTF-8\";:root{--border-col: #e0e0e0;--text: #222;--muted: #666;--chip-bg: #fff;--chip-bd: #bdbdbd;--chip-prio: #ff9800;--chip-status: #11a35d;--btn-bg: #fff;--btn-bd: #0067b8;--btn-tx: #0067b8;--row-gap: .6rem}.qdc-card{font-family:Roboto,sans-serif;display:flex;overflow:hidden;width:100%;flex-direction:column;border:1px solid var(--border-col);border-radius:4px;background:#fff}.qdc-card+.qdc-card{margin-top:clamp(.25rem,1vw,.5rem)}.row{display:flex;align-items:center;gap:.5rem}.wrap{flex-wrap:wrap}.ml-auto{margin-left:auto}.text-muted{color:var(--muted);font-size:.875rem}.fw-bold{font-weight:600}.chip{display:inline-flex;height:1.5rem;align-items:center;justify-content:center;padding:0 .6rem;border:1px solid var(--chip-bd);border-radius:16px;background:var(--chip-bg);font-size:.75rem;line-height:1;white-space:nowrap}.chip.prio{border-color:var(--chip-prio);color:var(--chip-prio)}.chip.status{border-color:var(--chip-status);color:var(--chip-status)}.btn{display:inline-flex;align-items:center;justify-content:center;padding:.4rem 1.2rem;border:2px solid var(--btn-bd);border-radius:2px;background:var(--btn-bg);color:var(--btn-tx);cursor:pointer;font-size:.875rem;font-weight:600;gap:.4rem;text-decoration:none}.btn:hover{background:#f0f8ff}.qdc-card__header{display:flex;align-items:center;padding:1rem;border-bottom:1px solid var(--border-col);gap:.8rem}.qdc-card__header-left{display:flex;align-items:center;gap:.5rem}.qdc-card__header-main{display:grid}.qdc-card__title{font-weight:700}.qdc-card__icon{font-size:1.4rem;line-height:1}.qdc-card__subtitle{color:var(--muted);font-size:.875rem}.qdc-card__header-right{display:flex;align-items:center;margin-left:auto;gap:.5rem}.qdc-card__menu{cursor:pointer;font-size:1.4rem;line-height:1}.qdc-card__body{display:grid;padding:1rem;column-gap:.5rem;grid-template-columns:1fr auto;row-gap:var(--row-gap)}.qdc-card__body>*{margin:0}.qdc-card__body-value{color:var(--text);font-size:.8rem}.qdc-card__body-chips{display:flex;flex-wrap:wrap;gap:.5rem}.qdc-card__footer{display:flex;justify-content:space-between;padding:.7rem 1rem;border-top:1px solid var(--border-col);gap:.8rem}.qdc-card__footer-start{display:flex;flex:1;align-items:center;justify-content:start;gap:.5rem}.qdc-card__footer-start qd-icon{font-size:1.5rem;line-height:1}.qdc-card__footer-end{display:flex;flex:2;justify-content:end;gap:.5rem}.qdc-card__footer-text{font-size:.7rem}.qdc-card__body-grid{display:flex;flex-direction:column;gap:14px}.qdc-card__body-row{display:grid;grid-template-columns:33% 66%;gap:5px}.qdc-card__body-label{color:var(--muted);font-size:.8rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qdc-card__body-content{color:var(--text);font-size:.8rem}.qdc-card__body-content qd-icon{color:var(--text);font-size:1.4rem;line-height:1}@media (max-width: 480px){.qdc-card{max-width:100%}.qdc-card__body{grid-template-columns:1fr}.qdc-card__header-right{margin-left:0}.qdc-card__footer .btn{width:100%;justify-content:center}}\n"], dependencies: [{ kind: "component", type: i1.QdButtonComponent, selector: "button[qdButton], a[qdButton], button[qd-button]", inputs: ["disabled", "color", "icon", "data-test-id", "additionalInfo"] }, { kind: "directive", type: i1.QdButtonGhostDirective, selector: "button[qdButtonGhost], a[qdButtonGhost]" }, { kind: "component", type: i1.QdChipComponent, selector: "qd-chip", inputs: ["state", "close", "data", "data-test-id"], outputs: ["closeClickEmitter"] }, { kind: "component", type: i1.QdIconComponent, selector: "qd-icon", inputs: ["icon", "status"] }, { kind: "component", type: i1.QdStatusIndicatorComponent, selector: "qd-status-indicator", inputs: ["type", "level", "caption", "data-test-id"] }, { kind: "component", type: i2.QdcCardMenuComponent, selector: "qdc-card-menu", inputs: ["actions", "data-test-id"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
37
|
+
}
|
|
38
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardComponent, decorators: [{
|
|
39
|
+
type: Component,
|
|
40
|
+
args: [{ selector: 'qdc-card', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
41
|
+
class: 'qdc-card',
|
|
42
|
+
'[attr.data-test-id]': 'testId'
|
|
43
|
+
}, standalone: false, template: "<article class=\"qdc-card\" (click)=\"cardConfig?.onCardClick()\">\n @if (cardConfig) {\n <!-- Header -->\n @if (cardConfig.icon || cardConfig.title || cardConfig.subTitle || cardConfig.chip) {\n <header class=\"qdc-card__header\">\n <div class=\"qdc-card__header-left\">\n @if (cardConfig.icon) {\n <qd-icon class=\"qdc-card__icon\" [icon]=\"cardConfig.icon\"></qd-icon>\n }\n <div class=\"qdc-card__header-main\">\n @if (cardConfig.title) {\n <span class=\"qdc-card__title\">{{ cardConfig.title }}</span>\n } @if (cardConfig.subTitle) {\n <span class=\"qdc-card__subtitle\">{{ cardConfig.subTitle }}</span>\n }\n </div>\n </div>\n\n <div class=\"qdc-card__header-right\">\n @if (cardConfig.chip) {\n <qd-chip [state]=\"cardConfig.chip!.state\" data-test-id=\"test-chip\">\n {{ cardConfig.chip!.label.i18n | translate }}\n </qd-chip>\n } @if (cardConfig.menuActions) {\n <div class=\"qdc-card__header-actions\">\n <qdc-card-menu [actions]=\"cardConfig.menuActions\"></qdc-card-menu>\n </div>\n }\n </div>\n </header>\n }\n\n <!-- Body -->\n @if (cardConfig.bodyPairs) {\n <div class=\"qdc-card__body\">\n <div class=\"qdc-card__body-grid\">\n @for (item of cardConfig.bodyPairs; track $index) {\n <div class=\"qdc-card__body-row\">\n <div class=\"qdc-card__body-label\">\n <span>{{ item.i18n | translate }}</span>\n </div>\n <div class=\"qdc-card__body-content\">\n @if (item.value) {\n <span class=\"qdc-card__body-value\">{{ item.value }}</span>\n } @if (item.status) {\n <qd-status-indicator [type]=\"item.status.type\" [level]=\"item.status.level\"></qd-status-indicator>\n } @if (item.icon) {\n <qd-icon [icon]=\"item.icon\"></qd-icon>\n } @if (item.chips) {\n <div class=\"qdc-card__body-chips\">\n @for (chip of item.chips; track $index) {\n <qd-chip [state]=\"chip.state\" class=\"qdc-card__body-chip\">\n {{ chip.label.i18n | translate }}\n </qd-chip>\n }\n </div>\n } @if (item.booleanValue !== undefined) {\n <qd-icon [icon]=\"item.booleanValue ? 'checkmark' : 'timesLarge'\"></qd-icon>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer -->\n @if (cardConfig.footer) {\n <footer class=\"qdc-card__footer\">\n @if (cardConfig.footer.icon || cardConfig.footer.text) {\n <div class=\"qdc-card__footer-start\">\n <qd-icon class=\"qdc-card__footer-icon\" [icon]=\"cardConfig.footer.icon?.icon\" [status]=\"cardConfig.footer.icon?.status\"></qd-icon>\n <span class=\"qdc-card__footer-text\">{{ cardConfig.footer.text | translate }}</span>\n </div>\n } @if (cardConfig.footer.action) {\n <div class=\"qdc-card__footer-end\">\n <button\n qdButton\n qdButtonGhost\n [disabled]=\"cardConfig.footer.action?.isDisabled\"\n (click)=\"cardConfig.footer.action?.handler()\"\n [icon]=\"cardConfig.footer.action?.icon\"\n data-test-id=\"test-footer-button\"\n >\n {{ cardConfig.footer.action?.label.i18n | translate }}\n </button>\n </div>\n }\n </footer>\n } } @else {\n <div class=\"qdc-card__empty\">\n <span class=\"qdc-card__empty-text\">No card configuration provided.</span>\n </div>\n }\n</article>\n", styles: ["@charset \"UTF-8\";:root{--border-col: #e0e0e0;--text: #222;--muted: #666;--chip-bg: #fff;--chip-bd: #bdbdbd;--chip-prio: #ff9800;--chip-status: #11a35d;--btn-bg: #fff;--btn-bd: #0067b8;--btn-tx: #0067b8;--row-gap: .6rem}.qdc-card{font-family:Roboto,sans-serif;display:flex;overflow:hidden;width:100%;flex-direction:column;border:1px solid var(--border-col);border-radius:4px;background:#fff}.qdc-card+.qdc-card{margin-top:clamp(.25rem,1vw,.5rem)}.row{display:flex;align-items:center;gap:.5rem}.wrap{flex-wrap:wrap}.ml-auto{margin-left:auto}.text-muted{color:var(--muted);font-size:.875rem}.fw-bold{font-weight:600}.chip{display:inline-flex;height:1.5rem;align-items:center;justify-content:center;padding:0 .6rem;border:1px solid var(--chip-bd);border-radius:16px;background:var(--chip-bg);font-size:.75rem;line-height:1;white-space:nowrap}.chip.prio{border-color:var(--chip-prio);color:var(--chip-prio)}.chip.status{border-color:var(--chip-status);color:var(--chip-status)}.btn{display:inline-flex;align-items:center;justify-content:center;padding:.4rem 1.2rem;border:2px solid var(--btn-bd);border-radius:2px;background:var(--btn-bg);color:var(--btn-tx);cursor:pointer;font-size:.875rem;font-weight:600;gap:.4rem;text-decoration:none}.btn:hover{background:#f0f8ff}.qdc-card__header{display:flex;align-items:center;padding:1rem;border-bottom:1px solid var(--border-col);gap:.8rem}.qdc-card__header-left{display:flex;align-items:center;gap:.5rem}.qdc-card__header-main{display:grid}.qdc-card__title{font-weight:700}.qdc-card__icon{font-size:1.4rem;line-height:1}.qdc-card__subtitle{color:var(--muted);font-size:.875rem}.qdc-card__header-right{display:flex;align-items:center;margin-left:auto;gap:.5rem}.qdc-card__menu{cursor:pointer;font-size:1.4rem;line-height:1}.qdc-card__body{display:grid;padding:1rem;column-gap:.5rem;grid-template-columns:1fr auto;row-gap:var(--row-gap)}.qdc-card__body>*{margin:0}.qdc-card__body-value{color:var(--text);font-size:.8rem}.qdc-card__body-chips{display:flex;flex-wrap:wrap;gap:.5rem}.qdc-card__footer{display:flex;justify-content:space-between;padding:.7rem 1rem;border-top:1px solid var(--border-col);gap:.8rem}.qdc-card__footer-start{display:flex;flex:1;align-items:center;justify-content:start;gap:.5rem}.qdc-card__footer-start qd-icon{font-size:1.5rem;line-height:1}.qdc-card__footer-end{display:flex;flex:2;justify-content:end;gap:.5rem}.qdc-card__footer-text{font-size:.7rem}.qdc-card__body-grid{display:flex;flex-direction:column;gap:14px}.qdc-card__body-row{display:grid;grid-template-columns:33% 66%;gap:5px}.qdc-card__body-label{color:var(--muted);font-size:.8rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qdc-card__body-content{color:var(--text);font-size:.8rem}.qdc-card__body-content qd-icon{color:var(--text);font-size:1.4rem;line-height:1}@media (max-width: 480px){.qdc-card{max-width:100%}.qdc-card__body{grid-template-columns:1fr}.qdc-card__header-right{margin-left:0}.qdc-card__footer .btn{width:100%;justify-content:center}}\n"] }]
|
|
44
|
+
}], propDecorators: { cardConfig: [{
|
|
45
|
+
type: Input
|
|
46
|
+
}], testId: [{
|
|
47
|
+
type: Input,
|
|
48
|
+
args: ['data-test-id']
|
|
49
|
+
}], isMobile: [{
|
|
50
|
+
type: HostBinding,
|
|
51
|
+
args: ['class.mobile']
|
|
52
|
+
}] } });
|
|
53
|
+
//# sourceMappingURL=card.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.component.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card/card.component.ts","../../../../../../libs/qdc-cards/src/lib/card/card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAEL,uBAAuB,EACvB,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EAEL,WAAW,EACX,iBAAiB,EAClB,MAAM,eAAe,CAAC;;;;;AAevB,MAAM,OAAO,gBAAgB;IAZ7B;QAaE,oEAAoE;QAC3D,eAAU,GAAkB,EAAE,CAAC;QAExC,oDAAoD;QAC7B,WAAM,GAAG,MAAM,CAAC;QAEvC,cAAS,GAAG,KAAK,CAAC;QAClB,cAAS,GAAG,KAAK,CAAC;QASV,QAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;KAkBzC;IAzBC,IAAiC,QAAQ;QACvC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC;QACzD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAID,kBAAkB;QAChB,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAEO,kBAAkB;QACxB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAClG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED,UAAU,CAAC,KAAc;QACvB,OAAO,KAAK,YAAY,WAAW,CAAC;IACtC,CAAC;+GAlCU,gBAAgB;mGAAhB,gBAAgB,0RC1B7B,65GA+FA;;4FDrEa,gBAAgB;kBAZ5B,SAAS;+BACE,UAAU,iBAGL,iBAAiB,CAAC,IAAI,mBACpB,uBAAuB,CAAC,MAAM,QACzC;wBACJ,KAAK,EAAE,UAAU;wBACjB,qBAAqB,EAAE,QAAQ;qBAChC,cACW,KAAK;;sBAIhB,KAAK;;sBAGL,KAAK;uBAAC,cAAc;;sBAKpB,WAAW;uBAAC,cAAc","sourcesContent":["import {\n AfterContentInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n HostBinding,\n inject,\n Input,\n OnChanges,\n TemplateRef,\n ViewEncapsulation\n} from '@angular/core';\nimport { QdcCardConfig } from './card.model';\n\n@Component({\n selector: 'qdc-card',\n templateUrl: './card.component.html',\n styleUrls: ['./card.component.scss'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'qdc-card',\n '[attr.data-test-id]': 'testId'\n },\n standalone: false\n})\nexport class QdcCardComponent implements AfterContentInit, OnChanges {\n /** JSON configuration driving the visual appearance of the card. */\n @Input() cardConfig: QdcCardConfig = {};\n\n /** Optional test-id for E2E / integration tests. */\n @Input('data-test-id') testId = 'card';\n\n hasHeader = false;\n hasFooter = false;\n\n @HostBinding('class.mobile') get isMobile(): boolean {\n if (typeof window !== 'undefined') {\n return window.matchMedia('(max-width: 599px)').matches;\n }\n return false;\n }\n\n private cdr = inject(ChangeDetectorRef);\n\n ngAfterContentInit(): void {\n this.evaluateVisibility();\n }\n\n ngOnChanges(): void {\n this.evaluateVisibility();\n }\n\n private evaluateVisibility(): void {\n this.hasHeader = !!(this.cardConfig?.icon || this.cardConfig?.title || this.cardConfig?.subTitle);\n this.cdr.markForCheck();\n }\n\n isTemplate(value: unknown): value is TemplateRef<unknown> {\n return value instanceof TemplateRef;\n }\n}\n","<article class=\"qdc-card\" (click)=\"cardConfig?.onCardClick()\">\n @if (cardConfig) {\n <!-- Header -->\n @if (cardConfig.icon || cardConfig.title || cardConfig.subTitle || cardConfig.chip) {\n <header class=\"qdc-card__header\">\n <div class=\"qdc-card__header-left\">\n @if (cardConfig.icon) {\n <qd-icon class=\"qdc-card__icon\" [icon]=\"cardConfig.icon\"></qd-icon>\n }\n <div class=\"qdc-card__header-main\">\n @if (cardConfig.title) {\n <span class=\"qdc-card__title\">{{ cardConfig.title }}</span>\n } @if (cardConfig.subTitle) {\n <span class=\"qdc-card__subtitle\">{{ cardConfig.subTitle }}</span>\n }\n </div>\n </div>\n\n <div class=\"qdc-card__header-right\">\n @if (cardConfig.chip) {\n <qd-chip [state]=\"cardConfig.chip!.state\" data-test-id=\"test-chip\">\n {{ cardConfig.chip!.label.i18n | translate }}\n </qd-chip>\n } @if (cardConfig.menuActions) {\n <div class=\"qdc-card__header-actions\">\n <qdc-card-menu [actions]=\"cardConfig.menuActions\"></qdc-card-menu>\n </div>\n }\n </div>\n </header>\n }\n\n <!-- Body -->\n @if (cardConfig.bodyPairs) {\n <div class=\"qdc-card__body\">\n <div class=\"qdc-card__body-grid\">\n @for (item of cardConfig.bodyPairs; track $index) {\n <div class=\"qdc-card__body-row\">\n <div class=\"qdc-card__body-label\">\n <span>{{ item.i18n | translate }}</span>\n </div>\n <div class=\"qdc-card__body-content\">\n @if (item.value) {\n <span class=\"qdc-card__body-value\">{{ item.value }}</span>\n } @if (item.status) {\n <qd-status-indicator [type]=\"item.status.type\" [level]=\"item.status.level\"></qd-status-indicator>\n } @if (item.icon) {\n <qd-icon [icon]=\"item.icon\"></qd-icon>\n } @if (item.chips) {\n <div class=\"qdc-card__body-chips\">\n @for (chip of item.chips; track $index) {\n <qd-chip [state]=\"chip.state\" class=\"qdc-card__body-chip\">\n {{ chip.label.i18n | translate }}\n </qd-chip>\n }\n </div>\n } @if (item.booleanValue !== undefined) {\n <qd-icon [icon]=\"item.booleanValue ? 'checkmark' : 'timesLarge'\"></qd-icon>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Footer -->\n @if (cardConfig.footer) {\n <footer class=\"qdc-card__footer\">\n @if (cardConfig.footer.icon || cardConfig.footer.text) {\n <div class=\"qdc-card__footer-start\">\n <qd-icon class=\"qdc-card__footer-icon\" [icon]=\"cardConfig.footer.icon?.icon\" [status]=\"cardConfig.footer.icon?.status\"></qd-icon>\n <span class=\"qdc-card__footer-text\">{{ cardConfig.footer.text | translate }}</span>\n </div>\n } @if (cardConfig.footer.action) {\n <div class=\"qdc-card__footer-end\">\n <button\n qdButton\n qdButtonGhost\n [disabled]=\"cardConfig.footer.action?.isDisabled\"\n (click)=\"cardConfig.footer.action?.handler()\"\n [icon]=\"cardConfig.footer.action?.icon\"\n data-test-id=\"test-footer-button\"\n >\n {{ cardConfig.footer.action?.label.i18n | translate }}\n </button>\n </div>\n }\n </footer>\n } } @else {\n <div class=\"qdc-card__empty\">\n <span class=\"qdc-card__empty-text\">No card configuration provided.</span>\n </div>\n }\n</article>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.model.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card/card.model.ts"],"names":[],"mappings":"","sourcesContent":["import {\n QdcCardActionConfig,\n QdcCardBodyPair,\n QdcCardChip,\n QdcCardFooter\n} from './model/card-actions-config.interface';\n\nexport interface QdcCardConfig {\n /**\n * Optional icon name shown in the header, left of the title.\n * */\n icon?: string | null;\n\n /**\n * Main headline of the card.\n * */\n title?: string | null;\n\n /**\n * Optional subtitle shown under the title.\n * */\n subTitle?: string | null;\n\n bodyPairs?: QdcCardBodyPair[];\n\n chip?: QdcCardChip;\n\n /**\n * Optional actions to display in the card menu.\n * */\n menuActions?: QdcCardActionConfig[];\n\n footer?: QdcCardFooter;\n\n onCardClick?: () => void;\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { NgModule } from '@angular/core';
|
|
3
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
4
|
+
import { QdUiModule } from '@quadrel-enterprise-ui/framework';
|
|
5
|
+
import { QdcCardComponent } from './card.component';
|
|
6
|
+
import { QdcCardMenuComponent } from './menu/card-menu.component';
|
|
7
|
+
import { QdcCardsPopoverModule } from '../shared/popover/cards-popover.module';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
export { QdcCardComponent, QdcCardMenuComponent };
|
|
10
|
+
export class QdcCardModule {
|
|
11
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
12
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.17", ngImport: i0, type: QdcCardModule, declarations: [QdcCardComponent, QdcCardMenuComponent], imports: [CommonModule, TranslateModule, QdUiModule, QdcCardsPopoverModule], exports: [QdcCardComponent, QdcCardMenuComponent] }); }
|
|
13
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardModule, imports: [CommonModule, TranslateModule, QdUiModule, QdcCardsPopoverModule] }); }
|
|
14
|
+
}
|
|
15
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardModule, decorators: [{
|
|
16
|
+
type: NgModule,
|
|
17
|
+
args: [{
|
|
18
|
+
imports: [CommonModule, TranslateModule, QdUiModule, QdcCardsPopoverModule],
|
|
19
|
+
declarations: [QdcCardComponent, QdcCardMenuComponent],
|
|
20
|
+
exports: [QdcCardComponent, QdcCardMenuComponent]
|
|
21
|
+
}]
|
|
22
|
+
}] });
|
|
23
|
+
//# sourceMappingURL=card.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.module.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card/card.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;;AAE/E,OAAO,EAAE,gBAAgB,EAAiB,oBAAoB,EAAE,CAAC;AAOjE,MAAM,OAAO,aAAa;+GAAb,aAAa;gHAAb,aAAa,iBAHT,gBAAgB,EAAE,oBAAoB,aAD3C,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,qBAAqB,aAEhE,gBAAgB,EAAE,oBAAoB;gHAErC,aAAa,YAJd,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,qBAAqB;;4FAI/D,aAAa;kBALzB,QAAQ;mBAAC;oBACR,OAAO,EAAE,CAAC,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,qBAAqB,CAAC;oBAC3E,YAAY,EAAE,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;oBACtD,OAAO,EAAE,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;iBAClD","sourcesContent":["import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { TranslateModule } from '@ngx-translate/core';\n\nimport { QdUiModule } from '@quadrel-enterprise-ui/framework';\nimport { QdcCardComponent } from './card.component';\nimport { QdcCardMenuComponent } from './menu/card-menu.component';\nimport { QdcCardConfig } from './card.model';\nimport { QdcCardsPopoverModule } from '../shared/popover/cards-popover.module';\n\nexport { QdcCardComponent, QdcCardConfig, QdcCardMenuComponent };\n\n@NgModule({\n imports: [CommonModule, TranslateModule, QdUiModule, QdcCardsPopoverModule],\n declarations: [QdcCardComponent, QdcCardMenuComponent],\n exports: [QdcCardComponent, QdcCardMenuComponent]\n})\nexport class QdcCardModule {}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
3
|
+
import { map, takeUntil } from 'rxjs/operators';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
import * as i2 from "@quadrel-enterprise-ui/framework";
|
|
7
|
+
import * as i3 from "../../shared/popover/popover-on-click/cards-popover-on-click.directive";
|
|
8
|
+
import * as i4 from "@ngx-translate/core";
|
|
9
|
+
export class QdcCardMenuComponent {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.testId = 'card-menu';
|
|
12
|
+
this._actionsSubject = new BehaviorSubject([]);
|
|
13
|
+
this._destroyed$ = new Subject();
|
|
14
|
+
}
|
|
15
|
+
set actions(actions) {
|
|
16
|
+
this._actionsSubject.next(actions);
|
|
17
|
+
}
|
|
18
|
+
get actions$() {
|
|
19
|
+
return this._actionsSubject.asObservable().pipe(takeUntil(this._destroyed$), map(actions => actions.map(action => ({ ...action, isDisabled: action.isDisabled }))));
|
|
20
|
+
}
|
|
21
|
+
ngOnDestroy() {
|
|
22
|
+
this._destroyed$.next();
|
|
23
|
+
this._destroyed$.complete();
|
|
24
|
+
}
|
|
25
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: QdcCardMenuComponent, isStandalone: false, selector: "qdc-card-menu", inputs: { actions: "actions", testId: ["data-test-id", "testId"] }, ngImport: i0, template: "<ng-container *ngIf=\"actions$ | async as actions\">\n <qd-icon\n *ngIf=\"actions.length > 0\"\n icon=\"overflowMenuVertical\"\n class=\"menu-opener\"\n [attr.data-test-id]=\"testId + '-opener'\"\n [qdcCardsPopoverOnClick]=\"menu\"\n ></qd-icon>\n\n <ng-template #menu>\n <ng-container *ngFor=\"let action of actions$ | async\">\n <button\n class=\"menu-entry\"\n (click)=\"action.handler()\"\n [disabled]=\"action.isDisabled\"\n [attr.data-test-id]=\"testId + '-action'\"\n >\n {{ action.label.i18n | translate }}\n </button>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [":host{font-family:Roboto,sans-serif}:host .menu-opener{position:sticky;top:1.5625rem;right:1.5rem;cursor:pointer;font-size:1.5rem;font-weight:700}button.menu-entry{display:block;overflow:hidden;width:100%;min-height:2.25rem;padding:0 1rem;background:#fff0;text-align:left;text-overflow:ellipsis;white-space:nowrap;color:inherit;font-size:.875rem;font-weight:400;line-height:1.3125rem}button.menu-entry:hover{background-color:#f2f7fa}button.menu-entry:hover[disabled]{background:#fff0;cursor:default}button.menu-entry[disabled]{color:#b4b4b4;cursor:default}button.menu-entry[disabled]:hover{background-color:#fff0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.QdIconComponent, selector: "qd-icon", inputs: ["icon", "status"] }, { kind: "directive", type: i3.QdcCardsPopoverOnClickDirective, selector: "[qdcCardsPopoverOnClick]", inputs: ["qdcCardsPopoverOnClick", "popoverWidth", "positionStrategy", "popoverCloseStrategy"], outputs: ["opened", "closed"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
27
|
+
}
|
|
28
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardMenuComponent, decorators: [{
|
|
29
|
+
type: Component,
|
|
30
|
+
args: [{ selector: 'qdc-card-menu', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<ng-container *ngIf=\"actions$ | async as actions\">\n <qd-icon\n *ngIf=\"actions.length > 0\"\n icon=\"overflowMenuVertical\"\n class=\"menu-opener\"\n [attr.data-test-id]=\"testId + '-opener'\"\n [qdcCardsPopoverOnClick]=\"menu\"\n ></qd-icon>\n\n <ng-template #menu>\n <ng-container *ngFor=\"let action of actions$ | async\">\n <button\n class=\"menu-entry\"\n (click)=\"action.handler()\"\n [disabled]=\"action.isDisabled\"\n [attr.data-test-id]=\"testId + '-action'\"\n >\n {{ action.label.i18n | translate }}\n </button>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [":host{font-family:Roboto,sans-serif}:host .menu-opener{position:sticky;top:1.5625rem;right:1.5rem;cursor:pointer;font-size:1.5rem;font-weight:700}button.menu-entry{display:block;overflow:hidden;width:100%;min-height:2.25rem;padding:0 1rem;background:#fff0;text-align:left;text-overflow:ellipsis;white-space:nowrap;color:inherit;font-size:.875rem;font-weight:400;line-height:1.3125rem}button.menu-entry:hover{background-color:#f2f7fa}button.menu-entry:hover[disabled]{background:#fff0;cursor:default}button.menu-entry[disabled]{color:#b4b4b4;cursor:default}button.menu-entry[disabled]:hover{background-color:#fff0}\n"] }]
|
|
31
|
+
}], propDecorators: { actions: [{
|
|
32
|
+
type: Input
|
|
33
|
+
}], testId: [{
|
|
34
|
+
type: Input,
|
|
35
|
+
args: ['data-test-id']
|
|
36
|
+
}] } });
|
|
37
|
+
//# sourceMappingURL=card-menu.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-menu.component.js","sourceRoot":"","sources":["../../../../../../../libs/qdc-cards/src/lib/card/menu/card-menu.component.ts","../../../../../../../libs/qdc-cards/src/lib/card/menu/card-menu.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAa,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,eAAe,EAAc,OAAO,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;;;;;;AAUhD,MAAM,OAAO,oBAAoB;IAPjC;QAmByB,WAAM,GAAG,WAAW,CAAC;QAEpC,oBAAe,GAAG,IAAI,eAAe,CAAwB,EAAE,CAAC,CAAC;QACjE,gBAAW,GAAG,IAAI,OAAO,EAAQ,CAAC;KAM3C;IApBC,IAAa,OAAO,CAAC,OAA8B;QACjD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC,IAAI,CAC7C,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,EAC3B,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CACtF,CAAC;IACJ,CAAC;IAOD,WAAW;QACT,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;+GApBU,oBAAoB;mGAApB,oBAAoB,8ICZjC,ipBAsBA;;4FDVa,oBAAoB;kBAPhC,SAAS;+BACE,eAAe,mBAGR,uBAAuB,CAAC,MAAM,cACnC,KAAK;;sBAGhB,KAAK;;sBAWL,KAAK;uBAAC,cAAc","sourcesContent":["import { ChangeDetectionStrategy, Component, Input, OnDestroy } from '@angular/core';\nimport { BehaviorSubject, Observable, Subject } from 'rxjs';\nimport { map, takeUntil } from 'rxjs/operators';\nimport { QdcCardActionConfig } from '../model/card-actions-config.interface';\n\n@Component({\n selector: 'qdc-card-menu',\n templateUrl: './card-menu.component.html',\n styleUrls: ['./card-menu.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false\n})\nexport class QdcCardMenuComponent implements OnDestroy {\n @Input() set actions(actions: QdcCardActionConfig[]) {\n this._actionsSubject.next(actions);\n }\n\n get actions$(): Observable<QdcCardActionConfig[]> {\n return this._actionsSubject.asObservable().pipe(\n takeUntil(this._destroyed$),\n map(actions => actions.map(action => ({ ...action, isDisabled: action.isDisabled })))\n );\n }\n\n @Input('data-test-id') testId = 'card-menu';\n\n private _actionsSubject = new BehaviorSubject<QdcCardActionConfig[]>([]);\n private _destroyed$ = new Subject<void>();\n\n ngOnDestroy(): void {\n this._destroyed$.next();\n this._destroyed$.complete();\n }\n}\n","<ng-container *ngIf=\"actions$ | async as actions\">\n <qd-icon\n *ngIf=\"actions.length > 0\"\n icon=\"overflowMenuVertical\"\n class=\"menu-opener\"\n [attr.data-test-id]=\"testId + '-opener'\"\n [qdcCardsPopoverOnClick]=\"menu\"\n ></qd-icon>\n\n <ng-template #menu>\n <ng-container *ngFor=\"let action of actions$ | async\">\n <button\n class=\"menu-entry\"\n (click)=\"action.handler()\"\n [disabled]=\"action.isDisabled\"\n [attr.data-test-id]=\"testId + '-action'\"\n >\n {{ action.label.i18n | translate }}\n </button>\n </ng-container>\n </ng-template>\n</ng-container>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-actions-config.interface.js","sourceRoot":"","sources":["../../../../../../../libs/qdc-cards/src/lib/card/model/card-actions-config.interface.ts"],"names":[],"mappings":"","sourcesContent":["import { QdChipColor } from '@quadrel-enterprise-ui/framework';\nimport type { QdStatus, QdStatusIndicator } from '@quadrel-enterprise-ui/framework';\n\nexport interface QdcCardActionConfig {\n /**\n * The label is shown as text in the UI for this action.\n */\n label: {\n /** This i18n key is translated directly inside the QdCardMenu component. */\n i18n: string;\n };\n\n /**\n * The handler to execute when the action is clicked.\n */\n handler: () => void;\n\n /**\n * Whether the action is disabled or not\n *\n * * @default false\n */\n isDisabled?: boolean;\n\n /**\n * Optional icon to display in the action.\n */\n icon?: string | null;\n}\n\nexport interface QdcCardBodyPair {\n /**\n * Translatable label text.\n * */\n i18n: string;\n\n /**\n * Value to display next to the label.\n * */\n value?: string | number | boolean | null;\n\n /**\n * Optional Qd-Status-Indicator\n * */\n status?: Pick<QdStatusIndicator, 'type' | 'level'> | null;\n\n icon?: string | null;\n\n booleanValue?: boolean | null;\n\n chips?: QdcCardChip[] | null;\n}\n\nexport interface QdcCardFooter {\n icon?: QdcCardIcon | null;\n text?: string | null;\n action?: QdcCardActionConfig | null;\n}\n\nexport interface QdcCardChip {\n /**\n * Color of the chip. Defaults to 'primary'.\n * */\n state: QdChipColor;\n\n /**\n * Text shown inside the chip.\n * */\n label: {\n /**\n * Translatable label text.\n * */\n i18n: string;\n };\n /**\n * Optional icon to display inside the chip.\n * */\n}\n\nexport interface QdcCardIcon {\n /**\n * Icon name.\n * */\n icon: string;\n\n /**\n * Optional status for definition of color\n */\n status: QdStatus\n}\n"]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Component, HostListener, inject, Input, ViewChild, NgZone } from '@angular/core';
|
|
2
|
+
import { FormGroup } from '@angular/forms';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
import { startWith } from 'rxjs/operators';
|
|
5
|
+
import { QdFormControl } from '@quadrel-enterprise-ui/framework';
|
|
6
|
+
import { QdcCardStatusSameHeightDirective } from './card-status/card-status-height.directive';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
import * as i1 from "@angular/forms";
|
|
9
|
+
import * as i2 from "@quadrel-enterprise-ui/framework";
|
|
10
|
+
import * as i3 from "./card-status/card-status.component";
|
|
11
|
+
import * as i4 from "./card-status/card-status-height.directive";
|
|
12
|
+
import * as i5 from "@angular/common";
|
|
13
|
+
export class QdcCardLayoutComponent {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.isMobile = false;
|
|
16
|
+
this.MAX_COLUMNS = 5;
|
|
17
|
+
this.statusTitlesDropDownConfig = {
|
|
18
|
+
label: { i18n: 'i18n.qdc-card.layout.mobile.dropdown.status.label' },
|
|
19
|
+
options: []
|
|
20
|
+
};
|
|
21
|
+
this.dropDownConfig = new BehaviorSubject(this.statusTitlesDropDownConfig);
|
|
22
|
+
this.selectedStatusTitle = new BehaviorSubject(null);
|
|
23
|
+
this.ngZone = inject(NgZone);
|
|
24
|
+
}
|
|
25
|
+
ngOnInit() {
|
|
26
|
+
this.checkColumnLimit();
|
|
27
|
+
this.updateLayoutState();
|
|
28
|
+
this.initializeDropDown();
|
|
29
|
+
}
|
|
30
|
+
ngOnChanges(changes) {
|
|
31
|
+
if (changes['config']?.currentValue) {
|
|
32
|
+
this.checkColumnLimit();
|
|
33
|
+
const defaultStatusLabel = this.config.cardStatusConfig[0]?.title.i18n ?? null;
|
|
34
|
+
if (defaultStatusLabel) {
|
|
35
|
+
this.updateSelectedStatus(defaultStatusLabel);
|
|
36
|
+
}
|
|
37
|
+
this.setDropDownConfig();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
onPaginationChanged() {
|
|
41
|
+
this.ngZone.runOutsideAngular(() => {
|
|
42
|
+
requestAnimationFrame(() => {
|
|
43
|
+
queueMicrotask(() => this.cardStatusHeightDirective?.triggerUpdate());
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
onResize() {
|
|
48
|
+
const wasMobile = this.isMobile;
|
|
49
|
+
this.updateLayoutState();
|
|
50
|
+
if (!wasMobile && this.isMobile) {
|
|
51
|
+
this.initializeDropDown();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
checkColumnLimit() {
|
|
55
|
+
if (this.config.cardStatusConfig.length > this.MAX_COLUMNS) {
|
|
56
|
+
throw new Error(`Too many columns. Max allowed is ${this.MAX_COLUMNS}.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
updateLayoutState() {
|
|
60
|
+
this.isMobile = window.innerWidth <= 480;
|
|
61
|
+
}
|
|
62
|
+
initializeDropDown() {
|
|
63
|
+
const defaultStatusLabel = this.config.cardStatusConfig[0]?.title.i18n ?? null;
|
|
64
|
+
this.dropDownForm = new FormGroup({
|
|
65
|
+
statusTitle: new QdFormControl(defaultStatusLabel)
|
|
66
|
+
});
|
|
67
|
+
this.setDropDownConfig();
|
|
68
|
+
this.dropDownForm
|
|
69
|
+
.get('statusTitle')
|
|
70
|
+
?.valueChanges.pipe(startWith(this.dropDownForm.get('statusTitle')?.value))
|
|
71
|
+
.subscribe(title => {
|
|
72
|
+
this.updateSelectedStatus(title);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
updateSelectedStatus(title) {
|
|
76
|
+
if (!title) {
|
|
77
|
+
this.selectedStatusTitle.next(null);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const statusConfig = this.config.cardStatusConfig.find(s => s.title.i18n === title);
|
|
81
|
+
if (statusConfig) {
|
|
82
|
+
this.selectedStatusTitle.next({
|
|
83
|
+
...statusConfig,
|
|
84
|
+
title: { ...statusConfig.title },
|
|
85
|
+
cards: [...(statusConfig.cards ?? [])]
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.selectedStatusTitle.next(null);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
setDropDownConfig() {
|
|
93
|
+
const options = this.config.cardStatusConfig.map(status => ({
|
|
94
|
+
i18n: status.title.i18n,
|
|
95
|
+
value: status.title.i18n
|
|
96
|
+
}));
|
|
97
|
+
this.dropDownConfig.next({
|
|
98
|
+
...this.dropDownConfig.value,
|
|
99
|
+
options
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
103
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: QdcCardLayoutComponent, isStandalone: false, selector: "qdc-card-layout", inputs: { config: "config" }, host: { listeners: { "window:resize": "onResize()" } }, viewQueries: [{ propertyName: "cardStatusHeightDirective", first: true, predicate: QdcCardStatusSameHeightDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"qdc-card-layout__wrapper\">\n <div class=\"qdc-card-layout__container\">\n <div class=\"qdc-card-layout__layout-header\">\n <h1>{{ config.layoutTitle }}</h1>\n </div>\n\n @if (isMobile) {\n <form [formGroup]=\"dropDownForm\">\n <div class=\"qdc-card-layout__mobile-filter-grid\">\n <div class=\"cell\">\n <qd-dropdown formControlName=\"statusTitle\" [config]=\"dropDownConfig | async\"> </qd-dropdown>\n </div>\n </div>\n </form>\n }\n\n <div class=\"qdc-card-layout__layout\" qdcCardStatusSameHeight>\n @if (!isMobile) {\n @for (status of config.cardStatusConfig; track $index) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\" (paginationChanged)=\"onPaginationChanged()\">\n </qdc-card-status>\n }\n } @else {\n @if (selectedStatusTitle | async; as status) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\">\n </qdc-card-status>\n }\n }\n\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.qdc-card-layout__wrapper{font-family:Roboto,sans-serif;width:100%;box-sizing:border-box;justify-content:center;padding:1rem 0;background-color:#efefef;overflow-x:auto}.qdc-card-layout__container{box-sizing:border-box;flex-direction:column;gap:1rem}@media (max-width: 959.98px){.qdc-card-layout__container{width:100%}}.qdc-card-layout__layout-header{align-items:center}.qdc-card-layout__layout-header h1{margin:0;font-family:Roboto,sans-serif;font-size:16px;font-weight:500;letter-spacing:.15px;line-height:100%;vertical-align:middle}.qdc-card-layout__layout{display:flex;box-sizing:border-box;padding:10px 25px 25px;gap:1rem}@media (max-width: 959.98px){.qdc-card-layout__layout{flex-direction:column;gap:6px}}.qdc-card-status-item{min-width:400px;max-width:100%;flex:1 1 0}@media (max-width: 959.98px){.qdc-card-status-item{width:100%!important;min-width:0}}@media (max-width: 959.98px){.qdc-card-layout__mobile-filter-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%;padding-left:10px}.qdc-card-layout__mobile-filter-grid .cell{grid-column:2}}@media (max-width: 599.98px){.qdc-card-layout__mobile-filter-grid .cell{grid-column:1}}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2.QdDropdownComponent, selector: "qd-dropdown", inputs: ["value", "id", "formControlName", "config", "data-test-id", "qdPopoverMaxHeight", "dense"], outputs: ["valueChange", "enterClick", "clickHint", "clickReadonly", "clickViewonly", "optionsResolved"] }, { kind: "component", type: i3.QdcCardStatusComponent, selector: "qdc-card-status", inputs: ["config"], outputs: ["paginationChanged"] }, { kind: "directive", type: i4.QdcCardStatusSameHeightDirective, selector: "[qdcCardStatusSameHeight]" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }] }); }
|
|
104
|
+
}
|
|
105
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutComponent, decorators: [{
|
|
106
|
+
type: Component,
|
|
107
|
+
args: [{ selector: 'qdc-card-layout', standalone: false, template: "<div class=\"qdc-card-layout__wrapper\">\n <div class=\"qdc-card-layout__container\">\n <div class=\"qdc-card-layout__layout-header\">\n <h1>{{ config.layoutTitle }}</h1>\n </div>\n\n @if (isMobile) {\n <form [formGroup]=\"dropDownForm\">\n <div class=\"qdc-card-layout__mobile-filter-grid\">\n <div class=\"cell\">\n <qd-dropdown formControlName=\"statusTitle\" [config]=\"dropDownConfig | async\"> </qd-dropdown>\n </div>\n </div>\n </form>\n }\n\n <div class=\"qdc-card-layout__layout\" qdcCardStatusSameHeight>\n @if (!isMobile) {\n @for (status of config.cardStatusConfig; track $index) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\" (paginationChanged)=\"onPaginationChanged()\">\n </qdc-card-status>\n }\n } @else {\n @if (selectedStatusTitle | async; as status) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\">\n </qdc-card-status>\n }\n }\n\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.qdc-card-layout__wrapper{font-family:Roboto,sans-serif;width:100%;box-sizing:border-box;justify-content:center;padding:1rem 0;background-color:#efefef;overflow-x:auto}.qdc-card-layout__container{box-sizing:border-box;flex-direction:column;gap:1rem}@media (max-width: 959.98px){.qdc-card-layout__container{width:100%}}.qdc-card-layout__layout-header{align-items:center}.qdc-card-layout__layout-header h1{margin:0;font-family:Roboto,sans-serif;font-size:16px;font-weight:500;letter-spacing:.15px;line-height:100%;vertical-align:middle}.qdc-card-layout__layout{display:flex;box-sizing:border-box;padding:10px 25px 25px;gap:1rem}@media (max-width: 959.98px){.qdc-card-layout__layout{flex-direction:column;gap:6px}}.qdc-card-status-item{min-width:400px;max-width:100%;flex:1 1 0}@media (max-width: 959.98px){.qdc-card-status-item{width:100%!important;min-width:0}}@media (max-width: 959.98px){.qdc-card-layout__mobile-filter-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%;padding-left:10px}.qdc-card-layout__mobile-filter-grid .cell{grid-column:2}}@media (max-width: 599.98px){.qdc-card-layout__mobile-filter-grid .cell{grid-column:1}}\n"] }]
|
|
108
|
+
}], propDecorators: { config: [{
|
|
109
|
+
type: Input
|
|
110
|
+
}], cardStatusHeightDirective: [{
|
|
111
|
+
type: ViewChild,
|
|
112
|
+
args: [QdcCardStatusSameHeightDirective]
|
|
113
|
+
}], onResize: [{
|
|
114
|
+
type: HostListener,
|
|
115
|
+
args: ['window:resize']
|
|
116
|
+
}] } });
|
|
117
|
+
//# sourceMappingURL=card-layout.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-layout.component.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card-layout/card-layout.component.ts","../../../../../../libs/qdc-cards/src/lib/card-layout/card-layout.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, HostListener, inject, Input, OnInit, OnChanges, SimpleChanges, ViewChild, NgZone } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { BehaviorSubject } from 'rxjs';\nimport { startWith } from 'rxjs/operators';\nimport { QdFormControl, QdFormDropdownConfiguration } from '@quadrel-enterprise-ui/framework';\n\nimport { QdcCardLayoutConfig } from './card-layout.model';\nimport { QdcCardStatusSameHeightDirective } from './card-status/card-status-height.directive';\nimport { QdcCardStatusConfig } from './card-status/card-status.model';\n\n@Component({\n selector: 'qdc-card-layout',\n templateUrl: './card-layout.component.html',\n styleUrl: './card-layout.component.scss',\n standalone: false\n})\nexport class QdcCardLayoutComponent implements OnInit, OnChanges {\n @Input() config!: QdcCardLayoutConfig;\n\n @ViewChild(QdcCardStatusSameHeightDirective)\n cardStatusHeightDirective?: QdcCardStatusSameHeightDirective;\n\n isMobile = false;\n readonly MAX_COLUMNS = 5;\n\n dropDownForm!: FormGroup;\n\n private statusTitlesDropDownConfig: QdFormDropdownConfiguration = {\n label: { i18n: 'i18n.qdc-card.layout.mobile.dropdown.status.label' },\n options: []\n };\n\n dropDownConfig = new BehaviorSubject<QdFormDropdownConfiguration>(this.statusTitlesDropDownConfig);\n\n selectedStatusTitle = new BehaviorSubject<QdcCardStatusConfig | null>(null);\n\n private ngZone = inject(NgZone);\n\n ngOnInit(): void {\n this.checkColumnLimit();\n this.updateLayoutState();\n this.initializeDropDown();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['config']?.currentValue) {\n this.checkColumnLimit();\n\n const defaultStatusLabel = this.config.cardStatusConfig[0]?.title.i18n ?? null;\n if (defaultStatusLabel) {\n this.updateSelectedStatus(defaultStatusLabel);\n }\n\n this.setDropDownConfig();\n }\n }\n\n onPaginationChanged(): void {\n this.ngZone.runOutsideAngular(() => {\n requestAnimationFrame(() => {\n queueMicrotask(() => this.cardStatusHeightDirective?.triggerUpdate());\n });\n });\n }\n\n @HostListener('window:resize')\n onResize(): void {\n const wasMobile = this.isMobile;\n this.updateLayoutState();\n if (!wasMobile && this.isMobile) {\n this.initializeDropDown();\n }\n }\n\n private checkColumnLimit(): void {\n if (this.config.cardStatusConfig.length > this.MAX_COLUMNS) {\n throw new Error(`Too many columns. Max allowed is ${this.MAX_COLUMNS}.`);\n }\n }\n\n private updateLayoutState(): void {\n this.isMobile = window.innerWidth <= 480;\n }\n\n private initializeDropDown(): void {\n const defaultStatusLabel = this.config.cardStatusConfig[0]?.title.i18n ?? null;\n\n this.dropDownForm = new FormGroup({\n statusTitle: new QdFormControl(defaultStatusLabel)\n });\n\n this.setDropDownConfig();\n\n this.dropDownForm\n .get('statusTitle')\n ?.valueChanges.pipe(startWith(this.dropDownForm.get('statusTitle')?.value))\n .subscribe(title => {\n this.updateSelectedStatus(title);\n });\n }\n\n private updateSelectedStatus(title: string | null): void {\n if (!title) {\n this.selectedStatusTitle.next(null);\n return;\n }\n\n const statusConfig = this.config.cardStatusConfig.find(s => s.title.i18n === title);\n\n if (statusConfig) {\n this.selectedStatusTitle.next({\n ...statusConfig,\n title: { ...statusConfig.title },\n cards: [...(statusConfig.cards ?? [])]\n });\n } else {\n this.selectedStatusTitle.next(null);\n }\n }\n\n private setDropDownConfig(): void {\n const options = this.config.cardStatusConfig.map(status => ({\n i18n: status.title.i18n,\n value: status.title.i18n\n }));\n\n this.dropDownConfig.next({\n ...this.dropDownConfig.value,\n options\n });\n }\n}\n","<div class=\"qdc-card-layout__wrapper\">\n <div class=\"qdc-card-layout__container\">\n <div class=\"qdc-card-layout__layout-header\">\n <h1>{{ config.layoutTitle }}</h1>\n </div>\n\n @if (isMobile) {\n <form [formGroup]=\"dropDownForm\">\n <div class=\"qdc-card-layout__mobile-filter-grid\">\n <div class=\"cell\">\n <qd-dropdown formControlName=\"statusTitle\" [config]=\"dropDownConfig | async\"> </qd-dropdown>\n </div>\n </div>\n </form>\n }\n\n <div class=\"qdc-card-layout__layout\" qdcCardStatusSameHeight>\n @if (!isMobile) {\n @for (status of config.cardStatusConfig; track $index) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\" (paginationChanged)=\"onPaginationChanged()\">\n </qdc-card-status>\n }\n } @else {\n @if (selectedStatusTitle | async; as status) {\n <qdc-card-status [config]=\"status\" class=\"qdc-card-status-item\">\n </qdc-card-status>\n }\n }\n\n </div>\n </div>\n</div>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-layout.model.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card-layout/card-layout.model.ts"],"names":[],"mappings":"","sourcesContent":["import { QdcCardStatusConfig } from './card-status/card-status.model';\n\nexport interface QdcCardLayoutConfig {\n /**\n * Title of the cards layout component\n * */\n layoutTitle: string;\n\n /**\n * Column with cards (max 5)\n * */\n cardStatusConfig: QdcCardStatusConfig[];\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { NgModule } from '@angular/core';
|
|
3
|
+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
5
|
+
import { QdUiModule } from '@quadrel-enterprise-ui/framework';
|
|
6
|
+
import { QdcCardModule } from '../card/card.module';
|
|
7
|
+
import { QdcCardLayoutComponent } from './card-layout.component';
|
|
8
|
+
import { QdcCardStatusComponent } from './card-status/card-status.component';
|
|
9
|
+
import { QdcCardStatusSameHeightDirective } from './card-status/card-status-height.directive';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
export { QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective };
|
|
12
|
+
export class QdcCardLayoutModule {
|
|
13
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
14
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutModule, declarations: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective], imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, QdUiModule, QdcCardModule], exports: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective] }); }
|
|
15
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutModule, imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, QdUiModule, QdcCardModule] }); }
|
|
16
|
+
}
|
|
17
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardLayoutModule, decorators: [{
|
|
18
|
+
type: NgModule,
|
|
19
|
+
args: [{
|
|
20
|
+
imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, QdUiModule, QdcCardModule],
|
|
21
|
+
declarations: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective],
|
|
22
|
+
exports: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective]
|
|
23
|
+
}]
|
|
24
|
+
}] });
|
|
25
|
+
//# sourceMappingURL=card-layout.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-layout.module.js","sourceRoot":"","sources":["../../../../../../libs/qdc-cards/src/lib/card-layout/card-layout.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;;AAE9F,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,gCAAgC,EAAE,CAAC;AAQ5F,MAAM,OAAO,mBAAmB;+GAAnB,mBAAmB;gHAAnB,mBAAmB,iBAHf,sBAAsB,EAAE,sBAAsB,EAAE,gCAAgC,aAFrF,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,aAG1F,sBAAsB,EAAE,sBAAsB,EAAE,gCAAgC;gHAE/E,mBAAmB,YALpB,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa;;4FAKzF,mBAAmB;kBAN/B,QAAQ;mBAAC;oBACR,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,CAAC;oBAErG,YAAY,EAAE,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,gCAAgC,CAAC;oBAChG,OAAO,EAAE,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,gCAAgC,CAAC;iBAC5F","sourcesContent":["import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { TranslateModule } from '@ngx-translate/core';\n\nimport { QdUiModule } from '@quadrel-enterprise-ui/framework';\n\nimport { QdcCardModule } from '../card/card.module';\nimport { QdcCardLayoutComponent } from './card-layout.component';\nimport { QdcCardStatusComponent } from './card-status/card-status.component';\nimport { QdcCardStatusSameHeightDirective } from './card-status/card-status-height.directive';\n\nexport { QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective };\n\n@NgModule({\n imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, QdUiModule, QdcCardModule],\n\n declarations: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective],\n exports: [QdcCardLayoutComponent, QdcCardStatusComponent, QdcCardStatusSameHeightDirective]\n})\nexport class QdcCardLayoutModule {}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, inject, Renderer2 } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class QdcCardStatusSameHeightDirective {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.el = inject(ElementRef);
|
|
6
|
+
this.renderer = inject(Renderer2);
|
|
7
|
+
}
|
|
8
|
+
ngAfterViewInit() {
|
|
9
|
+
this.updateHeights();
|
|
10
|
+
}
|
|
11
|
+
onResize() {
|
|
12
|
+
this.updateHeights();
|
|
13
|
+
}
|
|
14
|
+
triggerUpdate() {
|
|
15
|
+
this.updateHeights();
|
|
16
|
+
}
|
|
17
|
+
updateHeights() {
|
|
18
|
+
const container = this.el.nativeElement;
|
|
19
|
+
const items = container.querySelectorAll('.qd-status__cards');
|
|
20
|
+
if (!items || items.length === 0)
|
|
21
|
+
return;
|
|
22
|
+
// Reset all heights
|
|
23
|
+
items.forEach((item) => {
|
|
24
|
+
this.renderer.setStyle(item, 'height', 'auto');
|
|
25
|
+
});
|
|
26
|
+
// Find the tallest one
|
|
27
|
+
let maxHeight = 0;
|
|
28
|
+
items.forEach((item) => {
|
|
29
|
+
const h = item.offsetHeight;
|
|
30
|
+
if (h > maxHeight)
|
|
31
|
+
maxHeight = h;
|
|
32
|
+
});
|
|
33
|
+
// Apply max height to all
|
|
34
|
+
items.forEach((item) => {
|
|
35
|
+
this.renderer.setStyle(item, 'height', `${maxHeight}px`);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardStatusSameHeightDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
39
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.17", type: QdcCardStatusSameHeightDirective, isStandalone: false, selector: "[qdcCardStatusSameHeight]", host: { listeners: { "window:resize": "onResize()" } }, ngImport: i0 }); }
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QdcCardStatusSameHeightDirective, decorators: [{
|
|
42
|
+
type: Directive,
|
|
43
|
+
args: [{
|
|
44
|
+
selector: '[qdcCardStatusSameHeight]',
|
|
45
|
+
standalone: false
|
|
46
|
+
}]
|
|
47
|
+
}], propDecorators: { onResize: [{
|
|
48
|
+
type: HostListener,
|
|
49
|
+
args: ['window:resize']
|
|
50
|
+
}] } });
|
|
51
|
+
//# sourceMappingURL=card-status-height.directive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-status-height.directive.js","sourceRoot":"","sources":["../../../../../../../libs/qdc-cards/src/lib/card-layout/card-status/card-status-height.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;;AAMtG,MAAM,OAAO,gCAAgC;IAJ7C;QAKU,OAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QACxB,aAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;KAsCtC;IApCC,eAAe;QACb,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAGD,QAAQ;QACN,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEM,aAAa;QAClB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEO,aAAa;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,aAA4B,CAAC;QACvD,MAAM,KAAK,GAA4B,SAAS,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;QAEvF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEzC,oBAAoB;QACpB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAiB,EAAQ,EAAE;YACxC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,uBAAuB;QACvB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAiB,EAAQ,EAAE;YACxC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;YAC5B,IAAI,CAAC,GAAG,SAAS;gBAAE,SAAS,GAAG,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAiB,EAAQ,EAAE;YACxC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,IAAI,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;+GAvCU,gCAAgC;mGAAhC,gCAAgC;;4FAAhC,gCAAgC;kBAJ5C,SAAS;mBAAC;oBACT,QAAQ,EAAE,2BAA2B;oBACrC,UAAU,EAAE,KAAK;iBAClB;;sBASE,YAAY;uBAAC,eAAe","sourcesContent":["import { AfterViewInit, Directive, ElementRef, HostListener, inject, Renderer2 } from '@angular/core';\n\n@Directive({\n selector: '[qdcCardStatusSameHeight]',\n standalone: false\n})\nexport class QdcCardStatusSameHeightDirective implements AfterViewInit {\n private el = inject(ElementRef);\n private renderer = inject(Renderer2);\n\n ngAfterViewInit(): void {\n this.updateHeights();\n }\n\n @HostListener('window:resize')\n onResize(): void {\n this.updateHeights();\n }\n\n public triggerUpdate(): void {\n this.updateHeights();\n }\n\n private updateHeights(): void {\n const container = this.el.nativeElement as HTMLElement;\n const items: NodeListOf<HTMLElement> = container.querySelectorAll('.qd-status__cards');\n\n if (!items || items.length === 0) return;\n\n // Reset all heights\n items.forEach((item: HTMLElement): void => {\n this.renderer.setStyle(item, 'height', 'auto');\n });\n\n // Find the tallest one\n let maxHeight = 0;\n items.forEach((item: HTMLElement): void => {\n const h = item.offsetHeight;\n if (h > maxHeight) maxHeight = h;\n });\n\n // Apply max height to all\n items.forEach((item: HTMLElement): void => {\n this.renderer.setStyle(item, 'height', `${maxHeight}px`);\n });\n }\n}\n"]}
|