adminator-admin-dashboard 2.8.1 → 4.1.5

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