fastapi-lite-admin 0.1.2__tar.gz → 0.1.3__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 (25) hide show
  1. {fastapi_lite_admin-0.1.2/fastapi_lite_admin.egg-info → fastapi_lite_admin-0.1.3}/PKG-INFO +1 -1
  2. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/templates/dashboard.html +12 -11
  3. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/templates/layout.html +100 -27
  4. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/templates/model_detail.html +25 -16
  5. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/templates/model_form.html +30 -20
  6. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/templates/model_list.html +56 -40
  7. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/ui/views.py +13 -3
  8. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3/fastapi_lite_admin.egg-info}/PKG-INFO +1 -1
  9. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/pyproject.toml +1 -1
  10. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/LICENSE +0 -0
  11. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/README.md +0 -0
  12. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/__init__.py +0 -0
  13. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/core/config.py +0 -0
  14. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/core/crud.py +0 -0
  15. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/core/registry.py +0 -0
  16. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/core/schema.py +0 -0
  17. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/dependencies/db.py +0 -0
  18. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/integrations/sqlalchemy.py +0 -0
  19. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/main.py +0 -0
  20. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_admin_lite/routers/admin.py +0 -0
  21. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_lite_admin.egg-info/SOURCES.txt +0 -0
  22. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_lite_admin.egg-info/dependency_links.txt +0 -0
  23. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_lite_admin.egg-info/requires.txt +0 -0
  24. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/fastapi_lite_admin.egg-info/top_level.txt +0 -0
  25. {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-lite-admin
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A lightweight, pluggable admin panel for FastAPI
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -90,26 +90,27 @@
90
90
  }
91
91
 
92
92
  .badge {
93
- padding: 4px 8px;
94
- border-radius: 4px;
93
+ padding: 4px 10px;
94
+ border-radius: 12px;
95
95
  font-size: 0.7rem;
96
96
  font-weight: 700;
97
97
  text-transform: uppercase;
98
+ letter-spacing: 0.025em;
98
99
  }
99
100
 
100
- .badge-info { background-color: #e0f2fe; color: #0369a1; }
101
- .badge-warn { background-color: #fef3c7; color: #b45309; }
102
- .badge-error { background-color: #fee2e2; color: #b91c1c; }
103
- .badge-success { background-color: #dcfce7; color: #15803d; }
101
+ .badge-info { background-color: var(--info-bg); color: var(--info-text); }
102
+ .badge-warn { background-color: var(--warning-bg); color: var(--warning-text); }
103
+ .badge-error { background-color: var(--error-bg); color: var(--error-text); }
104
+ .badge-success { background-color: var(--success-bg); color: var(--success-text); }
104
105
 
105
106
  .status-text {
106
107
  font-weight: 600;
107
108
  font-family: monospace;
108
109
  }
109
110
 
110
- .status-200 { color: var(--success); }
111
- .status-422 { color: var(--error); }
112
- .status-latency { color: var(--warning); }
111
+ .status-200 { color: var(--success-text); }
112
+ .status-422 { color: var(--error-text); }
113
+ .status-latency { color: var(--warning-text); }
113
114
 
114
115
  /* Quick Actions */
115
116
  .quick-actions {
@@ -134,12 +135,12 @@
134
135
  .action-icon {
135
136
  width: 48px;
136
137
  height: 48px;
137
- background-color: #f1f5f9;
138
+ background-color: var(--bg-surface);
138
139
  border-radius: 12px;
139
140
  display: flex;
140
141
  align-items: center;
141
142
  justify-content: center;
142
- color: var(--text-muted);
143
+ color: var(--primary);
143
144
  font-size: 1.25rem;
144
145
  }
145
146
 
@@ -8,28 +8,68 @@
8
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
9
  <style>
10
10
  :root {
11
- --primary: #0089a7;
12
- --primary-hover: #00768f;
11
+ --primary: #6366f1;
12
+ --primary-hover: #4f46e5;
13
13
  --bg-main: #f8fafc;
14
- --bg-sidebar: #ffffff;
14
+ --bg-card: #ffffff;
15
+ --bg-surface: #f1f5f9;
16
+ --bg-header: #f8fafc;
17
+ --bg-sidebar: #0f172a;
15
18
  --text-main: #1e293b;
16
19
  --text-muted: #64748b;
20
+ --sidebar-text: #94a3b8;
21
+ --sidebar-text-active: #ffffff;
17
22
  --border: #e2e8f0;
18
- --surface: #ffffff;
19
- --success: #10b981;
20
- --warning: #f59e0b;
21
- --error: #ef4444;
22
- --sidebar-width: 260px;
23
+ --sidebar-hover: #1e293b;
24
+ --sidebar-active: #334155;
25
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
26
+ --sidebar-width: 240px;
27
+ --topbar-height: 48px;
28
+
29
+ /* Status Colors */
30
+ --success-bg: #dcfce7;
31
+ --success-text: #166534;
32
+ --warning-bg: #fef9c3;
33
+ --warning-text: #854d0e;
34
+ --error-bg: #fee2e2;
35
+ --error-text: #991b1b;
36
+ --info-bg: #e0f2fe;
37
+ --info-text: #075985;
38
+ }
39
+
40
+ [data-theme="dark"] {
41
+ --bg-main: #020617;
42
+ --bg-card: #0f172a;
43
+ --bg-surface: #1e293b;
44
+ --bg-header: #1e293b;
45
+ --bg-sidebar: #020617;
46
+ --text-main: #f1f5f9;
47
+ --text-muted: #94a3b8;
48
+ --border: #1e293b;
49
+ --sidebar-hover: #0f172a;
50
+ --sidebar-active: #1e293b;
51
+ --shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3);
52
+
53
+ /* Status Colors - Dark Mode */
54
+ --success-bg: rgba(22, 101, 52, 0.2);
55
+ --success-text: #4ade80;
56
+ --warning-bg: rgba(133, 77, 14, 0.2);
57
+ --warning-text: #facc15;
58
+ --error-bg: rgba(153, 27, 27, 0.2);
59
+ --error-text: #f87171;
60
+ --info-bg: rgba(7, 89, 133, 0.2);
61
+ --info-text: #38bdf8;
23
62
  }
24
63
 
25
64
  * {
26
65
  margin: 0;
27
66
  padding: 0;
28
67
  box-sizing: border-box;
68
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
69
+ transition: background-color 0.2s, border-color 0.2s, color 0.2s;
29
70
  }
30
71
 
31
72
  body {
32
- font-family: 'Inter', sans-serif;
33
73
  background-color: var(--bg-main);
34
74
  color: var(--text-main);
35
75
  display: flex;
@@ -69,14 +109,14 @@
69
109
  .logo-text {
70
110
  font-weight: 700;
71
111
  font-size: 1.1rem;
72
- color: var(--text-main);
112
+ color: var(--sidebar-text-active);
73
113
  }
74
114
 
75
115
  .logo-subtext {
76
116
  font-size: 0.7rem;
77
117
  text-transform: uppercase;
78
118
  letter-spacing: 0.05em;
79
- color: var(--text-muted);
119
+ color: var(--sidebar-text);
80
120
  margin-top: -2px;
81
121
  }
82
122
 
@@ -91,7 +131,7 @@
91
131
  gap: 12px;
92
132
  padding: 12px 16px;
93
133
  text-decoration: none;
94
- color: var(--text-muted);
134
+ color: var(--sidebar-text);
95
135
  border-radius: 8px;
96
136
  font-weight: 500;
97
137
  transition: all 0.2s;
@@ -99,13 +139,13 @@
99
139
  }
100
140
 
101
141
  .nav-item:hover {
102
- background-color: #f1f5f9;
103
- color: var(--text-main);
142
+ background-color: var(--sidebar-hover);
143
+ color: var(--sidebar-text-active);
104
144
  }
105
145
 
106
146
  .nav-item.active {
107
- background-color: #ecfeff;
108
- color: var(--primary);
147
+ background-color: var(--sidebar-active);
148
+ color: var(--sidebar-text-active);
109
149
  }
110
150
 
111
151
  .sidebar-footer {
@@ -134,11 +174,12 @@
134
174
  .user-info .name {
135
175
  font-size: 0.9rem;
136
176
  font-weight: 600;
177
+ color: var(--sidebar-text-active);
137
178
  }
138
179
 
139
180
  .user-info .email {
140
181
  font-size: 0.75rem;
141
- color: var(--text-muted);
182
+ color: var(--sidebar-text);
142
183
  }
143
184
 
144
185
  /* Main Content */
@@ -151,8 +192,8 @@
151
192
 
152
193
  /* Topbar */
153
194
  .topbar {
154
- height: 48px;
155
- background-color: var(--surface);
195
+ height: var(--topbar-height);
196
+ background-color: var(--bg-card);
156
197
  border-bottom: 1px solid var(--border);
157
198
  display: flex;
158
199
  align-items: center;
@@ -167,13 +208,14 @@
167
208
 
168
209
  .search-box input {
169
210
  width: 100%;
170
- padding: 6px 12px 6px 32px;
171
- background-color: #f1f5f9;
172
- border: 1px solid transparent;
173
- border-radius: 6px;
211
+ padding: 8px 12px 8px 36px;
212
+ background-color: var(--bg-surface);
213
+ border: 1px solid var(--border);
214
+ border-radius: 8px;
174
215
  outline: none;
175
216
  font-size: 0.85rem;
176
217
  transition: all 0.2s;
218
+ color: var(--text-main);
177
219
  }
178
220
 
179
221
  .search-box i {
@@ -217,11 +259,11 @@
217
259
 
218
260
  /* Shared Components */
219
261
  .card {
220
- background-color: var(--surface);
262
+ background-color: var(--bg-card);
221
263
  border: 1px solid var(--border);
222
264
  border-radius: 12px;
223
265
  padding: 24px;
224
- box-shadow: 0 1px 3px rgba(0,0,0,0.05);
266
+ box-shadow: var(--shadow);
225
267
  }
226
268
 
227
269
  .btn {
@@ -244,16 +286,17 @@
244
286
 
245
287
  .btn-primary:hover {
246
288
  background-color: var(--primary-hover);
289
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
247
290
  }
248
291
 
249
292
  .btn-secondary {
250
- background-color: white;
293
+ background-color: var(--bg-card);
251
294
  border-color: var(--border);
252
295
  color: var(--text-main);
253
296
  }
254
297
 
255
298
  .btn-secondary:hover {
256
- background-color: #f8fafc;
299
+ background-color: var(--bg-surface);
257
300
  }
258
301
 
259
302
  /* Extra CSS from child templates */
@@ -311,6 +354,9 @@
311
354
  <input type="text" placeholder="Search resources...">
312
355
  </div>
313
356
  <div class="topbar-actions">
357
+ <button id="theme-toggle" class="btn-icon" style="background: none; border: none; cursor: pointer; color: var(--text-muted);">
358
+ <i class="fas fa-moon"></i>
359
+ </button>
314
360
  <i class="far fa-bell"></i>
315
361
  <i class="far fa-question-circle"></i>
316
362
  <div class="avatar" style="width: 32px; height: 32px;">
@@ -324,6 +370,33 @@
324
370
  </div>
325
371
  </div>
326
372
 
373
+ <script>
374
+ // Theme Toggle Logic
375
+ const themeToggle = document.getElementById('theme-toggle');
376
+ const icon = themeToggle.querySelector('i');
377
+
378
+ // Check for saved theme or default to light
379
+ const savedTheme = localStorage.getItem('theme') || 'light';
380
+ document.documentElement.setAttribute('data-theme', savedTheme);
381
+ updateIcon(savedTheme);
382
+
383
+ themeToggle.addEventListener('click', () => {
384
+ const currentTheme = document.documentElement.getAttribute('data-theme');
385
+ const newTheme = currentTheme === 'light' ? 'dark' : 'light';
386
+
387
+ document.documentElement.setAttribute('data-theme', newTheme);
388
+ localStorage.setItem('theme', newTheme);
389
+ updateIcon(newTheme);
390
+ });
391
+
392
+ function updateIcon(theme) {
393
+ if (theme === 'dark') {
394
+ icon.className = 'fas fa-sun';
395
+ } else {
396
+ icon.className = 'fas fa-moon';
397
+ }
398
+ }
399
+ </script>
327
400
  {% block extra_js %}{% endblock %}
328
401
  </body>
329
402
  </html>
@@ -17,54 +17,63 @@
17
17
  border-radius: 12px;
18
18
  overflow: hidden;
19
19
  border: 1px solid var(--border);
20
+ background-color: var(--border); /* This creates the thin border lines */
20
21
  }
21
22
 
22
23
  .detail-item {
23
24
  padding: 24px;
24
- border-bottom: 1px solid var(--border);
25
- background-color: white;
25
+ background-color: var(--bg-card);
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: 8px;
26
29
  }
27
30
 
28
31
  .detail-item:nth-child(odd) {
29
- border-right: 1px solid var(--border);
32
+ margin-right: 1px;
30
33
  }
31
34
 
32
- .detail-item.full-width {
33
- grid-column: span 2;
34
- border-right: none;
35
+ .detail-item:not(:last-child) {
36
+ margin-bottom: 1px;
35
37
  }
36
38
 
37
- .detail-item:last-child, .detail-item:nth-last-child(2):not(.full-width) {
38
- border-bottom: none;
39
+ .detail-item.full-width {
40
+ grid-column: span 2;
41
+ margin-right: 0;
39
42
  }
40
43
 
41
44
  .detail-label {
42
- font-size: 0.75rem;
45
+ font-size: 0.7rem;
43
46
  font-weight: 700;
44
47
  text-transform: uppercase;
45
48
  color: var(--text-muted);
46
- margin-bottom: 8px;
47
49
  letter-spacing: 0.05em;
48
50
  }
49
51
 
50
52
  .detail-value {
51
53
  font-size: 1rem;
52
- font-weight: 500;
54
+ font-weight: 600;
55
+ color: var(--text-main);
53
56
  word-break: break-all;
54
57
  }
55
58
 
56
59
  .status-pill {
57
60
  display: inline-flex;
58
61
  align-items: center;
59
- gap: 6px;
60
- padding: 4px 12px;
62
+ gap: 8px;
63
+ padding: 4px 14px;
61
64
  border-radius: 20px;
62
65
  font-size: 0.8rem;
63
- font-weight: 600;
66
+ font-weight: 700;
64
67
  }
65
68
 
66
- .status-pill.active { background-color: #dcfce7; color: #15803d; }
67
- .status-pill.inactive { background-color: #f1f5f9; color: #64748b; }
69
+ .status-pill.active {
70
+ background-color: var(--success-bg);
71
+ color: var(--success-text);
72
+ }
73
+ .status-pill.inactive {
74
+ background-color: var(--bg-surface);
75
+ color: var(--text-muted);
76
+ }
68
77
  {% endblock %}
69
78
 
70
79
  {% block content %}
@@ -58,9 +58,10 @@
58
58
  font-size: 0.75rem;
59
59
  font-weight: 700;
60
60
  text-transform: uppercase;
61
- color: var(--text-muted);
61
+ color: var(--text-main);
62
62
  margin-bottom: 8px;
63
63
  letter-spacing: 0.05em;
64
+ opacity: 0.9;
64
65
  }
65
66
 
66
67
  .form-input {
@@ -71,11 +72,13 @@
71
72
  outline: none;
72
73
  font-size: 0.95rem;
73
74
  transition: all 0.2s;
75
+ background-color: var(--bg-card);
76
+ color: var(--text-main);
74
77
  }
75
78
 
76
79
  .form-input:focus {
77
80
  border-color: var(--primary);
78
- box-shadow: 0 0 0 4px rgba(0, 137, 167, 0.1);
81
+ box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
79
82
  }
80
83
 
81
84
  .form-footer {
@@ -83,7 +86,7 @@
83
86
  justify-content: flex-end;
84
87
  gap: 12px;
85
88
  padding: 20px 32px;
86
- background-color: #fafafa;
89
+ background-color: var(--bg-surface);
87
90
  border-top: 1px solid var(--border);
88
91
  border-bottom-left-radius: 12px;
89
92
  border-bottom-right-radius: 12px;
@@ -94,28 +97,29 @@
94
97
  display: flex;
95
98
  justify-content: space-between;
96
99
  align-items: center;
97
- padding: 16px;
98
- background-color: #f8fafc;
99
- border-radius: 8px;
100
+ padding: 20px;
101
+ background-color: var(--bg-card);
102
+ border-radius: 12px;
100
103
  border: 1px solid var(--border);
101
104
  }
102
105
 
103
106
  .toggle-info .title {
104
107
  font-weight: 700;
105
- font-size: 0.9rem;
108
+ font-size: 0.95rem;
106
109
  display: block;
110
+ color: var(--text-main);
107
111
  }
108
112
 
109
113
  .toggle-info .desc {
110
- font-size: 0.75rem;
114
+ font-size: 0.8rem;
111
115
  color: var(--text-muted);
112
116
  }
113
117
 
114
118
  .switch {
115
119
  position: relative;
116
120
  display: inline-block;
117
- width: 44px;
118
- height: 24px;
121
+ width: 48px;
122
+ height: 26px;
119
123
  }
120
124
 
121
125
  .switch input { opacity: 0; width: 0; height: 0; }
@@ -124,8 +128,9 @@
124
128
  position: absolute;
125
129
  cursor: pointer;
126
130
  top: 0; left: 0; right: 0; bottom: 0;
127
- background-color: #cbd5e1;
128
- transition: .4s;
131
+ background-color: var(--bg-surface);
132
+ border: 1px solid var(--border);
133
+ transition: .3s;
129
134
  border-radius: 24px;
130
135
  }
131
136
 
@@ -135,12 +140,16 @@
135
140
  height: 18px; width: 18px;
136
141
  left: 3px; bottom: 3px;
137
142
  background-color: white;
138
- transition: .4s;
143
+ transition: .3s;
139
144
  border-radius: 50%;
145
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
140
146
  }
141
147
 
142
- input:checked + .slider { background-color: var(--primary); }
143
- input:checked + .slider:before { transform: translateX(20px); }
148
+ input:checked + .slider {
149
+ background-color: var(--primary);
150
+ border-color: var(--primary);
151
+ }
152
+ input:checked + .slider:before { transform: translateX(22px); }
144
153
 
145
154
  /* Metadata Cards */
146
155
  .meta-cards {
@@ -157,10 +166,10 @@
157
166
  }
158
167
 
159
168
  .meta-icon {
160
- width: 40px;
161
- height: 40px;
162
- border-radius: 8px;
163
- background-color: #f1f5f9;
169
+ width: 44px;
170
+ height: 44px;
171
+ border-radius: 12px;
172
+ background-color: var(--bg-surface);
164
173
  display: flex;
165
174
  align-items: center;
166
175
  justify-content: center;
@@ -175,8 +184,9 @@
175
184
  }
176
185
 
177
186
  .meta-value {
178
- font-size: 0.9rem;
187
+ font-size: 0.95rem;
179
188
  font-weight: 600;
189
+ color: var(--text-main);
180
190
  }
181
191
  {% endblock %}
182
192
 
@@ -14,6 +14,8 @@
14
14
  padding: 0;
15
15
  overflow: hidden;
16
16
  margin-bottom: 32px;
17
+ background-color: var(--bg-card);
18
+ border: 1px solid var(--border);
17
19
  }
18
20
 
19
21
  .data-table {
@@ -23,63 +25,74 @@
23
25
 
24
26
  .data-table th {
25
27
  text-align: left;
26
- padding: 6px 12px;
27
- font-size: 0.75rem;
28
+ padding: 10px 16px;
29
+ font-size: 0.7rem;
28
30
  font-weight: 700;
29
31
  text-transform: uppercase;
30
32
  color: var(--text-muted);
31
33
  border-bottom: 1px solid var(--border);
32
- background-color: #f1f5f9;
34
+ background-color: var(--bg-surface);
35
+ letter-spacing: 0.025em;
33
36
  }
34
37
 
35
38
  .data-table td {
36
- padding: 4px 12px;
37
- font-size: 0.8rem;
39
+ padding: 12px 16px;
40
+ font-size: 0.85rem;
38
41
  border-bottom: 1px solid var(--border);
39
- color: #334155;
42
+ color: var(--text-main);
40
43
  }
41
44
 
42
45
  .status-badge {
43
46
  display: inline-flex;
44
47
  align-items: center;
45
- gap: 4px;
46
- font-size: 0.7rem;
48
+ gap: 6px;
49
+ padding: 2px 10px;
50
+ border-radius: 12px;
51
+ font-size: 0.75rem;
47
52
  font-weight: 600;
48
53
  }
49
54
 
50
55
  .status-dot {
51
- width: 4px;
52
- height: 4px;
56
+ width: 6px;
57
+ height: 6px;
53
58
  border-radius: 50%;
54
59
  }
55
60
 
56
- .status-active .status-dot { background-color: var(--success); }
57
- .status-active { color: #065f46; }
61
+ .status-active {
62
+ background-color: var(--success-bg);
63
+ color: var(--success-text);
64
+ }
65
+ .status-active .status-dot { background-color: var(--success-text); }
58
66
 
67
+ .status-inactive {
68
+ background-color: var(--bg-surface);
69
+ color: var(--text-muted);
70
+ }
59
71
  .status-inactive .status-dot { background-color: var(--text-muted); }
60
- .status-inactive { color: var(--text-muted); }
61
72
 
62
73
  .action-btns {
63
74
  display: flex;
64
- gap: 6px;
75
+ gap: 8px;
65
76
  }
66
77
 
67
78
  .action-btn {
68
79
  background: none;
69
80
  border: none;
70
- color: var(--primary);
81
+ color: var(--text-muted);
71
82
  cursor: pointer;
72
- font-size: 0.75rem;
73
- font-weight: 600;
74
- transition: color 0.2s;
83
+ padding: 4px;
84
+ border-radius: 4px;
85
+ transition: all 0.2s;
75
86
  }
76
87
 
77
88
  .action-btn:hover {
78
- color: var(--text-main);
89
+ background-color: var(--bg-surface);
90
+ color: var(--primary);
79
91
  }
80
92
 
81
93
  .action-btn.delete:hover {
82
- color: var(--error);
94
+ background-color: var(--error-bg);
95
+ color: var(--error-text);
83
96
  }
84
97
 
85
98
  /* Footer Stats */
@@ -97,13 +110,13 @@
97
110
  }
98
111
 
99
112
  .footer-stat-icon {
100
- width: 40px;
101
- height: 40px;
102
- border-radius: 8px;
113
+ width: 44px;
114
+ height: 44px;
115
+ border-radius: 12px;
103
116
  display: flex;
104
117
  align-items: center;
105
118
  justify-content: center;
106
- font-size: 1.2rem;
119
+ font-size: 1.25rem;
107
120
  }
108
121
 
109
122
  .footer-stat-info .label {
@@ -115,8 +128,9 @@
115
128
  }
116
129
 
117
130
  .footer-stat-info .value {
118
- font-size: 1.25rem;
131
+ font-size: 1.5rem;
119
132
  font-weight: 700;
133
+ color: var(--text-main);
120
134
  }
121
135
 
122
136
  /* Pagination */
@@ -126,7 +140,7 @@
126
140
  justify-content: space-between;
127
141
  align-items: center;
128
142
  border-top: 1px solid var(--border);
129
- background-color: #fafafa;
143
+ background-color: var(--bg-card);
130
144
  }
131
145
 
132
146
  .pagination-info {
@@ -149,30 +163,32 @@
149
163
  }
150
164
 
151
165
  .page-size-selector select {
152
- padding: 4px 8px;
166
+ padding: 4px 12px;
153
167
  border: 1px solid var(--border);
154
- border-radius: 4px;
168
+ border-radius: 6px;
155
169
  outline: none;
156
- background: white;
170
+ background-color: var(--bg-card);
171
+ color: var(--text-main);
172
+ cursor: pointer;
157
173
  }
158
174
 
159
175
  .activity-badge {
160
176
  display: inline-flex;
161
177
  align-items: center;
162
178
  gap: 6px;
163
- padding: 2px 8px;
164
- background-color: #f1f5f9;
179
+ padding: 4px 12px;
180
+ background-color: var(--bg-surface);
165
181
  color: var(--text-muted);
166
- border-radius: 12px;
182
+ border-radius: 20px;
167
183
  font-size: 0.75rem;
168
184
  font-weight: 600;
169
185
  border: 1px solid var(--border);
170
186
  }
171
187
 
172
188
  .activity-badge.active {
173
- background-color: #ecfeff;
174
- color: var(--primary);
175
- border-color: #cffafe;
189
+ background-color: var(--info-bg);
190
+ color: var(--info-text);
191
+ border-color: transparent;
176
192
  }
177
193
 
178
194
  .activity-badge i {
@@ -241,7 +257,7 @@
241
257
 
242
258
  <div class="table-footer-stats">
243
259
  <div class="card footer-stat-card">
244
- <div class="footer-stat-icon" style="background-color: #e0f2fe; color: #0369a1;">
260
+ <div class="footer-stat-icon" style="background-color: var(--info-bg); color: var(--info-text);">
245
261
  <i class="fas fa-user-group"></i>
246
262
  </div>
247
263
  <div class="footer-stat-info">
@@ -250,7 +266,7 @@
250
266
  </div>
251
267
  </div>
252
268
  <div class="card footer-stat-card">
253
- <div class="footer-stat-icon" style="background-color: #e0e7ff; color: #4338ca;">
269
+ <div class="footer-stat-icon" style="background-color: var(--bg-surface); color: var(--primary);">
254
270
  <i class="fas fa-bolt"></i>
255
271
  </div>
256
272
  <div class="footer-stat-info">
@@ -259,7 +275,7 @@
259
275
  </div>
260
276
  </div>
261
277
  <div class="card footer-stat-card">
262
- <div class="footer-stat-icon" style="background-color: #fee2e2; color: #b91c1c;">
278
+ <div class="footer-stat-icon" style="background-color: var(--error-bg); color: var(--error-text);">
263
279
  <i class="fas fa-triangle-exclamation"></i>
264
280
  </div>
265
281
  <div class="footer-stat-info">
@@ -331,7 +347,7 @@
331
347
  <th onclick="toggleSort('${col}')" style="cursor: pointer; user-select: none;">
332
348
  <div style="display: flex; align-items: center; gap: 8px;">
333
349
  ${col.replace('_', ' ')}
334
- <i class="fas ${icon}" style="font-size: 0.7rem; color: ${isSorted ? 'var(--primary)' : '#ccc'}"></i>
350
+ <i class="fas ${icon}" style="font-size: 0.7rem; color: ${isSorted ? 'var(--primary)' : 'var(--border)'}"></i>
335
351
  </div>
336
352
  </th>
337
353
  `;
@@ -351,7 +367,7 @@
351
367
  const name = row['name'] || (row['email'] ? row['email'].split('@')[0] : 'Item');
352
368
  return `
353
369
  <td>
354
- <span style="font-weight: 600;">${val}</span>
370
+ <span style="font-weight: 600; color: var(--text-main);">${val}</span>
355
371
  ${col === 'name' && row['email'] ? `<span style="font-size: 0.7rem; color: var(--text-muted); margin-left: 4px;">(${row['email']})</span>` : ''}
356
372
  </td>
357
373
  `;
@@ -1,8 +1,11 @@
1
1
  from typing import Any
2
- from fastapi import APIRouter, Request
2
+ import asyncio
3
+ from fastapi import APIRouter, HTTPException, Request, Depends
3
4
  from fastapi.responses import HTMLResponse
4
5
  from fastapi.templating import Jinja2Templates
6
+ from sqlalchemy.ext.asyncio import AsyncSession
5
7
  import os
8
+ import asyncio
6
9
 
7
10
  # Get path to templates directory relative to this file
8
11
  TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), "templates")
@@ -74,7 +77,13 @@ def create_ui_router(admin: Any) -> APIRouter:
74
77
  return templates.TemplateResponse(
75
78
  request=request,
76
79
  name="dashboard.html",
77
- context={"stats": stats, "recent_logs": recent_logs, "models": list(models.keys())}
80
+ context={
81
+ "stats": stats,
82
+ "recent_logs": recent_logs,
83
+ "models": list(models.keys()),
84
+ "logs_config": admin.logs_config,
85
+ "admin_title": admin.title
86
+ }
78
87
  )
79
88
 
80
89
  @router.get("/{model_name}", response_class=HTMLResponse)
@@ -127,7 +136,8 @@ def create_ui_router(admin: Any) -> APIRouter:
127
136
  "recent_count": recent_count,
128
137
  "attention_count": attention_count,
129
138
  "has_date_field": bool(date_field),
130
- "has_attention_filter": attn_filter is not None
139
+ "has_attention_filter": attn_filter is not None,
140
+ "admin_title": admin.title
131
141
  }
132
142
  )
133
143
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-lite-admin
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A lightweight, pluggable admin panel for FastAPI
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fastapi-lite-admin"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "A lightweight, pluggable admin panel for FastAPI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"