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
package/src/500.html ADDED
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6
+ <title>500</title>
7
+ </head>
8
+ <body class="app">
9
+ <div class='pos-a t-0 l-0 bgc-white w-100 h-100 d-f fxd-r fxw-w ai-c jc-c pos-r p-30'>
10
+ <div class='mR-60'>
11
+ <img alt='#' src='assets/static/images/500.png' />
12
+ </div>
13
+
14
+ <div class='d-f jc-c fxd-c'>
15
+ <h1 class='mB-30 fw-900 lh-1 c-red-500' style="font-size: 60px;">500</h1>
16
+ <h3 class='mB-10 fsz-lg c-grey-900 tt-c'>Internal server error</h3>
17
+ <p class='mB-30 fsz-def c-grey-700'>Something goes wrong with our servers, please try again later.</p>
18
+ <div>
19
+ <a href="index.html" type='primary' class='btn btn-primary'>Go to Home</a>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </body>
24
+ </html>
@@ -0,0 +1,644 @@
1
+ /**
2
+ * Modern Adminator Application
3
+ * Main application entry point with enhanced mobile support
4
+ */
5
+
6
+ // Note: Bootstrap 5 CSS is still available via SCSS imports
7
+ // Bootstrap JS components removed to eliminate jQuery dependency
8
+ import DOM from './utils/dom';
9
+ import DateUtils from './utils/date';
10
+ import Theme from './utils/theme';
11
+ import Sidebar from './components/Sidebar';
12
+ import ChartComponent from './components/Chart';
13
+
14
+ // Import styles
15
+ import '../styles/index.scss';
16
+
17
+ // Import other modules that don't need immediate modernization
18
+ import './fullcalendar';
19
+ import './masonry';
20
+ import './popover';
21
+ import './scrollbar';
22
+ import './search';
23
+ import './skycons';
24
+ import './vectorMaps';
25
+ import './chat';
26
+ import './email';
27
+ import './googleMaps';
28
+ import './ui';
29
+
30
+ class AdminatorApp {
31
+ constructor() {
32
+ this.components = new Map();
33
+ this.isInitialized = false;
34
+
35
+ // Initialize when DOM is ready
36
+ DOM.ready(() => {
37
+ this.init();
38
+ });
39
+ }
40
+
41
+ /**
42
+ * Initialize the application
43
+ */
44
+ init() {
45
+ if (this.isInitialized) return;
46
+
47
+
48
+ try {
49
+ // Initialize core components
50
+ this.initSidebar();
51
+ this.initCharts();
52
+ this.initDataTables();
53
+ this.initDatePickers();
54
+ this.initTheme();
55
+ this.initMobileEnhancements();
56
+
57
+ // Setup global event listeners
58
+ this.setupGlobalEvents();
59
+
60
+ this.isInitialized = true;
61
+
62
+ // Dispatch custom event for other scripts
63
+ window.dispatchEvent(new CustomEvent('adminator:ready', {
64
+ detail: { app: this },
65
+ }));
66
+
67
+ } catch {
68
+ // Error initializing Adminator App
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Initialize Sidebar component
74
+ */
75
+ initSidebar() {
76
+ if (DOM.exists('.sidebar')) {
77
+ const sidebar = new Sidebar();
78
+ this.components.set('sidebar', sidebar);
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Initialize Chart components
84
+ */
85
+ initCharts() {
86
+ // Check if we have any chart elements
87
+ const hasCharts = DOM.exists('#sparklinedash') ||
88
+ DOM.exists('.sparkline') ||
89
+ DOM.exists('.sparkbar') ||
90
+ DOM.exists('.sparktri') ||
91
+ DOM.exists('.sparkdisc') ||
92
+ DOM.exists('.sparkbull') ||
93
+ DOM.exists('.sparkbox') ||
94
+ DOM.exists('.easy-pie-chart') ||
95
+ DOM.exists('#line-chart') ||
96
+ DOM.exists('#area-chart') ||
97
+ DOM.exists('#scatter-chart') ||
98
+ DOM.exists('#bar-chart');
99
+
100
+ if (hasCharts) {
101
+ const charts = new ChartComponent();
102
+ this.components.set('charts', charts);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Initialize DataTables (modern approach)
108
+ */
109
+ initDataTables() {
110
+ const dataTableElement = DOM.select('#dataTable');
111
+ if (dataTableElement) {
112
+ // For now, use a lightweight approach
113
+ // In future iterations, we can replace with a modern table library
114
+ this.initBasicDataTable(dataTableElement);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Basic DataTable implementation (placeholder for full modernization)
120
+ */
121
+ initBasicDataTable(table) {
122
+ // Add basic sorting functionality
123
+ const headers = DOM.selectAll('th', table);
124
+
125
+ headers.forEach(header => {
126
+ if (header.textContent.trim()) {
127
+ header.style.cursor = 'pointer';
128
+ header.style.userSelect = 'none';
129
+
130
+ DOM.on(header, 'click', () => {
131
+ // Basic sort functionality can be added here
132
+ // For now, we'll keep the existing DataTables library
133
+ });
134
+ }
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Initialize Date Pickers (modern approach with Day.js)
140
+ */
141
+ initDatePickers() {
142
+ const startDatePickers = DOM.selectAll('.start-date');
143
+ const endDatePickers = DOM.selectAll('.end-date');
144
+
145
+ [...startDatePickers, ...endDatePickers].forEach(picker => {
146
+ // Convert to HTML5 date input for better UX
147
+ if (picker.type !== 'date') {
148
+ picker.type = 'date';
149
+ picker.classList.add('form-control');
150
+
151
+ // Clear the placeholder since HTML5 date inputs don't need it
152
+ picker.removeAttribute('placeholder');
153
+
154
+ // Set default value to today if no value is set
155
+ if (!picker.value) {
156
+ picker.value = DateUtils.form.toInputValue(DateUtils.now());
157
+ }
158
+
159
+ // Make sure the input is clickable and focusable
160
+ picker.style.pointerEvents = 'auto';
161
+ picker.style.cursor = 'pointer';
162
+
163
+ // Ensure proper styling for HTML5 date input
164
+ picker.style.minHeight = '38px';
165
+ picker.style.lineHeight = '1.5';
166
+
167
+ // Date picker converted to HTML5 with Day.js support
168
+ }
169
+ });
170
+
171
+ // Add enhanced interaction - handle both field and icon clicks
172
+ [...startDatePickers, ...endDatePickers].forEach(picker => {
173
+ // Handle direct field clicks
174
+ DOM.on(picker, 'click', (event) => {
175
+ event.target.focus();
176
+ // For mobile browsers, trigger the date picker
177
+ if (event.target.showPicker && typeof event.target.showPicker === 'function') {
178
+ try {
179
+ event.target.showPicker();
180
+ } catch {
181
+ // Fallback if showPicker is not supported
182
+ }
183
+ }
184
+ });
185
+
186
+ // Handle calendar icon clicks (find the icon in the input group)
187
+ const inputGroup = picker.closest('.input-group');
188
+ if (inputGroup) {
189
+ const calendarIcon = inputGroup.querySelector('.input-group-text i.ti-calendar');
190
+ if (calendarIcon) {
191
+ DOM.on(calendarIcon, 'click', (event) => {
192
+ event.preventDefault();
193
+ event.stopPropagation();
194
+ picker.focus();
195
+ if (picker.showPicker && typeof picker.showPicker === 'function') {
196
+ try {
197
+ picker.showPicker();
198
+ } catch {
199
+ // Date picker opened via icon click
200
+ }
201
+ }
202
+ });
203
+ }
204
+ }
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Initialize theme system with toggle
210
+ */
211
+ initTheme() {
212
+ // Initializing theme system
213
+
214
+ // Initialize theme system first
215
+ Theme.init();
216
+
217
+ // Inject theme toggle if missing - with retry mechanism
218
+ setTimeout(() => {
219
+ const navRight = DOM.select('.nav-right');
220
+ // Check for nav-right and theme-toggle existence
221
+
222
+ if (navRight && !DOM.exists('#theme-toggle')) {
223
+ const li = document.createElement('li');
224
+ li.className = 'theme-toggle d-flex ai-c';
225
+ li.innerHTML = `
226
+ <div class="form-check form-switch d-flex ai-c" style="margin: 0; padding: 0;">
227
+ <label class="form-check-label me-2 text-nowrap c-grey-700" for="theme-toggle" style="font-size: 12px; margin-right: 8px;">
228
+ <i class="ti-sun" style="margin-right: 4px;"></i><span class="theme-label">Light</span>
229
+ </label>
230
+ <input class="form-check-input" type="checkbox" id="theme-toggle" style="margin: 0;">
231
+ <label class="form-check-label ms-2 text-nowrap c-grey-700" for="theme-toggle" style="font-size: 12px; margin-left: 8px;">
232
+ <span class="theme-label">Dark</span><i class="ti-moon" style="margin-left: 4px;"></i>
233
+ </label>
234
+ </div>
235
+ `;
236
+
237
+ // Insert before user dropdown (last item) - safer approach
238
+ const lastItem = navRight.querySelector('li:last-child');
239
+
240
+ if (lastItem && lastItem.parentNode === navRight) {
241
+ navRight.insertBefore(li, lastItem);
242
+ // Theme toggle inserted before last item
243
+ } else {
244
+ navRight.appendChild(li);
245
+ // Theme toggle appended to nav-right (safer approach)
246
+ }
247
+
248
+ // Add toggle functionality
249
+ const toggle = DOM.select('#theme-toggle');
250
+ if (toggle) {
251
+ // Set initial state
252
+ const currentTheme = Theme.current();
253
+ toggle.checked = currentTheme === 'dark';
254
+
255
+ DOM.on(toggle, 'change', () => {
256
+ Theme.apply(toggle.checked ? 'dark' : 'light');
257
+ });
258
+
259
+ // Listen for theme changes from other sources
260
+ window.addEventListener('adminator:themeChanged', (event) => {
261
+ toggle.checked = event.detail.theme === 'dark';
262
+
263
+ // Update charts when theme changes
264
+ const charts = this.components.get('charts');
265
+ if (charts) charts.redrawCharts();
266
+ });
267
+ }
268
+ } else {
269
+ // No nav-right found or theme-toggle already exists
270
+ }
271
+ }, 100); // Wait 100ms for DOM to be fully ready
272
+ }
273
+
274
+ /**
275
+ * Initialize mobile-specific enhancements
276
+ */
277
+ initMobileEnhancements() {
278
+ // Initializing mobile enhancements
279
+ this.enhanceMobileDropdowns();
280
+ this.enhanceMobileSearch();
281
+
282
+ // Prevent horizontal scroll on mobile
283
+ if (this.isMobile()) {
284
+ document.body.style.overflowX = 'hidden';
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Setup global event listeners
290
+ */
291
+ setupGlobalEvents() {
292
+ // Global click handler
293
+ DOM.on(document, 'click', (event) => this.handleGlobalClick(event));
294
+
295
+ // Window resize handler with debouncing
296
+ let resizeTimeout;
297
+ DOM.on(window, 'resize', () => {
298
+ clearTimeout(resizeTimeout);
299
+ resizeTimeout = setTimeout(() => this.handleResize(), 250);
300
+ });
301
+
302
+ // Global event listeners set up
303
+ }
304
+
305
+ /**
306
+ * Handle window resize events
307
+ */
308
+ handleResize() {
309
+ // Window resized, updating mobile features
310
+
311
+ // Close all mobile-specific overlays when switching to desktop
312
+ if (!this.isMobile()) {
313
+ document.body.style.overflow = '';
314
+ document.body.style.overflowX = '';
315
+
316
+ // Close dropdowns
317
+ const dropdowns = DOM.selectAll('.nav-right .dropdown');
318
+ dropdowns.forEach(dropdown => {
319
+ dropdown.classList.remove('show');
320
+ const menu = dropdown.querySelector('.dropdown-menu');
321
+ if (menu) menu.classList.remove('show');
322
+ });
323
+
324
+ // Close search
325
+ const searchBox = DOM.select('.search-box');
326
+ const searchInput = DOM.select('.search-input');
327
+ if (searchBox && searchInput) {
328
+ searchBox.classList.remove('active');
329
+ searchInput.classList.remove('active');
330
+ }
331
+ } else {
332
+ // Re-enable mobile overflow protection
333
+ document.body.style.overflowX = 'hidden';
334
+ }
335
+
336
+ // Re-apply mobile enhancements
337
+ this.enhanceMobileDropdowns();
338
+ this.enhanceMobileSearch();
339
+ }
340
+
341
+ /**
342
+ * Handle global click events
343
+ */
344
+ handleGlobalClick(event) {
345
+ // Close mobile dropdowns when clicking outside
346
+ if (!event.target.closest('.dropdown')) {
347
+ const dropdowns = DOM.selectAll('.nav-right .dropdown');
348
+ dropdowns.forEach(dropdown => {
349
+ dropdown.classList.remove('show');
350
+ const menu = dropdown.querySelector('.dropdown-menu');
351
+ if (menu) menu.classList.remove('show');
352
+ });
353
+ document.body.style.overflow = '';
354
+ }
355
+
356
+ // Close search when clicking outside
357
+ if (!event.target.closest('.search-box') && !event.target.closest('.search-input')) {
358
+ const searchBox = DOM.select('.search-box');
359
+ const searchInput = DOM.select('.search-input');
360
+ if (searchBox && searchInput) {
361
+ searchBox.classList.remove('active');
362
+ searchInput.classList.remove('active');
363
+ document.body.style.overflow = '';
364
+ document.body.classList.remove('mobile-menu-open');
365
+ }
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Check if we're on a mobile device
371
+ */
372
+ isMobile() {
373
+ return window.innerWidth <= 768;
374
+ }
375
+
376
+ /**
377
+ * Enhanced mobile dropdown handling with improved email layout
378
+ */
379
+ enhanceMobileDropdowns() {
380
+ if (!this.isMobile()) return;
381
+
382
+ const dropdowns = DOM.selectAll('.nav-right .dropdown');
383
+
384
+ dropdowns.forEach(dropdown => {
385
+ const toggle = dropdown.querySelector('.dropdown-toggle');
386
+ const menu = dropdown.querySelector('.dropdown-menu');
387
+
388
+ if (toggle && menu) {
389
+ // Remove existing listeners to prevent duplicates
390
+ const newToggle = toggle.cloneNode(true);
391
+ toggle.replaceWith(newToggle);
392
+
393
+ // Add click functionality for mobile dropdowns
394
+ DOM.on(newToggle, 'click', (e) => {
395
+ e.preventDefault();
396
+ e.stopPropagation();
397
+
398
+ // Close search if open
399
+ const searchBox = DOM.select('.search-box');
400
+ const searchInput = DOM.select('.search-input');
401
+ if (searchBox && searchInput) {
402
+ searchBox.classList.remove('active');
403
+ searchInput.classList.remove('active');
404
+ }
405
+
406
+ // Close other dropdowns first
407
+ dropdowns.forEach(otherDropdown => {
408
+ if (otherDropdown !== dropdown) {
409
+ otherDropdown.classList.remove('show');
410
+ const otherMenu = otherDropdown.querySelector('.dropdown-menu');
411
+ if (otherMenu) otherMenu.classList.remove('show');
412
+ }
413
+ });
414
+
415
+ // Toggle current dropdown
416
+ const isOpen = dropdown.classList.contains('show');
417
+ if (isOpen) {
418
+ dropdown.classList.remove('show');
419
+ menu.classList.remove('show');
420
+ document.body.style.overflow = '';
421
+ document.body.classList.remove('mobile-menu-open');
422
+ } else {
423
+ dropdown.classList.add('show');
424
+ menu.classList.add('show');
425
+ document.body.style.overflow = 'hidden';
426
+ document.body.classList.add('mobile-menu-open');
427
+ }
428
+ });
429
+
430
+ // Enhanced mobile close button functionality
431
+ DOM.on(menu, 'click', (e) => {
432
+ // Check if clicked on the close area (::before pseudo-element area)
433
+ const rect = menu.getBoundingClientRect();
434
+ const clickY = e.clientY - rect.top;
435
+
436
+ // If clicked in top 50px (close button area)
437
+ if (clickY <= 50) {
438
+ dropdown.classList.remove('show');
439
+ menu.classList.remove('show');
440
+ document.body.style.overflow = '';
441
+ document.body.classList.remove('mobile-menu-open');
442
+ e.preventDefault();
443
+ e.stopPropagation();
444
+ }
445
+ });
446
+ }
447
+ });
448
+
449
+ // Close dropdowns on escape key
450
+ DOM.on(document, 'keydown', (e) => {
451
+ if (e.key === 'Escape') {
452
+ dropdowns.forEach(dropdown => {
453
+ dropdown.classList.remove('show');
454
+ const menu = dropdown.querySelector('.dropdown-menu');
455
+ if (menu) menu.classList.remove('show');
456
+ });
457
+ document.body.style.overflow = '';
458
+ document.body.classList.remove('mobile-menu-open');
459
+ }
460
+ });
461
+ }
462
+
463
+ /**
464
+ * Enhanced mobile search handling - Full-width search bar
465
+ */
466
+ enhanceMobileSearch() {
467
+ const searchBox = DOM.select('.search-box');
468
+ const searchInput = DOM.select('.search-input');
469
+
470
+ if (searchBox && searchInput) {
471
+ const searchToggle = searchBox.querySelector('a');
472
+ const searchField = searchInput.querySelector('input');
473
+
474
+ if (searchToggle && searchField) {
475
+ // Setting up full-width search functionality
476
+
477
+ // Remove existing listeners to prevent duplication
478
+ const newSearchToggle = searchToggle.cloneNode(true);
479
+ searchToggle.replaceWith(newSearchToggle);
480
+
481
+ DOM.on(newSearchToggle, 'click', (e) => {
482
+ e.preventDefault();
483
+ e.stopPropagation();
484
+
485
+ // Full-width search toggle clicked
486
+
487
+ // Close any open dropdowns first
488
+ const dropdowns = DOM.selectAll('.nav-right .dropdown');
489
+ dropdowns.forEach(dropdown => {
490
+ dropdown.classList.remove('show');
491
+ const menu = dropdown.querySelector('.dropdown-menu');
492
+ if (menu) menu.classList.remove('show');
493
+ });
494
+
495
+ // Toggle search state
496
+ const isActive = searchInput.classList.contains('active');
497
+ const searchIcon = newSearchToggle.querySelector('i');
498
+
499
+ if (isActive) {
500
+ // Close search
501
+ searchInput.classList.remove('active');
502
+ document.body.classList.remove('search-open');
503
+
504
+ // Change icon back to search
505
+ if (searchIcon) {
506
+ searchIcon.className = 'ti-search';
507
+ }
508
+
509
+ // Clear input
510
+ if (searchField) {
511
+ searchField.value = '';
512
+ searchField.blur();
513
+ }
514
+
515
+ // Full-width search closed
516
+ } else {
517
+ // Open search
518
+ searchInput.classList.add('active');
519
+ document.body.classList.add('search-open');
520
+
521
+ // Change icon to close
522
+ if (searchIcon) {
523
+ searchIcon.className = 'ti-close';
524
+ }
525
+
526
+ // Focus the input after a short delay
527
+ setTimeout(() => {
528
+ if (searchField) {
529
+ searchField.focus();
530
+ // Search field focused
531
+ }
532
+ }, 100);
533
+
534
+ // Full-width search opened
535
+ }
536
+ });
537
+
538
+ // Close search on escape
539
+ DOM.on(document, 'keydown', (e) => {
540
+ if (e.key === 'Escape' && searchInput.classList.contains('active')) {
541
+ searchInput.classList.remove('active');
542
+ document.body.classList.remove('search-open');
543
+
544
+ // Reset icon
545
+ const searchIcon = newSearchToggle.querySelector('i');
546
+ if (searchIcon) {
547
+ searchIcon.className = 'ti-search';
548
+ }
549
+
550
+ // Clear input
551
+ if (searchField) {
552
+ searchField.value = '';
553
+ searchField.blur();
554
+ }
555
+
556
+ // Full-width search closed via escape
557
+ }
558
+ });
559
+
560
+ // Handle search input
561
+ DOM.on(searchField, 'keypress', (e) => {
562
+ if (e.key === 'Enter') {
563
+ e.preventDefault();
564
+ const query = searchField.value.trim();
565
+ if (query) {
566
+ // Search query submitted
567
+ // Implement your search logic here
568
+
569
+ // For demo, close search after "searching"
570
+ searchInput.classList.remove('active');
571
+ document.body.classList.remove('search-open');
572
+
573
+ const searchIcon = newSearchToggle.querySelector('i');
574
+ if (searchIcon) {
575
+ searchIcon.className = 'ti-search';
576
+ }
577
+
578
+ searchField.value = '';
579
+ searchField.blur();
580
+ }
581
+ }
582
+ });
583
+
584
+ // Full-width search functionality initialized
585
+ }
586
+ }
587
+ }
588
+
589
+ /**
590
+ * Get a component by name
591
+ */
592
+ getComponent(name) {
593
+ return this.components.get(name);
594
+ }
595
+
596
+ /**
597
+ * Check if app is ready
598
+ */
599
+ isReady() {
600
+ return this.isInitialized;
601
+ }
602
+
603
+ /**
604
+ * Destroy the application
605
+ */
606
+ destroy() {
607
+ // Destroying Adminator App
608
+
609
+ // Destroy all components
610
+ this.components.forEach((component) => {
611
+ if (typeof component.destroy === 'function') {
612
+ component.destroy();
613
+ }
614
+ // Component destroyed
615
+ });
616
+
617
+ this.components.clear();
618
+ this.isInitialized = false;
619
+ }
620
+
621
+ /**
622
+ * Refresh/reinitialize the application
623
+ */
624
+ refresh() {
625
+ // Refreshing Adminator App
626
+
627
+ if (this.isInitialized) {
628
+ this.destroy();
629
+ }
630
+
631
+ setTimeout(() => {
632
+ this.init();
633
+ }, 100);
634
+ }
635
+ }
636
+
637
+ // Initialize the application
638
+ const app = new AdminatorApp();
639
+
640
+ // Make app globally available for debugging
641
+ window.AdminatorApp = app;
642
+
643
+ // Export for module usage
644
+ export default app;