admin-lte 4.0.0-rc6 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/README.md +44 -18
- package/dist/UI/general.html +311 -92
- package/dist/UI/icons.html +311 -92
- package/dist/UI/timeline.html +311 -92
- package/dist/css/adminlte.css +2814 -1138
- package/dist/css/adminlte.css.map +1 -1
- package/dist/css/adminlte.min.css +2 -2
- package/dist/css/adminlte.min.css.map +1 -1
- package/dist/css/adminlte.rtl.css +2814 -1138
- package/dist/css/adminlte.rtl.css.map +1 -1
- package/dist/css/adminlte.rtl.min.css +2 -2
- package/dist/css/adminlte.rtl.min.css.map +1 -1
- package/dist/docs/browser-support.html +291 -385
- package/dist/docs/color-mode.html +283 -381
- package/dist/docs/components/main-header.html +269 -363
- package/dist/docs/components/main-sidebar.html +284 -378
- package/dist/docs/customization.html +1056 -0
- package/dist/docs/deployment.html +1121 -0
- package/dist/docs/faq.html +887 -397
- package/dist/docs/getting-started.html +967 -0
- package/dist/docs/how-to-contribute.html +365 -450
- package/dist/docs/index.html +16 -0
- package/dist/docs/integrations.html +1207 -0
- package/dist/docs/introduction.html +483 -434
- package/dist/docs/javascript/accessibility.html +925 -0
- package/dist/docs/javascript/card-widget.html +995 -0
- package/dist/docs/javascript/direct-chat.html +872 -0
- package/dist/docs/javascript/fullscreen.html +881 -0
- package/dist/docs/javascript/layout.html +884 -0
- package/dist/docs/javascript/plugins-overview.html +1120 -0
- package/dist/docs/javascript/pushmenu.html +522 -377
- package/dist/docs/javascript/treeview.html +498 -390
- package/dist/docs/layout-blueprint.html +1063 -0
- package/dist/docs/layout.html +316 -402
- package/dist/docs/license.html +282 -375
- package/dist/docs/migration.html +1125 -0
- package/dist/docs/recipes.html +1161 -0
- package/dist/docs/rtl.html +933 -0
- package/dist/examples/lockscreen.html +66 -2
- package/dist/examples/login-v2.html +65 -1
- package/dist/examples/login.html +65 -1
- package/dist/examples/register-v2.html +65 -1
- package/dist/examples/register.html +65 -1
- package/dist/forms/elements.html +1381 -0
- package/dist/forms/{general.html → layout.html} +382 -452
- package/dist/forms/validation.html +1251 -0
- package/dist/forms/wizard.html +1386 -0
- package/dist/generate/theme.html +135 -5
- package/dist/index.html +311 -92
- package/dist/index2.html +314 -92
- package/dist/index3.html +311 -92
- package/dist/js/adminlte.js +135 -314
- package/dist/js/adminlte.js.map +1 -1
- package/dist/js/adminlte.min.js +3 -3
- package/dist/js/adminlte.min.js.map +1 -1
- package/dist/layout/collapsed-sidebar-without-hover.html +1120 -0
- package/dist/layout/collapsed-sidebar.html +311 -92
- package/dist/layout/fixed-complete.html +311 -92
- package/dist/layout/fixed-footer.html +311 -92
- package/dist/layout/fixed-header.html +311 -92
- package/dist/layout/fixed-sidebar.html +311 -92
- package/dist/layout/layout-custom-area.html +311 -92
- package/dist/layout/layout-rtl.html +311 -92
- package/dist/layout/logo-switch.html +135 -5
- package/dist/layout/sidebar-mini.html +311 -92
- package/dist/layout/unfixed-sidebar.html +311 -92
- package/dist/mailbox/compose.html +1127 -0
- package/dist/mailbox/inbox.html +1477 -0
- package/dist/mailbox/read.html +1178 -0
- package/dist/pages/404.html +213 -0
- package/dist/pages/500.html +201 -0
- package/dist/pages/calendar.html +1242 -0
- package/dist/pages/chat.html +1403 -0
- package/dist/pages/faq.html +1359 -0
- package/dist/pages/file-manager.html +1811 -0
- package/dist/pages/invoice.html +1175 -0
- package/dist/pages/kanban.html +1415 -0
- package/dist/pages/maintenance.html +204 -0
- package/dist/pages/pricing.html +1255 -0
- package/dist/pages/profile.html +1358 -0
- package/dist/pages/projects.html +1620 -0
- package/dist/pages/settings.html +1363 -0
- package/dist/tables/data.html +1295 -0
- package/dist/tables/simple.html +311 -92
- package/dist/widgets/cards.html +311 -92
- package/dist/widgets/info-box.html +311 -92
- package/dist/widgets/small-box.html +311 -92
- package/netlify.toml +16 -0
- package/package.json +32 -26
- package/src/scss/_accessibility.scss +44 -0
- package/src/scss/_app-footer.scss +9 -0
- package/src/scss/_app-header.scss +27 -0
- package/src/scss/_app-sidebar.scss +73 -74
- package/src/scss/_bootstrap-variables.scss +12 -5
- package/src/scss/_docs.scss +816 -0
- package/src/scss/_table.scss +4 -4
- package/src/scss/adminlte.scss +4 -1
- package/src/scss/pages/_login_and_register.scss +1 -1
- package/src/ts/accessibility.ts +9 -7
- package/src/ts/adminlte.ts +2 -14
- package/src/ts/fullscreen.ts +8 -4
- package/src/ts/layout.ts +34 -16
- package/src/ts/push-menu.ts +257 -104
- package/src/ts/util/index.ts +10 -0
- package/.claude/settings.local.json +0 -33
- package/CLAUDE.md +0 -79
package/src/ts/push-menu.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
3
|
* @file AdminLTE push-menu.ts
|
|
4
4
|
* @description Push menu for AdminLTE.
|
|
5
5
|
* @license MIT
|
|
6
|
-
*
|
|
6
|
+
* ----------------------------------------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import {
|
|
@@ -11,34 +11,44 @@ import {
|
|
|
11
11
|
} from './util/index'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* ----------------------------------------------------------------------------
|
|
15
15
|
* Constants
|
|
16
|
-
*
|
|
16
|
+
* ----------------------------------------------------------------------------
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
const DATA_KEY = 'lte.push-menu'
|
|
20
20
|
const EVENT_KEY = `.${DATA_KEY}`
|
|
21
|
-
|
|
22
21
|
const EVENT_OPEN = `open${EVENT_KEY}`
|
|
23
22
|
const EVENT_COLLAPSE = `collapse${EVENT_KEY}`
|
|
24
23
|
|
|
25
24
|
const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini'
|
|
26
|
-
const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse'
|
|
27
|
-
const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open'
|
|
28
25
|
const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand'
|
|
29
26
|
const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay'
|
|
30
|
-
|
|
27
|
+
|
|
28
|
+
// Classes used to explicitly indicate the sidebar state.
|
|
29
|
+
// - sidebar-collapse: Indicates the sidebar is explicitly collapsed.
|
|
30
|
+
// - sidebar-open: Indicates the sidebar is explicitly open on mobile sizes.
|
|
31
|
+
const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse'
|
|
32
|
+
const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open'
|
|
31
33
|
|
|
32
34
|
const SELECTOR_APP_SIDEBAR = '.app-sidebar'
|
|
33
|
-
const SELECTOR_SIDEBAR_MENU = '.sidebar-menu'
|
|
34
|
-
const SELECTOR_NAV_ITEM = '.nav-item'
|
|
35
|
-
const SELECTOR_NAV_TREEVIEW = '.nav-treeview'
|
|
36
35
|
const SELECTOR_APP_WRAPPER = '.app-wrapper'
|
|
37
36
|
const SELECTOR_SIDEBAR_EXPAND = `[class*="${CLASS_NAME_SIDEBAR_EXPAND}"]`
|
|
38
37
|
const SELECTOR_SIDEBAR_TOGGLE = '[data-lte-toggle="sidebar"]'
|
|
39
38
|
|
|
40
39
|
const STORAGE_KEY_SIDEBAR_STATE = 'lte.sidebar.state'
|
|
41
40
|
|
|
41
|
+
/**
|
|
42
|
+
* ----------------------------------------------------------------------------
|
|
43
|
+
* Configuration Object Interface
|
|
44
|
+
* - sidebarBreakpoint: The screen width (in pixels) below which the sidebar
|
|
45
|
+
* is considered to be on a "mobile" size and should be collapsed by default
|
|
46
|
+
* unless explicitly opened.
|
|
47
|
+
* - enablePersistence: Whether to save the sidebar state (collapsed/open) in
|
|
48
|
+
* localStorage and restore it on page load.
|
|
49
|
+
* ----------------------------------------------------------------------------
|
|
50
|
+
*/
|
|
51
|
+
|
|
42
52
|
type Config = {
|
|
43
53
|
sidebarBreakpoint: number;
|
|
44
54
|
enablePersistence: boolean;
|
|
@@ -46,12 +56,13 @@ type Config = {
|
|
|
46
56
|
|
|
47
57
|
const Defaults: Config = {
|
|
48
58
|
sidebarBreakpoint: 992,
|
|
49
|
-
enablePersistence:
|
|
59
|
+
enablePersistence: false
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
/**
|
|
63
|
+
* ----------------------------------------------------------------------------
|
|
53
64
|
* Class Definition
|
|
54
|
-
*
|
|
65
|
+
* ----------------------------------------------------------------------------
|
|
55
66
|
*/
|
|
56
67
|
|
|
57
68
|
class PushMenu {
|
|
@@ -63,120 +74,191 @@ class PushMenu {
|
|
|
63
74
|
this._config = { ...Defaults, ...config }
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Check if the sidebar is collapsed.
|
|
79
|
+
*
|
|
80
|
+
* @returns True if the sidebar is collapsed, false otherwise.
|
|
81
|
+
*/
|
|
82
|
+
isCollapsed(): boolean {
|
|
83
|
+
return document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)
|
|
84
|
+
}
|
|
68
85
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Check if the sidebar is explicitly open on mobile sizes.
|
|
88
|
+
*
|
|
89
|
+
* @returns True if the sidebar is explicitly open, false otherwise.
|
|
90
|
+
*/
|
|
91
|
+
isExplicitlyOpen(): boolean {
|
|
92
|
+
return document.body.classList.contains(CLASS_NAME_SIDEBAR_OPEN)
|
|
93
|
+
}
|
|
73
94
|
|
|
74
|
-
|
|
75
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Check if the sidebar is in mini mode.
|
|
97
|
+
*
|
|
98
|
+
* @returns True if the sidebar is in mini mode, false otherwise.
|
|
99
|
+
*/
|
|
100
|
+
isMiniMode(): boolean {
|
|
101
|
+
return document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI)
|
|
102
|
+
}
|
|
76
103
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Check if the current screen size is considered "mobile" based on the
|
|
106
|
+
* sidebarBreakpoint config value.
|
|
107
|
+
*
|
|
108
|
+
* @returns True if the screen size is mobile, false otherwise.
|
|
109
|
+
*/
|
|
110
|
+
isMobileSize(): boolean {
|
|
111
|
+
return globalThis.innerWidth <= this._config.sidebarBreakpoint
|
|
82
112
|
}
|
|
83
113
|
|
|
84
|
-
|
|
85
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Expand the sidebar menu.
|
|
116
|
+
*/
|
|
117
|
+
expand(): void {
|
|
118
|
+
// Remove the sidebar-collapse class. Only on mobile, add the sidebar-open
|
|
119
|
+
// class to indicate the sidebar is explicitly open.
|
|
86
120
|
|
|
87
121
|
document.body.classList.remove(CLASS_NAME_SIDEBAR_COLLAPSE)
|
|
88
|
-
document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN)
|
|
89
122
|
|
|
90
|
-
this.
|
|
123
|
+
if (this.isMobileSize()) {
|
|
124
|
+
document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Dispatch the expand event.
|
|
128
|
+
|
|
129
|
+
this._element.dispatchEvent(new Event(EVENT_OPEN))
|
|
91
130
|
}
|
|
92
131
|
|
|
93
|
-
|
|
94
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Collapse the sidebar menu.
|
|
134
|
+
*/
|
|
135
|
+
collapse(): void {
|
|
136
|
+
// Remove the sidebar-open class (if present), and add the sidebar-collapse
|
|
137
|
+
// class.
|
|
95
138
|
|
|
96
139
|
document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN)
|
|
97
140
|
document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE)
|
|
98
141
|
|
|
99
|
-
|
|
142
|
+
// Dispatch the collapse event.
|
|
143
|
+
|
|
144
|
+
this._element.dispatchEvent(new Event(EVENT_COLLAPSE))
|
|
100
145
|
}
|
|
101
146
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this._config = { ...this._config, sidebarBreakpoint: Number(sidebarContent.replace(/[^\d.-]/g, '')) }
|
|
108
|
-
|
|
109
|
-
// FIXED: Don't auto-collapse on mobile if sidebar is currently open
|
|
110
|
-
// This prevents resize events (triggered by scrolling) from closing the sidebar
|
|
111
|
-
const isCurrentlyOpen = document.body.classList.contains(CLASS_NAME_SIDEBAR_OPEN)
|
|
112
|
-
|
|
113
|
-
if (window.innerWidth <= this._config.sidebarBreakpoint) {
|
|
114
|
-
// Only collapse if not currently open (prevents scroll-triggered closes)
|
|
115
|
-
if (!isCurrentlyOpen) {
|
|
116
|
-
this.collapse()
|
|
117
|
-
}
|
|
118
|
-
} else {
|
|
119
|
-
if (!document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI)) {
|
|
120
|
-
this.expand()
|
|
121
|
-
}
|
|
147
|
+
/**
|
|
148
|
+
* Toggle the sidebar menu state.
|
|
149
|
+
*/
|
|
150
|
+
toggle(): void {
|
|
151
|
+
// Toggle the sidebar state.
|
|
122
152
|
|
|
123
|
-
|
|
124
|
-
this.collapse()
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
153
|
+
const isCollapsed = this.isCollapsed()
|
|
128
154
|
|
|
129
|
-
|
|
130
|
-
if (document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
|
|
155
|
+
if (isCollapsed) {
|
|
131
156
|
this.expand()
|
|
132
157
|
} else {
|
|
133
158
|
this.collapse()
|
|
134
159
|
}
|
|
135
160
|
|
|
136
|
-
|
|
161
|
+
// If persistence is enabled, save the new state to localStorage.
|
|
162
|
+
|
|
163
|
+
if (this._config.enablePersistence) {
|
|
164
|
+
this.saveSidebarState(
|
|
165
|
+
isCollapsed ? CLASS_NAME_SIDEBAR_OPEN : CLASS_NAME_SIDEBAR_COLLAPSE
|
|
166
|
+
)
|
|
167
|
+
}
|
|
137
168
|
}
|
|
138
169
|
|
|
139
170
|
/**
|
|
140
|
-
*
|
|
171
|
+
* Read the CSS breakpoint of the sidebar from the DOM and update the
|
|
172
|
+
* sidebarBreakpoint config. This breakpoint is defined using a CSS ::before
|
|
173
|
+
* pseudo element on the sidebar-expand element when @media queries are used
|
|
174
|
+
* to change the sidebar behavior based on screen size.
|
|
141
175
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
176
|
+
setupSidebarBreakPoint(): void {
|
|
177
|
+
// Find the sidebar-expand element in the DOM.
|
|
178
|
+
|
|
179
|
+
const sidebarExpand = document.querySelector(SELECTOR_SIDEBAR_EXPAND)
|
|
180
|
+
|
|
181
|
+
if (!sidebarExpand) {
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Read the content property of the ::before pseudo element to get the
|
|
186
|
+
// breakpoint value.
|
|
187
|
+
|
|
188
|
+
const content = globalThis.getComputedStyle(sidebarExpand, '::before')
|
|
189
|
+
.getPropertyValue('content')
|
|
190
|
+
|
|
191
|
+
// Update the config.sidebarBreakpoint value by extracting the numeric
|
|
192
|
+
// value from the content string.
|
|
193
|
+
|
|
194
|
+
if (!content || content === 'none') {
|
|
144
195
|
return
|
|
145
196
|
}
|
|
146
197
|
|
|
147
|
-
|
|
148
|
-
|
|
198
|
+
const breakpointValue = Number(content.replace(/[^\d.-]/g, ''))
|
|
199
|
+
|
|
200
|
+
if (Number.isNaN(breakpointValue)) {
|
|
149
201
|
return
|
|
150
202
|
}
|
|
151
203
|
|
|
204
|
+
this._config = { ...this._config, sidebarBreakpoint: breakpointValue }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Update the sidebar state based on the current screen size and the
|
|
209
|
+
* sidebarBreakpoint config value.
|
|
210
|
+
*/
|
|
211
|
+
updateStateByResponsiveLogic(): void {
|
|
212
|
+
if (this.isMobileSize()) {
|
|
213
|
+
// On mobile sizes, keep the sidebar collapsed unless explicitly opened
|
|
214
|
+
// by the user to prevent unintended collapse on scroll or resize events.
|
|
215
|
+
|
|
216
|
+
if (!this.isExplicitlyOpen()) {
|
|
217
|
+
this.collapse()
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// On big screen sizes, keep the sidebar expanded unless in mini mode and
|
|
221
|
+
// explicitly collapsed.
|
|
222
|
+
|
|
223
|
+
if (!(this.isMiniMode() && this.isCollapsed())) {
|
|
224
|
+
this.expand()
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Save sidebar state to localStorage.
|
|
231
|
+
*
|
|
232
|
+
* @param state The state to save ('sidebar-open' or 'sidebar-collapse').
|
|
233
|
+
*/
|
|
234
|
+
saveSidebarState(state: string): void {
|
|
235
|
+
// Check for localStorage availability (not a SSR environment).
|
|
236
|
+
|
|
237
|
+
if (globalThis.localStorage === undefined) {
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Save the sidebar state to local storage.
|
|
242
|
+
|
|
152
243
|
try {
|
|
153
|
-
const state = document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE) ?
|
|
154
|
-
CLASS_NAME_SIDEBAR_COLLAPSE :
|
|
155
|
-
CLASS_NAME_SIDEBAR_OPEN
|
|
156
244
|
localStorage.setItem(STORAGE_KEY_SIDEBAR_STATE, state)
|
|
157
245
|
} catch {
|
|
158
|
-
// localStorage may be unavailable (private browsing, quota exceeded,
|
|
246
|
+
// The localStorage may be unavailable (private browsing, quota exceeded,
|
|
247
|
+
// etc.). Fail silently in these cases.
|
|
159
248
|
}
|
|
160
249
|
}
|
|
161
250
|
|
|
162
251
|
/**
|
|
163
|
-
* Load sidebar state from localStorage
|
|
164
|
-
* Only applies on desktop; mobile always starts collapsed
|
|
252
|
+
* Load sidebar state from localStorage.
|
|
165
253
|
*/
|
|
166
254
|
loadSidebarState(): void {
|
|
167
|
-
|
|
168
|
-
return
|
|
169
|
-
}
|
|
255
|
+
// Check for localStorage availability (not a SSR environment).
|
|
170
256
|
|
|
171
|
-
|
|
172
|
-
if (globalThis.window === undefined || globalThis.localStorage === undefined) {
|
|
257
|
+
if (globalThis.localStorage === undefined) {
|
|
173
258
|
return
|
|
174
259
|
}
|
|
175
260
|
|
|
176
|
-
//
|
|
177
|
-
if (globalThis.innerWidth <= this._config.sidebarBreakpoint) {
|
|
178
|
-
return
|
|
179
|
-
}
|
|
261
|
+
// Load the sidebar state from local storage.
|
|
180
262
|
|
|
181
263
|
try {
|
|
182
264
|
const storedState = localStorage.getItem(STORAGE_KEY_SIDEBAR_STATE)
|
|
@@ -185,44 +267,118 @@ class PushMenu {
|
|
|
185
267
|
this.collapse()
|
|
186
268
|
} else if (storedState === CLASS_NAME_SIDEBAR_OPEN) {
|
|
187
269
|
this.expand()
|
|
270
|
+
} else {
|
|
271
|
+
// If null (never saved), let the responsive logic apply.
|
|
272
|
+
this.updateStateByResponsiveLogic()
|
|
188
273
|
}
|
|
189
|
-
// If null (never saved), let default behavior apply
|
|
190
274
|
} catch {
|
|
191
|
-
// localStorage may be unavailable
|
|
275
|
+
// The localStorage may be unavailable. Let the responsive logic apply.
|
|
276
|
+
this.updateStateByResponsiveLogic()
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Clear sidebar state from localStorage.
|
|
282
|
+
*/
|
|
283
|
+
clearSidebarState(): void {
|
|
284
|
+
// Check for localStorage availability (not a SSR environment).
|
|
285
|
+
|
|
286
|
+
if (globalThis.localStorage === undefined) {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Clear the sidebar state from local storage.
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
localStorage.removeItem(STORAGE_KEY_SIDEBAR_STATE)
|
|
294
|
+
} catch {
|
|
295
|
+
// The localStorage may be unavailable. Fail silently in these cases.
|
|
192
296
|
}
|
|
193
297
|
}
|
|
194
298
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Initialize the push menu plugin and setup the initial sidebar state.
|
|
301
|
+
*/
|
|
302
|
+
init(): void {
|
|
303
|
+
// Read and setup the sidebar breakpoint from the DOM. This breakpoint is
|
|
304
|
+
// used to determine when the sidebar should be considered "mobile" vs
|
|
305
|
+
// "desktop".
|
|
306
|
+
|
|
307
|
+
this.setupSidebarBreakPoint()
|
|
308
|
+
|
|
309
|
+
// When persistence is not enabled, clear any saved state, just for safety.
|
|
310
|
+
|
|
311
|
+
if (!this._config.enablePersistence) {
|
|
312
|
+
this.clearSidebarState()
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// When persistence is enabled and screen size is above the breakpoint, load
|
|
316
|
+
// the saved sidebar state from local storage. Otherwise, use responsive
|
|
317
|
+
// logic to set the initial state. On low screen sizes, the sidebar should
|
|
318
|
+
// always be collapsed by default unless explicitly opened.
|
|
319
|
+
|
|
320
|
+
if (this._config.enablePersistence && !this.isMobileSize()) {
|
|
321
|
+
this.loadSidebarState()
|
|
322
|
+
} else {
|
|
323
|
+
this.updateStateByResponsiveLogic()
|
|
324
|
+
}
|
|
198
325
|
}
|
|
199
326
|
}
|
|
200
327
|
|
|
201
328
|
/**
|
|
202
|
-
*
|
|
329
|
+
* ----------------------------------------------------------------------------
|
|
203
330
|
* Data Api implementation
|
|
204
|
-
*
|
|
331
|
+
* ----------------------------------------------------------------------------
|
|
205
332
|
*/
|
|
206
333
|
|
|
207
334
|
onDOMContentLoaded(() => {
|
|
335
|
+
// Find the sidebar element in the DOM.
|
|
336
|
+
|
|
208
337
|
const sidebar = document?.querySelector(SELECTOR_APP_SIDEBAR) as HTMLElement | undefined
|
|
209
338
|
|
|
210
|
-
if (sidebar) {
|
|
211
|
-
|
|
212
|
-
|
|
339
|
+
if (!sidebar) {
|
|
340
|
+
return
|
|
341
|
+
}
|
|
213
342
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
343
|
+
// Read config from data attributes on the sidebar element, falling back to
|
|
344
|
+
// Defaults if not present.
|
|
345
|
+
|
|
346
|
+
const sidebarBreakpointAttr = sidebar.dataset.sidebarBreakpoint
|
|
347
|
+
const enablePersistenceAttr = sidebar.dataset.enablePersistence
|
|
348
|
+
|
|
349
|
+
const config: Config = {
|
|
350
|
+
sidebarBreakpoint: sidebarBreakpointAttr === undefined ?
|
|
351
|
+
Defaults.sidebarBreakpoint :
|
|
352
|
+
Number(sidebarBreakpointAttr),
|
|
353
|
+
enablePersistence: enablePersistenceAttr === undefined ?
|
|
354
|
+
Defaults.enablePersistence :
|
|
355
|
+
enablePersistenceAttr === 'true'
|
|
217
356
|
}
|
|
218
357
|
|
|
358
|
+
// Initialize the PushMenu plugin (a unique instance).
|
|
359
|
+
|
|
360
|
+
const pushMenu = new PushMenu(sidebar, config)
|
|
361
|
+
pushMenu.init()
|
|
362
|
+
|
|
363
|
+
// Update the sidebar state on window resize events.
|
|
364
|
+
|
|
365
|
+
window.addEventListener('resize', () => {
|
|
366
|
+
pushMenu.setupSidebarBreakPoint()
|
|
367
|
+
pushMenu.updateStateByResponsiveLogic()
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
// Create the sidebar overlay element and append it to the app wrapper.
|
|
371
|
+
|
|
219
372
|
const sidebarOverlay = document.createElement('div')
|
|
220
373
|
sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY
|
|
221
374
|
document.querySelector(SELECTOR_APP_WRAPPER)?.append(sidebarOverlay)
|
|
222
375
|
|
|
376
|
+
// Handle touch events on overlay (area outside sidebar), usually we want to
|
|
377
|
+
// close the sidebar when the user taps outside the sidebar on mobile
|
|
378
|
+
// devices.
|
|
379
|
+
|
|
223
380
|
let overlayTouchMoved = false
|
|
224
381
|
|
|
225
|
-
// Handle touch events on overlay (area outside sidebar)
|
|
226
382
|
sidebarOverlay.addEventListener('touchstart', () => {
|
|
227
383
|
overlayTouchMoved = false
|
|
228
384
|
}, { passive: true })
|
|
@@ -234,21 +390,19 @@ onDOMContentLoaded(() => {
|
|
|
234
390
|
sidebarOverlay.addEventListener('touchend', event => {
|
|
235
391
|
if (!overlayTouchMoved) {
|
|
236
392
|
event.preventDefault()
|
|
237
|
-
|
|
238
|
-
const data = new PushMenu(target, Defaults)
|
|
239
|
-
data.collapse()
|
|
393
|
+
pushMenu.collapse()
|
|
240
394
|
}
|
|
395
|
+
|
|
241
396
|
overlayTouchMoved = false
|
|
242
397
|
}, { passive: false })
|
|
243
398
|
|
|
244
|
-
|
|
245
399
|
sidebarOverlay.addEventListener('click', event => {
|
|
246
400
|
event.preventDefault()
|
|
247
|
-
|
|
248
|
-
const data = new PushMenu(target, Defaults)
|
|
249
|
-
data.collapse()
|
|
401
|
+
pushMenu.collapse()
|
|
250
402
|
})
|
|
251
403
|
|
|
404
|
+
// Handle click events on sidebar toggle buttons.
|
|
405
|
+
|
|
252
406
|
const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE)
|
|
253
407
|
|
|
254
408
|
fullBtn.forEach(btn => {
|
|
@@ -263,8 +417,7 @@ onDOMContentLoaded(() => {
|
|
|
263
417
|
|
|
264
418
|
if (button) {
|
|
265
419
|
event?.preventDefault()
|
|
266
|
-
|
|
267
|
-
data.toggle()
|
|
420
|
+
pushMenu.toggle()
|
|
268
421
|
}
|
|
269
422
|
})
|
|
270
423
|
})
|
package/src/ts/util/index.ts
CHANGED
|
@@ -48,6 +48,11 @@ const safePropertyAccess = (obj: Record<string, unknown>, property: string): unk
|
|
|
48
48
|
|
|
49
49
|
/* SLIDE UP */
|
|
50
50
|
const slideUp = (target: HTMLElement, duration = 500) => {
|
|
51
|
+
if (duration <= 1) {
|
|
52
|
+
target.style.display = 'none'
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
target.style.transitionProperty = 'height, margin, padding'
|
|
52
57
|
target.style.transitionDuration = `${duration}ms`
|
|
53
58
|
target.style.boxSizing = 'border-box'
|
|
@@ -85,6 +90,11 @@ const slideDown = (target: HTMLElement, duration = 500) => {
|
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
target.style.display = display
|
|
93
|
+
|
|
94
|
+
if (duration <= 1) {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
const height = target.offsetHeight
|
|
89
99
|
target.style.overflow = 'hidden'
|
|
90
100
|
target.style.height = '0'
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(npm audit:*)",
|
|
5
|
-
"Bash(npm run build:*)",
|
|
6
|
-
"Bash(npm ls:*)",
|
|
7
|
-
"Bash(gh pr list:*)",
|
|
8
|
-
"Bash(npm outdated:*)",
|
|
9
|
-
"Bash(npm install:*)",
|
|
10
|
-
"Bash(gh pr view:*)",
|
|
11
|
-
"Bash(gh pr diff:*)",
|
|
12
|
-
"Bash(rm:*)",
|
|
13
|
-
"Bash(gh api:*)",
|
|
14
|
-
"Bash(gh issue list:*)",
|
|
15
|
-
"Bash(gh issue view:*)",
|
|
16
|
-
"Bash(npm run css:*)",
|
|
17
|
-
"Bash(npm run js:*)",
|
|
18
|
-
"Bash(npm run js-lint:*)",
|
|
19
|
-
"Bash(npm run css-lint:*)",
|
|
20
|
-
"Bash(npm run lint:*)",
|
|
21
|
-
"Bash(npm whoami:*)",
|
|
22
|
-
"Bash(npm run production:*)",
|
|
23
|
-
"Bash(git add:*)",
|
|
24
|
-
"Bash(git commit:*)",
|
|
25
|
-
"Bash(npm view:*)",
|
|
26
|
-
"Bash(cat:*)",
|
|
27
|
-
"Bash(npm pack:*)",
|
|
28
|
-
"Bash(npm publish:*)"
|
|
29
|
-
],
|
|
30
|
-
"deny": [],
|
|
31
|
-
"ask": []
|
|
32
|
-
}
|
|
33
|
-
}
|
package/CLAUDE.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
AdminLTE is a Bootstrap 5 admin dashboard template (v4.0.0-rc5). It provides responsive UI components for building admin panels and control dashboards.
|
|
8
|
-
|
|
9
|
-
## Build Commands
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install # Install dependencies
|
|
13
|
-
npm start # Start dev server with file watching (http://localhost:3000)
|
|
14
|
-
npm run build # Build all assets (CSS, JS, docs)
|
|
15
|
-
npm run production # Full production build with linting and bundlewatch
|
|
16
|
-
npm run lint # Run all linters (JS, CSS, docs, lockfile)
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### Individual Build Tasks
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm run css # Build CSS only (compile, prefix, rtl, minify)
|
|
23
|
-
npm run js # Build JavaScript only (compile, minify)
|
|
24
|
-
npm run css-lint # Lint SCSS files
|
|
25
|
-
npm run js-lint # Lint TypeScript/JavaScript files
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Architecture
|
|
29
|
-
|
|
30
|
-
### Source Structure
|
|
31
|
-
|
|
32
|
-
- **src/ts/** - TypeScript source files compiled via Rollup to `dist/js/adminlte.js`
|
|
33
|
-
- **src/scss/** - SCSS source files compiled via Sass to `dist/css/adminlte.css`
|
|
34
|
-
- **src/html/** - Astro-based documentation/demo pages
|
|
35
|
-
- **src/config/** - Build tool configurations (rollup, postcss, astro, assets)
|
|
36
|
-
- **src/assets/** - Static images copied to dist
|
|
37
|
-
|
|
38
|
-
### JavaScript Components (src/ts/)
|
|
39
|
-
|
|
40
|
-
Entry point: `adminlte.ts` exports all components:
|
|
41
|
-
- `Layout` - Core layout management and hold-transition behavior
|
|
42
|
-
- `PushMenu` - Sidebar toggle functionality
|
|
43
|
-
- `Treeview` - Hierarchical menu navigation
|
|
44
|
-
- `CardWidget` - Card collapse/expand/remove actions
|
|
45
|
-
- `DirectChat` - Chat widget toggle
|
|
46
|
-
- `FullScreen` - Fullscreen toggle functionality
|
|
47
|
-
- `initAccessibility` - WCAG 2.1 AA accessibility features
|
|
48
|
-
|
|
49
|
-
### SCSS Structure (src/scss/)
|
|
50
|
-
|
|
51
|
-
Entry point: `adminlte.scss` imports Bootstrap then AdminLTE components:
|
|
52
|
-
- `_bootstrap-variables.scss` - Bootstrap variable overrides
|
|
53
|
-
- `_variables.scss` / `_variables-dark.scss` - AdminLTE theme variables
|
|
54
|
-
- `parts/` - Organized component groups (core, components, extra-components, pages, miscellaneous)
|
|
55
|
-
- Individual component files (`_cards.scss`, `_app-sidebar.scss`, etc.)
|
|
56
|
-
|
|
57
|
-
### Documentation (src/html/)
|
|
58
|
-
|
|
59
|
-
Built with Astro framework:
|
|
60
|
-
- `pages/` - Demo pages and documentation
|
|
61
|
-
- `components/` - Reusable Astro components and MDX content
|
|
62
|
-
- Output goes to `dist/html/` then flattened to `dist/`
|
|
63
|
-
|
|
64
|
-
### Build Output (dist/)
|
|
65
|
-
|
|
66
|
-
Production assets:
|
|
67
|
-
- `dist/js/adminlte.min.js` - Compiled and minified JavaScript (UMD format)
|
|
68
|
-
- `dist/css/adminlte.min.css` - Compiled and minified CSS
|
|
69
|
-
- `dist/css/*.rtl.css` - RTL (right-to-left) variants
|
|
70
|
-
- `dist/assets/` - Static assets
|
|
71
|
-
|
|
72
|
-
## Key Technologies
|
|
73
|
-
|
|
74
|
-
- Bootstrap 5.3.x - CSS framework base
|
|
75
|
-
- TypeScript - JavaScript source language
|
|
76
|
-
- Sass - CSS preprocessor
|
|
77
|
-
- Rollup - JavaScript bundler
|
|
78
|
-
- Astro - Documentation site generator
|
|
79
|
-
- PostCSS with Autoprefixer and RTLCSS - CSS post-processing
|