ngx-opalbytes-components 1.18.0 → 1.20.0

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.
Files changed (78) hide show
  1. package/README.md +103 -0
  2. package/cli/cao-comp.cjs +186 -0
  3. package/fesm2022/ngx-opalbytes-components.mjs +331 -76
  4. package/fesm2022/ngx-opalbytes-components.mjs.map +1 -1
  5. package/package.json +4 -1
  6. package/src/lib/shared/components/autocomplete/autocomplete.component.html +126 -0
  7. package/src/lib/shared/components/autocomplete/autocomplete.component.scss +150 -0
  8. package/src/lib/shared/components/autocomplete/autocomplete.component.ts +552 -0
  9. package/src/lib/shared/components/base-button/base-button.component.html +33 -0
  10. package/src/lib/shared/components/base-button/base-button.component.scss +14 -0
  11. package/src/lib/shared/components/base-button/base-button.component.spec.ts +64 -0
  12. package/src/lib/shared/components/base-button/base-button.component.ts +48 -0
  13. package/src/lib/shared/components/base-icon/base-icon.css +0 -0
  14. package/src/lib/shared/components/base-icon/base-icon.html +11 -0
  15. package/src/lib/shared/components/base-icon/base-icon.spec.ts +23 -0
  16. package/src/lib/shared/components/base-icon/base-icon.ts +18 -0
  17. package/src/lib/shared/components/base-input/base-input.css +193 -0
  18. package/src/lib/shared/components/base-input/base-input.html +43 -0
  19. package/src/lib/shared/components/base-input/base-input.spec.ts +146 -0
  20. package/src/lib/shared/components/base-input/base-input.ts +133 -0
  21. package/src/lib/shared/components/base-time-range/base-time-range.css +27 -0
  22. package/src/lib/shared/components/base-time-range/base-time-range.html +23 -0
  23. package/src/lib/shared/components/base-time-range/base-time-range.spec.ts +27 -0
  24. package/src/lib/shared/components/base-time-range/base-time-range.ts +61 -0
  25. package/src/lib/shared/components/base-toggle/base-toggle.component.html +28 -0
  26. package/src/lib/shared/components/base-toggle/base-toggle.component.scss +45 -0
  27. package/src/lib/shared/components/base-toggle/base-toggle.component.spec.ts +22 -0
  28. package/src/lib/shared/components/base-toggle/base-toggle.component.ts +138 -0
  29. package/src/lib/shared/components/card/card.component.css +264 -0
  30. package/src/lib/shared/components/card/card.component.html +103 -0
  31. package/src/lib/shared/components/card/card.component.ts +63 -0
  32. package/src/lib/shared/components/date-picker/date-picker.html +82 -0
  33. package/src/lib/shared/components/date-picker/date-picker.scss +8 -0
  34. package/src/lib/shared/components/date-picker/date-picker.spec.ts +23 -0
  35. package/src/lib/shared/components/date-picker/date-picker.ts +165 -0
  36. package/src/lib/shared/components/drop-down/drop-down.css +61 -0
  37. package/src/lib/shared/components/drop-down/drop-down.html +96 -0
  38. package/src/lib/shared/components/drop-down/drop-down.spec.ts +335 -0
  39. package/src/lib/shared/components/drop-down/drop-down.ts +335 -0
  40. package/src/lib/shared/components/footer/footer.css +29 -0
  41. package/src/lib/shared/components/footer/footer.html +10 -0
  42. package/src/lib/shared/components/footer/footer.spec.ts +22 -0
  43. package/src/lib/shared/components/footer/footer.ts +15 -0
  44. package/src/lib/shared/components/index.ts +19 -0
  45. package/src/lib/shared/components/kpi/kpi.css +0 -0
  46. package/src/lib/shared/components/kpi/kpi.html +11 -0
  47. package/src/lib/shared/components/kpi/kpi.spec.ts +38 -0
  48. package/src/lib/shared/components/kpi/kpi.ts +25 -0
  49. package/src/lib/shared/components/links-button/links-button.css +70 -0
  50. package/src/lib/shared/components/links-button/links-button.html +23 -0
  51. package/src/lib/shared/components/links-button/links-button.spec.ts +139 -0
  52. package/src/lib/shared/components/links-button/links-button.ts +45 -0
  53. package/src/lib/shared/components/paginator/paginator.css +0 -0
  54. package/src/lib/shared/components/paginator/paginator.html +10 -0
  55. package/src/lib/shared/components/paginator/paginator.spec.ts +23 -0
  56. package/src/lib/shared/components/paginator/paginator.ts +25 -0
  57. package/src/lib/shared/components/stepper/step/step.css +8 -0
  58. package/src/lib/shared/components/stepper/step/step.html +1 -0
  59. package/src/lib/shared/components/stepper/step/step.spec.ts +131 -0
  60. package/src/lib/shared/components/stepper/step/step.ts +14 -0
  61. package/src/lib/shared/components/stepper/stepper.css +17 -0
  62. package/src/lib/shared/components/stepper/stepper.html +11 -0
  63. package/src/lib/shared/components/stepper/stepper.spec.ts +238 -0
  64. package/src/lib/shared/components/stepper/stepper.ts +57 -0
  65. package/src/lib/shared/components/tab-group/tab-group.component.html +84 -0
  66. package/src/lib/shared/components/tab-group/tab-group.component.scss +151 -0
  67. package/src/lib/shared/components/tab-group/tab-group.spec.ts +22 -0
  68. package/src/lib/shared/components/tab-group/tab-group.ts +218 -0
  69. package/src/lib/shared/components/tab-panel/tab-content.directive.ts +7 -0
  70. package/src/lib/shared/components/tab-panel/tab-label.directive.ts +7 -0
  71. package/src/lib/shared/components/tab-panel/tab-panel.css +0 -0
  72. package/src/lib/shared/components/tab-panel/tab-panel.spec.ts +22 -0
  73. package/src/lib/shared/components/tab-panel/tab-panel.ts +31 -0
  74. package/src/lib/shared/components/time-picker/time-picker.css +84 -0
  75. package/src/lib/shared/components/time-picker/time-picker.html +21 -0
  76. package/src/lib/shared/components/time-picker/time-picker.spec.ts +23 -0
  77. package/src/lib/shared/components/time-picker/time-picker.ts +90 -0
  78. package/types/ngx-opalbytes-components.d.ts +70 -13
@@ -0,0 +1,61 @@
1
+ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
2
+ import { MatDatepickerModule, MatDateRangeInput } from '@angular/material/datepicker';
3
+ import { MatFormFieldModule } from '@angular/material/form-field';
4
+ import { MatInputModule } from '@angular/material/input';
5
+
6
+ @Component({
7
+ selector: 'cao-base-time-range',
8
+ imports: [MatFormFieldModule, MatInputModule, MatDatepickerModule],
9
+ templateUrl: './base-time-range.html',
10
+ styleUrl: './base-time-range.css',
11
+ })
12
+ export class BaseTimeRange implements OnInit{
13
+ @Input() label = "";
14
+ @Input() max: Date | undefined;
15
+ @Input() minDate: Date | undefined;
16
+ @Input() maxDate: Date | undefined;
17
+ @Input() startDate: Date | undefined;
18
+ @Input() finalDate: Date | undefined;
19
+ @Input() dataCy?: string
20
+ @Input() controlName = "";
21
+
22
+ @Output() readonly rangeSelected = new EventEmitter<Date[]>();
23
+
24
+ @ViewChild(MatDateRangeInput) dateRangeInput!: MatDateRangeInput<Date>;
25
+
26
+ ngOnInit(): void {
27
+ if(!this.dataCy){
28
+ this.dataCy = `time-range-${this.label}`
29
+ }
30
+ }
31
+
32
+ onSelectStartDate(event: any) {
33
+ const date = event.target.value as Date;
34
+ this.startDate = date;
35
+ this.finalDate = undefined;
36
+
37
+ const maxDate = new Date(date);
38
+ maxDate.setDate(maxDate.getDate() + 30);
39
+
40
+ this.maxDate = maxDate;
41
+ }
42
+
43
+ onInputMaxDate(event: any) {
44
+ const finalDate = event.target.value as Date;
45
+ if (this.startDate && finalDate) {
46
+ const data = [this.startDate, finalDate];
47
+ this.rangeSelected.emit(data);
48
+ }
49
+ }
50
+
51
+ clearInputs() {
52
+ this.max = undefined;
53
+ this.minDate = undefined;
54
+ this.maxDate = undefined;
55
+ this.startDate = undefined;
56
+ this.finalDate = undefined;
57
+
58
+ this.dateRangeInput._startInput.value = "";
59
+ this.dateRangeInput._endInput.value = "";
60
+ }
61
+ }
@@ -0,0 +1,28 @@
1
+ <div class="d-flex col aic jcc base-toggle">
2
+ <input #checkbox type="checkbox" class="checkbox" [checked]="isChecked" [disabled]="isDisabled" />
3
+ <div
4
+ class="d-flex checkbox-element aic jcsb"
5
+ tabindex="0"
6
+ role="button"
7
+ [class.activated-toggle]="isChecked"
8
+ (click)="onToggleCheckbox()"
9
+ (keydown.enter)="onToggleCheckbox()"
10
+ (keydown.space)="onToggleCheckbox(); $event.preventDefault()">
11
+ @if (isChecked) {
12
+ <mat-icon class="eye-icon" />
13
+ <div class="check-text"> Ativada </div>
14
+ <div class="line"></div>
15
+ <p class="unchecked">Desativar</p>
16
+ }@else {
17
+ <mat-icon class="fa-circle" />
18
+ <div class="check-text"> Não ativada </div>
19
+ <div class="line"></div>
20
+ <p>Ativar</p>
21
+ }
22
+ </div>
23
+ @if(isChecked){
24
+ <span>{{ checkedTextPlaceholder }} ativada com sucesso</span>
25
+ } @else{
26
+ <span>Clique para ativar {{ uncheckedTextPlaceholder }}</span>
27
+ }
28
+ </div>
@@ -0,0 +1,45 @@
1
+ .base-toggle {
2
+ input {
3
+ display: none;
4
+ visibility: hidden;
5
+ }
6
+
7
+ .checkbox-element {
8
+ border-radius: 24px;
9
+ cursor: pointer;
10
+ gap: 10px;
11
+ padding: 10px 20px;
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ border: 2px solid var(--border-toggle);
16
+ background-color: transparent;
17
+
18
+ .check-text {
19
+ font-weight: 700;
20
+ }
21
+
22
+ .line {
23
+ height: 24px;
24
+ width: 1px;
25
+ background-color: var(--data-bg);
26
+ }
27
+
28
+ &.activated-toggle {
29
+ border: 2px solid var(--border-toggle-checked);
30
+ background-color: var(--bg-toggle-checked);
31
+
32
+ .check-text {
33
+ color: var(--text-toggle-checked);
34
+ }
35
+
36
+ .unchecked {
37
+ color: var(--text-unselected-toggle-checked);
38
+ }
39
+ }
40
+
41
+ p {
42
+ margin: 0;
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from "@angular/core/testing";
2
+
3
+ import { CaoBaseToggleComponent } from "./base-toggle.component";
4
+
5
+ describe("CaoBaseToggleComponent", () => {
6
+ let component: CaoBaseToggleComponent;
7
+ let fixture: ComponentFixture<CaoBaseToggleComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [CaoBaseToggleComponent],
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(CaoBaseToggleComponent);
15
+ component = fixture.componentInstance;
16
+ fixture.detectChanges();
17
+ });
18
+
19
+ it("should create", () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,138 @@
1
+ import { CommonModule } from "@angular/common";
2
+ import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core";
3
+ import { AbstractControl } from "@angular/forms";
4
+
5
+ import { MaterialModule } from "../../../material.module";
6
+
7
+ @Component({
8
+ selector: "cao-base-toggle",
9
+ standalone: true,
10
+ templateUrl: "./base-toggle.component.html",
11
+ styleUrl: "./base-toggle.component.scss",
12
+ imports: [CommonModule, MaterialModule],
13
+ })
14
+ export class CaoBaseToggleComponent {
15
+ @Input() type = "text";
16
+ @Input() placeholder = "";
17
+ @Input() inputClass = "";
18
+ @Input() value: string | number | boolean | Date = "";
19
+ @Input() errorMessage = "";
20
+ @Input() isDisabled = false;
21
+ @Input() maxLength?: number;
22
+ @Input() searchMode = false;
23
+ @Input() showBorder = false;
24
+ @Input() isLucideIcon = false;
25
+ @Input() iconColor = "";
26
+ @Input() mask?: string;
27
+ @Input() control?: AbstractControl | null;
28
+ @Input() tooltip = "";
29
+ @Input() dataCy?: string = "";
30
+ @Input() textareaRows?: string = "";
31
+
32
+ @Input() decimalMarker: "." | "," | [".", ","] = ",";
33
+ @Input() thousandSeparator = ".";
34
+ @Input() allowNegativeNumbers = false;
35
+ @Input() separatorLimit = "";
36
+
37
+ @Input() set leadingIcon(value: string) {
38
+ this._leadingIcon = value;
39
+ this.icon = true;
40
+ }
41
+
42
+ @Input() set trailingIcon(value: string) {
43
+ this._trailingIcon = value;
44
+ this.icon = true;
45
+ }
46
+
47
+ @Output() readonly valueChange = new EventEmitter<string>();
48
+ @Output() readonly searchClick = new EventEmitter<void>();
49
+ @Output() readonly inputChange = new EventEmitter<string>();
50
+
51
+ isFocused = false;
52
+ icon = false;
53
+ _leadingIcon?: string;
54
+ _trailingIcon?: string;
55
+
56
+ onChange: any = () => { };
57
+ onTouched: any = () => { };
58
+
59
+ get hasError() {
60
+ return !!this.errorMessage;
61
+ }
62
+
63
+ @Input() controlName = "";
64
+
65
+ get controlNameValue(): string {
66
+ return this.controlName;
67
+ }
68
+
69
+ onInput(event: Event) {
70
+ const newValue = (event.target as HTMLInputElement).value;
71
+ this.value = newValue;
72
+ this.onChange(newValue);
73
+ this.valueChange.emit(newValue);
74
+ }
75
+
76
+ onInputChange(event: Event) {
77
+ const newValue = (event.target as HTMLInputElement).value;
78
+ this.value = newValue;
79
+ this.inputChange.emit(newValue);
80
+ }
81
+
82
+ onFocus() {
83
+ this.isFocused = true;
84
+ this.onTouched();
85
+ }
86
+
87
+ onBlur() {
88
+ this.isFocused = false;
89
+ this.onTouched();
90
+
91
+ if (this.control?.touched && this.control?.valid && this.control?.value) {
92
+ setTimeout(() => {
93
+ const active = document.activeElement as HTMLElement;
94
+ const current = document.querySelector(`[formcontrolname="${this.controlNameValue}"]`);
95
+ if (!current || !active || !current.contains(active)) {
96
+ this.control?.markAsUntouched();
97
+ }
98
+ });
99
+ }
100
+ }
101
+
102
+ onSearchClick() {
103
+ this.searchClick.emit();
104
+ }
105
+
106
+ writeValue(value: string | null | undefined): void {
107
+ this.value = value || "";
108
+ }
109
+
110
+ registerOnChange(fn: any): void {
111
+ this.onChange = fn;
112
+ }
113
+
114
+ registerOnTouched(fn: any): void {
115
+ this.onTouched = fn;
116
+ }
117
+
118
+ setDisabledState(isDisabled: boolean): void {
119
+ this.isDisabled = isDisabled;
120
+ }
121
+ @Input() isChecked = false;
122
+ @Input() checkedTextPlaceholder = "";
123
+ @Input() uncheckedTextPlaceholder = "";
124
+
125
+ @Output() readonly statusChanged = new EventEmitter<CaoBaseToggleComponent>();
126
+
127
+ @ViewChild("checkbox") checkboxInput!: HTMLInputElement;
128
+
129
+ onToggleCheckbox() {
130
+ if (this.isDisabled) {
131
+ return;
132
+ }
133
+
134
+ this.isChecked = !this.isChecked;
135
+
136
+ this.statusChanged.emit(this);
137
+ }
138
+ }
@@ -0,0 +1,264 @@
1
+ :host {
2
+ --radius-card: 0.5rem;
3
+ --color-bg-main: #ffffff;
4
+ --color-bg-gray: #f3f4f6;
5
+ --color-border-gray: #d1d5db;
6
+ --color-border-orange: #fb923c;
7
+ --color-text-gray-400: #9ca3af;
8
+ --color-text-gray-500: #6b7280;
9
+ --color-text-gray-600: #4b5563;
10
+ --color-text-gray-700: #374151;
11
+ --color-text-gray-900: #111827;
12
+ --color-white: #ffffff;
13
+ }
14
+
15
+ .card {
16
+ display: flex;
17
+ position: relative;
18
+ width: 100%;
19
+ height: 100%;
20
+ transition-property: box-shadow;
21
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
22
+ transition-duration: 150ms;
23
+ }
24
+
25
+ .card-horizontal {
26
+ border: 1px solid var(--color-border-gray);
27
+ border-radius: var(--radius-card);
28
+ padding: 1rem 1.25rem;
29
+ align-items: center;
30
+ gap: 1rem;
31
+ }
32
+
33
+ .card-square {
34
+ background-color: var(--color-bg-main);
35
+ border-radius: var(--radius-card);
36
+ padding: 1rem 5rem;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ justify-content: center;
40
+ transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
41
+ }
42
+
43
+ .card-clickable {
44
+ cursor: pointer;
45
+ }
46
+
47
+ .card-hover-shadow:hover {
48
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
49
+ 0 2px 4px -2px rgba(0, 0, 0, 0.1);
50
+ }
51
+
52
+ .card-hover-bg:hover {
53
+ background-color: var(--color-bg-gray);
54
+ }
55
+
56
+ .card-hover-bold:hover {
57
+ font-weight: 700;
58
+ }
59
+
60
+ .card-selected {
61
+ border-color: var(--color-border-orange);
62
+ }
63
+
64
+ .card-selected-border-2 {
65
+ border-width: 2px;
66
+ }
67
+
68
+ /* ---------- AVATAR / ICON CONTAINER ---------- */
69
+ .card-avatar-container {
70
+ width: 3rem;
71
+ height: 3rem;
72
+ border-radius: 9999px;
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ flex-shrink: 0;
77
+ color: var(--color-white);
78
+ font-size: 1.25rem;
79
+ font-weight: 700;
80
+ }
81
+
82
+ .card-avatar-img {
83
+ width: 100%;
84
+ height: 100%;
85
+ border-radius: 9999px;
86
+ object-fit: cover;
87
+ }
88
+
89
+ .card-icon-container {
90
+ width: 3rem;
91
+ height: 3rem;
92
+ border-radius: 9999px;
93
+ background-color: #e5e7eb;
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ flex-shrink: 0;
98
+ }
99
+
100
+ .card-icon-img {
101
+ width: 1.5rem;
102
+ height: 1.5rem;
103
+ opacity: 0.6;
104
+ }
105
+
106
+ /* ---------- CONTENT AREA ---------- */
107
+ .card-content {
108
+ flex: 1 1 0%;
109
+ min-width: 0;
110
+ display: flex;
111
+ flex-direction: column;
112
+ gap: 0.125rem;
113
+ height: 100%;
114
+ }
115
+
116
+ .card-title {
117
+ font-size: 0.875rem;
118
+ font-weight: 600;
119
+ color: var(--color-text-gray-900);
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ white-space: nowrap;
123
+ }
124
+
125
+ .card-subtitle {
126
+ font-size: 0.875rem;
127
+ color: var(--color-text-gray-500);
128
+ overflow: hidden;
129
+ text-overflow: ellipsis;
130
+ white-space: nowrap;
131
+ }
132
+
133
+ .card-detail {
134
+ font-size: 0.875rem;
135
+ font-weight: 500;
136
+ color: var(--color-text-gray-700);
137
+ }
138
+
139
+ /* ---------- BADGE ---------- */
140
+ .card-badge-wrapper {
141
+ display: flex;
142
+ flex-direction: column;
143
+ align-items: flex-end;
144
+ gap: 2rem;
145
+ flex-shrink: 0;
146
+ }
147
+
148
+ .card-badge {
149
+ padding: 0.5rem 0.75rem;
150
+ border-radius: 9999px;
151
+ border: 1px solid var(--color-border-gray);
152
+ font-size: 0.875rem;
153
+ font-weight: 500;
154
+ color: var(--color-text-gray-600);
155
+ }
156
+
157
+ /* ---------- META ---------- */
158
+ .card-meta-list {
159
+ display: flex;
160
+ flex-wrap: wrap;
161
+ align-items: center;
162
+ gap: 1.25rem;
163
+ }
164
+
165
+ .card-meta-item {
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 0.375rem;
169
+ font-size: 0.875rem;
170
+ color: var(--color-text-gray-400);
171
+ }
172
+
173
+ .card-meta-icon {
174
+ width: 1rem;
175
+ height: 1rem;
176
+ opacity: 0.6;
177
+ }
178
+
179
+ /* ---------- SQUARE CARD SPECIFIC ---------- */
180
+ .card-square-content {
181
+ width: 50%;
182
+ display: flex;
183
+ flex-direction: column;
184
+ align-items: center;
185
+ justify-content: center;
186
+ gap: 0.5rem;
187
+ transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
188
+ }
189
+
190
+ .card-square-title {
191
+ font-size: 1rem;
192
+ color: var(--color-text-gray-900);
193
+ text-align: center;
194
+ }
195
+
196
+ .card-square-icon {
197
+ width: 3rem;
198
+ height: 3rem;
199
+ }
200
+
201
+ /* ---------- UTILITY HELPERS ---------- */
202
+ .truncate {
203
+ overflow: hidden;
204
+ text-overflow: ellipsis;
205
+ white-space: nowrap;
206
+ }
207
+
208
+ .text-center {
209
+ text-align: center;
210
+ }
211
+
212
+ /* ---------- RESPONSIVE ADJUSTMENTS ---------- */
213
+ @media (max-width: 640px) {
214
+ .card-horizontal {
215
+ padding: 0.75rem 1rem;
216
+ gap: 0.75rem;
217
+ }
218
+
219
+ .card-square {
220
+ padding: 1rem 2rem;
221
+ }
222
+
223
+ .card-square-content {
224
+ width: 80%;
225
+ }
226
+
227
+ .card-badge-wrapper {
228
+ gap: 1rem;
229
+ }
230
+
231
+ .card-meta-list {
232
+ gap: 0.75rem;
233
+ }
234
+ }
235
+
236
+ @media (max-width: 480px) {
237
+ .card-horizontal {
238
+ flex-wrap: wrap;
239
+ justify-content: center;
240
+ text-align: center;
241
+ }
242
+
243
+ .card-content {
244
+ width: 100%;
245
+ align-items: center;
246
+ }
247
+
248
+ .card-badge-wrapper {
249
+ width: 100%;
250
+ align-items: center;
251
+ }
252
+
253
+ .card-meta-list {
254
+ justify-content: center;
255
+ }
256
+
257
+ .card-square {
258
+ padding: 1rem;
259
+ }
260
+
261
+ .card-square-content {
262
+ width: 100%;
263
+ }
264
+ }
@@ -0,0 +1,103 @@
1
+ @switch (variant) {
2
+ @case ('horizontal') {
3
+ <div
4
+ class="card card-horizontal"
5
+ [class.card-clickable]="clickable"
6
+ [class.card-hover-shadow]="clickable"
7
+ [class.card-selected]="selected"
8
+ [ngClass]="[bgColor, borderColor]"
9
+ [attr.role]="clickable ? 'button' : null"
10
+ [attr.tabindex]="clickable ? 0 : null"
11
+ (click)="handleClick()"
12
+ (keydown)="handleKeydown($event)">
13
+
14
+ @if (avatar) {
15
+ <div class="card-avatar-container" [ngClass]="avatarBg">
16
+ @if (avatar.src) {
17
+ <img
18
+ class="card-avatar-img"
19
+ [src]="avatar.src"
20
+ [alt]="title" />
21
+ } @else {
22
+ {{ avatar.initials }}
23
+ }
24
+ </div>
25
+ } @else if (icon) {
26
+ <div class="card-icon-container">
27
+ <img
28
+ class="card-icon-img"
29
+ [src]="icon"
30
+ [alt]="title" />
31
+ </div>
32
+ }
33
+
34
+ <div class="card-content">
35
+ @if (title) {
36
+ <span class="card-title">{{ title }}</span>
37
+ }
38
+ @if (subtitle) {
39
+ <span class="card-subtitle">{{ subtitle }}</span>
40
+ }
41
+ @if (detail) {
42
+ <span class="card-detail" [ngClass]="detailColor ?? ''">
43
+ {{ detail }}
44
+ </span>
45
+ }
46
+ <ng-content />
47
+ </div>
48
+
49
+ @if (badge || (meta && meta.length)) {
50
+ <div class="card-badge-wrapper">
51
+ @if (badge) {
52
+ <div
53
+ class="card-badge"
54
+ [ngClass]="[badge.color ?? '', badge.borderColor ?? '']"
55
+ [style.background-color]="badge.bg">
56
+ {{ badge.label }}
57
+ </div>
58
+ }
59
+ @if (meta && meta.length) {
60
+ <div class="card-meta-list">
61
+ @for (m of meta; track m.label) {
62
+ <div class="card-meta-item">
63
+ <img
64
+ class="card-meta-icon"
65
+ [src]="m.icon"
66
+ [alt]="m.label" />
67
+ <span>{{ m.label }}</span>
68
+ </div>
69
+ }
70
+ </div>
71
+ }
72
+ </div>
73
+ }
74
+ </div>
75
+ }
76
+
77
+ @case ('square') {
78
+ <div
79
+ class="card card-square"
80
+ [class.card-clickable]="clickable"
81
+ [class.card-hover-bg]="clickable"
82
+ [class.card-hover-bold]="clickable"
83
+ [class.card-selected]="selected"
84
+ [class.card-selected-border-2]="selected"
85
+ [attr.role]="clickable ? 'button' : null"
86
+ [attr.tabindex]="clickable ? 0 : null"
87
+ [matTooltip]="title"
88
+ (click)="handleClick()"
89
+ (keydown)="handleKeydown($event)">
90
+
91
+ <div class="card-square-content">
92
+ <span class="card-square-title">{{ title }}</span>
93
+
94
+ @if (icon) {
95
+ <img
96
+ class="card-square-icon"
97
+ [src]="icon"
98
+ [alt]="title" />
99
+ }
100
+ </div>
101
+ </div>
102
+ }
103
+ }