vanta-admin 0.3.0__tar.gz → 0.4.0__tar.gz

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 (45) hide show
  1. {vanta_admin-0.3.0/vanta_admin.egg-info → vanta_admin-0.4.0}/PKG-INFO +7 -3
  2. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/README.md +6 -2
  3. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/pyproject.toml +1 -1
  4. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.admin.css +77 -20
  5. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.responsive.css +1 -1
  6. vanta_admin-0.4.0/vanta_admin/static/admin/js/vanta-theme.js +128 -0
  7. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/base_site.html +1 -1
  8. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/nav_sidebar.html +36 -11
  9. {vanta_admin-0.3.0 → vanta_admin-0.4.0/vanta_admin.egg-info}/PKG-INFO +7 -3
  10. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin.egg-info/SOURCES.txt +1 -1
  11. vanta_admin-0.3.0/vanta_admin/static/admin/js/theme.js +0 -37
  12. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/LICENSE +0 -0
  13. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/MANIFEST.in +0 -0
  14. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/setup.cfg +0 -0
  15. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/__init__.py +0 -0
  16. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/apps.py +0 -0
  17. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.base.css +0 -0
  18. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.css +0 -0
  19. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.login.css +0 -0
  20. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/theme.tokens.css +0 -0
  21. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/css/two_factor.css +0 -0
  22. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/img/favicon.png +0 -0
  23. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/js/changelist.js +0 -0
  24. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/js/forms.js +0 -0
  25. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/js/messages.js +0 -0
  26. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/static/admin/js/sidebar.js +0 -0
  27. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/app_index.html +0 -0
  28. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/base.html +0 -0
  29. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/change_form.html +0 -0
  30. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/change_list.html +0 -0
  31. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/filter.html +0 -0
  32. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/includes/breadcrumbs.html +0 -0
  33. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/index.html +0 -0
  34. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/admin/login.html +0 -0
  35. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/_base.html +0 -0
  36. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/_base_focus.html +0 -0
  37. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/_wizard_actions.html +0 -0
  38. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/core/login.html +0 -0
  39. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/core/setup_complete.html +0 -0
  40. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templates/two_factor/profile/profile.html +0 -0
  41. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templatetags/__init__.py +0 -0
  42. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin/templatetags/admin_theme.py +0 -0
  43. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin.egg-info/dependency_links.txt +0 -0
  44. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin.egg-info/requires.txt +0 -0
  45. {vanta_admin-0.3.0 → vanta_admin-0.4.0}/vanta_admin.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vanta-admin
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: A sharp, dark, and portable Django admin theme forged for builders who want the admin to feel less default.
5
5
  Author: oli-dev0
6
6
  License-Expression: MIT
@@ -47,8 +47,12 @@ feels more deliberate in everyday use.
47
47
  - Styled select controls for common admin dropdowns, while Django's native
48
48
  multi-select fields stay unchanged.
49
49
  - Built-in icons for common admin areas, models, and recent actions.
50
- - A cleaner account menu with theme controls, project links, password access,
51
- logout, and a Vanta support link.
50
+ - A cleaner account menu with display preferences, project links, password
51
+ access, logout, and a Vanta support link.
52
+ - A 12-hour and 24-hour time-format preference for changelist date/time values,
53
+ stored in the browser for each admin user.
54
+ - Shorter changelist date formatting that makes date-heavy tables easier to
55
+ scan.
52
56
  - A packaged favicon for the admin.
53
57
  - A mobile sidebar overlay that makes the admin easier to use on smaller
54
58
  screens.
@@ -22,8 +22,12 @@ feels more deliberate in everyday use.
22
22
  - Styled select controls for common admin dropdowns, while Django's native
23
23
  multi-select fields stay unchanged.
24
24
  - Built-in icons for common admin areas, models, and recent actions.
25
- - A cleaner account menu with theme controls, project links, password access,
26
- logout, and a Vanta support link.
25
+ - A cleaner account menu with display preferences, project links, password
26
+ access, logout, and a Vanta support link.
27
+ - A 12-hour and 24-hour time-format preference for changelist date/time values,
28
+ stored in the browser for each admin user.
29
+ - Shorter changelist date formatting that makes date-heavy tables easier to
30
+ scan.
27
31
  - A packaged favicon for the admin.
28
32
  - A mobile sidebar overlay that makes the admin easier to use on smaller
29
33
  screens.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vanta-admin"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "A sharp, dark, and portable Django admin theme forged for builders who want the admin to feel less default."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -332,8 +332,8 @@ body.admin-sidebar-collapsed .admin-sidebar__collapse-arrow {
332
332
  position: absolute;
333
333
  bottom: -0.2rem;
334
334
  left: 10.45rem;
335
- width: 12.7rem;
336
- padding: 0.72rem;
335
+ width: 16.6rem;
336
+ padding: 0.42rem 0.72rem;
337
337
  border: 1px solid var(--border-strong);
338
338
  border-radius: var(--radius-md);
339
339
  background: var(--surface-strong);
@@ -341,17 +341,65 @@ body.admin-sidebar-collapsed .admin-sidebar__collapse-arrow {
341
341
  color: var(--text);
342
342
  }
343
343
 
344
- .admin-sidebar__theme-controls {
344
+ .admin-sidebar__account-section {
345
+ padding: 0.64rem 0;
346
+ }
347
+
348
+ .admin-sidebar__account-section + .admin-sidebar__account-section {
349
+ border-top: 1px solid var(--border);
350
+ }
351
+
352
+ .admin-sidebar__section-title {
353
+ margin: 0 0 0.48rem;
354
+ color: var(--subtle);
355
+ font-size: 0.72rem;
356
+ font-weight: 760;
357
+ }
358
+
359
+ .admin-sidebar__display-section {
360
+ display: grid;
361
+ gap: 0.38rem;
362
+ }
363
+
364
+ .admin-sidebar__display-row {
365
+ display: grid;
366
+ grid-template-columns: minmax(0, 1fr) auto;
367
+ align-items: center;
368
+ gap: 0.28rem;
369
+ min-height: 2.15rem;
370
+ }
371
+
372
+ .admin-sidebar__display-label {
373
+ display: inline-flex;
374
+ align-items: center;
375
+ min-width: 0;
376
+ gap: 0.18rem;
377
+ color: var(--text);
378
+ font-size: 0.82rem;
379
+ font-weight: 680;
380
+ }
381
+
382
+ .admin-sidebar__display-label svg {
383
+ width: 0.95rem;
384
+ height: 0.95rem;
385
+ flex: 0 0 auto;
386
+ color: var(--muted);
387
+ transform: translateX(-0.08rem);
388
+ }
389
+
390
+ .admin-sidebar__theme-controls,
391
+ .admin-sidebar__time-controls {
345
392
  display: grid;
346
393
  grid-template-columns: 1fr 1fr;
347
394
  gap: 0.32rem;
348
395
  padding: 0.25rem;
349
- margin-bottom: 0.64rem;
396
+ width: 5.4rem;
350
397
  border-radius: 0.34rem;
351
398
  background: var(--surface-muted);
352
399
  }
353
400
 
354
- .admin-sidebar__theme-button {
401
+ .admin-sidebar__theme-button,
402
+ .admin-sidebar__time-button {
355
403
  display: inline-flex;
356
404
  align-items: center;
357
405
  justify-content: center;
@@ -365,15 +413,21 @@ body.admin-sidebar-collapsed .admin-sidebar__collapse-arrow {
365
413
  cursor: pointer;
366
414
  font-size: 0.82rem;
367
415
  font-weight: 720;
416
+ white-space: nowrap;
417
+ }
418
+
419
+ .admin-sidebar__time-button {
420
+ letter-spacing: 0;
368
421
  }
369
422
 
370
423
  .admin-sidebar__theme-button svg {
371
- width: 0.95rem;
372
- height: 0.95rem;
424
+ width: 0.92rem;
425
+ height: 0.92rem;
373
426
  }
374
427
 
375
428
  html[data-theme="dark"] .admin-sidebar__theme-button--dark,
376
- html[data-theme="light"] .admin-sidebar__theme-button--light {
429
+ html[data-theme="light"] .admin-sidebar__theme-button--light,
430
+ .admin-sidebar__time-button[aria-pressed="true"] {
377
431
  color: var(--accent-strong);
378
432
  background: var(--accent-soft);
379
433
  }
@@ -382,13 +436,18 @@ html[data-theme="light"] .admin-sidebar__theme-button--light {
382
436
  background: var(--accent-softer);
383
437
  }
384
438
 
439
+ html[data-theme="light"] .admin-sidebar__time-button[aria-pressed="true"] {
440
+ background: var(--accent-softer);
441
+ }
442
+
385
443
  .admin-sidebar__account-links {
386
444
  display: grid;
387
445
  gap: 0.1rem;
388
446
  }
389
447
 
390
448
  .admin-sidebar__account-links a,
391
- .admin-sidebar__account-links button {
449
+ .admin-sidebar__account-links button,
450
+ .admin-sidebar__logout-section button {
392
451
  display: flex;
393
452
  align-items: center;
394
453
  gap: 0.68rem;
@@ -409,7 +468,8 @@ html[data-theme="light"] .admin-sidebar__theme-button--light {
409
468
  transform 130ms var(--ease);
410
469
  }
411
470
 
412
- .admin-sidebar__account-links svg {
471
+ .admin-sidebar__account-links svg,
472
+ .admin-sidebar__logout-section svg {
413
473
  width: 1rem;
414
474
  height: 1rem;
415
475
  color: var(--muted);
@@ -486,13 +546,15 @@ html[data-theme="light"] .admin-sidebar__theme-button--light {
486
546
  .admin-sidebar__account-links .admin-sidebar__external-icon {
487
547
  width: 0.86rem;
488
548
  height: 0.86rem;
489
- margin-left: auto;
549
+ margin-left: 0.58rem;
490
550
  }
491
551
 
492
552
  .admin-sidebar__account-links a:hover,
493
553
  .admin-sidebar__account-links a:focus,
494
554
  .admin-sidebar__account-links button:hover,
495
- .admin-sidebar__account-links button:focus {
555
+ .admin-sidebar__account-links button:focus,
556
+ .admin-sidebar__logout-section button:hover,
557
+ .admin-sidebar__logout-section button:focus {
496
558
  color: var(--accent-strong);
497
559
  background: var(--accent-softer);
498
560
  transform: translateX(1px);
@@ -501,17 +563,12 @@ html[data-theme="light"] .admin-sidebar__theme-button--light {
501
563
  .admin-sidebar__account-links a:hover svg,
502
564
  .admin-sidebar__account-links a:focus svg,
503
565
  .admin-sidebar__account-links button:hover svg,
504
- .admin-sidebar__account-links button:focus svg {
566
+ .admin-sidebar__account-links button:focus svg,
567
+ .admin-sidebar__logout-section button:hover svg,
568
+ .admin-sidebar__logout-section button:focus svg {
505
569
  color: var(--accent);
506
570
  }
507
571
 
508
- .admin-sidebar__account-divider {
509
- display: block;
510
- height: 1px;
511
- margin: 0.42rem 0.24rem;
512
- background: var(--border);
513
- }
514
-
515
572
  @keyframes donation-steam {
516
573
  0%,
517
574
  100% {
@@ -182,7 +182,7 @@
182
182
  right: 0;
183
183
  left: auto;
184
184
  bottom: calc(100% + 0.55rem);
185
- width: min(12.7rem, calc(100vw - 2.4rem));
185
+ width: min(16.6rem, calc(100vw - 2.4rem));
186
186
  }
187
187
 
188
188
  .admin-model-row {
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ {
4
+ const validThemeValues = new Set(['light', 'dark']);
5
+ const validTimeFormatValues = new Set(['12', '24']);
6
+ const timeFormatStorageKey = 'django.admin.theme.timeFormat';
7
+ const root = document.documentElement;
8
+ const themeButtons = document.querySelectorAll('[data-admin-theme-value]');
9
+ const timeFormatButtons = document.querySelectorAll('[data-admin-time-format-value]');
10
+
11
+ function updateThemeButtons(theme) {
12
+ themeButtons.forEach((button) => {
13
+ button.setAttribute('aria-pressed', String(button.dataset.adminThemeValue === theme));
14
+ });
15
+ }
16
+
17
+ function applyTheme(theme) {
18
+ if (!validThemeValues.has(theme)) {
19
+ return;
20
+ }
21
+
22
+ root.dataset.theme = theme;
23
+ localStorage.setItem('theme', theme);
24
+ updateThemeButtons(theme);
25
+ }
26
+
27
+ function updateTimeFormatButtons(timeFormat) {
28
+ timeFormatButtons.forEach((button) => {
29
+ button.setAttribute('aria-pressed', String(button.dataset.adminTimeFormatValue === timeFormat));
30
+ });
31
+ }
32
+
33
+ function formatHour(hour, meridiem) {
34
+ let formattedHour = Number(hour);
35
+
36
+ if (meridiem === 'p.m.' && formattedHour !== 12) {
37
+ formattedHour += 12;
38
+ } else if (meridiem === 'a.m.' && formattedHour === 12) {
39
+ formattedHour = 0;
40
+ }
41
+
42
+ return String(formattedHour).padStart(2, '0');
43
+ }
44
+
45
+ function abbreviateMonth(text) {
46
+ return text.replace(
47
+ /\b(January|February|March|April|May|June|July|August|September|October|November|December)\b/g,
48
+ (month) => month.slice(0, 3),
49
+ );
50
+ }
51
+
52
+ function formatDateOrder(text) {
53
+ return text.replace(
54
+ /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{1,2}), (\d{4}), ([^,]+)/g,
55
+ (match, month, day, year, time) => `${day} ${month} ${year} ${time}`,
56
+ );
57
+ }
58
+
59
+ function formatTableDateText(text) {
60
+ return formatDateOrder(abbreviateMonth(text));
61
+ }
62
+
63
+ function formatTableTimeText(text) {
64
+ const formattedMinuteTime = text.replace(
65
+ /(\b[A-Z][a-z]+ \d{1,2}, \d{4}, )(\d{1,2}):(\d{2}) (a\.m\.|p\.m\.)(?=$|[^\w])/g,
66
+ (match, datePrefix, hour, minute, meridiem) => `${datePrefix}${formatHour(hour, meridiem)}:${minute}`,
67
+ );
68
+
69
+ const formattedTime = formattedMinuteTime.replace(
70
+ /(\b[A-Z][a-z]+ \d{1,2}, \d{4}, )(\d{1,2}) (a\.m\.|p\.m\.)(?=$|[^\w])/g,
71
+ (match, datePrefix, hour, meridiem) => `${datePrefix}${Number(formatHour(hour, meridiem))}h`,
72
+ );
73
+
74
+ return formatTableDateText(formattedTime);
75
+ }
76
+
77
+ function updateTableTimeFormat(timeFormat) {
78
+ document.querySelectorAll('#changelist table tbody th, #changelist table tbody td').forEach((cell) => {
79
+ if (cell.childElementCount !== 0) {
80
+ return;
81
+ }
82
+
83
+ if (!cell.dataset.adminOriginalTimeText) {
84
+ cell.dataset.adminOriginalTimeText = cell.textContent;
85
+ }
86
+
87
+ const originalText = cell.dataset.adminOriginalTimeText;
88
+ const formattedText = timeFormat === '24' ? formatTableTimeText(originalText) : formatTableDateText(originalText);
89
+
90
+ cell.textContent = formattedText;
91
+ });
92
+ }
93
+
94
+ function applyTimeFormat(timeFormat) {
95
+ if (!validTimeFormatValues.has(timeFormat)) {
96
+ return;
97
+ }
98
+
99
+ localStorage.setItem(timeFormatStorageKey, timeFormat);
100
+ updateTimeFormatButtons(timeFormat);
101
+ updateTableTimeFormat(timeFormat);
102
+ }
103
+
104
+ const storedTheme = localStorage.getItem('theme');
105
+ if (validThemeValues.has(storedTheme)) {
106
+ root.dataset.theme = storedTheme;
107
+ updateThemeButtons(storedTheme);
108
+ } else {
109
+ updateThemeButtons(root.dataset.theme);
110
+ }
111
+
112
+ themeButtons.forEach((button) => {
113
+ button.addEventListener('click', () => {
114
+ applyTheme(button.dataset.adminThemeValue);
115
+ });
116
+ });
117
+
118
+ const storedTimeFormat = localStorage.getItem(timeFormatStorageKey);
119
+ const initialTimeFormat = validTimeFormatValues.has(storedTimeFormat) ? storedTimeFormat : '12';
120
+ updateTimeFormatButtons(initialTimeFormat);
121
+ updateTableTimeFormat(initialTimeFormat);
122
+
123
+ timeFormatButtons.forEach((button) => {
124
+ button.addEventListener('click', () => {
125
+ applyTimeFormat(button.dataset.adminTimeFormatValue);
126
+ });
127
+ });
128
+ }
@@ -25,7 +25,7 @@ Thin local override entrypoint for admin branding and theme CSS.
25
25
  }
26
26
  } catch (error) {}
27
27
  </script>
28
- <script src="{% static 'admin/js/theme.js' %}" defer></script>
28
+ <script src="{% static 'admin/js/vanta-theme.js' %}" defer></script>
29
29
  <script src="{% static 'admin/js/sidebar.js' %}" defer></script>
30
30
  <script src="{% static 'admin/js/messages.js' %}" defer></script>
31
31
  <script src="{% static 'admin/js/forms.js' %}" defer></script>
@@ -103,18 +103,41 @@
103
103
  </summary>
104
104
 
105
105
  <div class="admin-sidebar__account-menu">
106
- <div class="admin-sidebar__theme-controls" aria-label="Theme controls">
107
- <button class="admin-sidebar__theme-button admin-sidebar__theme-button--light" type="button" data-admin-theme-value="light">
108
- <svg aria-hidden="true"><use href="#admin-icon-sun"></use></svg>
109
- <span>Light</span>
110
- </button>
111
- <button class="admin-sidebar__theme-button admin-sidebar__theme-button--dark" type="button" data-admin-theme-value="dark">
112
- <svg aria-hidden="true"><use href="#admin-icon-moon"></use></svg>
113
- <span>Dark</span>
114
- </button>
106
+ <div class="admin-sidebar__account-section admin-sidebar__display-section">
107
+ <div class="admin-sidebar__section-title">Display</div>
108
+ <div class="admin-sidebar__display-row">
109
+ <span class="admin-sidebar__display-label">
110
+ <svg aria-hidden="true"><use href="#admin-icon-sun"></use></svg>
111
+ <span>Theme</span>
112
+ </span>
113
+ <span class="admin-sidebar__theme-controls" aria-label="Theme controls">
114
+ <button class="admin-sidebar__theme-button admin-sidebar__theme-button--light" type="button" data-admin-theme-value="light">
115
+ <svg aria-hidden="true"><use href="#admin-icon-sun"></use></svg>
116
+ <span class="visually-hidden">Light</span>
117
+ </button>
118
+ <button class="admin-sidebar__theme-button admin-sidebar__theme-button--dark" type="button" data-admin-theme-value="dark">
119
+ <svg aria-hidden="true"><use href="#admin-icon-moon"></use></svg>
120
+ <span class="visually-hidden">Dark</span>
121
+ </button>
122
+ </span>
123
+ </div>
124
+ <div class="admin-sidebar__display-row">
125
+ <span class="admin-sidebar__display-label">
126
+ <svg aria-hidden="true"><use href="#admin-icon-clock"></use></svg>
127
+ <span>Time format</span>
128
+ </span>
129
+ <span class="admin-sidebar__time-controls" aria-label="Time format controls">
130
+ <button class="admin-sidebar__time-button admin-sidebar__time-button--12" type="button" data-admin-time-format-value="12">
131
+ <span>12h</span>
132
+ </button>
133
+ <button class="admin-sidebar__time-button admin-sidebar__time-button--24" type="button" data-admin-time-format-value="24">
134
+ <span>24h</span>
135
+ </button>
136
+ </span>
137
+ </div>
115
138
  </div>
116
139
 
117
- <div class="admin-sidebar__account-links">
140
+ <div class="admin-sidebar__account-section admin-sidebar__account-links">
118
141
  {% if site_url %}
119
142
  <a href="{{ site_url }}">
120
143
  <svg aria-hidden="true"><use href="#admin-icon-external"></use></svg>
@@ -134,7 +157,9 @@
134
157
  <span class="donation-button__label">Buy me a coffee</span>
135
158
  <svg class="admin-sidebar__external-icon" aria-hidden="true"><use href="#admin-icon-external"></use></svg>
136
159
  </a>
137
- <span class="admin-sidebar__account-divider" aria-hidden="true"></span>
160
+ </div>
161
+
162
+ <div class="admin-sidebar__account-section admin-sidebar__logout-section">
138
163
  <form method="post" action="{% url 'admin:logout' %}">
139
164
  {% csrf_token %}
140
165
  <button type="submit">
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vanta-admin
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: A sharp, dark, and portable Django admin theme forged for builders who want the admin to feel less default.
5
5
  Author: oli-dev0
6
6
  License-Expression: MIT
@@ -47,8 +47,12 @@ feels more deliberate in everyday use.
47
47
  - Styled select controls for common admin dropdowns, while Django's native
48
48
  multi-select fields stay unchanged.
49
49
  - Built-in icons for common admin areas, models, and recent actions.
50
- - A cleaner account menu with theme controls, project links, password access,
51
- logout, and a Vanta support link.
50
+ - A cleaner account menu with display preferences, project links, password
51
+ access, logout, and a Vanta support link.
52
+ - A 12-hour and 24-hour time-format preference for changelist date/time values,
53
+ stored in the browser for each admin user.
54
+ - Shorter changelist date formatting that makes date-heavy tables easier to
55
+ scan.
52
56
  - A packaged favicon for the admin.
53
57
  - A mobile sidebar overlay that makes the admin easier to use on smaller
54
58
  screens.
@@ -21,7 +21,7 @@ vanta_admin/static/admin/js/changelist.js
21
21
  vanta_admin/static/admin/js/forms.js
22
22
  vanta_admin/static/admin/js/messages.js
23
23
  vanta_admin/static/admin/js/sidebar.js
24
- vanta_admin/static/admin/js/theme.js
24
+ vanta_admin/static/admin/js/vanta-theme.js
25
25
  vanta_admin/templates/admin/app_index.html
26
26
  vanta_admin/templates/admin/base.html
27
27
  vanta_admin/templates/admin/base_site.html
@@ -1,37 +0,0 @@
1
- 'use strict';
2
-
3
- {
4
- const validThemeValues = new Set(['light', 'dark']);
5
- const root = document.documentElement;
6
- const themeButtons = document.querySelectorAll('[data-admin-theme-value]');
7
-
8
- function updateThemeButtons(theme) {
9
- themeButtons.forEach((button) => {
10
- button.setAttribute('aria-pressed', String(button.dataset.adminThemeValue === theme));
11
- });
12
- }
13
-
14
- function applyTheme(theme) {
15
- if (!validThemeValues.has(theme)) {
16
- return;
17
- }
18
-
19
- root.dataset.theme = theme;
20
- localStorage.setItem('theme', theme);
21
- updateThemeButtons(theme);
22
- }
23
-
24
- const storedTheme = localStorage.getItem('theme');
25
- if (validThemeValues.has(storedTheme)) {
26
- root.dataset.theme = storedTheme;
27
- updateThemeButtons(storedTheme);
28
- } else {
29
- updateThemeButtons(root.dataset.theme);
30
- }
31
-
32
- themeButtons.forEach((button) => {
33
- button.addEventListener('click', () => {
34
- applyTheme(button.dataset.adminThemeValue);
35
- });
36
- });
37
- }
File without changes
File without changes
File without changes