adminator-admin-dashboard 2.7.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.
Files changed (191) hide show
  1. package/CLAUDE.md +162 -0
  2. package/LICENSE +21 -0
  3. package/README.md +376 -0
  4. package/RELEASE_NOTES.md +92 -0
  5. package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
  6. package/dist/20fd1704ea223900efa9.woff2 +0 -0
  7. package/dist/29b39089170885ae2967.woff +0 -0
  8. package/dist/404.html +24 -0
  9. package/dist/500.html +24 -0
  10. package/dist/55b07f26c86c8e3d3754.svg +1 -0
  11. package/dist/8b43027f47b20503057d.eot +0 -0
  12. package/dist/9bad94440d49256265a5.eot +0 -0
  13. package/dist/9fad440d8ee7a949a9a9.svg +1 -0
  14. package/dist/assets/c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg +2671 -0
  15. package/dist/assets/f0fc8c798eac5636249c4ea287832422.svg +362 -0
  16. package/dist/assets/static/fonts/icons/fontawesome/FontAwesome.otf +0 -0
  17. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.eot +0 -0
  18. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.svg +2671 -0
  19. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.ttf +0 -0
  20. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff +0 -0
  21. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff2 +0 -0
  22. package/dist/assets/static/fonts/icons/themify/themify.eot +0 -0
  23. package/dist/assets/static/fonts/icons/themify/themify.svg +362 -0
  24. package/dist/assets/static/fonts/icons/themify/themify.ttf +0 -0
  25. package/dist/assets/static/fonts/icons/themify/themify.woff +0 -0
  26. package/dist/assets/static/images/404.png +0 -0
  27. package/dist/assets/static/images/500.png +0 -0
  28. package/dist/assets/static/images/bg.jpg +0 -0
  29. package/dist/assets/static/images/datatables/sort_asc.png +0 -0
  30. package/dist/assets/static/images/datatables/sort_asc_disabled.png +0 -0
  31. package/dist/assets/static/images/datatables/sort_both.png +0 -0
  32. package/dist/assets/static/images/datatables/sort_desc.png +0 -0
  33. package/dist/assets/static/images/datatables/sort_desc_disabled.png +0 -0
  34. package/dist/assets/static/images/logo-circle.svg +7 -0
  35. package/dist/assets/static/images/logo-gradient.svg +13 -0
  36. package/dist/assets/static/images/logo-outline.svg +7 -0
  37. package/dist/assets/static/images/logo.png +0 -0
  38. package/dist/assets/static/images/logo.svg +5 -0
  39. package/dist/basic-table.html +715 -0
  40. package/dist/blank.html +522 -0
  41. package/dist/buttons.html +467 -0
  42. package/dist/calendar.html +692 -0
  43. package/dist/charts.html +681 -0
  44. package/dist/chat.html +730 -0
  45. package/dist/compose.html +643 -0
  46. package/dist/datatable.html +1009 -0
  47. package/dist/eda8b94308c6f538f04a.ttf +0 -0
  48. package/dist/email.html +992 -0
  49. package/dist/f691f37e57f04c152e23.woff +0 -0
  50. package/dist/forms.html +760 -0
  51. package/dist/google-maps.html +530 -0
  52. package/dist/index.html +1090 -0
  53. package/dist/main.js +61239 -0
  54. package/dist/main.js.map +1 -0
  55. package/dist/signin.html +107 -0
  56. package/dist/signup.html +104 -0
  57. package/dist/test.html +91 -0
  58. package/dist/ui.html +931 -0
  59. package/dist/vector-maps.html +529 -0
  60. package/package.json +112 -0
  61. package/src/404.html +24 -0
  62. package/src/500.html +24 -0
  63. package/src/assets/scripts/app.js +644 -0
  64. package/src/assets/scripts/charts/chartJS/index.js +148 -0
  65. package/src/assets/scripts/charts/easyPieChart/index.js +200 -0
  66. package/src/assets/scripts/charts/index.js +3 -0
  67. package/src/assets/scripts/charts/sparkline/index.js +208 -0
  68. package/src/assets/scripts/chat/index.js +11 -0
  69. package/src/assets/scripts/components/Chart.js +1390 -0
  70. package/src/assets/scripts/components/Sidebar.js +241 -0
  71. package/src/assets/scripts/constants/colors.js +274 -0
  72. package/src/assets/scripts/datatable/index.js +379 -0
  73. package/src/assets/scripts/datepicker/index.js +302 -0
  74. package/src/assets/scripts/email/index.js +25 -0
  75. package/src/assets/scripts/fullcalendar/index.js +86 -0
  76. package/src/assets/scripts/googleMaps/index.js +93 -0
  77. package/src/assets/scripts/index.js +18 -0
  78. package/src/assets/scripts/masonry/index.js +14 -0
  79. package/src/assets/scripts/popover/index.js +109 -0
  80. package/src/assets/scripts/scrollbar/index.js +10 -0
  81. package/src/assets/scripts/search/index.js +15 -0
  82. package/src/assets/scripts/sidebar/index.js +140 -0
  83. package/src/assets/scripts/skycons/index.js +52 -0
  84. package/src/assets/scripts/ui/index.js +412 -0
  85. package/src/assets/scripts/utils/date.js +242 -0
  86. package/src/assets/scripts/utils/dom.js +349 -0
  87. package/src/assets/scripts/utils/index.js +45 -0
  88. package/src/assets/scripts/utils/theme.js +105 -0
  89. package/src/assets/scripts/vectorMaps/index.js +277 -0
  90. package/src/assets/static/fonts/icons/fontawesome/FontAwesome.otf +0 -0
  91. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.eot +0 -0
  92. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.svg +2671 -0
  93. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.ttf +0 -0
  94. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff +0 -0
  95. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff2 +0 -0
  96. package/src/assets/static/fonts/icons/themify/themify.eot +0 -0
  97. package/src/assets/static/fonts/icons/themify/themify.svg +362 -0
  98. package/src/assets/static/fonts/icons/themify/themify.ttf +0 -0
  99. package/src/assets/static/fonts/icons/themify/themify.woff +0 -0
  100. package/src/assets/static/images/404.png +0 -0
  101. package/src/assets/static/images/500.png +0 -0
  102. package/src/assets/static/images/bg.jpg +0 -0
  103. package/src/assets/static/images/datatables/sort_asc.png +0 -0
  104. package/src/assets/static/images/datatables/sort_asc_disabled.png +0 -0
  105. package/src/assets/static/images/datatables/sort_both.png +0 -0
  106. package/src/assets/static/images/datatables/sort_desc.png +0 -0
  107. package/src/assets/static/images/datatables/sort_desc_disabled.png +0 -0
  108. package/src/assets/static/images/logo-circle.svg +7 -0
  109. package/src/assets/static/images/logo-gradient.svg +13 -0
  110. package/src/assets/static/images/logo-outline.svg +7 -0
  111. package/src/assets/static/images/logo.png +0 -0
  112. package/src/assets/static/images/logo.svg +5 -0
  113. package/src/assets/styles/index.scss +801 -0
  114. package/src/assets/styles/spec/components/easyPieChart.scss +11 -0
  115. package/src/assets/styles/spec/components/footer.scss +4 -0
  116. package/src/assets/styles/spec/components/forms.scss +288 -0
  117. package/src/assets/styles/spec/components/index.scss +9 -0
  118. package/src/assets/styles/spec/components/loader.scss +46 -0
  119. package/src/assets/styles/spec/components/masonry.scss +1 -0
  120. package/src/assets/styles/spec/components/pageContainer.scss +255 -0
  121. package/src/assets/styles/spec/components/progressBar.scss +6 -0
  122. package/src/assets/styles/spec/components/sidebar.scss +642 -0
  123. package/src/assets/styles/spec/components/topbar.scss +455 -0
  124. package/src/assets/styles/spec/generic/base.scss +102 -0
  125. package/src/assets/styles/spec/generic/index.scss +1 -0
  126. package/src/assets/styles/spec/index.scss +4 -0
  127. package/src/assets/styles/spec/screens/chat.scss +147 -0
  128. package/src/assets/styles/spec/screens/email.scss +108 -0
  129. package/src/assets/styles/spec/screens/index.scss +2 -0
  130. package/src/assets/styles/spec/settings/baseColors.scss +103 -0
  131. package/src/assets/styles/spec/settings/borders.scss +6 -0
  132. package/src/assets/styles/spec/settings/breakpoints.scss +26 -0
  133. package/src/assets/styles/spec/settings/fonts.scss +4 -0
  134. package/src/assets/styles/spec/settings/index.scss +4 -0
  135. package/src/assets/styles/spec/settings/materialColors.scss +550 -0
  136. package/src/assets/styles/spec/tools/index.scss +1 -0
  137. package/src/assets/styles/spec/tools/mixins/clearfix.scss +15 -0
  138. package/src/assets/styles/spec/tools/mixins/index.scss +3 -0
  139. package/src/assets/styles/spec/tools/mixins/mediaQueriesRanges.scss +58 -0
  140. package/src/assets/styles/spec/tools/mixins/placeholder.scss +10 -0
  141. package/src/assets/styles/spec/utils/colors.scss +33 -0
  142. package/src/assets/styles/spec/utils/index.scss +2 -0
  143. package/src/assets/styles/spec/utils/layout/helpers/border.scss +78 -0
  144. package/src/assets/styles/spec/utils/layout/helpers/flex.scss +220 -0
  145. package/src/assets/styles/spec/utils/layout/helpers/index.scss +11 -0
  146. package/src/assets/styles/spec/utils/layout/helpers/layout.scss +137 -0
  147. package/src/assets/styles/spec/utils/layout/helpers/lists.scss +23 -0
  148. package/src/assets/styles/spec/utils/layout/helpers/margin.scss +266 -0
  149. package/src/assets/styles/spec/utils/layout/helpers/objects.scss +91 -0
  150. package/src/assets/styles/spec/utils/layout/helpers/padding.scss +147 -0
  151. package/src/assets/styles/spec/utils/layout/helpers/positions.scss +118 -0
  152. package/src/assets/styles/spec/utils/layout/helpers/pseudo.scss +6 -0
  153. package/src/assets/styles/spec/utils/layout/helpers/sizes.scss +157 -0
  154. package/src/assets/styles/spec/utils/layout/helpers/typography.scss +127 -0
  155. package/src/assets/styles/spec/utils/layout/index.scss +3 -0
  156. package/src/assets/styles/spec/utils/layout/mixins/generateResponsive.scss +25 -0
  157. package/src/assets/styles/spec/utils/layout/mixins/index.scss +2 -0
  158. package/src/assets/styles/spec/utils/layout/mixins/mediaQueryCondition.scss +28 -0
  159. package/src/assets/styles/spec/utils/layout/utils/center.scss +54 -0
  160. package/src/assets/styles/spec/utils/layout/utils/gap.scss +229 -0
  161. package/src/assets/styles/spec/utils/layout/utils/index.scss +5 -0
  162. package/src/assets/styles/spec/utils/layout/utils/layers.scss +5 -0
  163. package/src/assets/styles/spec/utils/layout/utils/peers.scss +35 -0
  164. package/src/assets/styles/utils/mobile.scss +954 -0
  165. package/src/assets/styles/utils/theme.css +97 -0
  166. package/src/assets/styles/vendor/datepicker.scss +183 -0
  167. package/src/assets/styles/vendor/font-awesome.css +2337 -0
  168. package/src/assets/styles/vendor/fullcalendar.scss +217 -0
  169. package/src/assets/styles/vendor/index.scss +8 -0
  170. package/src/assets/styles/vendor/jquery.datatables.scss +162 -0
  171. package/src/assets/styles/vendor/perfectScrollbar.scss +4 -0
  172. package/src/assets/styles/vendor/sparkline.scss +6 -0
  173. package/src/assets/styles/vendor/themify-icons.css +1081 -0
  174. package/src/basic-table.html +725 -0
  175. package/src/blank.html +532 -0
  176. package/src/buttons.html +477 -0
  177. package/src/calendar.html +702 -0
  178. package/src/charts.html +691 -0
  179. package/src/chat.html +740 -0
  180. package/src/compose.html +653 -0
  181. package/src/datatable.html +1019 -0
  182. package/src/email.html +1002 -0
  183. package/src/forms.html +770 -0
  184. package/src/google-maps.html +540 -0
  185. package/src/index.html +1100 -0
  186. package/src/signin.html +107 -0
  187. package/src/signup.html +104 -0
  188. package/src/test.html +96 -0
  189. package/src/ui.html +941 -0
  190. package/src/vector-maps.html +539 -0
  191. package/webpack.config.js +3 -0
@@ -0,0 +1,412 @@
1
+ /**
2
+ * UI Page Bootstrap Components
3
+ * Vanilla JavaScript implementations for Bootstrap components
4
+ */
5
+
6
+ export default (function () {
7
+
8
+ // Modal functionality
9
+ class VanillaModal {
10
+ constructor(element) {
11
+ this.element = element;
12
+ this.modal = null;
13
+ this.backdrop = null;
14
+ this.isOpen = false;
15
+ this.init();
16
+ }
17
+
18
+ init() {
19
+ this.modal = document.querySelector(this.element.getAttribute('data-bs-target'));
20
+ if (this.modal) {
21
+ this.element.addEventListener('click', (e) => {
22
+ e.preventDefault();
23
+ this.show();
24
+ });
25
+
26
+ // Close button functionality
27
+ const closeButtons = this.modal.querySelectorAll('[data-bs-dismiss="modal"]');
28
+ closeButtons.forEach(btn => {
29
+ btn.addEventListener('click', () => this.hide());
30
+ });
31
+
32
+ // Close on backdrop click
33
+ this.modal.addEventListener('click', (e) => {
34
+ if (e.target === this.modal) {
35
+ this.hide();
36
+ }
37
+ });
38
+ }
39
+ }
40
+
41
+ show() {
42
+ if (this.isOpen) return;
43
+
44
+ // Create backdrop
45
+ this.backdrop = document.createElement('div');
46
+ this.backdrop.className = 'modal-backdrop fade show';
47
+ document.body.appendChild(this.backdrop);
48
+
49
+ // Show modal
50
+ this.modal.style.display = 'block';
51
+ this.modal.classList.add('show');
52
+ document.body.classList.add('modal-open');
53
+
54
+ this.isOpen = true;
55
+
56
+ // Focus the modal
57
+ this.modal.setAttribute('tabindex', '-1');
58
+ this.modal.focus();
59
+
60
+ // Escape key handler
61
+ this.escapeHandler = (e) => {
62
+ if (e.key === 'Escape') {
63
+ this.hide();
64
+ }
65
+ };
66
+ document.addEventListener('keydown', this.escapeHandler);
67
+ }
68
+
69
+ hide() {
70
+ if (!this.isOpen) return;
71
+
72
+ // Hide modal
73
+ this.modal.classList.remove('show');
74
+ this.modal.style.display = 'none';
75
+ document.body.classList.remove('modal-open');
76
+
77
+ // Remove backdrop
78
+ if (this.backdrop) {
79
+ this.backdrop.remove();
80
+ this.backdrop = null;
81
+ }
82
+
83
+ this.isOpen = false;
84
+
85
+ // Remove escape handler
86
+ if (this.escapeHandler) {
87
+ document.removeEventListener('keydown', this.escapeHandler);
88
+ this.escapeHandler = null;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Dropdown functionality
94
+ class VanillaDropdown {
95
+ constructor(element) {
96
+ this.element = element;
97
+ this.menu = null;
98
+ this.isOpen = false;
99
+ this.init();
100
+ }
101
+
102
+ init() {
103
+ this.menu = this.element.parentNode.querySelector('.dropdown-menu');
104
+ if (this.menu) {
105
+ this.element.addEventListener('click', (e) => {
106
+ e.preventDefault();
107
+ e.stopPropagation();
108
+ this.toggle();
109
+ });
110
+
111
+ // Close on outside click
112
+ document.addEventListener('click', (e) => {
113
+ if (!this.element.parentNode.contains(e.target)) {
114
+ this.hide();
115
+ }
116
+ });
117
+
118
+ // Close on escape
119
+ document.addEventListener('keydown', (e) => {
120
+ if (e.key === 'Escape' && this.isOpen) {
121
+ this.hide();
122
+ }
123
+ });
124
+ }
125
+ }
126
+
127
+ toggle() {
128
+ if (this.isOpen) {
129
+ this.hide();
130
+ } else {
131
+ this.show();
132
+ }
133
+ }
134
+
135
+ show() {
136
+ if (this.isOpen) return;
137
+
138
+ // Close other dropdowns
139
+ document.querySelectorAll('.dropdown-menu.show').forEach(menu => {
140
+ menu.classList.remove('show');
141
+ });
142
+
143
+ this.menu.classList.add('show');
144
+ this.element.setAttribute('aria-expanded', 'true');
145
+ this.isOpen = true;
146
+ }
147
+
148
+ hide() {
149
+ if (!this.isOpen) return;
150
+
151
+ this.menu.classList.remove('show');
152
+ this.element.setAttribute('aria-expanded', 'false');
153
+ this.isOpen = false;
154
+ }
155
+ }
156
+
157
+ // Popover functionality
158
+ class VanillaPopover {
159
+ constructor(element) {
160
+ this.element = element;
161
+ this.popover = null;
162
+ this.isOpen = false;
163
+ this.init();
164
+ }
165
+
166
+ init() {
167
+ this.element.addEventListener('click', (e) => {
168
+ e.preventDefault();
169
+ this.toggle();
170
+ });
171
+
172
+ // Close on outside click
173
+ document.addEventListener('click', (e) => {
174
+ if (!this.element.contains(e.target) && (!this.popover || !this.popover.contains(e.target))) {
175
+ this.hide();
176
+ }
177
+ });
178
+ }
179
+
180
+ toggle() {
181
+ if (this.isOpen) {
182
+ this.hide();
183
+ } else {
184
+ this.show();
185
+ }
186
+ }
187
+
188
+ show() {
189
+ if (this.isOpen) return;
190
+
191
+ // Close other popovers
192
+ document.querySelectorAll('.popover').forEach(popover => {
193
+ popover.remove();
194
+ });
195
+
196
+ const title = this.element.getAttribute('title') || this.element.getAttribute('data-bs-title');
197
+ const content = this.element.getAttribute('data-bs-content');
198
+
199
+ this.popover = document.createElement('div');
200
+ this.popover.className = 'popover bs-popover-top show';
201
+ this.popover.style.position = 'absolute';
202
+ this.popover.style.zIndex = '1070';
203
+ this.popover.style.maxWidth = '276px';
204
+ this.popover.style.backgroundColor = '#fff';
205
+ this.popover.style.border = '1px solid rgba(0,0,0,.2)';
206
+ this.popover.style.borderRadius = '6px';
207
+ this.popover.style.boxShadow = '0 5px 10px rgba(0,0,0,.2)';
208
+
209
+ let popoverContent = '';
210
+ if (title) {
211
+ popoverContent += `<div class="popover-header" style="padding: 8px 14px; margin-bottom: 0; font-size: 14px; background-color: #f7f7f7; border-bottom: 1px solid #ebebeb; border-radius: 5px 5px 0 0; font-weight: 600;">${title}</div>`;
212
+ }
213
+ popoverContent += `<div class="popover-body" style="padding: 9px 14px; word-wrap: break-word;">${content}</div>`;
214
+
215
+ this.popover.innerHTML = popoverContent;
216
+ document.body.appendChild(this.popover);
217
+
218
+ // Position popover
219
+ const rect = this.element.getBoundingClientRect();
220
+ this.popover.style.left = `${rect.left + (rect.width / 2) - (this.popover.offsetWidth / 2)}px`;
221
+ this.popover.style.top = `${rect.top - this.popover.offsetHeight - 10}px`;
222
+
223
+ this.isOpen = true;
224
+ }
225
+
226
+ hide() {
227
+ if (!this.isOpen) return;
228
+
229
+ if (this.popover) {
230
+ this.popover.remove();
231
+ this.popover = null;
232
+ }
233
+ this.isOpen = false;
234
+ }
235
+ }
236
+
237
+ // Tooltip functionality
238
+ class VanillaTooltip {
239
+ constructor(element) {
240
+ this.element = element;
241
+ this.tooltip = null;
242
+ this.init();
243
+ }
244
+
245
+ init() {
246
+ this.element.addEventListener('mouseenter', () => this.show());
247
+ this.element.addEventListener('mouseleave', () => this.hide());
248
+ this.element.addEventListener('focus', () => this.show());
249
+ this.element.addEventListener('blur', () => this.hide());
250
+ }
251
+
252
+ show() {
253
+ if (this.tooltip) return;
254
+
255
+ const title = this.element.getAttribute('title') || this.element.getAttribute('data-bs-title');
256
+ const placement = this.element.getAttribute('data-bs-placement') || 'top';
257
+
258
+ if (!title) return;
259
+
260
+ this.tooltip = document.createElement('div');
261
+ this.tooltip.className = `tooltip bs-tooltip-${placement} show`;
262
+ this.tooltip.style.position = 'absolute';
263
+ this.tooltip.style.zIndex = '1070';
264
+ this.tooltip.style.maxWidth = '200px';
265
+ this.tooltip.style.padding = '4px 8px';
266
+ this.tooltip.style.fontSize = '12px';
267
+ this.tooltip.style.backgroundColor = '#000';
268
+ this.tooltip.style.color = '#fff';
269
+ this.tooltip.style.borderRadius = '4px';
270
+ this.tooltip.style.pointerEvents = 'none';
271
+ this.tooltip.style.whiteSpace = 'nowrap';
272
+
273
+ this.tooltip.innerHTML = `<div class="tooltip-inner">${title}</div>`;
274
+ document.body.appendChild(this.tooltip);
275
+
276
+ // Position tooltip
277
+ const rect = this.element.getBoundingClientRect();
278
+
279
+ switch (placement) {
280
+ case 'top':
281
+ this.tooltip.style.left = `${rect.left + (rect.width / 2) - (this.tooltip.offsetWidth / 2)}px`;
282
+ this.tooltip.style.top = `${rect.top - this.tooltip.offsetHeight - 5}px`;
283
+ break;
284
+ case 'bottom':
285
+ this.tooltip.style.left = `${rect.left + (rect.width / 2) - (this.tooltip.offsetWidth / 2)}px`;
286
+ this.tooltip.style.top = `${rect.bottom + 5}px`;
287
+ break;
288
+ case 'left':
289
+ this.tooltip.style.left = `${rect.left - this.tooltip.offsetWidth - 5}px`;
290
+ this.tooltip.style.top = `${rect.top + (rect.height / 2) - (this.tooltip.offsetHeight / 2)}px`;
291
+ break;
292
+ case 'right':
293
+ this.tooltip.style.left = `${rect.right + 5}px`;
294
+ this.tooltip.style.top = `${rect.top + (rect.height / 2) - (this.tooltip.offsetHeight / 2)}px`;
295
+ break;
296
+ }
297
+ }
298
+
299
+ hide() {
300
+ if (this.tooltip) {
301
+ this.tooltip.remove();
302
+ this.tooltip = null;
303
+ }
304
+ }
305
+ }
306
+
307
+ // Accordion functionality
308
+ class VanillaAccordion {
309
+ constructor(element) {
310
+ this.element = element;
311
+ this.accordion = element.closest('.accordion');
312
+ this.target = document.querySelector(element.getAttribute('data-bs-target'));
313
+ this.isOpen = !element.classList.contains('collapsed');
314
+ this.init();
315
+ }
316
+
317
+ init() {
318
+ this.element.addEventListener('click', (e) => {
319
+ e.preventDefault();
320
+ this.toggle();
321
+ });
322
+ }
323
+
324
+ toggle() {
325
+ if (this.isOpen) {
326
+ this.hide();
327
+ } else {
328
+ this.show();
329
+ }
330
+ }
331
+
332
+ show() {
333
+ if (this.isOpen) return;
334
+
335
+ // Close other accordion items in the same parent
336
+ const parentAccordion = this.accordion;
337
+ if (parentAccordion) {
338
+ const otherItems = parentAccordion.querySelectorAll('.accordion-collapse.show');
339
+ otherItems.forEach(item => {
340
+ if (item !== this.target) {
341
+ item.classList.remove('show');
342
+ const button = parentAccordion.querySelector(`[data-bs-target="#${item.id}"]`);
343
+ if (button) {
344
+ button.classList.add('collapsed');
345
+ button.setAttribute('aria-expanded', 'false');
346
+ }
347
+ }
348
+ });
349
+ }
350
+
351
+ // Show this item
352
+ this.target.classList.add('show');
353
+ this.element.classList.remove('collapsed');
354
+ this.element.setAttribute('aria-expanded', 'true');
355
+ this.isOpen = true;
356
+ }
357
+
358
+ hide() {
359
+ if (!this.isOpen) return;
360
+
361
+ this.target.classList.remove('show');
362
+ this.element.classList.add('collapsed');
363
+ this.element.setAttribute('aria-expanded', 'false');
364
+ this.isOpen = false;
365
+ }
366
+ }
367
+
368
+ // Initialize all components
369
+ const initComponents = () => {
370
+ // Initialize modals
371
+ document.querySelectorAll('[data-bs-toggle="modal"]').forEach(element => {
372
+ new VanillaModal(element);
373
+ });
374
+
375
+ // Initialize dropdowns
376
+ document.querySelectorAll('[data-bs-toggle="dropdown"]').forEach(element => {
377
+ new VanillaDropdown(element);
378
+ });
379
+
380
+ // Initialize popovers
381
+ document.querySelectorAll('[data-bs-toggle="popover"]').forEach(element => {
382
+ new VanillaPopover(element);
383
+ });
384
+
385
+ // Initialize tooltips
386
+ document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(element => {
387
+ new VanillaTooltip(element);
388
+ });
389
+
390
+ // Initialize accordions
391
+ document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(element => {
392
+ new VanillaAccordion(element);
393
+ });
394
+ };
395
+
396
+ // Initialize when DOM is ready
397
+ if (document.readyState === 'loading') {
398
+ document.addEventListener('DOMContentLoaded', initComponents);
399
+ } else {
400
+ initComponents();
401
+ }
402
+
403
+ // Public API
404
+ return {
405
+ init: initComponents,
406
+ Modal: VanillaModal,
407
+ Dropdown: VanillaDropdown,
408
+ Popover: VanillaPopover,
409
+ Tooltip: VanillaTooltip,
410
+ Accordion: VanillaAccordion,
411
+ };
412
+ }());
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Modern Date Utilities
3
+ * Using Day.js (2KB) instead of Moment.js (67KB) - 97% size reduction
4
+ * Provides consistent date formatting and manipulation across the application
5
+ */
6
+
7
+ import dayjs from 'dayjs';
8
+ import utc from 'dayjs/plugin/utc';
9
+ import timezone from 'dayjs/plugin/timezone';
10
+ import relativeTime from 'dayjs/plugin/relativeTime';
11
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
12
+ import advancedFormat from 'dayjs/plugin/advancedFormat';
13
+
14
+ // Enable Day.js plugins
15
+ dayjs.extend(utc);
16
+ dayjs.extend(timezone);
17
+ dayjs.extend(relativeTime);
18
+ dayjs.extend(customParseFormat);
19
+ dayjs.extend(advancedFormat);
20
+
21
+ export const DateUtils = {
22
+ /**
23
+ * Get current date/time
24
+ */
25
+ now: () => dayjs(),
26
+
27
+ /**
28
+ * Parse date from string or Date object
29
+ */
30
+ parse: (input, format = null) => {
31
+ return format ? dayjs(input, format) : dayjs(input);
32
+ },
33
+
34
+ /**
35
+ * Format date for display
36
+ */
37
+ format: (date, format = 'YYYY-MM-DD') => {
38
+ return dayjs(date).format(format);
39
+ },
40
+
41
+ /**
42
+ * Common date formatting presets
43
+ */
44
+ formatters: {
45
+ // Dashboard display formats
46
+ shortDate: (date) => dayjs(date).format('MMM DD, YYYY'),
47
+ longDate: (date) => dayjs(date).format('MMMM DD, YYYY'),
48
+ dateTime: (date) => dayjs(date).format('MMM DD, YYYY h:mm A'),
49
+
50
+ // Calendar formats
51
+ calendarDate: (date) => dayjs(date).format('YYYY-MM-DD'),
52
+ calendarDateTime: (date) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'),
53
+
54
+ // Form input formats
55
+ inputDate: (date) => dayjs(date).format('YYYY-MM-DD'),
56
+ inputDateTime: (date) => dayjs(date).format('YYYY-MM-DDTHH:mm'),
57
+
58
+ // Display formats
59
+ timeOnly: (date) => dayjs(date).format('h:mm A'),
60
+ monthYear: (date) => dayjs(date).format('MMMM YYYY'),
61
+ dayMonth: (date) => dayjs(date).format('DD MMM'),
62
+
63
+ // Relative time
64
+ relative: (date) => dayjs(date).fromNow(),
65
+ relativeCalendar: (date) => {
66
+ const now = dayjs();
67
+ const target = dayjs(date);
68
+ const diffDays = now.diff(target, 'day');
69
+
70
+ if (diffDays === 0) return 'Today';
71
+ if (diffDays === 1) return 'Yesterday';
72
+ if (diffDays === -1) return 'Tomorrow';
73
+ if (diffDays > 1 && diffDays < 7) return `${diffDays} days ago`;
74
+ if (diffDays < -1 && diffDays > -7) return `In ${Math.abs(diffDays)} days`;
75
+ return target.format('MMM DD, YYYY');
76
+ },
77
+ },
78
+
79
+ /**
80
+ * Date manipulation
81
+ */
82
+ add: (date, amount, unit) => dayjs(date).add(amount, unit),
83
+ subtract: (date, amount, unit) => dayjs(date).subtract(amount, unit),
84
+ startOf: (date, unit) => dayjs(date).startOf(unit),
85
+ endOf: (date, unit) => dayjs(date).endOf(unit),
86
+
87
+ /**
88
+ * Date comparison
89
+ */
90
+ isBefore: (date1, date2) => dayjs(date1).isBefore(dayjs(date2)),
91
+ isAfter: (date1, date2) => dayjs(date1).isAfter(dayjs(date2)),
92
+ isSame: (date1, date2, unit = 'day') => dayjs(date1).isSame(dayjs(date2), unit),
93
+ isBetween: (date, start, end) => dayjs(date).isBetween(dayjs(start), dayjs(end)),
94
+
95
+ /**
96
+ * Date validation
97
+ */
98
+ isValid: (date) => dayjs(date).isValid(),
99
+
100
+ /**
101
+ * Timezone utilities
102
+ */
103
+ timezone: {
104
+ convert: (date, tz) => dayjs(date).tz(tz),
105
+ utc: (date) => dayjs(date).utc(),
106
+ local: (date) => dayjs(date).local(),
107
+ guess: () => dayjs.tz.guess(),
108
+ },
109
+
110
+ /**
111
+ * Calendar utilities
112
+ */
113
+ calendar: {
114
+ // Get calendar month data for building calendar views
115
+ getMonthData: (date = null) => {
116
+ const target = date ? dayjs(date) : dayjs();
117
+ const startOfMonth = target.startOf('month');
118
+ const endOfMonth = target.endOf('month');
119
+ const startOfCalendar = startOfMonth.startOf('week');
120
+ const endOfCalendar = endOfMonth.endOf('week');
121
+
122
+ const days = [];
123
+ let current = startOfCalendar;
124
+
125
+ while (current.isBefore(endOfCalendar) || current.isSame(endOfCalendar, 'day')) {
126
+ days.push({
127
+ date: current.format('YYYY-MM-DD'),
128
+ day: current.date(),
129
+ isCurrentMonth: current.isSame(target, 'month'),
130
+ isToday: current.isSame(dayjs(), 'day'),
131
+ dayjs: current.clone(),
132
+ });
133
+ current = current.add(1, 'day');
134
+ }
135
+
136
+ return {
137
+ month: target.format('MMMM YYYY'),
138
+ year: target.year(),
139
+ monthIndex: target.month(),
140
+ days,
141
+ };
142
+ },
143
+
144
+ // Get week data
145
+ getWeekData: (date = null) => {
146
+ const target = date ? dayjs(date) : dayjs();
147
+ const startOfWeek = target.startOf('week');
148
+ const endOfWeek = target.endOf('week');
149
+
150
+ const days = [];
151
+ let current = startOfWeek;
152
+
153
+ while (current.isBefore(endOfWeek) || current.isSame(endOfWeek, 'day')) {
154
+ days.push({
155
+ date: current.format('YYYY-MM-DD'),
156
+ day: current.date(),
157
+ dayName: current.format('dddd'),
158
+ shortDayName: current.format('ddd'),
159
+ isToday: current.isSame(dayjs(), 'day'),
160
+ dayjs: current.clone(),
161
+ });
162
+ current = current.add(1, 'day');
163
+ }
164
+
165
+ return {
166
+ weekStart: startOfWeek.format('MMM DD'),
167
+ weekEnd: endOfWeek.format('MMM DD, YYYY'),
168
+ days,
169
+ };
170
+ },
171
+ },
172
+
173
+ /**
174
+ * Form utilities
175
+ */
176
+ form: {
177
+ // Convert date to HTML5 input format
178
+ toInputValue: (date) => dayjs(date).format('YYYY-MM-DD'),
179
+ toDateTimeInputValue: (date) => dayjs(date).format('YYYY-MM-DDTHH:mm'),
180
+
181
+ // Parse from HTML5 input
182
+ fromInputValue: (value) => dayjs(value),
183
+
184
+ // Validate date input
185
+ validateDateInput: (value) => {
186
+ const parsed = dayjs(value);
187
+ return parsed.isValid() && value.length >= 8; // Basic validation
188
+ },
189
+ },
190
+
191
+ /**
192
+ * Chart/Data utilities
193
+ */
194
+ charts: {
195
+ // Generate date ranges for charts
196
+ generateDateRange: (start, end, interval = 'day') => {
197
+ const dates = [];
198
+ let current = dayjs(start);
199
+ const endDate = dayjs(end);
200
+
201
+ while (current.isBefore(endDate) || current.isSame(endDate, interval)) {
202
+ dates.push({
203
+ date: current.format('YYYY-MM-DD'),
204
+ label: current.format('MMM DD'),
205
+ value: current.toISOString(),
206
+ dayjs: current.clone(),
207
+ });
208
+ current = current.add(1, interval);
209
+ }
210
+
211
+ return dates;
212
+ },
213
+
214
+ // Get common chart date labels
215
+ getChartLabels: (period = 'week') => {
216
+ const now = dayjs();
217
+
218
+ switch (period) {
219
+ case 'week':
220
+ return Array.from({ length: 7 }, (_, i) =>
221
+ now.subtract(6 - i, 'day').format('ddd')
222
+ );
223
+ case 'month':
224
+ return Array.from({ length: 30 }, (_, i) =>
225
+ now.subtract(29 - i, 'day').format('DD')
226
+ );
227
+ case 'year':
228
+ return Array.from({ length: 12 }, (_, i) =>
229
+ now.subtract(11 - i, 'month').format('MMM')
230
+ );
231
+ default:
232
+ return [];
233
+ }
234
+ },
235
+ },
236
+ };
237
+
238
+ // Export dayjs instance for direct use when needed
239
+ export { dayjs };
240
+
241
+ // Default export
242
+ export default DateUtils;