@ammarkhalidfarooq/dashboard-package 0.1.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.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @ammarkhalidfarooq/dashboard-package
2
+
3
+ A reusable React Dashboard component library.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @ammarkhalidfarooq/dashboard-package
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```jsx
14
+ import React from "react";
15
+ import { Dashboard } from "@ammarkhalidfarooq/dashboard-package";
16
+
17
+ const App = () => {
18
+ return <Dashboard />;
19
+ };
20
+
21
+ export default App;
22
+ ```
23
+
24
+ ## Development
25
+
26
+ To preview the component locally:
27
+
28
+ ```bash
29
+ npm run dev
30
+ ```
31
+
32
+ To build the package:
33
+
34
+ ```bash
35
+ npm run build
36
+ ```
37
+
38
+ The build outputs both ESM and CommonJS bundles in the `dist` folder.
@@ -0,0 +1,600 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var material = require('@mui/material');
5
+ var iconsMaterial = require('@mui/icons-material');
6
+ var styles = require('@mui/material/styles');
7
+ var Chart = require('react-apexcharts');
8
+
9
+ function _arrayLikeToArray(r, a) {
10
+ (null == a || a > r.length) && (a = r.length);
11
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
12
+ return n;
13
+ }
14
+ function _arrayWithHoles(r) {
15
+ if (Array.isArray(r)) return r;
16
+ }
17
+ function _iterableToArrayLimit(r, l) {
18
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
19
+ if (null != t) {
20
+ var e,
21
+ n,
22
+ i,
23
+ u,
24
+ a = [],
25
+ f = true,
26
+ o = false;
27
+ try {
28
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
29
+ } catch (r) {
30
+ o = true, n = r;
31
+ } finally {
32
+ try {
33
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
34
+ } finally {
35
+ if (o) throw n;
36
+ }
37
+ }
38
+ return a;
39
+ }
40
+ }
41
+ function _nonIterableRest() {
42
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
43
+ }
44
+ function _slicedToArray(r, e) {
45
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
46
+ }
47
+ function _unsupportedIterableToArray(r, a) {
48
+ if (r) {
49
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
50
+ var t = {}.toString.call(r).slice(8, -1);
51
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
52
+ }
53
+ }
54
+
55
+ var theme = styles.createTheme({
56
+ cssVariables: true,
57
+ // Enable CSS variables for better SSR support
58
+ typography: {
59
+ fontFamily: ["var(--font-league-spartan)", "var(--font-noto-sans-arabic)",
60
+ // Added as a fallback for Arabic text
61
+ "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"].join(",")
62
+ },
63
+ palette: {
64
+ primary: {
65
+ main: "#6363E6",
66
+ mainLight: "#F7F7FF",
67
+ light: "#FFFFFF",
68
+ gray: "#A1A1A8",
69
+ lightGreen: "#E1FBF2",
70
+ green: "#0CAB72",
71
+ red: "#E61D1D",
72
+ lightRed: "#FFEDED",
73
+ lightGray: "#E9E9EB",
74
+ darkGray: "#606062",
75
+ dark: "#090909"
76
+ },
77
+ text: {
78
+ primary: "#666666"
79
+ },
80
+ secondary: {
81
+ main: "#E0C2FF",
82
+ light: "#F5EBFF",
83
+ // dark: will be calculated from palette.secondary.main,
84
+ contrastText: "#47008F"
85
+ },
86
+ white: {
87
+ main: "#FFFFFF",
88
+ light: "#F8F8F8"
89
+ },
90
+ gradients: {
91
+ primary: "linear-gradient(90deg, #6363E6 0.05%, #59C9F9 99.96%)",
92
+ secondary: "linear-gradient(180deg, #E9E9FF 0%, #C9EEFF 100%)"
93
+ // You can add more gradients if needed
94
+ }
95
+ }
96
+ });
97
+
98
+ var MetricSelector = function MetricSelector(_ref) {
99
+ var metric = _ref.metric,
100
+ onMetricChange = _ref.onMetricChange,
101
+ _ref$options = _ref.options,
102
+ options = _ref$options === void 0 ? ['Revenue', 'Donations'] : _ref$options;
103
+ var _React$useState = React.useState(null),
104
+ _React$useState2 = _slicedToArray(_React$useState, 2),
105
+ anchorEl = _React$useState2[0],
106
+ setAnchorEl = _React$useState2[1];
107
+ var open = Boolean(anchorEl);
108
+ var handleClick = function handleClick(event) {
109
+ setAnchorEl(event.currentTarget);
110
+ };
111
+ var handleClose = function handleClose(value) {
112
+ if (typeof value === 'string') {
113
+ onMetricChange(value);
114
+ }
115
+ setAnchorEl(null);
116
+ };
117
+ return /*#__PURE__*/React.createElement(material.Box, {
118
+ sx: {
119
+ display: 'flex',
120
+ gap: 1
121
+ }
122
+ }, /*#__PURE__*/React.createElement(material.Button, {
123
+ id: "metric-button",
124
+ "aria-controls": open ? 'metric-menu' : undefined,
125
+ "aria-haspopup": "true",
126
+ "aria-expanded": open ? 'true' : undefined,
127
+ onClick: handleClick,
128
+ variant: "outlined",
129
+ sx: {
130
+ borderRadius: '8px',
131
+ borderColor: '#E9E9EB',
132
+ color: '#000',
133
+ textTransform: 'none',
134
+ fontWeight: 600,
135
+ px: 2,
136
+ height: '40px',
137
+ '&:hover': {
138
+ borderColor: 'primary.main',
139
+ bgcolor: 'rgba(99, 99, 230, 0.04)'
140
+ }
141
+ }
142
+ }, "Metric: ", metric), /*#__PURE__*/React.createElement(material.Menu, {
143
+ id: "metric-menu",
144
+ anchorEl: anchorEl,
145
+ open: open,
146
+ onClose: function onClose() {
147
+ return handleClose();
148
+ },
149
+ MenuListProps: {
150
+ 'aria-labelledby': 'metric-button'
151
+ },
152
+ PaperProps: {
153
+ sx: {
154
+ borderRadius: '8px',
155
+ mt: 1,
156
+ boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
157
+ minWidth: '150px'
158
+ }
159
+ }
160
+ }, options.map(function (option) {
161
+ return /*#__PURE__*/React.createElement(material.MenuItem, {
162
+ key: option,
163
+ onClick: function onClick() {
164
+ return handleClose(option);
165
+ },
166
+ sx: {
167
+ fontWeight: metric === option ? 700 : 400
168
+ }
169
+ }, option);
170
+ })));
171
+ };
172
+
173
+ var RevenueChart = function RevenueChart(_ref) {
174
+ var metric = _ref.metric,
175
+ data = _ref.data,
176
+ series = _ref.series,
177
+ categories = _ref.categories,
178
+ _ref$height = _ref.height,
179
+ height = _ref$height === void 0 ? 350 : _ref$height,
180
+ _ref$stacked = _ref.stacked,
181
+ stacked = _ref$stacked === void 0 ? false : _ref$stacked;
182
+ var theme = styles.useTheme();
183
+ var chartOptions = {
184
+ chart: {
185
+ id: 'revenue-chart',
186
+ stacked: stacked,
187
+ toolbar: {
188
+ show: false
189
+ },
190
+ sparkline: {
191
+ enabled: false
192
+ }
193
+ },
194
+ stroke: {
195
+ curve: 'straight',
196
+ width: 2
197
+ },
198
+ fill: {
199
+ type: 'gradient',
200
+ gradient: {
201
+ shadeIntensity: 1,
202
+ opacityFrom: 0.8,
203
+ opacityTo: 0.4,
204
+ stops: [0, 100]
205
+ }
206
+ },
207
+ xaxis: {
208
+ categories: categories,
209
+ axisBorder: {
210
+ show: false
211
+ },
212
+ axisTicks: {
213
+ show: false
214
+ },
215
+ labels: {
216
+ style: {
217
+ colors: '#A1A1A8',
218
+ fontSize: '12px'
219
+ }
220
+ }
221
+ },
222
+ yaxis: {
223
+ show: true,
224
+ labels: {
225
+ style: {
226
+ colors: '#A1A1A8',
227
+ fontSize: '12px'
228
+ },
229
+ formatter: function formatter(value) {
230
+ return metric === 'Revenue' ? "$".concat(value) : value;
231
+ }
232
+ }
233
+ },
234
+ grid: {
235
+ show: true,
236
+ borderColor: '#f1f1f1',
237
+ strokeDashArray: 4,
238
+ position: 'back'
239
+ },
240
+ // Use primary main and a darker version of it for differentiation
241
+ colors: [theme.palette.primary.main, '#4B4BC2'],
242
+ dataLabels: {
243
+ enabled: false
244
+ },
245
+ tooltip: {
246
+ theme: 'light',
247
+ y: {
248
+ formatter: function formatter(value) {
249
+ return metric === 'Revenue' ? "$".concat(value) : value;
250
+ }
251
+ }
252
+ },
253
+ legend: {
254
+ show: stacked,
255
+ position: 'top',
256
+ horizontalAlign: 'left'
257
+ }
258
+ };
259
+ var chartSeries = series || [{
260
+ name: metric,
261
+ data: data
262
+ }];
263
+ return /*#__PURE__*/React.createElement(Chart, {
264
+ options: chartOptions,
265
+ series: chartSeries,
266
+ type: "area",
267
+ height: height,
268
+ width: "100%"
269
+ });
270
+ };
271
+
272
+ var Dashboard = function Dashboard(_ref) {
273
+ var _ref$title = _ref.title,
274
+ title = _ref$title === void 0 ? "Overview" : _ref$title,
275
+ _ref$initialMetric = _ref.initialMetric,
276
+ initialMetric = _ref$initialMetric === void 0 ? 'Revenue' : _ref$initialMetric,
277
+ _ref$revenueData = _ref.revenueData,
278
+ revenueData = _ref$revenueData === void 0 ? [3000, 4500, 4200, 5800, 5200, 7100, 8500, 9200, 5000] : _ref$revenueData,
279
+ _ref$donationsData = _ref.donationsData,
280
+ donationsData = _ref$donationsData === void 0 ? [15, 22, 18, 30, 25, 35, 42, 45, 28] : _ref$donationsData,
281
+ _ref$categories = _ref.categories,
282
+ categories = _ref$categories === void 0 ? ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'] : _ref$categories;
283
+ var _React$useState = React.useState(initialMetric),
284
+ _React$useState2 = _slicedToArray(_React$useState, 2),
285
+ metric = _React$useState2[0],
286
+ setMetric = _React$useState2[1];
287
+ var currentData = metric === 'Revenue' ? revenueData : donationsData;
288
+ var primaryCharts = [{
289
+ label: 'Total Revenue',
290
+ value: '$9,200.00',
291
+ subValue: 'Total Donations: 215',
292
+ data: currentData,
293
+ categories: categories,
294
+ showSelector: true
295
+ }, {
296
+ label: 'First installments',
297
+ value: '$510.00',
298
+ data: currentData.slice(-7),
299
+ categories: categories.slice(-7)
300
+ }, {
301
+ label: 'One-time donations',
302
+ value: '$7,100.00',
303
+ data: currentData,
304
+ categories: categories
305
+ }];
306
+ var secondaryCharts = [{
307
+ label: 'New vs Returning Donors',
308
+ series: [{
309
+ name: 'New Donors',
310
+ data: [10, 15, 12, 20, 18, 25, 30, 35, 20]
311
+ }, {
312
+ name: 'Returning',
313
+ data: [5, 7, 6, 10, 7, 10, 12, 10, 8]
314
+ }],
315
+ categories: categories,
316
+ stacked: true,
317
+ footer: {
318
+ left: 'New donors: 195',
319
+ right: 'Returning donors: 20'
320
+ }
321
+ }, {
322
+ label: 'Average Donation Amount',
323
+ value: '$42.80',
324
+ data: currentData.map(function (v) {
325
+ return v * 0.5;
326
+ }),
327
+ categories: categories
328
+ }, {
329
+ label: 'Tip Amount',
330
+ value: '$1,250.00',
331
+ subValue: 'Number of Tips: 110',
332
+ data: currentData.map(function (v) {
333
+ return v * 0.2;
334
+ }),
335
+ categories: categories
336
+ }];
337
+ var tertiaryCharts = [{
338
+ label: 'Conversion Rate',
339
+ value: '2%',
340
+ data: [1.5, 1.8, 1.7, 2.1, 2.0, 1.9, 2.2, 2.5, 2.0],
341
+ categories: categories
342
+ }, {
343
+ label: 'Organic vs Paid Traffic',
344
+ series: [{
345
+ name: 'Organic',
346
+ data: [500, 600, 550, 700, 800, 750, 900, 1000, 950]
347
+ }, {
348
+ name: 'Paid',
349
+ data: [200, 250, 220, 300, 350, 320, 400, 450, 420]
350
+ }],
351
+ categories: categories,
352
+ stacked: true
353
+ }, {
354
+ label: 'Organic Donations',
355
+ value: '120',
356
+ data: [8, 12, 10, 15, 14, 18, 22, 20, 12],
357
+ categories: categories
358
+ }];
359
+ var quaternaryCharts = [{
360
+ label: 'Email Marketing',
361
+ value: '56',
362
+ data: [45, 48, 52, 50, 56, 54, 58, 60, 56],
363
+ categories: categories
364
+ }, {
365
+ label: 'Traffic source',
366
+ value: '23%',
367
+ data: [18, 22, 20, 25, 23, 21, 24, 26, 23],
368
+ categories: categories
369
+ }, {
370
+ label: 'URL',
371
+ value: '10%',
372
+ data: [8, 9, 11, 10, 10, 12, 9, 11, 10],
373
+ categories: categories
374
+ }];
375
+ var renderChartCard = function renderChartCard(item, index) {
376
+ var isPrimary = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
377
+ return /*#__PURE__*/React.createElement(material.Grid, {
378
+ item: true,
379
+ xs: 12,
380
+ md: 4,
381
+ key: item.label + index,
382
+ sx: {
383
+ display: 'flex'
384
+ }
385
+ }, /*#__PURE__*/React.createElement(material.Card, {
386
+ sx: {
387
+ width: '100%',
388
+ display: 'flex',
389
+ flexDirection: 'column',
390
+ boxShadow: '0 4px 24px rgba(0,0,0,0.06)',
391
+ borderRadius: 4,
392
+ border: '1px solid #f0f0f0'
393
+ }
394
+ }, /*#__PURE__*/React.createElement(material.CardContent, {
395
+ sx: {
396
+ p: 3,
397
+ flexGrow: 1,
398
+ display: 'flex',
399
+ flexDirection: 'column'
400
+ }
401
+ }, /*#__PURE__*/React.createElement(material.Box, {
402
+ sx: {
403
+ display: 'flex',
404
+ justifyContent: 'space-between',
405
+ alignItems: 'flex-start',
406
+ mb: 2
407
+ }
408
+ }, /*#__PURE__*/React.createElement(material.Box, {
409
+ sx: {
410
+ textAlign: 'left'
411
+ }
412
+ }, /*#__PURE__*/React.createElement(material.Typography, {
413
+ variant: "subtitle2",
414
+ sx: {
415
+ color: '#000000',
416
+ fontWeight: 600,
417
+ textTransform: 'uppercase',
418
+ letterSpacing: '0.5px',
419
+ mb: 0.5
420
+ }
421
+ }, item.label), item.value && /*#__PURE__*/React.createElement(material.Typography, {
422
+ variant: "subtitle2",
423
+ sx: {
424
+ fontWeight: 600,
425
+ color: '#000000',
426
+ mb: 0.5
427
+ }
428
+ }, item.value), item.subValue && /*#__PURE__*/React.createElement(material.Typography, {
429
+ variant: "subtitle2",
430
+ sx: {
431
+ color: '#000000',
432
+ fontWeight: 600
433
+ }
434
+ }, item.subValue)), /*#__PURE__*/React.createElement(material.Box, {
435
+ sx: {
436
+ display: 'flex',
437
+ gap: 1
438
+ }
439
+ }, item.showSelector && /*#__PURE__*/React.createElement(MetricSelector, {
440
+ metric: metric,
441
+ onMetricChange: setMetric,
442
+ options: ['Revenue', 'Donations']
443
+ }), /*#__PURE__*/React.createElement(material.IconButton, {
444
+ sx: {
445
+ border: '1px solid #E9E9EB',
446
+ borderRadius: '8px',
447
+ color: '#000',
448
+ height: '40px',
449
+ width: '40px',
450
+ '&:hover': {
451
+ borderColor: 'primary.main',
452
+ bgcolor: 'rgba(99, 99, 230, 0.04)'
453
+ }
454
+ }
455
+ }, /*#__PURE__*/React.createElement(iconsMaterial.MoreHoriz, {
456
+ sx: {
457
+ fontSize: '1.2rem'
458
+ }
459
+ })))), /*#__PURE__*/React.createElement(material.Box, {
460
+ sx: {
461
+ flexGrow: 1,
462
+ minHeight: isPrimary ? '250px' : '200px'
463
+ }
464
+ }, /*#__PURE__*/React.createElement(RevenueChart, {
465
+ metric: item.label.includes('Rate') || item.label.includes('Performance') || item.label.includes('source') || item.label === 'URL' ? 'Percent' : item.stacked ? item.label.includes('Traffic') ? 'Visitors' : 'Donors' : metric,
466
+ data: item.data,
467
+ series: item.series,
468
+ categories: item.categories,
469
+ height: isPrimary ? 250 : 200,
470
+ stacked: item.stacked
471
+ })), item.footer && /*#__PURE__*/React.createElement(material.Box, {
472
+ sx: {
473
+ display: 'flex',
474
+ justifyContent: 'space-between',
475
+ mt: 2,
476
+ pt: 2,
477
+ borderTop: '1px solid #f0f0f0'
478
+ }
479
+ }, /*#__PURE__*/React.createElement(material.Typography, {
480
+ variant: "caption",
481
+ sx: {
482
+ color: '#606062',
483
+ fontWeight: 600
484
+ }
485
+ }, item.footer.left), /*#__PURE__*/React.createElement(material.Typography, {
486
+ variant: "caption",
487
+ sx: {
488
+ color: '#606062',
489
+ fontWeight: 600
490
+ }
491
+ }, item.footer.right)))));
492
+ };
493
+ return /*#__PURE__*/React.createElement(material.ThemeProvider, {
494
+ theme: theme
495
+ }, /*#__PURE__*/React.createElement(material.Box, {
496
+ sx: {
497
+ p: 4,
498
+ bgcolor: 'primary.mainLight',
499
+ minHeight: '100vh',
500
+ display: 'flex',
501
+ flexDirection: 'column',
502
+ alignItems: 'stretch'
503
+ }
504
+ }, /*#__PURE__*/React.createElement(material.Typography, {
505
+ variant: "h4",
506
+ gutterBottom: true,
507
+ sx: {
508
+ fontWeight: 'bold',
509
+ color: 'primary.main',
510
+ mb: 4
511
+ }
512
+ }, title), /*#__PURE__*/React.createElement(material.Grid, {
513
+ container: true,
514
+ spacing: 3,
515
+ sx: {
516
+ mb: 1
517
+ }
518
+ }, primaryCharts.map(function (item, index) {
519
+ return renderChartCard(item, index, true);
520
+ })), /*#__PURE__*/React.createElement(material.Grid, {
521
+ container: true,
522
+ spacing: 3,
523
+ sx: {
524
+ mt: 1
525
+ }
526
+ }, secondaryCharts.map(function (item, index) {
527
+ return renderChartCard(item, index, false);
528
+ })), /*#__PURE__*/React.createElement(material.Grid, {
529
+ container: true,
530
+ spacing: 3,
531
+ sx: {
532
+ mt: 1
533
+ }
534
+ }, tertiaryCharts.map(function (item, index) {
535
+ return renderChartCard(item, index, false);
536
+ })), /*#__PURE__*/React.createElement(material.Grid, {
537
+ container: true,
538
+ spacing: 3,
539
+ sx: {
540
+ mt: 1
541
+ }
542
+ }, quaternaryCharts.map(function (item, index) {
543
+ return renderChartCard(item, index, false);
544
+ }))));
545
+ };
546
+
547
+ /**
548
+ * Theme colors for server components
549
+ *
550
+ * These are plain JavaScript objects that can be safely imported
551
+ * in both server and client components without triggering
552
+ * client-only code in server components.
553
+ *
554
+ * For client components, use the full theme from @/config/customTheme
555
+ */
556
+
557
+ var themeColors = {
558
+ primary: {
559
+ main: "#6363E6",
560
+ mainLight: "#F7F7FF",
561
+ light: "#FFFFFF",
562
+ gray: "#A1A1A8",
563
+ lightGreen: "#E1FBF2",
564
+ green: "#0CAB72",
565
+ red: "#E61D1D",
566
+ lightRed: "#FFEDED",
567
+ lightGray: "#E9E9EB",
568
+ darkGray: "#606062",
569
+ dark: "#090909"
570
+ },
571
+ text: {
572
+ primary: "#666666"
573
+ },
574
+ secondary: {
575
+ main: "#E0C2FF",
576
+ light: "#F5EBFF",
577
+ contrastText: "#47008F"
578
+ },
579
+ white: {
580
+ main: "#FFFFFF",
581
+ light: "#F8F8F8"
582
+ },
583
+ gradients: {
584
+ primary: "linear-gradient(90deg, #6363E6 0.05%, #59C9F9 99.96%)",
585
+ secondary: "linear-gradient(180deg, #E9E9FF 0%, #C9EEFF 100%)"
586
+ }
587
+ };
588
+
589
+ // Typography settings for server components
590
+ var themeTypography = {
591
+ fontFamily: ["var(--font-league-spartan)", "var(--font-noto-sans-arabic)", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"].join(",")
592
+ };
593
+
594
+ exports.Dashboard = Dashboard;
595
+ exports.DashboardTheme = theme;
596
+ exports.MetricSelector = MetricSelector;
597
+ exports.RevenueChart = RevenueChart;
598
+ exports.themeColors = themeColors;
599
+ exports.themeTypography = themeTypography;
600
+ //# sourceMappingURL=index.cjs.js.map