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.
- package/CHANGELOG.md +499 -0
- package/CLAUDE.md +126 -154
- package/README.md +321 -370
- package/dist/2026.js +8751 -0
- package/dist/2026.js.map +1 -0
- package/dist/404.html +36 -16
- package/dist/500.html +36 -16
- package/dist/assets/static/images/logo.svg +3 -3
- package/dist/basic-table.html +152 -699
- package/dist/blank.html +42 -507
- package/dist/buttons.html +152 -448
- package/dist/calendar.html +246 -658
- package/dist/charts.html +124 -658
- package/dist/chat.html +209 -706
- package/dist/compose.html +141 -618
- package/dist/datatable.html +467 -991
- package/dist/email.html +430 -943
- package/dist/forms.html +208 -733
- package/dist/google-maps.html +123 -513
- package/dist/index.html +436 -1041
- package/dist/runtime.js +1299 -0
- package/dist/runtime.js.map +1 -0
- package/dist/signin.html +92 -92
- package/dist/signup.html +106 -91
- package/dist/ui.html +268 -897
- package/dist/vector-maps.html +132 -511
- package/dist/vendor-chartjs.js +14593 -0
- package/dist/vendor-chartjs.js.map +1 -0
- package/dist/vendor-fullcalendar.js +14793 -0
- package/dist/vendor-fullcalendar.js.map +1 -0
- package/dist/vendors.js +3758 -0
- package/dist/vendors.js.map +1 -0
- package/package.json +50 -52
- package/src/404.html +35 -15
- package/src/500.html +35 -15
- package/src/assets/scripts/2026/Shell.js +312 -0
- package/src/assets/scripts/2026/calendar.js +123 -0
- package/src/assets/scripts/2026/charts.js +259 -0
- package/src/assets/scripts/2026/index.js +35 -0
- package/src/assets/scripts/2026/init.js +207 -0
- package/src/assets/scripts/2026/maps.js +78 -0
- package/src/assets/scripts/2026/palette.js +266 -0
- package/src/assets/static/images/logo.svg +3 -3
- package/src/assets/styles/2026/_animations.scss +14 -0
- package/src/assets/styles/2026/_auth.scss +215 -0
- package/src/assets/styles/2026/_base.scss +37 -0
- package/src/assets/styles/2026/_calendar.scss +380 -0
- package/src/assets/styles/2026/_charts.scss +44 -0
- package/src/assets/styles/2026/_chat.scss +350 -0
- package/src/assets/styles/2026/_components.scss +140 -0
- package/src/assets/styles/2026/_dashboard.scss +520 -0
- package/src/assets/styles/2026/_data.scss +130 -0
- package/src/assets/styles/2026/_dropdowns.scss +128 -0
- package/src/assets/styles/2026/_email.scss +599 -0
- package/src/assets/styles/2026/_error.scss +98 -0
- package/src/assets/styles/2026/_forms.scss +215 -0
- package/src/assets/styles/2026/_fullcalendar.scss +134 -0
- package/src/assets/styles/2026/_palette.scss +173 -0
- package/src/assets/styles/2026/_responsive.scss +229 -0
- package/src/assets/styles/2026/_shell.scss +290 -0
- package/src/assets/styles/2026/_tokens.scss +80 -0
- package/src/assets/styles/2026/_ui.scss +365 -0
- package/src/assets/styles/2026/index.scss +23 -0
- package/src/basic-table.html +153 -710
- package/src/blank.html +42 -517
- package/src/buttons.html +152 -458
- package/src/calendar.html +246 -668
- package/src/charts.html +124 -668
- package/src/chat.html +209 -716
- package/src/compose.html +142 -629
- package/src/datatable.html +466 -1000
- package/src/email.html +429 -952
- package/src/forms.html +207 -742
- package/src/google-maps.html +128 -523
- package/src/index.html +438 -1050
- package/src/signin.html +92 -92
- package/src/signup.html +106 -91
- package/src/ui.html +267 -906
- package/src/vector-maps.html +133 -522
- package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
- package/dist/20fd1704ea223900efa9.woff2 +0 -0
- package/dist/29b39089170885ae2967.woff +0 -0
- package/dist/8b43027f47b20503057d.eot +0 -0
- package/dist/9bad94440d49256265a5.eot +0 -0
- package/dist/assets/fontawesome-webfont.svg +0 -2671
- package/dist/assets/themify.svg +0 -362
- package/dist/eda8b94308c6f538f04a.ttf +0 -0
- package/dist/f691f37e57f04c152e23.woff +0 -0
- package/dist/main.js +0 -61323
- package/dist/main.js.map +0 -1
- package/src/assets/scripts/app 2.js +0 -645
- package/src/assets/scripts/app.js +0 -645
- package/src/assets/scripts/charts/chartJS/index.js +0 -148
- package/src/assets/scripts/charts/easyPieChart/index.js +0 -200
- package/src/assets/scripts/charts/index.js +0 -3
- package/src/assets/scripts/charts/sparkline/index.js +0 -208
- package/src/assets/scripts/chat/index.js +0 -11
- package/src/assets/scripts/components/Chart.js +0 -1390
- package/src/assets/scripts/components/Sidebar.js +0 -241
- package/src/assets/scripts/constants/colors.js +0 -274
- package/src/assets/scripts/datatable/index.js +0 -379
- package/src/assets/scripts/datepicker/index.js +0 -302
- package/src/assets/scripts/email/index.js +0 -25
- package/src/assets/scripts/fullcalendar/index.js +0 -86
- package/src/assets/scripts/googleMaps/index.js +0 -93
- package/src/assets/scripts/index.js +0 -18
- package/src/assets/scripts/masonry/index.js +0 -14
- package/src/assets/scripts/popover/index.js +0 -109
- package/src/assets/scripts/scrollbar/index.js +0 -10
- package/src/assets/scripts/search/index.js +0 -15
- package/src/assets/scripts/sidebar/index.js +0 -140
- package/src/assets/scripts/skycons/index.js +0 -52
- package/src/assets/scripts/ui/index.js +0 -412
- package/src/assets/scripts/utils/date.js +0 -242
- package/src/assets/scripts/utils/dom.js +0 -349
- package/src/assets/scripts/utils/index.js +0 -45
- package/src/assets/scripts/utils/theme.js +0 -107
- package/src/assets/scripts/vectorMaps/index.js +0 -277
- package/src/assets/styles/index.scss +0 -801
- package/src/assets/styles/spec/components/easyPieChart.scss +0 -11
- package/src/assets/styles/spec/components/footer.scss +0 -4
- package/src/assets/styles/spec/components/forms.scss +0 -288
- package/src/assets/styles/spec/components/index.scss +0 -9
- package/src/assets/styles/spec/components/loader.scss +0 -46
- package/src/assets/styles/spec/components/masonry.scss +0 -1
- package/src/assets/styles/spec/components/pageContainer.scss +0 -255
- package/src/assets/styles/spec/components/progressBar.scss +0 -6
- package/src/assets/styles/spec/components/sidebar.scss +0 -642
- package/src/assets/styles/spec/components/topbar.scss +0 -455
- package/src/assets/styles/spec/generic/base.scss +0 -102
- package/src/assets/styles/spec/generic/index.scss +0 -1
- package/src/assets/styles/spec/index.scss +0 -4
- package/src/assets/styles/spec/screens/chat.scss +0 -147
- package/src/assets/styles/spec/screens/email.scss +0 -108
- package/src/assets/styles/spec/screens/index.scss +0 -2
- package/src/assets/styles/spec/settings/baseColors.scss +0 -103
- package/src/assets/styles/spec/settings/borders.scss +0 -6
- package/src/assets/styles/spec/settings/breakpoints.scss +0 -26
- package/src/assets/styles/spec/settings/fonts.scss +0 -4
- package/src/assets/styles/spec/settings/index.scss +0 -4
- package/src/assets/styles/spec/settings/materialColors.scss +0 -550
- package/src/assets/styles/spec/tools/index.scss +0 -1
- package/src/assets/styles/spec/tools/mixins/clearfix.scss +0 -15
- package/src/assets/styles/spec/tools/mixins/index.scss +0 -3
- package/src/assets/styles/spec/tools/mixins/mediaQueriesRanges.scss +0 -58
- package/src/assets/styles/spec/tools/mixins/placeholder.scss +0 -10
- package/src/assets/styles/spec/utils/colors.scss +0 -33
- package/src/assets/styles/spec/utils/index.scss +0 -2
- package/src/assets/styles/spec/utils/layout/helpers/border.scss +0 -78
- package/src/assets/styles/spec/utils/layout/helpers/flex.scss +0 -220
- package/src/assets/styles/spec/utils/layout/helpers/index.scss +0 -11
- package/src/assets/styles/spec/utils/layout/helpers/layout.scss +0 -137
- package/src/assets/styles/spec/utils/layout/helpers/lists.scss +0 -23
- package/src/assets/styles/spec/utils/layout/helpers/margin.scss +0 -266
- package/src/assets/styles/spec/utils/layout/helpers/objects.scss +0 -91
- package/src/assets/styles/spec/utils/layout/helpers/padding.scss +0 -147
- package/src/assets/styles/spec/utils/layout/helpers/positions.scss +0 -118
- package/src/assets/styles/spec/utils/layout/helpers/pseudo.scss +0 -6
- package/src/assets/styles/spec/utils/layout/helpers/sizes.scss +0 -157
- package/src/assets/styles/spec/utils/layout/helpers/typography.scss +0 -127
- package/src/assets/styles/spec/utils/layout/index.scss +0 -3
- package/src/assets/styles/spec/utils/layout/mixins/generateResponsive.scss +0 -25
- package/src/assets/styles/spec/utils/layout/mixins/index.scss +0 -2
- package/src/assets/styles/spec/utils/layout/mixins/mediaQueryCondition.scss +0 -28
- package/src/assets/styles/spec/utils/layout/utils/center.scss +0 -54
- package/src/assets/styles/spec/utils/layout/utils/gap.scss +0 -229
- package/src/assets/styles/spec/utils/layout/utils/index.scss +0 -5
- package/src/assets/styles/spec/utils/layout/utils/layers.scss +0 -5
- package/src/assets/styles/spec/utils/layout/utils/peers.scss +0 -35
- package/src/assets/styles/utils/mobile.scss +0 -954
- package/src/assets/styles/utils/theme.css +0 -97
- package/src/assets/styles/vendor/datepicker.scss +0 -183
- package/src/assets/styles/vendor/font-awesome.css +0 -2337
- package/src/assets/styles/vendor/fullcalendar.scss +0 -217
- package/src/assets/styles/vendor/index.scss +0 -8
- package/src/assets/styles/vendor/jquery.datatables.scss +0 -162
- package/src/assets/styles/vendor/perfectScrollbar.scss +0 -4
- package/src/assets/styles/vendor/sparkline.scss +0 -6
- 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;
|