admin-lte 4.0.0-rc7 → 4.0.1

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 (104) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +202 -102
  3. package/dist/UI/general.html +330 -129
  4. package/dist/UI/icons.html +330 -129
  5. package/dist/UI/timeline.html +330 -129
  6. package/dist/css/adminlte.css +2798 -1167
  7. package/dist/css/adminlte.css.map +1 -1
  8. package/dist/css/adminlte.min.css +2 -2
  9. package/dist/css/adminlte.min.css.map +1 -1
  10. package/dist/css/adminlte.rtl.css +2798 -1167
  11. package/dist/css/adminlte.rtl.css.map +1 -1
  12. package/dist/css/adminlte.rtl.min.css +2 -2
  13. package/dist/css/adminlte.rtl.min.css.map +1 -1
  14. package/dist/docs/browser-support.html +287 -399
  15. package/dist/docs/color-mode.html +268 -384
  16. package/dist/docs/components/main-header.html +264 -376
  17. package/dist/docs/components/main-sidebar.html +279 -391
  18. package/dist/docs/customization.html +1080 -0
  19. package/dist/docs/deployment.html +1145 -0
  20. package/dist/docs/faq.html +883 -411
  21. package/dist/docs/getting-started.html +991 -0
  22. package/dist/docs/how-to-contribute.html +361 -464
  23. package/dist/docs/index.html +16 -0
  24. package/dist/docs/integrations.html +1231 -0
  25. package/dist/docs/introduction.html +479 -448
  26. package/dist/docs/javascript/accessibility.html +387 -493
  27. package/dist/docs/javascript/card-widget.html +472 -452
  28. package/dist/docs/javascript/direct-chat.html +350 -423
  29. package/dist/docs/javascript/fullscreen.html +374 -418
  30. package/dist/docs/javascript/layout.html +371 -438
  31. package/dist/docs/javascript/plugins-overview.html +1144 -0
  32. package/dist/docs/javascript/pushmenu.html +511 -494
  33. package/dist/docs/javascript/treeview.html +492 -402
  34. package/dist/docs/layout-blueprint.html +1087 -0
  35. package/dist/docs/layout.html +313 -417
  36. package/dist/docs/license.html +278 -389
  37. package/dist/docs/migration.html +1149 -0
  38. package/dist/docs/recipes.html +1185 -0
  39. package/dist/docs/rtl.html +957 -0
  40. package/dist/examples/lockscreen.html +91 -1
  41. package/dist/examples/login-v2.html +91 -1
  42. package/dist/examples/login.html +91 -1
  43. package/dist/examples/register-v2.html +91 -1
  44. package/dist/examples/register.html +91 -1
  45. package/dist/forms/elements.html +1405 -0
  46. package/dist/forms/{general.html → layout.html} +401 -489
  47. package/dist/forms/validation.html +1275 -0
  48. package/dist/forms/wizard.html +1410 -0
  49. package/dist/generate/theme.html +160 -4
  50. package/dist/index.html +330 -129
  51. package/dist/index2.html +333 -129
  52. package/dist/index3.html +330 -129
  53. package/dist/js/adminlte.js +8 -5
  54. package/dist/js/adminlte.js.map +1 -1
  55. package/dist/js/adminlte.min.js +2 -2
  56. package/dist/js/adminlte.min.js.map +1 -1
  57. package/dist/layout/collapsed-sidebar-without-hover.html +330 -129
  58. package/dist/layout/collapsed-sidebar.html +330 -129
  59. package/dist/layout/fixed-complete.html +330 -129
  60. package/dist/layout/fixed-footer.html +330 -129
  61. package/dist/layout/fixed-header.html +330 -129
  62. package/dist/layout/fixed-sidebar.html +330 -129
  63. package/dist/layout/layout-custom-area.html +330 -129
  64. package/dist/layout/layout-rtl.html +330 -129
  65. package/dist/layout/logo-switch.html +160 -4
  66. package/dist/layout/sidebar-mini.html +330 -129
  67. package/dist/layout/unfixed-sidebar.html +330 -129
  68. package/dist/mailbox/compose.html +1151 -0
  69. package/dist/mailbox/inbox.html +1509 -0
  70. package/dist/mailbox/read.html +1202 -0
  71. package/dist/pages/404.html +239 -0
  72. package/dist/pages/500.html +227 -0
  73. package/dist/pages/calendar.html +1266 -0
  74. package/dist/pages/chat.html +1427 -0
  75. package/dist/pages/faq.html +1383 -0
  76. package/dist/pages/file-manager.html +1835 -0
  77. package/dist/pages/invoice.html +1199 -0
  78. package/dist/pages/kanban.html +1439 -0
  79. package/dist/pages/maintenance.html +230 -0
  80. package/dist/pages/pricing.html +1279 -0
  81. package/dist/pages/profile.html +1382 -0
  82. package/dist/pages/projects.html +1644 -0
  83. package/dist/pages/settings.html +1387 -0
  84. package/dist/tables/data.html +1319 -0
  85. package/dist/tables/simple.html +330 -129
  86. package/dist/widgets/cards.html +330 -129
  87. package/dist/widgets/info-box.html +330 -129
  88. package/dist/widgets/small-box.html +330 -129
  89. package/github-issue-response.md +40 -0
  90. package/netlify.toml +16 -0
  91. package/package.json +31 -24
  92. package/src/scss/_app-header.scss +27 -0
  93. package/src/scss/_app-sidebar.scss +24 -30
  94. package/src/scss/_bootstrap-variables.scss +11 -4
  95. package/src/scss/_docs.scss +816 -0
  96. package/src/scss/_table.scss +4 -4
  97. package/src/scss/adminlte.scss +4 -1
  98. package/src/ts/accessibility.ts +9 -1
  99. package/src/ts/adminlte.ts +1 -1
  100. package/src/ts/fullscreen.ts +8 -4
  101. package/src/ts/push-menu.ts +66 -5
  102. package/.claude/settings.local.json +0 -37
  103. package/CLAUDE.md +0 -79
  104. package/release.md +0 -75
@@ -5,6 +5,32 @@
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
6
  <title>AdminLTE 4 | Lockscreen</title>
7
7
 
8
+ <!--begin::Theme Init (prevents flash of incorrect theme on load, #6043)-->
9
+ <script>
10
+ (() => {
11
+ 'use strict';
12
+ const STORAGE_KEY = 'lte-theme';
13
+ let stored = null;
14
+ try {
15
+ stored = localStorage.getItem(STORAGE_KEY);
16
+ } catch {
17
+ // localStorage may be unavailable (private mode, sandboxed iframe).
18
+ }
19
+ const prefersDark = globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
20
+ // Mirror the resolution in _scripts.astro: explicit "dark"/"light" win,
21
+ // otherwise ("auto" or unset) fall back to the OS preference.
22
+ let resolved = 'light';
23
+ if (stored === 'dark' || stored === 'light') {
24
+ resolved = stored;
25
+ } else if (prefersDark) {
26
+ resolved = 'dark';
27
+ }
28
+ document.documentElement.setAttribute('data-bs-theme', resolved);
29
+ document.documentElement.style.colorScheme = resolved;
30
+ })();
31
+ </script>
32
+ <!--end::Theme Init-->
33
+
8
34
  <!--begin::Accessibility Meta Tags-->
9
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
10
36
  <meta name="color-scheme" content="light dark" />
@@ -153,7 +179,71 @@
153
179
  }
154
180
  });
155
181
  </script>
156
- <!--end::OverlayScrollbars Configure-->
182
+ <!--end::OverlayScrollbars Configure--><!--begin::Color Mode Toggle (#6010)-->
183
+ <script>
184
+ (() => {
185
+ 'use strict';
186
+
187
+ const STORAGE_KEY = 'lte-theme';
188
+
189
+ const getStoredTheme = () => localStorage.getItem(STORAGE_KEY);
190
+ const setStoredTheme = (theme) => localStorage.setItem(STORAGE_KEY, theme);
191
+
192
+ const prefersDark = () => globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
193
+
194
+ const getPreferredTheme = () => {
195
+ const stored = getStoredTheme();
196
+ if (stored) return stored;
197
+ return prefersDark() ? 'dark' : 'light';
198
+ };
199
+
200
+ const setTheme = (theme) => {
201
+ const resolved = theme === 'auto' ? (prefersDark() ? 'dark' : 'light') : theme;
202
+ document.documentElement.setAttribute('data-bs-theme', resolved);
203
+ };
204
+
205
+ setTheme(getPreferredTheme());
206
+
207
+ const showActiveTheme = (theme) => {
208
+ // Highlight the active dropdown option
209
+ document.querySelectorAll('[data-bs-theme-value]').forEach((el) => {
210
+ el.classList.remove('active');
211
+ el.setAttribute('aria-pressed', 'false');
212
+ const check = el.querySelector('.bi-check-lg');
213
+ if (check) check.classList.add('d-none');
214
+ });
215
+ const active = document.querySelector(`[data-bs-theme-value="${theme}"]`);
216
+ if (active) {
217
+ active.classList.add('active');
218
+ active.setAttribute('aria-pressed', 'true');
219
+ const check = active.querySelector('.bi-check-lg');
220
+ if (check) check.classList.remove('d-none');
221
+ }
222
+ // Sync the topbar trigger icon
223
+ document.querySelectorAll('[data-lte-theme-icon]').forEach((icon) => {
224
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
225
+ });
226
+ };
227
+
228
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
229
+ const stored = getStoredTheme();
230
+ if (!stored || stored === 'auto') setTheme(getPreferredTheme());
231
+ });
232
+
233
+ document.addEventListener('DOMContentLoaded', () => {
234
+ showActiveTheme(getPreferredTheme());
235
+ document.querySelectorAll('[data-bs-theme-value]').forEach((toggle) => {
236
+ toggle.addEventListener('click', () => {
237
+ const theme = toggle.getAttribute('data-bs-theme-value');
238
+ setStoredTheme(theme);
239
+ setTheme(theme);
240
+ showActiveTheme(theme);
241
+ });
242
+ });
243
+ });
244
+ })();
245
+ </script>
246
+ <!--end::Color Mode Toggle-->
157
247
  </body>
158
248
  <!--end::Body-->
159
249
  </html>
@@ -5,6 +5,32 @@
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
6
  <title>AdminLTE 4 | Login Page v2</title>
7
7
 
8
+ <!--begin::Theme Init (prevents flash of incorrect theme on load, #6043)-->
9
+ <script>
10
+ (() => {
11
+ 'use strict';
12
+ const STORAGE_KEY = 'lte-theme';
13
+ let stored = null;
14
+ try {
15
+ stored = localStorage.getItem(STORAGE_KEY);
16
+ } catch {
17
+ // localStorage may be unavailable (private mode, sandboxed iframe).
18
+ }
19
+ const prefersDark = globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
20
+ // Mirror the resolution in _scripts.astro: explicit "dark"/"light" win,
21
+ // otherwise ("auto" or unset) fall back to the OS preference.
22
+ let resolved = 'light';
23
+ if (stored === 'dark' || stored === 'light') {
24
+ resolved = stored;
25
+ } else if (prefersDark) {
26
+ resolved = 'dark';
27
+ }
28
+ document.documentElement.setAttribute('data-bs-theme', resolved);
29
+ document.documentElement.style.colorScheme = resolved;
30
+ })();
31
+ </script>
32
+ <!--end::Theme Init-->
33
+
8
34
  <!--begin::Accessibility Meta Tags-->
9
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
10
36
  <meta name="color-scheme" content="light dark" />
@@ -185,7 +211,71 @@
185
211
  }
186
212
  });
187
213
  </script>
188
- <!--end::OverlayScrollbars Configure-->
214
+ <!--end::OverlayScrollbars Configure--><!--begin::Color Mode Toggle (#6010)-->
215
+ <script>
216
+ (() => {
217
+ 'use strict';
218
+
219
+ const STORAGE_KEY = 'lte-theme';
220
+
221
+ const getStoredTheme = () => localStorage.getItem(STORAGE_KEY);
222
+ const setStoredTheme = (theme) => localStorage.setItem(STORAGE_KEY, theme);
223
+
224
+ const prefersDark = () => globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
225
+
226
+ const getPreferredTheme = () => {
227
+ const stored = getStoredTheme();
228
+ if (stored) return stored;
229
+ return prefersDark() ? 'dark' : 'light';
230
+ };
231
+
232
+ const setTheme = (theme) => {
233
+ const resolved = theme === 'auto' ? (prefersDark() ? 'dark' : 'light') : theme;
234
+ document.documentElement.setAttribute('data-bs-theme', resolved);
235
+ };
236
+
237
+ setTheme(getPreferredTheme());
238
+
239
+ const showActiveTheme = (theme) => {
240
+ // Highlight the active dropdown option
241
+ document.querySelectorAll('[data-bs-theme-value]').forEach((el) => {
242
+ el.classList.remove('active');
243
+ el.setAttribute('aria-pressed', 'false');
244
+ const check = el.querySelector('.bi-check-lg');
245
+ if (check) check.classList.add('d-none');
246
+ });
247
+ const active = document.querySelector(`[data-bs-theme-value="${theme}"]`);
248
+ if (active) {
249
+ active.classList.add('active');
250
+ active.setAttribute('aria-pressed', 'true');
251
+ const check = active.querySelector('.bi-check-lg');
252
+ if (check) check.classList.remove('d-none');
253
+ }
254
+ // Sync the topbar trigger icon
255
+ document.querySelectorAll('[data-lte-theme-icon]').forEach((icon) => {
256
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
257
+ });
258
+ };
259
+
260
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
261
+ const stored = getStoredTheme();
262
+ if (!stored || stored === 'auto') setTheme(getPreferredTheme());
263
+ });
264
+
265
+ document.addEventListener('DOMContentLoaded', () => {
266
+ showActiveTheme(getPreferredTheme());
267
+ document.querySelectorAll('[data-bs-theme-value]').forEach((toggle) => {
268
+ toggle.addEventListener('click', () => {
269
+ const theme = toggle.getAttribute('data-bs-theme-value');
270
+ setStoredTheme(theme);
271
+ setTheme(theme);
272
+ showActiveTheme(theme);
273
+ });
274
+ });
275
+ });
276
+ })();
277
+ </script>
278
+ <!--end::Color Mode Toggle-->
189
279
  <!--end::Script-->
190
280
  </body>
191
281
  <!--end::Body-->
@@ -5,6 +5,32 @@
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
6
  <title>AdminLTE 4 | Login Page</title>
7
7
 
8
+ <!--begin::Theme Init (prevents flash of incorrect theme on load, #6043)-->
9
+ <script>
10
+ (() => {
11
+ 'use strict';
12
+ const STORAGE_KEY = 'lte-theme';
13
+ let stored = null;
14
+ try {
15
+ stored = localStorage.getItem(STORAGE_KEY);
16
+ } catch {
17
+ // localStorage may be unavailable (private mode, sandboxed iframe).
18
+ }
19
+ const prefersDark = globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
20
+ // Mirror the resolution in _scripts.astro: explicit "dark"/"light" win,
21
+ // otherwise ("auto" or unset) fall back to the OS preference.
22
+ let resolved = 'light';
23
+ if (stored === 'dark' || stored === 'light') {
24
+ resolved = stored;
25
+ } else if (prefersDark) {
26
+ resolved = 'dark';
27
+ }
28
+ document.documentElement.setAttribute('data-bs-theme', resolved);
29
+ document.documentElement.style.colorScheme = resolved;
30
+ })();
31
+ </script>
32
+ <!--end::Theme Init-->
33
+
8
34
  <!--begin::Accessibility Meta Tags-->
9
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
10
36
  <meta name="color-scheme" content="light dark" />
@@ -175,7 +201,71 @@
175
201
  }
176
202
  });
177
203
  </script>
178
- <!--end::OverlayScrollbars Configure-->
204
+ <!--end::OverlayScrollbars Configure--><!--begin::Color Mode Toggle (#6010)-->
205
+ <script>
206
+ (() => {
207
+ 'use strict';
208
+
209
+ const STORAGE_KEY = 'lte-theme';
210
+
211
+ const getStoredTheme = () => localStorage.getItem(STORAGE_KEY);
212
+ const setStoredTheme = (theme) => localStorage.setItem(STORAGE_KEY, theme);
213
+
214
+ const prefersDark = () => globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
215
+
216
+ const getPreferredTheme = () => {
217
+ const stored = getStoredTheme();
218
+ if (stored) return stored;
219
+ return prefersDark() ? 'dark' : 'light';
220
+ };
221
+
222
+ const setTheme = (theme) => {
223
+ const resolved = theme === 'auto' ? (prefersDark() ? 'dark' : 'light') : theme;
224
+ document.documentElement.setAttribute('data-bs-theme', resolved);
225
+ };
226
+
227
+ setTheme(getPreferredTheme());
228
+
229
+ const showActiveTheme = (theme) => {
230
+ // Highlight the active dropdown option
231
+ document.querySelectorAll('[data-bs-theme-value]').forEach((el) => {
232
+ el.classList.remove('active');
233
+ el.setAttribute('aria-pressed', 'false');
234
+ const check = el.querySelector('.bi-check-lg');
235
+ if (check) check.classList.add('d-none');
236
+ });
237
+ const active = document.querySelector(`[data-bs-theme-value="${theme}"]`);
238
+ if (active) {
239
+ active.classList.add('active');
240
+ active.setAttribute('aria-pressed', 'true');
241
+ const check = active.querySelector('.bi-check-lg');
242
+ if (check) check.classList.remove('d-none');
243
+ }
244
+ // Sync the topbar trigger icon
245
+ document.querySelectorAll('[data-lte-theme-icon]').forEach((icon) => {
246
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
247
+ });
248
+ };
249
+
250
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
251
+ const stored = getStoredTheme();
252
+ if (!stored || stored === 'auto') setTheme(getPreferredTheme());
253
+ });
254
+
255
+ document.addEventListener('DOMContentLoaded', () => {
256
+ showActiveTheme(getPreferredTheme());
257
+ document.querySelectorAll('[data-bs-theme-value]').forEach((toggle) => {
258
+ toggle.addEventListener('click', () => {
259
+ const theme = toggle.getAttribute('data-bs-theme-value');
260
+ setStoredTheme(theme);
261
+ setTheme(theme);
262
+ showActiveTheme(theme);
263
+ });
264
+ });
265
+ });
266
+ })();
267
+ </script>
268
+ <!--end::Color Mode Toggle-->
179
269
  <!--end::Script-->
180
270
  </body>
181
271
  <!--end::Body-->
@@ -5,6 +5,32 @@
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
6
  <title>AdminLTE 4 | Register Page v2</title>
7
7
 
8
+ <!--begin::Theme Init (prevents flash of incorrect theme on load, #6043)-->
9
+ <script>
10
+ (() => {
11
+ 'use strict';
12
+ const STORAGE_KEY = 'lte-theme';
13
+ let stored = null;
14
+ try {
15
+ stored = localStorage.getItem(STORAGE_KEY);
16
+ } catch {
17
+ // localStorage may be unavailable (private mode, sandboxed iframe).
18
+ }
19
+ const prefersDark = globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
20
+ // Mirror the resolution in _scripts.astro: explicit "dark"/"light" win,
21
+ // otherwise ("auto" or unset) fall back to the OS preference.
22
+ let resolved = 'light';
23
+ if (stored === 'dark' || stored === 'light') {
24
+ resolved = stored;
25
+ } else if (prefersDark) {
26
+ resolved = 'dark';
27
+ }
28
+ document.documentElement.setAttribute('data-bs-theme', resolved);
29
+ document.documentElement.style.colorScheme = resolved;
30
+ })();
31
+ </script>
32
+ <!--end::Theme Init-->
33
+
8
34
  <!--begin::Accessibility Meta Tags-->
9
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
10
36
  <meta name="color-scheme" content="light dark" />
@@ -194,7 +220,71 @@
194
220
  }
195
221
  });
196
222
  </script>
197
- <!--end::OverlayScrollbars Configure-->
223
+ <!--end::OverlayScrollbars Configure--><!--begin::Color Mode Toggle (#6010)-->
224
+ <script>
225
+ (() => {
226
+ 'use strict';
227
+
228
+ const STORAGE_KEY = 'lte-theme';
229
+
230
+ const getStoredTheme = () => localStorage.getItem(STORAGE_KEY);
231
+ const setStoredTheme = (theme) => localStorage.setItem(STORAGE_KEY, theme);
232
+
233
+ const prefersDark = () => globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
234
+
235
+ const getPreferredTheme = () => {
236
+ const stored = getStoredTheme();
237
+ if (stored) return stored;
238
+ return prefersDark() ? 'dark' : 'light';
239
+ };
240
+
241
+ const setTheme = (theme) => {
242
+ const resolved = theme === 'auto' ? (prefersDark() ? 'dark' : 'light') : theme;
243
+ document.documentElement.setAttribute('data-bs-theme', resolved);
244
+ };
245
+
246
+ setTheme(getPreferredTheme());
247
+
248
+ const showActiveTheme = (theme) => {
249
+ // Highlight the active dropdown option
250
+ document.querySelectorAll('[data-bs-theme-value]').forEach((el) => {
251
+ el.classList.remove('active');
252
+ el.setAttribute('aria-pressed', 'false');
253
+ const check = el.querySelector('.bi-check-lg');
254
+ if (check) check.classList.add('d-none');
255
+ });
256
+ const active = document.querySelector(`[data-bs-theme-value="${theme}"]`);
257
+ if (active) {
258
+ active.classList.add('active');
259
+ active.setAttribute('aria-pressed', 'true');
260
+ const check = active.querySelector('.bi-check-lg');
261
+ if (check) check.classList.remove('d-none');
262
+ }
263
+ // Sync the topbar trigger icon
264
+ document.querySelectorAll('[data-lte-theme-icon]').forEach((icon) => {
265
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
266
+ });
267
+ };
268
+
269
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
270
+ const stored = getStoredTheme();
271
+ if (!stored || stored === 'auto') setTheme(getPreferredTheme());
272
+ });
273
+
274
+ document.addEventListener('DOMContentLoaded', () => {
275
+ showActiveTheme(getPreferredTheme());
276
+ document.querySelectorAll('[data-bs-theme-value]').forEach((toggle) => {
277
+ toggle.addEventListener('click', () => {
278
+ const theme = toggle.getAttribute('data-bs-theme-value');
279
+ setStoredTheme(theme);
280
+ setTheme(theme);
281
+ showActiveTheme(theme);
282
+ });
283
+ });
284
+ });
285
+ })();
286
+ </script>
287
+ <!--end::Color Mode Toggle-->
198
288
  <!--end::Script-->
199
289
  </body>
200
290
  <!--end::Body-->
@@ -5,6 +5,32 @@
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
6
  <title>AdminLTE 4 | Register Page</title>
7
7
 
8
+ <!--begin::Theme Init (prevents flash of incorrect theme on load, #6043)-->
9
+ <script>
10
+ (() => {
11
+ 'use strict';
12
+ const STORAGE_KEY = 'lte-theme';
13
+ let stored = null;
14
+ try {
15
+ stored = localStorage.getItem(STORAGE_KEY);
16
+ } catch {
17
+ // localStorage may be unavailable (private mode, sandboxed iframe).
18
+ }
19
+ const prefersDark = globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
20
+ // Mirror the resolution in _scripts.astro: explicit "dark"/"light" win,
21
+ // otherwise ("auto" or unset) fall back to the OS preference.
22
+ let resolved = 'light';
23
+ if (stored === 'dark' || stored === 'light') {
24
+ resolved = stored;
25
+ } else if (prefersDark) {
26
+ resolved = 'dark';
27
+ }
28
+ document.documentElement.setAttribute('data-bs-theme', resolved);
29
+ document.documentElement.style.colorScheme = resolved;
30
+ })();
31
+ </script>
32
+ <!--end::Theme Init-->
33
+
8
34
  <!--begin::Accessibility Meta Tags-->
9
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
10
36
  <meta name="color-scheme" content="light dark" />
@@ -180,7 +206,71 @@
180
206
  }
181
207
  });
182
208
  </script>
183
- <!--end::OverlayScrollbars Configure-->
209
+ <!--end::OverlayScrollbars Configure--><!--begin::Color Mode Toggle (#6010)-->
210
+ <script>
211
+ (() => {
212
+ 'use strict';
213
+
214
+ const STORAGE_KEY = 'lte-theme';
215
+
216
+ const getStoredTheme = () => localStorage.getItem(STORAGE_KEY);
217
+ const setStoredTheme = (theme) => localStorage.setItem(STORAGE_KEY, theme);
218
+
219
+ const prefersDark = () => globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
220
+
221
+ const getPreferredTheme = () => {
222
+ const stored = getStoredTheme();
223
+ if (stored) return stored;
224
+ return prefersDark() ? 'dark' : 'light';
225
+ };
226
+
227
+ const setTheme = (theme) => {
228
+ const resolved = theme === 'auto' ? (prefersDark() ? 'dark' : 'light') : theme;
229
+ document.documentElement.setAttribute('data-bs-theme', resolved);
230
+ };
231
+
232
+ setTheme(getPreferredTheme());
233
+
234
+ const showActiveTheme = (theme) => {
235
+ // Highlight the active dropdown option
236
+ document.querySelectorAll('[data-bs-theme-value]').forEach((el) => {
237
+ el.classList.remove('active');
238
+ el.setAttribute('aria-pressed', 'false');
239
+ const check = el.querySelector('.bi-check-lg');
240
+ if (check) check.classList.add('d-none');
241
+ });
242
+ const active = document.querySelector(`[data-bs-theme-value="${theme}"]`);
243
+ if (active) {
244
+ active.classList.add('active');
245
+ active.setAttribute('aria-pressed', 'true');
246
+ const check = active.querySelector('.bi-check-lg');
247
+ if (check) check.classList.remove('d-none');
248
+ }
249
+ // Sync the topbar trigger icon
250
+ document.querySelectorAll('[data-lte-theme-icon]').forEach((icon) => {
251
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
252
+ });
253
+ };
254
+
255
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
256
+ const stored = getStoredTheme();
257
+ if (!stored || stored === 'auto') setTheme(getPreferredTheme());
258
+ });
259
+
260
+ document.addEventListener('DOMContentLoaded', () => {
261
+ showActiveTheme(getPreferredTheme());
262
+ document.querySelectorAll('[data-bs-theme-value]').forEach((toggle) => {
263
+ toggle.addEventListener('click', () => {
264
+ const theme = toggle.getAttribute('data-bs-theme-value');
265
+ setStoredTheme(theme);
266
+ setTheme(theme);
267
+ showActiveTheme(theme);
268
+ });
269
+ });
270
+ });
271
+ })();
272
+ </script>
273
+ <!--end::Color Mode Toggle-->
184
274
  <!--end::Script-->
185
275
  </body>
186
276
  <!--end::Body-->