@quicdata/analytics 0.0.8 → 0.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quicdata/analytics",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -1 +1 @@
1
- {"version":3,"file":"base-chart.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/base-chart.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base-chart.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/base-chart.ts"],"names":[],"mappings":"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"}
@@ -41,15 +41,122 @@ export class BaseChartWidget extends LitElement {
41
41
  .loading-overlay {
42
42
  position: absolute;
43
43
  inset: 0;
44
- z-index: 2;
44
+ z-index: 10;
45
45
  display: flex;
46
46
  align-items: center;
47
47
  justify-content: center;
48
- background: rgba(255, 255, 255, 0.65);
48
+ background: rgba(255, 255, 255, 0.8);
49
49
  backdrop-filter: blur(4px);
50
50
  -webkit-backdrop-filter: blur(4px);
51
51
  border-radius: 4px;
52
52
  }
53
+ .skeleton-line-chart {
54
+ width: 100%;
55
+ height: 100%;
56
+ min-height: 120px;
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ padding: 1rem;
61
+ box-sizing: border-box;
62
+ }
63
+ .skeleton-line-chart-canvas {
64
+ width: 70%;
65
+ max-width: 180px;
66
+ aspect-ratio: 1;
67
+ min-width: 0;
68
+ }
69
+ .skeleton-line-chart-canvas svg {
70
+ width: 100%;
71
+ height: 100%;
72
+ display: block;
73
+ }
74
+ .skeleton-line-chart .zigzag {
75
+ fill: none;
76
+ stroke: #e5e7eb;
77
+ stroke-width: 2.5;
78
+ stroke-linecap: round;
79
+ stroke-linejoin: round;
80
+ }
81
+ .skeleton-line-chart .zigzag-shine {
82
+ fill: none;
83
+ stroke: url(#skeleton-line-gradient);
84
+ stroke-width: 2.5;
85
+ stroke-linecap: round;
86
+ stroke-linejoin: round;
87
+ stroke-dasharray: 15 85;
88
+ animation: analytics-line-shimmer 1.2s ease-in-out infinite;
89
+ }
90
+ @keyframes analytics-line-shimmer {
91
+ to { stroke-dashoffset: -100; }
92
+ }
93
+ .skeleton-bar-chart {
94
+ width: 100%;
95
+ height: 100%;
96
+ min-height: 120px;
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ padding: 1rem;
101
+ box-sizing: border-box;
102
+ }
103
+ .skeleton-bar-chart-canvas {
104
+ width: 70%;
105
+ max-width: 180px;
106
+ aspect-ratio: 1;
107
+ display: flex;
108
+ align-items: flex-end;
109
+ gap: 1rem;
110
+ min-width: 0;
111
+ }
112
+ .skeleton-bar-vert {
113
+ flex: 1;
114
+ min-width: 0;
115
+ border-radius: 4px 4px 0 0;
116
+ background: linear-gradient(
117
+ 90deg,
118
+ #e5e7eb 0%,
119
+ #e5e7eb 40%,
120
+ #f3f4f6 50%,
121
+ #e5e7eb 60%,
122
+ #e5e7eb 100%
123
+ );
124
+ background-size: 200% 100%;
125
+ animation: analytics-skeleton-shimmer 1.2s ease-in-out infinite;
126
+ }
127
+ .skeleton-bar-vert:nth-child(1) { height: 55%; }
128
+ .skeleton-bar-vert:nth-child(2) { height: 70%; }
129
+ .skeleton-bar-vert:nth-child(3) { height: 60%; }
130
+ .skeleton-bar-vert:nth-child(4) { height: 80%; }
131
+ .skeleton-pie {
132
+ width: 100%;
133
+ height: 100%;
134
+ min-height: 120px;
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: center;
138
+ padding: 1rem;
139
+ box-sizing: border-box;
140
+ }
141
+ .skeleton-circle {
142
+ width: 70%;
143
+ max-width: 180px;
144
+ aspect-ratio: 1;
145
+ border-radius: 50%;
146
+ background: linear-gradient(
147
+ 90deg,
148
+ #e5e7eb 0%,
149
+ #e5e7eb 40%,
150
+ #f3f4f6 50%,
151
+ #e5e7eb 60%,
152
+ #e5e7eb 100%
153
+ );
154
+ background-size: 200% 100%;
155
+ animation: analytics-skeleton-shimmer 1.2s ease-in-out infinite;
156
+ }
157
+ @keyframes analytics-skeleton-shimmer {
158
+ to { background-position: 200% 0; }
159
+ }
53
160
  .loading-spinner {
54
161
  width: 2rem;
55
162
  height: 2rem;
@@ -97,6 +204,22 @@ export class BaseChartWidget extends LitElement {
97
204
  overflow: hidden;
98
205
  text-overflow: ellipsis;
99
206
  }
207
+ .skeleton-title {
208
+ height: 1rem;
209
+ width: 8rem;
210
+ max-width: 60%;
211
+ border-radius: 4px;
212
+ background: linear-gradient(
213
+ 90deg,
214
+ #e5e7eb 0%,
215
+ #e5e7eb 40%,
216
+ #f3f4f6 50%,
217
+ #e5e7eb 60%,
218
+ #e5e7eb 100%
219
+ );
220
+ background-size: 200% 100%;
221
+ animation: analytics-skeleton-shimmer 1.2s ease-in-out infinite;
222
+ }
100
223
  .widget-body {
101
224
  flex: 1;
102
225
  min-height: 0;
@@ -275,10 +398,8 @@ export class BaseChartWidget extends LitElement {
275
398
  this._viewportUnobserve = observeViewport(this, { rootMargin: this.prefetchMargin || '200px', threshold: 0 }, {
276
399
  onEnter: () => {
277
400
  this._viewportVisible = true;
278
- if (!this._hasLoadedOnce) {
279
- this._hasLoadedOnce = true;
401
+ if (!this._hasLoadedOnce)
280
402
  this._loadData();
281
- }
282
403
  },
283
404
  onLeave: () => {
284
405
  this._viewportVisible = false;
@@ -389,6 +510,7 @@ export class BaseChartWidget extends LitElement {
389
510
  this._widgetFilters = filters;
390
511
  if (hideFilter !== undefined)
391
512
  this._hideFilter = hideFilter;
513
+ this._hasLoadedOnce = true;
392
514
  this._loading = false;
393
515
  this._renderChart();
394
516
  });
@@ -406,6 +528,7 @@ export class BaseChartWidget extends LitElement {
406
528
  this.data = data;
407
529
  this.meta = meta;
408
530
  this._widgetData = null;
531
+ this._hasLoadedOnce = true;
409
532
  this._loading = false;
410
533
  this._renderChart();
411
534
  });
@@ -470,10 +593,16 @@ export class BaseChartWidget extends LitElement {
470
593
  const hasWidgetFilters = this._widgetFilters.length > 0 && !this._hideFilter;
471
594
  const widgetActiveCount = Object.keys(this._widgetFilterParams).filter((k) => this._widgetFilterParams[k] !== '' && this._widgetFilterParams[k] != null).length;
472
595
  const canRefresh = Boolean(this._getEffectiveDataUrl());
473
- const headerContent = this._effectiveTitle || canRefresh
596
+ const showSkeleton = this._loading && !this._hasLoadedOnce;
597
+ const showTitlePlaceholder = !this._effectiveTitle;
598
+ const headerContent = this._effectiveTitle || canRefresh || showTitlePlaceholder
474
599
  ? html `
475
600
  <header class="widget-header">
476
- ${this._effectiveTitle ? html `<h2 class="widget-title">${this._effectiveTitle}</h2>` : html `<span></span>`}
601
+ ${this._effectiveTitle
602
+ ? html `<h2 class="widget-title">${this._effectiveTitle}</h2>`
603
+ : showTitlePlaceholder
604
+ ? html `<div class="skeleton-title" aria-hidden="true"></div>`
605
+ : html `<span></span>`}
477
606
  ${canRefresh
478
607
  ? html `
479
608
  <button
@@ -496,19 +625,62 @@ export class BaseChartWidget extends LitElement {
496
625
  </header>
497
626
  `
498
627
  : '';
628
+ const showSpinnerOverlay = this._loading && this._hasLoadedOnce;
629
+ const isBarChart = this.tagName === 'ANALYTICS-BAR-CHART';
630
+ const isPieChart = this.tagName === 'ANALYTICS-PIE-CHART';
631
+ const skeletonContent = showSkeleton
632
+ ? isBarChart
633
+ ? html `
634
+ <div class="skeleton-bar-chart" aria-busy="true" aria-live="polite">
635
+ <div class="skeleton-bar-chart-canvas">
636
+ <div class="skeleton-bar-vert"></div>
637
+ <div class="skeleton-bar-vert"></div>
638
+ <div class="skeleton-bar-vert"></div>
639
+ <div class="skeleton-bar-vert"></div>
640
+ </div>
641
+ </div>
642
+ `
643
+ : isPieChart
644
+ ? html `
645
+ <div class="skeleton-pie" aria-busy="true" aria-live="polite">
646
+ <div class="skeleton-circle"></div>
647
+ </div>
648
+ `
649
+ : html `
650
+ <div class="skeleton-line-chart" aria-busy="true" aria-live="polite">
651
+ <div class="skeleton-line-chart-canvas">
652
+ <svg viewBox="0 0 100 100" preserveAspectRatio="none">
653
+ <defs>
654
+ <linearGradient id="skeleton-line-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
655
+ <stop offset="0%" stop-color="#e5e7eb"/>
656
+ <stop offset="40%" stop-color="#e5e7eb"/>
657
+ <stop offset="50%" stop-color="#f3f4f6"/>
658
+ <stop offset="60%" stop-color="#e5e7eb"/>
659
+ <stop offset="100%" stop-color="#e5e7eb"/>
660
+ </linearGradient>
661
+ </defs>
662
+ <polyline class="zigzag" points="8,80 23,29 38,33 53,37 68,90 83,82 95,10"/>
663
+ <polyline class="zigzag zigzag-shine" points="8,80 23,29 38,33 53,37 68,90 83,82 95,10"/>
664
+ </svg>
665
+ </div>
666
+ </div>
667
+ `
668
+ : null;
499
669
  return html `
500
670
  <div class="widget-with-toolbar">
501
671
  ${headerContent}
502
672
  <div class="widget-body">
503
- ${this._error
504
- ? html `<div class="error">${this._error}</div>`
505
- : html `<div class="chart"></div>`}
506
- ${this._loading
673
+ ${skeletonContent !== null
674
+ ? skeletonContent
675
+ : this._error
676
+ ? html `<div class="error">${this._error}</div>`
677
+ : html `<div class="chart"></div>`}
678
+ </div>
679
+ ${showSpinnerOverlay
507
680
  ? html `<div class="loading-overlay" aria-busy="true" aria-live="polite">
508
- <div class="loading-spinner" aria-hidden="true"></div>
509
- </div>`
681
+ <div class="loading-spinner" aria-hidden="true"></div>
682
+ </div>`
510
683
  : nothing}
511
- </div>
512
684
  ${hasWidgetFilters
513
685
  ? html `
514
686
  <analytics-widget-toolbar
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/table.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/table.ts"],"names":[],"mappings":"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"}
package/widgets/table.js CHANGED
@@ -75,15 +75,54 @@ let TableWidget = class TableWidget extends LitElement {
75
75
  .loading-overlay {
76
76
  position: absolute;
77
77
  inset: 0;
78
- z-index: 2;
78
+ z-index: 10;
79
79
  display: flex;
80
80
  align-items: center;
81
81
  justify-content: center;
82
- background: rgba(255, 255, 255, 0.65);
82
+ background: rgba(255, 255, 255, 0.8);
83
83
  backdrop-filter: blur(4px);
84
84
  -webkit-backdrop-filter: blur(4px);
85
85
  border-radius: 4px;
86
86
  }
87
+ .skeleton {
88
+ width: 100%;
89
+ padding: 0.75rem 1rem;
90
+ box-sizing: border-box;
91
+ }
92
+ .skeleton-row {
93
+ display: flex;
94
+ gap: 0.75rem;
95
+ align-items: center;
96
+ padding: 0.5rem 0;
97
+ border-bottom: 1px solid #f3f4f6;
98
+ }
99
+ .skeleton-cell {
100
+ height: 1rem;
101
+ border-radius: 4px;
102
+ background: linear-gradient(
103
+ 90deg,
104
+ #e5e7eb 0%,
105
+ #e5e7eb 40%,
106
+ #f3f4f6 50%,
107
+ #e5e7eb 60%,
108
+ #e5e7eb 100%
109
+ );
110
+ background-size: 200% 100%;
111
+ animation: analytics-table-skeleton-shimmer 1.2s ease-in-out infinite;
112
+ }
113
+ .skeleton-row:first-child .skeleton-cell {
114
+ height: 1.25rem;
115
+ background: #f3f4f6;
116
+ }
117
+ .skeleton-row:first-child .skeleton-cell:nth-child(1) { flex: 1.2; }
118
+ .skeleton-row:first-child .skeleton-cell:nth-child(2) { flex: 1; }
119
+ .skeleton-row:first-child .skeleton-cell:nth-child(3) { flex: 0.8; }
120
+ .skeleton-row:not(:first-child) .skeleton-cell:nth-child(1) { flex: 1.2; min-width: 0; }
121
+ .skeleton-row:not(:first-child) .skeleton-cell:nth-child(2) { flex: 1; min-width: 0; }
122
+ .skeleton-row:not(:first-child) .skeleton-cell:nth-child(3) { flex: 0.8; min-width: 0; }
123
+ @keyframes analytics-table-skeleton-shimmer {
124
+ to { background-position: 200% 0; }
125
+ }
87
126
  .loading-spinner {
88
127
  width: 2rem;
89
128
  height: 2rem;
@@ -167,6 +206,22 @@ let TableWidget = class TableWidget extends LitElement {
167
206
  overflow: hidden;
168
207
  text-overflow: ellipsis;
169
208
  }
209
+ .skeleton-title {
210
+ height: 1rem;
211
+ width: 8rem;
212
+ max-width: 60%;
213
+ border-radius: 4px;
214
+ background: linear-gradient(
215
+ 90deg,
216
+ #e5e7eb 0%,
217
+ #e5e7eb 40%,
218
+ #f3f4f6 50%,
219
+ #e5e7eb 60%,
220
+ #e5e7eb 100%
221
+ );
222
+ background-size: 200% 100%;
223
+ animation: analytics-table-skeleton-shimmer 1.2s ease-in-out infinite;
224
+ }
170
225
  .widget-body {
171
226
  flex: 1;
172
227
  min-height: 0;
@@ -299,10 +354,8 @@ let TableWidget = class TableWidget extends LitElement {
299
354
  }, {
300
355
  onEnter: () => {
301
356
  this._viewportVisible = true;
302
- if (!this._hasLoadedOnce) {
303
- this._hasLoadedOnce = true;
357
+ if (!this._hasLoadedOnce)
304
358
  this._loadData();
305
- }
306
359
  },
307
360
  onLeave: () => {
308
361
  this._viewportVisible = false;
@@ -446,6 +499,7 @@ let TableWidget = class TableWidget extends LitElement {
446
499
  this._widgetFilters = [];
447
500
  if (hideFilter !== undefined)
448
501
  this._hideFilter = hideFilter;
502
+ this._hasLoadedOnce = true;
449
503
  this._loading = false;
450
504
  if (this._loadDataPendingRefresh) {
451
505
  this._loadDataPendingRefresh = false;
@@ -489,6 +543,7 @@ let TableWidget = class TableWidget extends LitElement {
489
543
  this._widgetFilters = [];
490
544
  if (hideFilter !== undefined)
491
545
  this._hideFilter = hideFilter;
546
+ this._hasLoadedOnce = true;
492
547
  this._loading = false;
493
548
  if (this._loadDataPendingRefresh) {
494
549
  this._loadDataPendingRefresh = false;
@@ -577,10 +632,16 @@ let TableWidget = class TableWidget extends LitElement {
577
632
  const hasHeaderRows = Boolean(wd?.header_rows?.length);
578
633
  const tableFontSizeStyle = wd?.font_size ? `font-size: ${wd.font_size}` : nothing;
579
634
  const canRefresh = Boolean(this._getEffectiveDataUrl()) && !this.hideRefreshButton;
580
- const headerContent = this._effectiveTitle || canRefresh
635
+ const showSkeleton = this._loading && !this._hasLoadedOnce;
636
+ const showTitlePlaceholder = !this._effectiveTitle && !this.hideRefreshButton;
637
+ const headerContent = this._effectiveTitle || canRefresh || showTitlePlaceholder
581
638
  ? html `
582
639
  <header class="widget-header">
583
- ${this._effectiveTitle ? html `<h2 class="widget-title">${this._effectiveTitle}</h2>` : html `<span></span>`}
640
+ ${this._effectiveTitle
641
+ ? html `<h2 class="widget-title">${this._effectiveTitle}</h2>`
642
+ : showTitlePlaceholder
643
+ ? html `<div class="skeleton-title" aria-hidden="true"></div>`
644
+ : html `<span></span>`}
584
645
  ${canRefresh
585
646
  ? html `
586
647
  <button
@@ -613,12 +674,43 @@ let TableWidget = class TableWidget extends LitElement {
613
674
  ></analytics-widget-toolbar>
614
675
  `
615
676
  : html ``;
616
- const bodyContent = this._error
617
- ? html `<div class="error">${this._error}</div>`
618
- : columns.length === 0
619
- ? html `<div class="empty">No columns</div>`
620
- : rows.length === 0
621
- ? html `
677
+ const showSpinnerOverlay = this._loading && this._hasLoadedOnce;
678
+ const bodyContent = showSkeleton
679
+ ? html `
680
+ <div class="skeleton" aria-busy="true" aria-live="polite">
681
+ <div class="skeleton-row">
682
+ <div class="skeleton-cell"></div>
683
+ <div class="skeleton-cell"></div>
684
+ <div class="skeleton-cell"></div>
685
+ </div>
686
+ <div class="skeleton-row">
687
+ <div class="skeleton-cell"></div>
688
+ <div class="skeleton-cell"></div>
689
+ <div class="skeleton-cell"></div>
690
+ </div>
691
+ <div class="skeleton-row">
692
+ <div class="skeleton-cell"></div>
693
+ <div class="skeleton-cell"></div>
694
+ <div class="skeleton-cell"></div>
695
+ </div>
696
+ <div class="skeleton-row">
697
+ <div class="skeleton-cell"></div>
698
+ <div class="skeleton-cell"></div>
699
+ <div class="skeleton-cell"></div>
700
+ </div>
701
+ <div class="skeleton-row">
702
+ <div class="skeleton-cell"></div>
703
+ <div class="skeleton-cell"></div>
704
+ <div class="skeleton-cell"></div>
705
+ </div>
706
+ </div>
707
+ `
708
+ : this._error
709
+ ? html `<div class="error">${this._error}</div>`
710
+ : columns.length === 0
711
+ ? html `<div class="empty">No columns</div>`
712
+ : rows.length === 0
713
+ ? html `
622
714
  <table style=${tableFontSizeStyle}>
623
715
  <thead>
624
716
  ${this._renderThead(columns, hasHeaderRows)}
@@ -630,7 +722,7 @@ let TableWidget = class TableWidget extends LitElement {
630
722
  </tbody>
631
723
  </table>
632
724
  `
633
- : html `
725
+ : html `
634
726
  <table style=${tableFontSizeStyle}>
635
727
  <thead>
636
728
  ${this._renderThead(columns, hasHeaderRows)}
@@ -645,12 +737,12 @@ let TableWidget = class TableWidget extends LitElement {
645
737
  ${headerContent}
646
738
  <div class="widget-body">
647
739
  ${bodyContent}
648
- ${this._loading
740
+ </div>
741
+ ${showSpinnerOverlay
649
742
  ? html `<div class="loading-overlay" aria-busy="true" aria-live="polite">
650
- <div class="loading-spinner" aria-hidden="true"></div>
651
- </div>`
743
+ <div class="loading-spinner" aria-hidden="true"></div>
744
+ </div>`
652
745
  : nothing}
653
- </div>
654
746
  ${filterToolbar}
655
747
  </div>
656
748
  `;