juxscript 1.0.5 → 1.0.7
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/README.md +7 -0
- package/lib/components/areachart.ts +1246 -0
- package/lib/components/areachartsmooth.ts +1380 -0
- package/lib/components/barchart.ts +16 -14
- package/lib/components/docs-data.json +764 -86
- package/lib/components/doughnutchart.ts +1191 -0
- package/lib/components/kpicard.ts +501 -0
- package/lib/jux.ts +25 -3
- package/package.json +1 -1
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { State } from '../reactivity/state.js';
|
|
2
|
+
import {
|
|
3
|
+
googleTheme,
|
|
4
|
+
seriesaTheme,
|
|
5
|
+
hrTheme,
|
|
6
|
+
figmaTheme,
|
|
7
|
+
notionTheme,
|
|
8
|
+
chalkTheme,
|
|
9
|
+
mintTheme
|
|
10
|
+
} from '../themes/charts.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* KPI card options
|
|
14
|
+
*/
|
|
15
|
+
export interface KPICardOptions {
|
|
16
|
+
title?: string;
|
|
17
|
+
value?: string | number;
|
|
18
|
+
delta?: number; // Percentage change (e.g., 10 for +10%, -5 for -5%)
|
|
19
|
+
prefix?: string; // e.g., "$", "€"
|
|
20
|
+
suffix?: string; // e.g., "k", "M", "%"
|
|
21
|
+
width?: number;
|
|
22
|
+
height?: number;
|
|
23
|
+
theme?: 'google' | 'seriesa' | 'hr' | 'figma' | 'notion' | 'chalk' | 'mint';
|
|
24
|
+
styleMode?: 'default' | 'gradient' | 'glass' | 'outline';
|
|
25
|
+
animate?: boolean;
|
|
26
|
+
animationDuration?: number;
|
|
27
|
+
class?: string;
|
|
28
|
+
style?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* KPI card state
|
|
33
|
+
*/
|
|
34
|
+
type KPICardState = {
|
|
35
|
+
title: string;
|
|
36
|
+
value: string | number;
|
|
37
|
+
delta: number;
|
|
38
|
+
prefix: string;
|
|
39
|
+
suffix: string;
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
theme: 'google' | 'seriesa' | 'hr' | 'figma' | 'notion' | 'chalk' | 'mint';
|
|
43
|
+
styleMode: 'default' | 'gradient' | 'glass' | 'outline';
|
|
44
|
+
animate: boolean;
|
|
45
|
+
animationDuration: number;
|
|
46
|
+
class: string;
|
|
47
|
+
style: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* KPI card component - Displays key performance indicators
|
|
52
|
+
*
|
|
53
|
+
* Usage:
|
|
54
|
+
* jux.kpicard('users-kpi')
|
|
55
|
+
* .title('New users')
|
|
56
|
+
* .value('78k')
|
|
57
|
+
* .delta(10)
|
|
58
|
+
* .theme('mint')
|
|
59
|
+
* .render('#app');
|
|
60
|
+
*/
|
|
61
|
+
export class KPICard {
|
|
62
|
+
private _id: string;
|
|
63
|
+
private _element?: HTMLElement;
|
|
64
|
+
private _container?: string;
|
|
65
|
+
|
|
66
|
+
public state: KPICardState = {
|
|
67
|
+
title: 'KPI',
|
|
68
|
+
value: 0,
|
|
69
|
+
delta: 0,
|
|
70
|
+
prefix: '',
|
|
71
|
+
suffix: '',
|
|
72
|
+
width: 280,
|
|
73
|
+
height: 200,
|
|
74
|
+
theme: 'google',
|
|
75
|
+
styleMode: 'default',
|
|
76
|
+
animate: true,
|
|
77
|
+
animationDuration: 600,
|
|
78
|
+
class: '',
|
|
79
|
+
style: ''
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
private _boundTheme?: State<string>;
|
|
83
|
+
private _boundStyleMode?: State<string>;
|
|
84
|
+
private _boundTitle?: State<string>;
|
|
85
|
+
private _boundValue?: State<string | number>;
|
|
86
|
+
private _boundDelta?: State<number>;
|
|
87
|
+
|
|
88
|
+
constructor(id: string, options: KPICardOptions = {}) {
|
|
89
|
+
this._id = id;
|
|
90
|
+
|
|
91
|
+
// Apply options
|
|
92
|
+
if (options.title !== undefined) this.state.title = options.title;
|
|
93
|
+
if (options.value !== undefined) this.state.value = options.value;
|
|
94
|
+
if (options.delta !== undefined) this.state.delta = options.delta;
|
|
95
|
+
if (options.prefix !== undefined) this.state.prefix = options.prefix;
|
|
96
|
+
if (options.suffix !== undefined) this.state.suffix = options.suffix;
|
|
97
|
+
if (options.width !== undefined) this.state.width = options.width;
|
|
98
|
+
if (options.height !== undefined) this.state.height = options.height;
|
|
99
|
+
if (options.theme !== undefined) this.state.theme = options.theme;
|
|
100
|
+
if (options.styleMode !== undefined) this.state.styleMode = options.styleMode;
|
|
101
|
+
if (options.animate !== undefined) this.state.animate = options.animate;
|
|
102
|
+
if (options.animationDuration !== undefined) this.state.animationDuration = options.animationDuration;
|
|
103
|
+
if (options.class !== undefined) this.state.class = options.class;
|
|
104
|
+
if (options.style !== undefined) this.state.style = options.style;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Chainable setters
|
|
108
|
+
title(value: string | State<string>): this {
|
|
109
|
+
if (value instanceof State) {
|
|
110
|
+
this._boundTitle = value;
|
|
111
|
+
this.state.title = value.value;
|
|
112
|
+
value.subscribe((newValue) => {
|
|
113
|
+
this.state.title = newValue;
|
|
114
|
+
this._updateCard();
|
|
115
|
+
});
|
|
116
|
+
} else {
|
|
117
|
+
this.state.title = value;
|
|
118
|
+
}
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
value(value: string | number | State<string | number>): this {
|
|
123
|
+
if (value instanceof State) {
|
|
124
|
+
this._boundValue = value;
|
|
125
|
+
this.state.value = value.value;
|
|
126
|
+
value.subscribe((newValue) => {
|
|
127
|
+
this.state.value = newValue;
|
|
128
|
+
this._updateCard();
|
|
129
|
+
});
|
|
130
|
+
} else {
|
|
131
|
+
this.state.value = value;
|
|
132
|
+
}
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
delta(value: number | State<number>): this {
|
|
137
|
+
if (value instanceof State) {
|
|
138
|
+
this._boundDelta = value;
|
|
139
|
+
this.state.delta = value.value;
|
|
140
|
+
value.subscribe((newValue) => {
|
|
141
|
+
this.state.delta = newValue;
|
|
142
|
+
this._updateCard();
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
this.state.delta = value;
|
|
146
|
+
}
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
prefix(value: string): this {
|
|
151
|
+
this.state.prefix = value;
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
suffix(value: string): this {
|
|
156
|
+
this.state.suffix = value;
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
width(value: number): this {
|
|
161
|
+
this.state.width = value;
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
height(value: number): this {
|
|
166
|
+
this.state.height = value;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
theme(value: string | State<string>): this {
|
|
171
|
+
if (value instanceof State) {
|
|
172
|
+
this._boundTheme = value;
|
|
173
|
+
this.state.theme = value.value as any;
|
|
174
|
+
value.subscribe((newValue) => {
|
|
175
|
+
this.state.theme = newValue as any;
|
|
176
|
+
this._updateCard();
|
|
177
|
+
});
|
|
178
|
+
} else {
|
|
179
|
+
this.state.theme = value as any;
|
|
180
|
+
}
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
styleMode(value: string | State<string>): this {
|
|
185
|
+
if (value instanceof State) {
|
|
186
|
+
this._boundStyleMode = value;
|
|
187
|
+
this.state.styleMode = value.value as any;
|
|
188
|
+
value.subscribe((newValue) => {
|
|
189
|
+
this.state.styleMode = newValue as any;
|
|
190
|
+
this._updateCard();
|
|
191
|
+
});
|
|
192
|
+
} else {
|
|
193
|
+
this.state.styleMode = value as any;
|
|
194
|
+
}
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
animate(value: boolean): this {
|
|
199
|
+
this.state.animate = value;
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
animationDuration(value: number): this {
|
|
204
|
+
this.state.animationDuration = value;
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
class(value: string): this {
|
|
209
|
+
this.state.class = value;
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
style(value: string): this {
|
|
214
|
+
this.state.style = value;
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
render(container: string): this {
|
|
219
|
+
this._container = container;
|
|
220
|
+
const element = document.querySelector(container);
|
|
221
|
+
if (!element) {
|
|
222
|
+
console.warn(`Container ${container} not found`);
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
this._buildCard(element as HTMLElement);
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private _updateCard(): void {
|
|
231
|
+
if (!this._container) return;
|
|
232
|
+
|
|
233
|
+
const element = document.querySelector(this._container);
|
|
234
|
+
if (!element) return;
|
|
235
|
+
|
|
236
|
+
// Clear and rebuild
|
|
237
|
+
element.innerHTML = '';
|
|
238
|
+
this._buildCard(element as HTMLElement);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private _buildCard(container: HTMLElement): void {
|
|
242
|
+
const { width, height, class: className, style, animate, animationDuration } = this.state;
|
|
243
|
+
|
|
244
|
+
// Create wrapper
|
|
245
|
+
const wrapper = document.createElement('div');
|
|
246
|
+
wrapper.className = `jux-kpicard ${className}`;
|
|
247
|
+
wrapper.id = this._id;
|
|
248
|
+
wrapper.style.cssText = `
|
|
249
|
+
width: ${width}px;
|
|
250
|
+
height: ${height}px;
|
|
251
|
+
${style}
|
|
252
|
+
`;
|
|
253
|
+
|
|
254
|
+
// Apply theme colors and style mode
|
|
255
|
+
this._applyThemeAndStyle(wrapper);
|
|
256
|
+
|
|
257
|
+
// Build card content
|
|
258
|
+
const content = this._createContent();
|
|
259
|
+
wrapper.appendChild(content);
|
|
260
|
+
|
|
261
|
+
// Add animation
|
|
262
|
+
if (animate) {
|
|
263
|
+
wrapper.style.opacity = '0';
|
|
264
|
+
wrapper.style.transform = 'translateY(20px)';
|
|
265
|
+
wrapper.style.transition = `opacity ${animationDuration}ms ease-out, transform ${animationDuration}ms ease-out`;
|
|
266
|
+
|
|
267
|
+
requestAnimationFrame(() => {
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
wrapper.style.opacity = '1';
|
|
270
|
+
wrapper.style.transform = 'translateY(0)';
|
|
271
|
+
}, 50);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
container.appendChild(wrapper);
|
|
276
|
+
this._element = wrapper;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private _createContent(): HTMLElement {
|
|
280
|
+
const { title, value, delta, prefix, suffix, animate, animationDuration } = this.state;
|
|
281
|
+
|
|
282
|
+
const content = document.createElement('div');
|
|
283
|
+
content.className = 'jux-kpicard-content';
|
|
284
|
+
content.style.cssText = `
|
|
285
|
+
padding: 24px;
|
|
286
|
+
display: flex;
|
|
287
|
+
flex-direction: column;
|
|
288
|
+
height: 100%;
|
|
289
|
+
position: relative;
|
|
290
|
+
`;
|
|
291
|
+
|
|
292
|
+
// Title
|
|
293
|
+
const titleEl = document.createElement('div');
|
|
294
|
+
titleEl.className = 'jux-kpicard-title';
|
|
295
|
+
titleEl.textContent = title;
|
|
296
|
+
titleEl.style.cssText = `
|
|
297
|
+
font-size: 16px;
|
|
298
|
+
font-weight: 500;
|
|
299
|
+
color: #6b7280;
|
|
300
|
+
margin-bottom: 16px;
|
|
301
|
+
font-family: inherit;
|
|
302
|
+
`;
|
|
303
|
+
content.appendChild(titleEl);
|
|
304
|
+
|
|
305
|
+
// Value container
|
|
306
|
+
const valueContainer = document.createElement('div');
|
|
307
|
+
valueContainer.style.cssText = `
|
|
308
|
+
display: flex;
|
|
309
|
+
align-items: baseline;
|
|
310
|
+
margin-bottom: 12px;
|
|
311
|
+
`;
|
|
312
|
+
|
|
313
|
+
// Value
|
|
314
|
+
const valueEl = document.createElement('div');
|
|
315
|
+
valueEl.className = 'jux-kpicard-value';
|
|
316
|
+
valueEl.textContent = `${prefix}${value}${suffix}`;
|
|
317
|
+
valueEl.style.cssText = `
|
|
318
|
+
font-size: 56px;
|
|
319
|
+
font-weight: 800;
|
|
320
|
+
color: #1f2937;
|
|
321
|
+
line-height: 1;
|
|
322
|
+
font-family: inherit;
|
|
323
|
+
`;
|
|
324
|
+
|
|
325
|
+
if (animate) {
|
|
326
|
+
valueEl.style.opacity = '0';
|
|
327
|
+
valueEl.style.transform = 'scale(0.8)';
|
|
328
|
+
valueEl.style.transition = `opacity ${animationDuration}ms ease-out ${animationDuration / 2}ms, transform ${animationDuration}ms cubic-bezier(0.34, 1.56, 0.64, 1) ${animationDuration / 2}ms`;
|
|
329
|
+
|
|
330
|
+
requestAnimationFrame(() => {
|
|
331
|
+
setTimeout(() => {
|
|
332
|
+
valueEl.style.opacity = '1';
|
|
333
|
+
valueEl.style.transform = 'scale(1)';
|
|
334
|
+
}, 100);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
valueContainer.appendChild(valueEl);
|
|
339
|
+
content.appendChild(valueContainer);
|
|
340
|
+
|
|
341
|
+
// Delta with arrow
|
|
342
|
+
if (delta !== 0) {
|
|
343
|
+
const deltaContainer = document.createElement('div');
|
|
344
|
+
deltaContainer.className = 'jux-kpicard-delta';
|
|
345
|
+
deltaContainer.style.cssText = `
|
|
346
|
+
display: flex;
|
|
347
|
+
align-items: center;
|
|
348
|
+
gap: 8px;
|
|
349
|
+
`;
|
|
350
|
+
|
|
351
|
+
// Arrow SVG
|
|
352
|
+
const arrow = this._createArrowSVG(delta > 0);
|
|
353
|
+
deltaContainer.appendChild(arrow);
|
|
354
|
+
|
|
355
|
+
// Delta text
|
|
356
|
+
const deltaText = document.createElement('span');
|
|
357
|
+
deltaText.textContent = `${delta > 0 ? '+' : ''}${delta}%`;
|
|
358
|
+
deltaText.style.cssText = `
|
|
359
|
+
font-size: 18px;
|
|
360
|
+
font-weight: 700;
|
|
361
|
+
color: ${delta > 0 ? '#10b981' : '#ef4444'};
|
|
362
|
+
font-family: inherit;
|
|
363
|
+
`;
|
|
364
|
+
|
|
365
|
+
if (animate) {
|
|
366
|
+
deltaContainer.style.opacity = '0';
|
|
367
|
+
deltaContainer.style.transform = 'translateX(-10px)';
|
|
368
|
+
deltaContainer.style.transition = `opacity ${animationDuration}ms ease-out ${animationDuration}ms, transform ${animationDuration}ms ease-out ${animationDuration}ms`;
|
|
369
|
+
|
|
370
|
+
requestAnimationFrame(() => {
|
|
371
|
+
setTimeout(() => {
|
|
372
|
+
deltaContainer.style.opacity = '1';
|
|
373
|
+
deltaContainer.style.transform = 'translateX(0)';
|
|
374
|
+
}, 150);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
deltaContainer.appendChild(deltaText);
|
|
379
|
+
content.appendChild(deltaContainer);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return content;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private _createArrowSVG(isUp: boolean): SVGSVGElement {
|
|
386
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
387
|
+
svg.setAttribute('width', '24');
|
|
388
|
+
svg.setAttribute('height', '24');
|
|
389
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
390
|
+
svg.setAttribute('fill', 'none');
|
|
391
|
+
svg.style.flexShrink = '0';
|
|
392
|
+
|
|
393
|
+
const color = isUp ? '#10b981' : '#ef4444';
|
|
394
|
+
|
|
395
|
+
// Create squiggly arrow path
|
|
396
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
397
|
+
|
|
398
|
+
if (isUp) {
|
|
399
|
+
// Up arrow with squiggly line
|
|
400
|
+
path.setAttribute('d', 'M12 4L12 20M12 4L8 8M12 4L16 8M10 10Q11 11 12 10T14 10M10 14Q11 15 12 14T14 14');
|
|
401
|
+
} else {
|
|
402
|
+
// Down arrow with squiggly line
|
|
403
|
+
path.setAttribute('d', 'M12 20L12 4M12 20L8 16M12 20L16 16M10 10Q11 9 12 10T14 10M10 14Q11 13 12 14T14 14');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
path.setAttribute('stroke', color);
|
|
407
|
+
path.setAttribute('stroke-width', '2');
|
|
408
|
+
path.setAttribute('stroke-linecap', 'round');
|
|
409
|
+
path.setAttribute('stroke-linejoin', 'round');
|
|
410
|
+
|
|
411
|
+
svg.appendChild(path);
|
|
412
|
+
return svg;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private _getThemeColors(): string[] {
|
|
416
|
+
const { theme } = this.state;
|
|
417
|
+
|
|
418
|
+
switch (theme) {
|
|
419
|
+
case 'google':
|
|
420
|
+
return googleTheme;
|
|
421
|
+
case 'seriesa':
|
|
422
|
+
return seriesaTheme;
|
|
423
|
+
case 'hr':
|
|
424
|
+
return hrTheme;
|
|
425
|
+
case 'figma':
|
|
426
|
+
return figmaTheme;
|
|
427
|
+
case 'notion':
|
|
428
|
+
return notionTheme;
|
|
429
|
+
case 'chalk':
|
|
430
|
+
return chalkTheme;
|
|
431
|
+
case 'mint':
|
|
432
|
+
return mintTheme;
|
|
433
|
+
default:
|
|
434
|
+
return googleTheme;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private _applyThemeAndStyle(wrapper: HTMLElement): void {
|
|
439
|
+
const { styleMode } = this.state;
|
|
440
|
+
const colors = this._getThemeColors();
|
|
441
|
+
|
|
442
|
+
const baseStyles = `
|
|
443
|
+
border-radius: 16px;
|
|
444
|
+
overflow: hidden;
|
|
445
|
+
position: relative;
|
|
446
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
447
|
+
`;
|
|
448
|
+
|
|
449
|
+
if (styleMode === 'gradient') {
|
|
450
|
+
wrapper.style.cssText += `
|
|
451
|
+
${baseStyles}
|
|
452
|
+
background: linear-gradient(135deg, ${colors[0]} 0%, ${colors[1]} 100%);
|
|
453
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
454
|
+
`;
|
|
455
|
+
|
|
456
|
+
// Adjust text colors for gradient
|
|
457
|
+
const titleElements = wrapper.querySelectorAll('.jux-kpicard-title');
|
|
458
|
+
const valueElements = wrapper.querySelectorAll('.jux-kpicard-value');
|
|
459
|
+
titleElements.forEach(el => (el as HTMLElement).style.color = 'rgba(255, 255, 255, 0.9)');
|
|
460
|
+
valueElements.forEach(el => (el as HTMLElement).style.color = '#ffffff');
|
|
461
|
+
} else if (styleMode === 'glass') {
|
|
462
|
+
wrapper.style.cssText += `
|
|
463
|
+
${baseStyles}
|
|
464
|
+
background: rgba(255, 255, 255, 0.7);
|
|
465
|
+
backdrop-filter: blur(10px);
|
|
466
|
+
border: 1px solid rgba(255, 255, 255, 0.8);
|
|
467
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
|
468
|
+
`;
|
|
469
|
+
} else if (styleMode === 'outline') {
|
|
470
|
+
wrapper.style.cssText += `
|
|
471
|
+
${baseStyles}
|
|
472
|
+
background: transparent;
|
|
473
|
+
border: 3px solid ${colors[0]};
|
|
474
|
+
`;
|
|
475
|
+
} else {
|
|
476
|
+
// default
|
|
477
|
+
wrapper.style.cssText += `
|
|
478
|
+
${baseStyles}
|
|
479
|
+
background: #ffffff;
|
|
480
|
+
border: 1px solid #e5e7eb;
|
|
481
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
482
|
+
`;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Apply theme color accent
|
|
486
|
+
const accentBar = document.createElement('div');
|
|
487
|
+
accentBar.style.cssText = `
|
|
488
|
+
position: absolute;
|
|
489
|
+
top: 0;
|
|
490
|
+
left: 0;
|
|
491
|
+
right: 0;
|
|
492
|
+
height: 4px;
|
|
493
|
+
background: linear-gradient(90deg, ${colors[0]}, ${colors[1]});
|
|
494
|
+
`;
|
|
495
|
+
wrapper.appendChild(accentBar);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export function kpicard(id: string, options: KPICardOptions = {}): KPICard {
|
|
500
|
+
return new KPICard(id, options);
|
|
501
|
+
}
|
package/lib/jux.ts
CHANGED
|
@@ -50,7 +50,10 @@ import { req, Req, type RequestInfo } from './components/req.js';
|
|
|
50
50
|
import { heading, Heading, type HeadingOptions } from './components/heading.js';
|
|
51
51
|
import { paragraph, Paragraph, type ParagraphOptions } from './components/paragraph.js';
|
|
52
52
|
import { barchart, BarChart, type BarChartOptions, type BarChartDataPoint } from './components/barchart.js';
|
|
53
|
-
|
|
53
|
+
import { areachart, AreaChart, type AreaChartOptions, type AreaChartDataPoint } from './components/areachart.js';
|
|
54
|
+
import { areachartsmooth, AreaChartSmooth, type AreaChartSmoothOptions, AreaChartSmoothDataPoint } from './components/areachartsmooth.js';
|
|
55
|
+
import { doughnutchart, DoughnutChart, type DoughnutChartOptions, type DoughnutChartDataPoint } from './components/doughnutchart.js';
|
|
56
|
+
import { kpicard, KPICard, type KPICardOptions } from './components/kpicard.js';
|
|
54
57
|
|
|
55
58
|
/* -------------------------
|
|
56
59
|
* Type Exports
|
|
@@ -106,7 +109,14 @@ export type {
|
|
|
106
109
|
HeadingOptions,
|
|
107
110
|
ParagraphOptions,
|
|
108
111
|
BarChartOptions,
|
|
109
|
-
BarChartDataPoint
|
|
112
|
+
BarChartDataPoint,
|
|
113
|
+
AreaChartOptions,
|
|
114
|
+
AreaChartDataPoint,
|
|
115
|
+
AreaChartSmoothOptions,
|
|
116
|
+
AreaChartSmoothDataPoint,
|
|
117
|
+
DoughnutChartOptions,
|
|
118
|
+
DoughnutChartDataPoint,
|
|
119
|
+
KPICardOptions
|
|
110
120
|
};
|
|
111
121
|
|
|
112
122
|
/* -------------------------
|
|
@@ -158,7 +168,11 @@ export {
|
|
|
158
168
|
Req,
|
|
159
169
|
Heading,
|
|
160
170
|
Paragraph,
|
|
161
|
-
BarChart
|
|
171
|
+
BarChart,
|
|
172
|
+
AreaChart,
|
|
173
|
+
AreaChartSmooth,
|
|
174
|
+
DoughnutChart,
|
|
175
|
+
KPICard
|
|
162
176
|
};
|
|
163
177
|
|
|
164
178
|
/* -------------------------
|
|
@@ -216,6 +230,10 @@ export interface JuxAPI {
|
|
|
216
230
|
heading: typeof heading;
|
|
217
231
|
paragraph: typeof paragraph;
|
|
218
232
|
barchart: typeof barchart;
|
|
233
|
+
areachart: typeof areachart;
|
|
234
|
+
areachartsmooth: typeof areachartsmooth;
|
|
235
|
+
doughnutchart: typeof doughnutchart;
|
|
236
|
+
kpicard: typeof kpicard;
|
|
219
237
|
}
|
|
220
238
|
|
|
221
239
|
/* -------------------------
|
|
@@ -289,6 +307,10 @@ class Jux implements JuxAPI {
|
|
|
289
307
|
heading = heading;
|
|
290
308
|
paragraph = paragraph;
|
|
291
309
|
barchart = barchart;
|
|
310
|
+
areachart = areachart;
|
|
311
|
+
areachartsmooth = areachartsmooth;
|
|
312
|
+
doughnutchart = doughnutchart;
|
|
313
|
+
kpicard = kpicard;
|
|
292
314
|
}
|
|
293
315
|
|
|
294
316
|
/**
|