@keenmate/pure-admin-core 1.5.0 → 2.0.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,608 @@
1
+ /* ========================================
2
+ Data Visualization Components
3
+ Progress bars, rings, gauges, heatmaps, sparklines
4
+ ======================================== */
5
+ @use '../variables' as *;
6
+
7
+ // ============================================================================
8
+ // 1. PROGRESS BAR (pa-progress)
9
+ // ============================================================================
10
+
11
+ .pa-progress {
12
+ width: 100%;
13
+ height: $progress-height;
14
+ background: $progress-bg;
15
+ border-radius: $progress-border-radius;
16
+ overflow: hidden;
17
+ position: relative;
18
+
19
+ // Fill bar
20
+ &__fill {
21
+ height: 100%;
22
+ width: var(--value, 0%);
23
+ background: $accent-color;
24
+ border-radius: inherit;
25
+ transition: width $transition-medium $easing-smooth;
26
+ }
27
+
28
+ // Label (outside, above the bar)
29
+ &__label {
30
+ display: flex;
31
+ justify-content: space-between;
32
+ margin-bottom: $spacing-xs;
33
+ font-size: $progress-label-font-size;
34
+ font-weight: $progress-label-font-weight;
35
+ color: var(--pa-text-color-1);
36
+ }
37
+
38
+ &__label-value {
39
+ color: var(--pa-text-color-2);
40
+ }
41
+
42
+ // Size variants
43
+ &--xs {
44
+ height: $progress-height-xs;
45
+ }
46
+
47
+ &--sm {
48
+ height: $progress-height-sm;
49
+ }
50
+
51
+ &--lg {
52
+ height: $progress-height-lg;
53
+ }
54
+
55
+ // Color variants
56
+ &--success > .pa-progress__fill { background: $success-bg; }
57
+ &--warning > .pa-progress__fill { background: $warning-bg; }
58
+ &--danger > .pa-progress__fill { background: $danger-bg; }
59
+ &--info > .pa-progress__fill { background: $info-bg; }
60
+
61
+ // Rounded (pill shape)
62
+ &--rounded {
63
+ border-radius: 50rem;
64
+ }
65
+
66
+ // Striped
67
+ &--striped > .pa-progress__fill {
68
+ background-image: repeating-linear-gradient(
69
+ $progress-stripe-angle,
70
+ rgba(255, 255, 255, 0.2) 0,
71
+ rgba(255, 255, 255, 0.2) 25%,
72
+ transparent 25%,
73
+ transparent 50%
74
+ );
75
+ background-size: $progress-stripe-size $progress-stripe-size;
76
+ }
77
+
78
+ // Animated (moving stripes)
79
+ &--animated > .pa-progress__fill {
80
+ animation: pa-progress-stripe $progress-animation-duration linear infinite;
81
+ }
82
+ }
83
+
84
+ @keyframes pa-progress-stripe {
85
+ 0% {
86
+ background-position: $progress-stripe-size 0;
87
+ }
88
+ 100% {
89
+ background-position: 0 0;
90
+ }
91
+ }
92
+
93
+ // Wrapper for label + bar combo
94
+ .pa-progress-group {
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: $spacing-xs;
98
+ }
99
+
100
+
101
+ // ============================================================================
102
+ // 2. STACKED BAR (pa-stacked-bar)
103
+ // ============================================================================
104
+
105
+ .pa-stacked-bar {
106
+ display: flex;
107
+ width: 100%;
108
+ height: $stacked-bar-height;
109
+ border-radius: $stacked-bar-border-radius;
110
+ overflow: hidden;
111
+ background: $progress-bg;
112
+
113
+ &__segment {
114
+ height: 100%;
115
+ width: var(--value, 0%);
116
+ transition: width $transition-medium $easing-smooth;
117
+
118
+ // Default color
119
+ background: $accent-color;
120
+
121
+ &--success { background: $success-bg; }
122
+ &--warning { background: $warning-bg; }
123
+ &--danger { background: $danger-bg; }
124
+ &--info { background: $info-bg; }
125
+ &--secondary { background: $btn-secondary-bg; }
126
+ }
127
+
128
+ // Legend
129
+ &__legend {
130
+ display: flex;
131
+ flex-wrap: wrap;
132
+ gap: $stacked-bar-legend-gap;
133
+ margin-top: $spacing-sm;
134
+ }
135
+
136
+ &__legend-item {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: $spacing-xs;
140
+ font-size: $stacked-bar-legend-font-size;
141
+ color: var(--pa-text-color-2);
142
+ }
143
+
144
+ &__legend-swatch {
145
+ width: $stacked-bar-legend-swatch-size;
146
+ height: $stacked-bar-legend-swatch-size;
147
+ border-radius: $border-radius-sm;
148
+ flex-shrink: 0;
149
+
150
+ &--primary { background: $accent-color; }
151
+ &--success { background: $success-bg; }
152
+ &--warning { background: $warning-bg; }
153
+ &--danger { background: $danger-bg; }
154
+ &--info { background: $info-bg; }
155
+ &--secondary { background: $btn-secondary-bg; }
156
+ }
157
+
158
+ // Size variants
159
+ &--sm { height: $progress-height-sm; }
160
+ &--lg { height: $progress-height-lg; }
161
+
162
+ // Rounded
163
+ &--rounded { border-radius: 50rem; }
164
+ }
165
+
166
+
167
+ // ============================================================================
168
+ // 3. PROGRESS RING (pa-progress-ring)
169
+ // ============================================================================
170
+
171
+ .pa-progress-ring {
172
+ width: $progress-ring-size;
173
+ height: $progress-ring-size;
174
+ border-radius: 50%;
175
+ background: conic-gradient(
176
+ $accent-color calc(var(--value, 0) * 3.6deg),
177
+ $progress-ring-track-color 0deg
178
+ );
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ flex-shrink: 0;
183
+
184
+ &__inner {
185
+ width: 70%;
186
+ height: 70%;
187
+ border-radius: 50%;
188
+ background: $card-bg;
189
+ display: flex;
190
+ flex-direction: column;
191
+ align-items: center;
192
+ justify-content: center;
193
+ }
194
+
195
+ &__value {
196
+ font-size: $progress-ring-value-font-size;
197
+ font-weight: $progress-ring-value-font-weight;
198
+ line-height: 1;
199
+ color: var(--pa-text-color-1);
200
+ }
201
+
202
+ &__label {
203
+ font-size: $progress-ring-label-font-size;
204
+ color: var(--pa-text-color-2);
205
+ margin-top: $spacing-xs;
206
+ }
207
+
208
+ // Size variants
209
+ &--sm {
210
+ width: $progress-ring-size-sm;
211
+ height: $progress-ring-size-sm;
212
+
213
+ .pa-progress-ring__value {
214
+ font-size: $font-size-base;
215
+ }
216
+
217
+ .pa-progress-ring__label {
218
+ font-size: $font-size-2xs;
219
+ }
220
+ }
221
+
222
+ &--lg {
223
+ width: $progress-ring-size-lg;
224
+ height: $progress-ring-size-lg;
225
+
226
+ .pa-progress-ring__value {
227
+ font-size: $font-size-2xl;
228
+ }
229
+
230
+ .pa-progress-ring__label {
231
+ font-size: $font-size-xs;
232
+ }
233
+ }
234
+
235
+ // Color variants
236
+ &--success {
237
+ background: conic-gradient(
238
+ $success-bg calc(var(--value, 0) * 3.6deg),
239
+ $progress-ring-track-color 0deg
240
+ );
241
+ }
242
+
243
+ &--warning {
244
+ background: conic-gradient(
245
+ $warning-bg calc(var(--value, 0) * 3.6deg),
246
+ $progress-ring-track-color 0deg
247
+ );
248
+ }
249
+
250
+ &--danger {
251
+ background: conic-gradient(
252
+ $danger-bg calc(var(--value, 0) * 3.6deg),
253
+ $progress-ring-track-color 0deg
254
+ );
255
+ }
256
+
257
+ &--info {
258
+ background: conic-gradient(
259
+ $info-bg calc(var(--value, 0) * 3.6deg),
260
+ $progress-ring-track-color 0deg
261
+ );
262
+ }
263
+ }
264
+
265
+
266
+ // ============================================================================
267
+ // 4. DASHBOARD GAUGE (pa-gauge)
268
+ // ============================================================================
269
+
270
+ .pa-gauge {
271
+ width: $gauge-size;
272
+ height: calc(#{$gauge-size} / 2);
273
+ border-radius: #{$gauge-size} #{$gauge-size} 0 0;
274
+ overflow: hidden;
275
+ background: conic-gradient(
276
+ from 0.75turn,
277
+ $accent-color calc(var(--value, 0) * 1.8deg),
278
+ $gauge-track-color 0deg
279
+ );
280
+ position: relative;
281
+ flex-shrink: 0;
282
+
283
+ // Inner mask (creates the donut shape)
284
+ &__inner {
285
+ position: absolute;
286
+ bottom: 0;
287
+ left: 15%;
288
+ right: 15%;
289
+ height: 70%;
290
+ border-radius: #{$gauge-size} #{$gauge-size} 0 0;
291
+ background: $card-bg;
292
+ display: flex;
293
+ flex-direction: column;
294
+ align-items: center;
295
+ justify-content: flex-end;
296
+ padding-bottom: $spacing-xs;
297
+ }
298
+
299
+ &__value {
300
+ font-size: $gauge-value-font-size;
301
+ font-weight: $gauge-value-font-weight;
302
+ line-height: 1;
303
+ color: var(--pa-text-color-1);
304
+ }
305
+
306
+ &__label {
307
+ font-size: $gauge-label-font-size;
308
+ color: var(--pa-text-color-2);
309
+ margin-top: $spacing-xs;
310
+ }
311
+
312
+ // Min/max labels at arc endpoints
313
+ &__min,
314
+ &__max {
315
+ position: absolute;
316
+ bottom: 0;
317
+ font-size: $font-size-2xs;
318
+ color: var(--pa-text-color-2);
319
+ }
320
+
321
+ &__min { left: 0; }
322
+ &__max { right: 0; }
323
+
324
+ // Color variants
325
+ &--success {
326
+ background: conic-gradient(
327
+ from 0.75turn,
328
+ $success-bg calc(var(--value, 0) * 1.8deg),
329
+ $gauge-track-color 0deg
330
+ );
331
+ }
332
+
333
+ &--warning {
334
+ background: conic-gradient(
335
+ from 0.75turn,
336
+ $warning-bg calc(var(--value, 0) * 1.8deg),
337
+ $gauge-track-color 0deg
338
+ );
339
+ }
340
+
341
+ &--danger {
342
+ background: conic-gradient(
343
+ from 0.75turn,
344
+ $danger-bg calc(var(--value, 0) * 1.8deg),
345
+ $gauge-track-color 0deg
346
+ );
347
+ }
348
+
349
+ &--info {
350
+ background: conic-gradient(
351
+ from 0.75turn,
352
+ $info-bg calc(var(--value, 0) * 1.8deg),
353
+ $gauge-track-color 0deg
354
+ );
355
+ }
356
+
357
+ // Multi-zone gauge (green/yellow/red)
358
+ &--zones {
359
+ background: conic-gradient(
360
+ from 0.75turn,
361
+ $success-bg 0deg,
362
+ $success-bg 90deg,
363
+ $warning-bg 90deg,
364
+ $warning-bg 135deg,
365
+ $danger-bg 135deg,
366
+ $danger-bg 180deg,
367
+ $gauge-track-color 180deg
368
+ );
369
+ }
370
+ }
371
+
372
+
373
+ // ============================================================================
374
+ // 5. DATA BAR (pa-data-bar) - inline bar for table cells
375
+ // ============================================================================
376
+
377
+ .pa-data-bar {
378
+ display: flex;
379
+ flex-direction: column;
380
+ gap: $spacing-xs;
381
+ min-width: 6rem;
382
+
383
+ &__value {
384
+ font-size: $font-size-sm;
385
+ font-weight: $font-weight-medium;
386
+ color: var(--pa-text-color-1);
387
+ line-height: 1;
388
+ }
389
+
390
+ &__track {
391
+ width: 100%;
392
+ height: $data-bar-height;
393
+ background: $data-bar-bg;
394
+ border-radius: $data-bar-border-radius;
395
+ overflow: hidden;
396
+ }
397
+
398
+ &__fill {
399
+ height: 100%;
400
+ width: var(--value, 0%);
401
+ background: $accent-color;
402
+ border-radius: inherit;
403
+ transition: width $transition-medium $easing-smooth;
404
+ }
405
+
406
+ // Color variants
407
+ &--success .pa-data-bar__fill { background: $success-bg; }
408
+ &--warning .pa-data-bar__fill { background: $warning-bg; }
409
+ &--danger .pa-data-bar__fill { background: $danger-bg; }
410
+ &--info .pa-data-bar__fill { background: $info-bg; }
411
+
412
+ // Negative variant (red, right-aligned)
413
+ &--negative .pa-data-bar__fill {
414
+ background: $danger-bg;
415
+ margin-inline-start: auto;
416
+ }
417
+ }
418
+
419
+
420
+ // ============================================================================
421
+ // 6. HEATMAP GRID (pa-heatmap)
422
+ // ============================================================================
423
+
424
+ .pa-heatmap {
425
+ display: inline-grid;
426
+ grid-template-columns: repeat(53, $heatmap-cell-size);
427
+ grid-auto-rows: $heatmap-cell-size;
428
+ gap: $heatmap-gap;
429
+
430
+ &__cell {
431
+ border-radius: $heatmap-border-radius;
432
+ background: $progress-bg;
433
+
434
+ &[data-level="1"] { background: rgba($accent-color, 0.2); }
435
+ &[data-level="2"] { background: rgba($accent-color, 0.4); }
436
+ &[data-level="3"] { background: rgba($accent-color, 0.65); }
437
+ &[data-level="4"] { background: $accent-color; }
438
+ }
439
+
440
+ // Color variants
441
+ &--success .pa-heatmap__cell {
442
+ &[data-level="1"] { background: rgba($success-bg, 0.2); }
443
+ &[data-level="2"] { background: rgba($success-bg, 0.4); }
444
+ &[data-level="3"] { background: rgba($success-bg, 0.65); }
445
+ &[data-level="4"] { background: $success-bg; }
446
+ }
447
+
448
+ &--danger .pa-heatmap__cell {
449
+ &[data-level="1"] { background: rgba($danger-bg, 0.2); }
450
+ &[data-level="2"] { background: rgba($danger-bg, 0.4); }
451
+ &[data-level="3"] { background: rgba($danger-bg, 0.65); }
452
+ &[data-level="4"] { background: $danger-bg; }
453
+ }
454
+
455
+ // Legend
456
+ &__legend {
457
+ display: flex;
458
+ align-items: center;
459
+ gap: $heatmap-legend-gap;
460
+ margin-top: $spacing-sm;
461
+ font-size: $heatmap-legend-font-size;
462
+ color: var(--pa-text-color-2);
463
+ }
464
+
465
+ &__legend-cell {
466
+ width: $heatmap-cell-size;
467
+ height: $heatmap-cell-size;
468
+ border-radius: $heatmap-border-radius;
469
+ background: $progress-bg;
470
+
471
+ &[data-level="1"] { background: rgba($accent-color, 0.2); }
472
+ &[data-level="2"] { background: rgba($accent-color, 0.4); }
473
+ &[data-level="3"] { background: rgba($accent-color, 0.65); }
474
+ &[data-level="4"] { background: $accent-color; }
475
+ }
476
+
477
+ // Compact variant (smaller cells, for inline use)
478
+ &--compact {
479
+ grid-template-columns: repeat(53, 1rem);
480
+ grid-auto-rows: 1rem;
481
+ gap: 0.1rem;
482
+
483
+ .pa-heatmap__cell {
484
+ border-radius: 1px;
485
+ }
486
+ }
487
+ }
488
+
489
+
490
+ // ============================================================================
491
+ // 7. SPARKLINE BARS (pa-sparkline)
492
+ // ============================================================================
493
+
494
+ .pa-sparkline {
495
+ display: inline-flex;
496
+ align-items: flex-end;
497
+ gap: $sparkline-gap;
498
+ height: $sparkline-height;
499
+
500
+ &__bar {
501
+ width: $sparkline-bar-width;
502
+ height: var(--value, 50%);
503
+ background: $accent-color;
504
+ border-radius: $sparkline-border-radius $sparkline-border-radius 0 0;
505
+ transition: height $transition-medium $easing-smooth;
506
+ min-height: 1px;
507
+ }
508
+
509
+ // Color variants
510
+ &--success .pa-sparkline__bar { background: $success-bg; }
511
+ &--warning .pa-sparkline__bar { background: $warning-bg; }
512
+ &--danger .pa-sparkline__bar { background: $danger-bg; }
513
+ &--info .pa-sparkline__bar { background: $info-bg; }
514
+
515
+ // Size variants
516
+ &--sm {
517
+ height: 2rem;
518
+ }
519
+
520
+ &--lg {
521
+ height: 4.8rem;
522
+ .pa-sparkline__bar {
523
+ width: 0.4rem;
524
+ }
525
+ }
526
+ }
527
+
528
+
529
+ // ============================================================================
530
+ // 8. BAR LIST (pa-bar-list) - labeled horizontal bar chart
531
+ // ============================================================================
532
+
533
+ .pa-bar-list {
534
+ display: flex;
535
+ flex-direction: column;
536
+ gap: $bar-list-gap;
537
+
538
+ &__item {
539
+ display: flex;
540
+ flex-direction: column;
541
+ gap: $spacing-xs;
542
+ }
543
+
544
+ &__header {
545
+ display: flex;
546
+ justify-content: space-between;
547
+ align-items: baseline;
548
+ gap: $spacing-sm;
549
+ }
550
+
551
+ &__label {
552
+ font-size: $bar-list-label-font-size;
553
+ color: var(--pa-text-color-1);
554
+ min-width: 0;
555
+ overflow: hidden;
556
+ text-overflow: ellipsis;
557
+ white-space: nowrap;
558
+ }
559
+
560
+ &__value {
561
+ font-size: $bar-list-value-font-size;
562
+ font-weight: $bar-list-value-font-weight;
563
+ color: var(--pa-text-color-1);
564
+ flex-shrink: 0;
565
+ }
566
+
567
+ &__bar {
568
+ width: 100%;
569
+ height: $bar-list-bar-height;
570
+ background: $bar-list-bar-bg;
571
+ border-radius: $bar-list-bar-border-radius;
572
+ overflow: hidden;
573
+
574
+ &::after {
575
+ content: '';
576
+ display: block;
577
+ height: 100%;
578
+ width: var(--value, 0%);
579
+ background: $accent-color;
580
+ border-radius: inherit;
581
+ transition: width $transition-medium $easing-smooth;
582
+ }
583
+ }
584
+
585
+ // Color variants
586
+ &--success .pa-bar-list__bar::after { background: $success-bg; }
587
+ &--warning .pa-bar-list__bar::after { background: $warning-bg; }
588
+ &--danger .pa-bar-list__bar::after { background: $danger-bg; }
589
+ &--info .pa-bar-list__bar::after { background: $info-bg; }
590
+
591
+ // Compact modifier (tighter spacing)
592
+ &--compact {
593
+ gap: $spacing-sm;
594
+
595
+ .pa-bar-list__item {
596
+ gap: 0.2rem;
597
+ }
598
+
599
+ .pa-bar-list__label,
600
+ .pa-bar-list__value {
601
+ font-size: $font-size-xs;
602
+ }
603
+
604
+ .pa-bar-list__bar {
605
+ height: 0.3rem;
606
+ }
607
+ }
608
+ }
@@ -127,6 +127,11 @@
127
127
  background-color: var(--pa-card-bg);
128
128
  position: relative;
129
129
 
130
+ // Bordered modifier: adds top and bottom borders
131
+ &--bordered {
132
+ border-block: $border-width-base solid var(--pa-border-color);
133
+ }
134
+
130
135
  // In overlay mode: slide-in from end side (right in LTR, left in RTL)
131
136
  .pa-detail-panel--overlay & {
132
137
  position: absolute;
@@ -237,6 +242,7 @@
237
242
  .pa-detail-panel__body {
238
243
  flex: 1;
239
244
  overflow-y: auto;
245
+ overscroll-behavior: contain; // Prevent scroll chaining to parent
240
246
  padding: $detail-panel-body-padding-v $detail-panel-body-padding-h;
241
247
  }
242
248
 
@@ -156,10 +156,11 @@ $grid-columns-fractions: (
156
156
  }
157
157
 
158
158
  // ============================================================================
159
- // RESPONSIVE COLUMNS & OFFSETS
159
+ // RESPONSIVE COLUMNS & OFFSETS (Container-query based)
160
+ // Requires a containment context ancestor: .pa-layout__main (automatic) or .pa-cq
160
161
  // ============================================================================
161
162
  @each $bp, $min-width in $grid-breakpoints {
162
- @media (min-width: $min-width) {
163
+ @container (min-width: #{$min-width}) {
163
164
  // Responsive percentage columns (5% increments)
164
165
  @each $size in $grid-columns-5 {
165
166
  .pa-col-#{$bp}-#{$size} {
@@ -56,32 +56,33 @@
56
56
  font-size: $font-size-sm;
57
57
  }
58
58
 
59
- // Hero variant - big focus on the number
60
- &--hero {
59
+ // Hero variant - big focus on the number, compact padding
60
+ &--hero,
61
+ &--hero-compact {
61
62
  display: block;
62
63
  text-align: center;
63
- padding: $spacing-lg;
64
+ padding: $spacing-sm $spacing-sm $spacing-md;
64
65
 
65
66
  .pa-stat__label {
66
- font-size: $font-size-sm;
67
+ font-size: $font-size-xs;
67
68
  text-transform: uppercase;
68
69
  letter-spacing: $stat-label-letter-spacing;
69
- font-weight: $font-weight-medium;
70
+ font-weight: $font-weight-semibold;
70
71
  color: var(--pa-text-color-2);
71
- margin-bottom: $spacing-sm;
72
+ margin-bottom: $spacing-xs;
72
73
  }
73
74
 
74
75
  .pa-stat__value {
75
- font-size: $font-size-4xl;
76
+ font-size: $font-size-4xl * 1.4;
76
77
  font-weight: $font-weight-bold;
77
78
  color: var(--pa-text-color-1);
78
- line-height: 1.1;
79
- margin-bottom: $spacing-sm;
79
+ line-height: 1;
80
+ margin-bottom: $spacing-xs;
80
81
  }
81
82
 
82
83
  .pa-stat__change {
83
84
  font-size: $font-size-xs;
84
- font-weight: $font-weight-medium;
85
+ font-weight: $font-weight-semibold;
85
86
 
86
87
  &--positive {
87
88
  color: $success-bg;
@@ -84,6 +84,13 @@
84
84
  .pa-table-card__body {
85
85
  position: relative;
86
86
  overflow: hidden; // Clip detail panel to card boundaries
87
+ display: flex;
88
+ flex-direction: column;
89
+
90
+ // Detail view stretches to fill body
91
+ .pa-detail-view {
92
+ flex: 1;
93
+ }
87
94
  }
88
95
  }
89
96
 
@@ -91,6 +91,7 @@ body.pa-layout--sticky .pa-layout__inner {
91
91
  .pa-layout__main {
92
92
  flex: 1;
93
93
  padding: $spacing-base;
94
+ container-type: inline-size;
94
95
  }
95
96
 
96
97
  // Footer - outside inner, sibling to inner