@acontplus/ng-components 2.3.0 → 2.4.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.
@@ -0,0 +1,741 @@
1
+ @use '@angular/material' as mat;
2
+ @use '../../../core/tokens/token-utils';
3
+ @use './m3-kpi-card';
4
+
5
+ $fallbacks: m3-kpi-card.get-tokens();
6
+
7
+ .acp-kpi-card {
8
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-primary-bg, $fallbacks)};
9
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-primary-color, $fallbacks)};
10
+
11
+ display: flex;
12
+ vertical-align: middle;
13
+ width: 100%;
14
+ max-width: 100%;
15
+
16
+ &__card {
17
+ width: 100%;
18
+ display: flex;
19
+ flex-direction: column;
20
+ border-radius: 12px;
21
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
22
+ overflow: hidden;
23
+ background-color: #ffffff;
24
+ }
25
+
26
+ // Default (md) sizes - baseline
27
+ &__header {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: space-between;
31
+ padding: 16px;
32
+ gap: 12px;
33
+ }
34
+
35
+ &__header-content {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 12px;
39
+ flex: 1;
40
+ min-width: 0;
41
+ }
42
+
43
+ &__icon-container {
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ flex-shrink: 0;
48
+ }
49
+
50
+ &__icon {
51
+ font-size: 24px;
52
+ width: 24px;
53
+ height: 24px;
54
+ color: var(--acp-kpi-card-fg);
55
+ }
56
+
57
+ &__avatar {
58
+ width: 40px;
59
+ height: 40px;
60
+ border-radius: 50%;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ background: color-mix(in srgb, var(--acp-kpi-card-bg) 30%, transparent);
65
+ color: var(--acp-kpi-card-fg);
66
+ font-weight: 500;
67
+ font-size: 14px;
68
+ flex-shrink: 0;
69
+ }
70
+
71
+ &__avatar-image {
72
+ width: 40px;
73
+ height: 40px;
74
+ border-radius: 50%;
75
+ object-fit: cover;
76
+ flex-shrink: 0;
77
+ }
78
+
79
+ &__avatar-initials {
80
+ width: 40px;
81
+ height: 40px;
82
+ border-radius: 50%;
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ background: color-mix(in srgb, var(--acp-kpi-card-bg) 30%, transparent);
87
+ color: var(--acp-kpi-card-fg);
88
+ font-weight: 500;
89
+ font-size: 14px;
90
+ flex-shrink: 0;
91
+ }
92
+
93
+ &__title-container {
94
+ flex: 1;
95
+ min-width: 0;
96
+ }
97
+
98
+ &__title {
99
+ margin: 0;
100
+ font-size: 14px;
101
+ font-weight: 500;
102
+ letter-spacing: 0.25px;
103
+ color: var(--acp-kpi-card-fg);
104
+ white-space: nowrap;
105
+ overflow: hidden;
106
+ text-overflow: ellipsis;
107
+ }
108
+
109
+ &__subtitle {
110
+ margin: 2px 0 0 0;
111
+ font-size: 12px;
112
+ font-weight: 400;
113
+ letter-spacing: 0.4px;
114
+ color: rgba(var(--acp-kpi-card-fg), 0.6);
115
+ white-space: nowrap;
116
+ overflow: hidden;
117
+ text-overflow: ellipsis;
118
+ }
119
+
120
+ &__menu-button {
121
+ flex-shrink: 0;
122
+ opacity: 0.7;
123
+ transition: opacity 0.2s ease-in-out;
124
+
125
+ &:hover {
126
+ opacity: 1;
127
+ }
128
+
129
+ &:focus-visible {
130
+ outline: 2px solid currentColor;
131
+ outline-offset: 2px;
132
+ }
133
+ }
134
+
135
+ &__menu {
136
+ will-change: transform;
137
+ }
138
+
139
+ &__content {
140
+ flex: 1;
141
+ padding: 16px;
142
+ display: flex;
143
+ flex-direction: column;
144
+ gap: 12px;
145
+ }
146
+
147
+ &__value-section {
148
+ display: flex;
149
+ align-items: baseline;
150
+ gap: 8px;
151
+ }
152
+
153
+ &__value {
154
+ font-size: 28px;
155
+ font-weight: 600;
156
+ letter-spacing: -0.5px;
157
+ color: var(--acp-kpi-card-fg);
158
+ line-height: 1.2;
159
+ }
160
+
161
+ &__metric {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 4px;
165
+ font-size: 13px;
166
+ font-weight: 500;
167
+ letter-spacing: 0.25px;
168
+ color: rgba(var(--acp-kpi-card-fg), 0.8);
169
+ }
170
+
171
+ &__trend-icon {
172
+ font-size: 16px;
173
+ width: 16px;
174
+ height: 16px;
175
+ // Trend icon inherits color from parent metric element
176
+ }
177
+
178
+ &__percentage {
179
+ white-space: nowrap;
180
+ }
181
+
182
+ // Trend color styling - applied to metric section when trending
183
+ &.acp-kpi-card--success &__metric {
184
+ color: #{token-utils.slot(kpi-card-success-color, $fallbacks)};
185
+ }
186
+
187
+ &.acp-kpi-card--success-light &__metric {
188
+ color: #{token-utils.slot(kpi-card-success-light-color, $fallbacks)};
189
+ }
190
+
191
+ &.acp-kpi-card--warning &__metric {
192
+ color: #{token-utils.slot(kpi-card-warning-color, $fallbacks)};
193
+ }
194
+
195
+ &.acp-kpi-card--warning-light &__metric {
196
+ color: #{token-utils.slot(kpi-card-warning-light-color, $fallbacks)};
197
+ }
198
+
199
+ &.acp-kpi-card--error &__metric {
200
+ color: #{token-utils.slot(kpi-card-error-color, $fallbacks)};
201
+ }
202
+
203
+ &.acp-kpi-card--error-light &__metric {
204
+ color: #{token-utils.slot(kpi-card-error-light-color, $fallbacks)};
205
+ }
206
+
207
+ &.acp-kpi-card--info &__metric {
208
+ color: #{token-utils.slot(kpi-card-info-color, $fallbacks)};
209
+ }
210
+
211
+ &.acp-kpi-card--info-light &__metric {
212
+ color: #{token-utils.slot(kpi-card-info-light-color, $fallbacks)};
213
+ }
214
+
215
+ &__description {
216
+ margin: 0;
217
+ font-size: 12px;
218
+ font-weight: 400;
219
+ letter-spacing: 0.4px;
220
+ color: rgba(var(--acp-kpi-card-fg), 0.6);
221
+ line-height: 1.5;
222
+ }
223
+
224
+ &__progress {
225
+ height: 4px;
226
+ border-radius: 2px;
227
+ background-color: rgba(var(--acp-kpi-card-fg), 0.12);
228
+ }
229
+
230
+ &__footer {
231
+ padding: 12px 16px;
232
+ font-size: 12px;
233
+ font-weight: 400;
234
+ letter-spacing: 0.4px;
235
+ color: rgba(var(--acp-kpi-card-fg), 0.6);
236
+ }
237
+
238
+ &__footer-text {
239
+ margin: 0;
240
+ }
241
+
242
+ &__skeleton {
243
+ padding: 16px;
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 12px;
247
+ }
248
+
249
+ &__skeleton-header {
250
+ width: 60%;
251
+ height: 16px;
252
+ background: linear-gradient(
253
+ 90deg,
254
+ rgba(0, 0, 0, 0.1) 25%,
255
+ rgba(0, 0, 0, 0.05) 50%,
256
+ rgba(0, 0, 0, 0.1) 75%
257
+ );
258
+ background-size: 200% 100%;
259
+ animation: loading 1.5s infinite;
260
+ border-radius: 4px;
261
+ }
262
+
263
+ &__skeleton-value {
264
+ width: 40%;
265
+ height: 28px;
266
+ background: linear-gradient(
267
+ 90deg,
268
+ rgba(0, 0, 0, 0.1) 25%,
269
+ rgba(0, 0, 0, 0.05) 50%,
270
+ rgba(0, 0, 0, 0.1) 75%
271
+ );
272
+ background-size: 200% 100%;
273
+ animation: loading 1.5s infinite;
274
+ border-radius: 4px;
275
+ }
276
+
277
+ &__skeleton-text {
278
+ width: 80%;
279
+ height: 12px;
280
+ background: linear-gradient(
281
+ 90deg,
282
+ rgba(0, 0, 0, 0.1) 25%,
283
+ rgba(0, 0, 0, 0.05) 50%,
284
+ rgba(0, 0, 0, 0.1) 75%
285
+ );
286
+ background-size: 200% 100%;
287
+ animation: loading 1.5s infinite;
288
+ border-radius: 4px;
289
+ }
290
+
291
+ @keyframes loading {
292
+ 0% {
293
+ background-position: 200% 0;
294
+ }
295
+ 100% {
296
+ background-position: -200% 0;
297
+ }
298
+ }
299
+
300
+ // Colors
301
+ &.acp-kpi-card--primary {
302
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-primary-bg, $fallbacks)};
303
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-primary-color, $fallbacks)};
304
+ }
305
+
306
+ &.acp-kpi-card--secondary {
307
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-secondary-bg, $fallbacks)};
308
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-secondary-color, $fallbacks)};
309
+ }
310
+
311
+ &.acp-kpi-card--success {
312
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-success-bg, $fallbacks)};
313
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-success-color, $fallbacks)};
314
+ }
315
+
316
+ &.acp-kpi-card--success-light {
317
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-success-light-bg, $fallbacks)};
318
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-success-light-color, $fallbacks)};
319
+ }
320
+
321
+ &.acp-kpi-card--warning {
322
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-warning-bg, $fallbacks)};
323
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-warning-color, $fallbacks)};
324
+ }
325
+
326
+ &.acp-kpi-card--warning-light {
327
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-warning-light-bg, $fallbacks)};
328
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-warning-light-color, $fallbacks)};
329
+ }
330
+
331
+ &.acp-kpi-card--error {
332
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-error-bg, $fallbacks)};
333
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-error-color, $fallbacks)};
334
+ }
335
+
336
+ &.acp-kpi-card--error-light {
337
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-error-light-bg, $fallbacks)};
338
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-error-light-color, $fallbacks)};
339
+ }
340
+
341
+ &.acp-kpi-card--info {
342
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-info-bg, $fallbacks)};
343
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-info-color, $fallbacks)};
344
+ }
345
+
346
+ &.acp-kpi-card--info-light {
347
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-info-light-bg, $fallbacks)};
348
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-info-light-color, $fallbacks)};
349
+ }
350
+
351
+ &.acp-kpi-card--neutral {
352
+ --acp-kpi-card-bg: #{token-utils.slot(kpi-card-neutral-bg, $fallbacks)};
353
+ --acp-kpi-card-fg: #{token-utils.slot(kpi-card-neutral-color, $fallbacks)};
354
+ }
355
+
356
+ &.acp-kpi-card--white {
357
+ --acp-kpi-card-bg: #ffffff;
358
+ --acp-kpi-card-fg: #1f2937;
359
+ }
360
+
361
+ &.acp-kpi-card--custom {
362
+ --acp-kpi-card-bg: var(
363
+ --acp-kpi-card-custom-bg,
364
+ #{token-utils.slot(kpi-card-custom-bg, $fallbacks)}
365
+ );
366
+ --acp-kpi-card-fg: var(
367
+ --acp-kpi-card-custom-fg,
368
+ #{token-utils.slot(kpi-card-custom-color, $fallbacks)}
369
+ );
370
+ }
371
+
372
+ // Variants - Professional Material Design 3 styling
373
+ &.acp-kpi-card--default &__card {
374
+ background: var(--acp-kpi-card-bg);
375
+ color: var(--acp-kpi-card-fg);
376
+ border: 1px solid rgba(var(--acp-kpi-card-fg), 0.12);
377
+ }
378
+
379
+ &.acp-kpi-card--elevated &__card {
380
+ background: var(--acp-kpi-card-bg);
381
+ color: var(--acp-kpi-card-fg);
382
+ box-shadow:
383
+ 0 3px 8px rgba(0, 0, 0, 0.08),
384
+ 0 1px 3px rgba(0, 0, 0, 0.04);
385
+ }
386
+
387
+ &.acp-kpi-card--outlined &__card {
388
+ background: transparent;
389
+ color: var(--acp-kpi-card-fg);
390
+ border: 2px solid rgba(var(--acp-kpi-card-fg), 0.2);
391
+ }
392
+
393
+ &.acp-kpi-card--filled &__card {
394
+ background: var(--acp-kpi-card-bg);
395
+ color: var(--acp-kpi-card-fg);
396
+ }
397
+
398
+ &.acp-kpi-card--tonal &__card {
399
+ // Subtle tonal background using color-mix for better theme support
400
+ background: color-mix(in srgb, var(--acp-kpi-card-bg) 12%, transparent);
401
+ color: var(--acp-kpi-card-fg);
402
+ border: 1px solid rgba(var(--acp-kpi-card-fg), 0.08);
403
+ }
404
+
405
+ // States - Professional interaction patterns
406
+ &.acp-kpi-card--clickable &__card {
407
+ cursor: pointer;
408
+
409
+ &:hover {
410
+ // Subtle elevation increase on hover
411
+ box-shadow:
412
+ 0 6px 12px rgba(0, 0, 0, 0.1),
413
+ 0 2px 4px rgba(0, 0, 0, 0.06);
414
+ // Minimal vertical translation for feedback
415
+ transform: translateY(-1px);
416
+ }
417
+
418
+ &:active {
419
+ // Slight press-down effect
420
+ transform: translateY(0);
421
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
422
+ }
423
+
424
+ &:focus-visible {
425
+ outline: 2px solid currentColor;
426
+ outline-offset: 2px;
427
+ }
428
+ }
429
+
430
+ &.acp-kpi-card--disabled &__card {
431
+ opacity: 0.6;
432
+ cursor: not-allowed;
433
+ pointer-events: none;
434
+ }
435
+
436
+ &.acp-kpi-card--selected &__card {
437
+ // Subtle selection indicator using border instead of inset shadow
438
+ border: 2px solid var(--acp-kpi-card-fg);
439
+ }
440
+
441
+ &.acp-kpi-card--loading &__card {
442
+ pointer-events: none;
443
+ opacity: 0.8;
444
+ }
445
+
446
+ // Responsive
447
+ @media (max-width: 768px) {
448
+ &__header {
449
+ padding: 12px;
450
+ }
451
+
452
+ &__content {
453
+ padding: 12px;
454
+ }
455
+
456
+ &__value {
457
+ font-size: 24px;
458
+ }
459
+
460
+ &__title {
461
+ font-size: 13px;
462
+ }
463
+ }
464
+
465
+ @media (prefers-reduced-motion: reduce) {
466
+ &__card {
467
+ transition: none;
468
+ }
469
+
470
+ &__skeleton-header,
471
+ &__skeleton-value,
472
+ &__skeleton-text {
473
+ animation: none;
474
+ }
475
+ }
476
+
477
+ @media (prefers-contrast: more) {
478
+ &__card {
479
+ border-width: 2px;
480
+ }
481
+ }
482
+ }
483
+
484
+ // Responsive scaling - Mobile first
485
+ @media (max-width: 768px) {
486
+ .acp-kpi-card {
487
+ &__header {
488
+ padding: 12px;
489
+ gap: 8px;
490
+ }
491
+
492
+ &__content {
493
+ padding: 12px;
494
+ gap: 8px;
495
+ }
496
+
497
+ &__footer {
498
+ padding: 12px;
499
+ }
500
+
501
+ &__icon {
502
+ font-size: 20px;
503
+ width: 20px;
504
+ height: 20px;
505
+ }
506
+
507
+ &__avatar,
508
+ &__avatar-image,
509
+ &__avatar-initials {
510
+ width: 32px;
511
+ height: 32px;
512
+ font-size: 12px;
513
+ }
514
+
515
+ &__title {
516
+ font-size: 13px;
517
+ }
518
+
519
+ &__subtitle {
520
+ font-size: 11px;
521
+ }
522
+
523
+ &__value {
524
+ font-size: 24px;
525
+ }
526
+ }
527
+ }
528
+
529
+ // Size variants with harmonic scaling
530
+ // xs: Very compact (tables, lists)
531
+ .acp-kpi-card__card.acp-kpi-card--xs {
532
+ min-height: 96px;
533
+
534
+ .acp-kpi-card__header {
535
+ padding: 8px;
536
+ gap: 6px;
537
+ }
538
+
539
+ .acp-kpi-card__content {
540
+ padding: 8px;
541
+ gap: 6px;
542
+ }
543
+
544
+ .acp-kpi-card__footer {
545
+ padding: 8px;
546
+ }
547
+
548
+ .acp-kpi-card__icon {
549
+ font-size: 16px;
550
+ width: 16px;
551
+ height: 16px;
552
+ }
553
+
554
+ .acp-kpi-card__avatar,
555
+ .acp-kpi-card__avatar-image,
556
+ .acp-kpi-card__avatar-initials {
557
+ width: 28px;
558
+ height: 28px;
559
+ font-size: 11px;
560
+ }
561
+
562
+ .acp-kpi-card__title {
563
+ font-size: 12px;
564
+ }
565
+
566
+ .acp-kpi-card__subtitle {
567
+ font-size: 10px;
568
+ margin-top: 1px;
569
+ }
570
+
571
+ .acp-kpi-card__value {
572
+ font-size: 18px;
573
+ }
574
+
575
+ .acp-kpi-card__percentage {
576
+ font-size: 10px;
577
+ }
578
+
579
+ .acp-kpi-card__description {
580
+ font-size: 11px;
581
+ }
582
+ }
583
+
584
+ // sm: Compact (forms, filters)
585
+ .acp-kpi-card__card.acp-kpi-card--sm {
586
+ min-height: 128px;
587
+
588
+ .acp-kpi-card__header {
589
+ padding: 12px;
590
+ gap: 8px;
591
+ }
592
+
593
+ .acp-kpi-card__content {
594
+ padding: 12px;
595
+ gap: 8px;
596
+ }
597
+
598
+ .acp-kpi-card__footer {
599
+ padding: 12px;
600
+ }
601
+
602
+ .acp-kpi-card__icon {
603
+ font-size: 20px;
604
+ width: 20px;
605
+ height: 20px;
606
+ }
607
+
608
+ .acp-kpi-card__avatar,
609
+ .acp-kpi-card__avatar-image,
610
+ .acp-kpi-card__avatar-initials {
611
+ width: 32px;
612
+ height: 32px;
613
+ font-size: 12px;
614
+ }
615
+
616
+ .acp-kpi-card__title {
617
+ font-size: 13px;
618
+ }
619
+
620
+ .acp-kpi-card__subtitle {
621
+ font-size: 11px;
622
+ }
623
+
624
+ .acp-kpi-card__value {
625
+ font-size: 22px;
626
+ }
627
+
628
+ .acp-kpi-card__percentage {
629
+ font-size: 11px;
630
+ }
631
+
632
+ .acp-kpi-card__description {
633
+ font-size: 12px;
634
+ }
635
+ }
636
+
637
+ // md: Standard (general use) - DEFAULT
638
+ .acp-kpi-card__card.acp-kpi-card--md {
639
+ min-height: 160px;
640
+
641
+ .acp-kpi-card__header {
642
+ padding: 16px;
643
+ gap: 12px;
644
+ }
645
+
646
+ .acp-kpi-card__content {
647
+ padding: 16px;
648
+ gap: 12px;
649
+ }
650
+
651
+ .acp-kpi-card__footer {
652
+ padding: 16px;
653
+ }
654
+
655
+ .acp-kpi-card__icon {
656
+ font-size: 24px;
657
+ width: 24px;
658
+ height: 24px;
659
+ }
660
+
661
+ .acp-kpi-card__avatar,
662
+ .acp-kpi-card__avatar-image,
663
+ .acp-kpi-card__avatar-initials {
664
+ width: 40px;
665
+ height: 40px;
666
+ font-size: 14px;
667
+ }
668
+
669
+ .acp-kpi-card__title {
670
+ font-size: 14px;
671
+ }
672
+
673
+ .acp-kpi-card__subtitle {
674
+ font-size: 12px;
675
+ }
676
+
677
+ .acp-kpi-card__value {
678
+ font-size: 28px;
679
+ }
680
+
681
+ .acp-kpi-card__percentage {
682
+ font-size: 12px;
683
+ }
684
+
685
+ .acp-kpi-card__description {
686
+ font-size: 13px;
687
+ }
688
+ }
689
+
690
+ // lg: Large (dashboards, featured)
691
+ .acp-kpi-card__card.acp-kpi-card--lg {
692
+ min-height: 224px;
693
+
694
+ .acp-kpi-card__header {
695
+ padding: 20px;
696
+ gap: 16px;
697
+ }
698
+
699
+ .acp-kpi-card__content {
700
+ padding: 20px;
701
+ gap: 16px;
702
+ }
703
+
704
+ .acp-kpi-card__footer {
705
+ padding: 20px;
706
+ }
707
+
708
+ .acp-kpi-card__icon {
709
+ font-size: 32px;
710
+ width: 32px;
711
+ height: 32px;
712
+ }
713
+
714
+ .acp-kpi-card__avatar,
715
+ .acp-kpi-card__avatar-image,
716
+ .acp-kpi-card__avatar-initials {
717
+ width: 48px;
718
+ height: 48px;
719
+ font-size: 16px;
720
+ }
721
+
722
+ .acp-kpi-card__title {
723
+ font-size: 16px;
724
+ }
725
+
726
+ .acp-kpi-card__subtitle {
727
+ font-size: 13px;
728
+ }
729
+
730
+ .acp-kpi-card__value {
731
+ font-size: 36px;
732
+ }
733
+
734
+ .acp-kpi-card__percentage {
735
+ font-size: 14px;
736
+ }
737
+
738
+ .acp-kpi-card__description {
739
+ font-size: 14px;
740
+ }
741
+ }