lean-spec 0.2.5-dev.20251124062211 → 0.2.5-dev.20251124070920

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.
@@ -4,156 +4,618 @@
4
4
  box-sizing: border-box;
5
5
  }
6
6
 
7
+ :root {
8
+ /* Light theme colors */
9
+ --bg-primary: #f8f9fa;
10
+ --bg-secondary: #ffffff;
11
+ --bg-tertiary: #f1f3f5;
12
+ --bg-hover: #e9ecef;
13
+ --bg-active: #dee2e6;
14
+
15
+ --text-primary: #212529;
16
+ --text-secondary: #495057;
17
+ --text-tertiary: #868e96;
18
+
19
+ --border-color: #dee2e6;
20
+ --border-light: #e9ecef;
21
+
22
+ --accent-blue: #0066cc;
23
+ --accent-blue-hover: #0052a3;
24
+ --accent-blue-light: #e7f3ff;
25
+
26
+ --accent-green: #00a854;
27
+ --accent-green-light: #e6f7ed;
28
+
29
+ --accent-purple: #7c3aed;
30
+ --accent-purple-light: #f3ebff;
31
+
32
+ --accent-orange: #ff8c00;
33
+ --accent-orange-light: #fff3e0;
34
+
35
+ --accent-red: #d9363e;
36
+ --accent-red-light: #ffebee;
37
+
38
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
39
+ --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
40
+ --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
41
+
42
+ --sidebar-width: 240px;
43
+ --topbar-height: 64px;
44
+ }
45
+
46
+ /* Note: Dark theme will be added in the tutorial */
47
+ @media (prefers-color-scheme: dark) {
48
+ :root {
49
+ /* Dark theme colors - to be implemented */
50
+ }
51
+ }
52
+
7
53
  body {
8
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
9
- background-color: #f5f5f5;
10
- color: #333;
54
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
55
+ background-color: var(--bg-primary);
56
+ color: var(--text-primary);
11
57
  line-height: 1.6;
58
+ }
59
+
60
+ /* ============================================
61
+ SIDEBAR
62
+ ============================================ */
63
+
64
+ .sidebar {
65
+ position: fixed;
66
+ top: 0;
67
+ left: 0;
68
+ width: var(--sidebar-width);
69
+ height: 100vh;
70
+ background: var(--bg-secondary);
71
+ border-right: 1px solid var(--border-color);
72
+ display: flex;
73
+ flex-direction: column;
74
+ z-index: 100;
75
+ }
76
+
77
+ .sidebar-header {
12
78
  padding: 20px;
79
+ border-bottom: 1px solid var(--border-color);
13
80
  }
14
81
 
15
- .container {
16
- max-width: 600px;
17
- margin: 0 auto;
18
- background: white;
19
- border-radius: 12px;
20
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
21
- padding: 30px;
82
+ .logo {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 12px;
86
+ color: var(--accent-blue);
87
+ font-weight: 600;
88
+ font-size: 1.1rem;
22
89
  }
23
90
 
24
- header {
25
- text-align: center;
26
- margin-bottom: 30px;
27
- padding-bottom: 20px;
28
- border-bottom: 2px solid #e0e0e0;
91
+ .logo svg {
92
+ flex-shrink: 0;
93
+ }
94
+
95
+ .logo-text {
96
+ color: var(--text-primary);
97
+ }
98
+
99
+ .sidebar-nav {
100
+ flex: 1;
101
+ padding: 20px 0;
102
+ overflow-y: auto;
103
+ }
104
+
105
+ .nav-item {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 12px;
109
+ padding: 12px 20px;
110
+ color: var(--text-secondary);
111
+ text-decoration: none;
112
+ transition: all 0.2s;
113
+ border-left: 3px solid transparent;
114
+ }
115
+
116
+ .nav-item:hover {
117
+ background: var(--bg-tertiary);
118
+ color: var(--text-primary);
119
+ }
120
+
121
+ .nav-item.active {
122
+ background: var(--accent-blue-light);
123
+ color: var(--accent-blue);
124
+ border-left-color: var(--accent-blue);
125
+ }
126
+
127
+ .nav-item svg {
128
+ flex-shrink: 0;
129
+ }
130
+
131
+ .sidebar-footer {
132
+ padding: 16px;
133
+ border-top: 1px solid var(--border-color);
134
+ }
135
+
136
+ .user-profile {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 12px;
140
+ padding: 8px;
141
+ border-radius: 8px;
142
+ cursor: pointer;
143
+ transition: background 0.2s;
144
+ }
145
+
146
+ .user-profile:hover {
147
+ background: var(--bg-tertiary);
148
+ }
149
+
150
+ .avatar {
151
+ width: 40px;
152
+ height: 40px;
153
+ border-radius: 50%;
154
+ background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
155
+ display: flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ color: white;
159
+ font-weight: 600;
160
+ font-size: 0.9rem;
161
+ flex-shrink: 0;
162
+ }
163
+
164
+ .user-info {
165
+ flex: 1;
166
+ min-width: 0;
167
+ }
168
+
169
+ .user-name {
170
+ font-weight: 500;
171
+ font-size: 0.9rem;
172
+ color: var(--text-primary);
173
+ white-space: nowrap;
174
+ overflow: hidden;
175
+ text-overflow: ellipsis;
29
176
  }
30
177
 
31
- h1 {
32
- font-size: 2em;
33
- color: #2c3e50;
34
- margin-bottom: 8px;
178
+ .user-role {
179
+ font-size: 0.8rem;
180
+ color: var(--text-tertiary);
181
+ white-space: nowrap;
182
+ overflow: hidden;
183
+ text-overflow: ellipsis;
35
184
  }
36
185
 
37
- .subtitle {
38
- color: #7f8c8d;
39
- font-size: 0.95em;
186
+ /* ============================================
187
+ MAIN CONTENT
188
+ ============================================ */
189
+
190
+ .main-content {
191
+ margin-left: var(--sidebar-width);
192
+ min-height: 100vh;
193
+ display: flex;
194
+ flex-direction: column;
40
195
  }
41
196
 
42
- .task-input {
197
+ .top-bar {
198
+ position: sticky;
199
+ top: 0;
200
+ height: var(--topbar-height);
201
+ background: var(--bg-secondary);
202
+ border-bottom: 1px solid var(--border-color);
43
203
  display: flex;
44
- gap: 10px;
45
- margin-bottom: 25px;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ padding: 0 32px;
207
+ gap: 24px;
208
+ z-index: 90;
46
209
  }
47
210
 
48
- #taskInput {
211
+ .search-bar {
49
212
  flex: 1;
50
- padding: 12px 16px;
51
- border: 2px solid #e0e0e0;
213
+ max-width: 400px;
214
+ position: relative;
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 12px;
218
+ padding: 10px 16px;
219
+ background: var(--bg-tertiary);
220
+ border: 1px solid var(--border-light);
52
221
  border-radius: 8px;
53
- font-size: 1em;
54
- transition: border-color 0.2s;
222
+ color: var(--text-tertiary);
55
223
  }
56
224
 
57
- #taskInput:focus {
225
+ .search-bar input {
226
+ flex: 1;
227
+ border: none;
228
+ background: transparent;
58
229
  outline: none;
59
- border-color: #3498db;
230
+ color: var(--text-primary);
231
+ font-size: 0.95rem;
232
+ }
233
+
234
+ .search-bar input::placeholder {
235
+ color: var(--text-tertiary);
236
+ }
237
+
238
+ .top-bar-actions {
239
+ display: flex;
240
+ align-items: center;
241
+ gap: 12px;
60
242
  }
61
243
 
62
- #addButton {
244
+ .icon-button {
245
+ position: relative;
246
+ width: 40px;
247
+ height: 40px;
248
+ border: none;
249
+ background: transparent;
250
+ border-radius: 8px;
251
+ cursor: pointer;
252
+ display: flex;
253
+ align-items: center;
254
+ justify-content: center;
255
+ color: var(--text-secondary);
256
+ transition: all 0.2s;
257
+ }
258
+
259
+ .icon-button:hover {
260
+ background: var(--bg-tertiary);
261
+ color: var(--text-primary);
262
+ }
263
+
264
+ .badge {
265
+ position: absolute;
266
+ top: 6px;
267
+ right: 6px;
268
+ background: var(--accent-red);
269
+ color: white;
270
+ font-size: 0.7rem;
271
+ font-weight: 600;
272
+ padding: 2px 6px;
273
+ border-radius: 10px;
274
+ min-width: 18px;
275
+ text-align: center;
276
+ }
277
+
278
+ /* ============================================
279
+ DASHBOARD CONTENT
280
+ ============================================ */
281
+
282
+ .dashboard-content {
283
+ flex: 1;
284
+ padding: 32px;
285
+ }
286
+
287
+ .page-header {
288
+ display: flex;
289
+ align-items: center;
290
+ justify-content: space-between;
291
+ margin-bottom: 32px;
292
+ }
293
+
294
+ .page-header h1 {
295
+ font-size: 1.8rem;
296
+ font-weight: 600;
297
+ color: var(--text-primary);
298
+ margin-bottom: 4px;
299
+ }
300
+
301
+ .page-subtitle {
302
+ font-size: 0.95rem;
303
+ color: var(--text-secondary);
304
+ }
305
+
306
+ .btn-primary {
307
+ display: flex;
308
+ align-items: center;
309
+ gap: 8px;
63
310
  padding: 12px 24px;
64
- background: #3498db;
311
+ background: var(--accent-blue);
65
312
  color: white;
66
313
  border: none;
67
314
  border-radius: 8px;
68
- font-size: 1em;
315
+ font-weight: 500;
316
+ font-size: 0.95rem;
69
317
  cursor: pointer;
70
- transition: background 0.2s;
318
+ transition: all 0.2s;
319
+ box-shadow: var(--shadow-sm);
320
+ }
321
+
322
+ .btn-primary:hover {
323
+ background: var(--accent-blue-hover);
324
+ box-shadow: var(--shadow-md);
325
+ transform: translateY(-1px);
71
326
  }
72
327
 
73
- #addButton:hover {
74
- background: #2980b9;
328
+ /* ============================================
329
+ STATS GRID
330
+ ============================================ */
331
+
332
+ .stats-grid {
333
+ display: grid;
334
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
335
+ gap: 24px;
336
+ margin-bottom: 32px;
75
337
  }
76
338
 
77
- .task-list {
78
- min-height: 200px;
339
+ .stat-card {
340
+ background: var(--bg-secondary);
341
+ border: 1px solid var(--border-color);
342
+ border-radius: 12px;
343
+ padding: 24px;
344
+ transition: all 0.2s;
79
345
  }
80
346
 
81
- #taskList {
82
- list-style: none;
347
+ .stat-card:hover {
348
+ box-shadow: var(--shadow-md);
349
+ transform: translateY(-2px);
83
350
  }
84
351
 
85
- .task-item {
86
- padding: 15px;
87
- margin-bottom: 10px;
88
- background: #f8f9fa;
89
- border-radius: 8px;
352
+ .stat-header {
90
353
  display: flex;
91
354
  align-items: center;
92
355
  justify-content: space-between;
93
- transition: background 0.2s;
356
+ margin-bottom: 16px;
357
+ }
358
+
359
+ .stat-icon {
360
+ width: 48px;
361
+ height: 48px;
362
+ border-radius: 12px;
363
+ display: flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ }
367
+
368
+ .stat-icon.blue {
369
+ background: var(--accent-blue-light);
370
+ color: var(--accent-blue);
371
+ }
372
+
373
+ .stat-icon.green {
374
+ background: var(--accent-green-light);
375
+ color: var(--accent-green);
376
+ }
377
+
378
+ .stat-icon.purple {
379
+ background: var(--accent-purple-light);
380
+ color: var(--accent-purple);
94
381
  }
95
382
 
96
- .task-item:hover {
97
- background: #e9ecef;
383
+ .stat-icon.orange {
384
+ background: var(--accent-orange-light);
385
+ color: var(--accent-orange);
386
+ }
387
+
388
+ .stat-change {
389
+ font-size: 0.85rem;
390
+ font-weight: 600;
391
+ padding: 4px 8px;
392
+ border-radius: 6px;
98
393
  }
99
394
 
100
- .task-item.completed {
101
- opacity: 0.6;
395
+ .stat-change.positive {
396
+ color: var(--accent-green);
397
+ background: var(--accent-green-light);
102
398
  }
103
399
 
104
- .task-item.completed .task-text {
105
- text-decoration: line-through;
400
+ .stat-change.negative {
401
+ color: var(--accent-red);
402
+ background: var(--accent-red-light);
106
403
  }
107
404
 
108
- .task-content {
405
+ .stat-content {
109
406
  display: flex;
110
- align-items: center;
111
- gap: 12px;
112
- flex: 1;
407
+ flex-direction: column;
113
408
  }
114
409
 
115
- .task-checkbox {
116
- width: 20px;
117
- height: 20px;
118
- cursor: pointer;
410
+ .stat-value {
411
+ font-size: 2rem;
412
+ font-weight: 700;
413
+ color: var(--text-primary);
414
+ margin-bottom: 4px;
415
+ }
416
+
417
+ .stat-label {
418
+ font-size: 0.9rem;
419
+ color: var(--text-secondary);
119
420
  }
120
421
 
121
- .task-text {
122
- font-size: 1em;
123
- color: #2c3e50;
422
+ /* ============================================
423
+ CHARTS
424
+ ============================================ */
425
+
426
+ .charts-row {
427
+ display: grid;
428
+ grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
429
+ gap: 24px;
430
+ margin-bottom: 32px;
431
+ }
432
+
433
+ .chart-card {
434
+ background: var(--bg-secondary);
435
+ border: 1px solid var(--border-color);
436
+ border-radius: 12px;
437
+ padding: 24px;
124
438
  }
125
439
 
126
- .delete-button {
440
+ .chart-header {
441
+ display: flex;
442
+ align-items: center;
443
+ justify-content: space-between;
444
+ margin-bottom: 20px;
445
+ }
446
+
447
+ .chart-header h3 {
448
+ font-size: 1.1rem;
449
+ font-weight: 600;
450
+ color: var(--text-primary);
451
+ }
452
+
453
+ .chart-period {
127
454
  padding: 6px 12px;
128
- background: #e74c3c;
129
- color: white;
130
- border: none;
455
+ border: 1px solid var(--border-color);
131
456
  border-radius: 6px;
132
- font-size: 0.85em;
457
+ background: var(--bg-tertiary);
458
+ color: var(--text-secondary);
459
+ font-size: 0.85rem;
133
460
  cursor: pointer;
461
+ outline: none;
462
+ }
463
+
464
+ .chart-period:hover {
465
+ border-color: var(--accent-blue);
466
+ }
467
+
468
+ canvas {
469
+ max-height: 280px;
470
+ }
471
+
472
+ /* ============================================
473
+ ACTIVITY SECTION
474
+ ============================================ */
475
+
476
+ .activity-section {
477
+ background: var(--bg-secondary);
478
+ border: 1px solid var(--border-color);
479
+ border-radius: 12px;
480
+ padding: 24px;
481
+ }
482
+
483
+ .section-header {
484
+ display: flex;
485
+ align-items: center;
486
+ justify-content: space-between;
487
+ margin-bottom: 20px;
488
+ }
489
+
490
+ .section-header h3 {
491
+ font-size: 1.1rem;
492
+ font-weight: 600;
493
+ color: var(--text-primary);
494
+ }
495
+
496
+ .view-all {
497
+ font-size: 0.9rem;
498
+ color: var(--accent-blue);
499
+ text-decoration: none;
500
+ font-weight: 500;
501
+ transition: color 0.2s;
502
+ }
503
+
504
+ .view-all:hover {
505
+ color: var(--accent-blue-hover);
506
+ }
507
+
508
+ .activity-list {
509
+ display: flex;
510
+ flex-direction: column;
511
+ gap: 16px;
512
+ }
513
+
514
+ .activity-item {
515
+ display: flex;
516
+ align-items: flex-start;
517
+ gap: 16px;
518
+ padding: 16px;
519
+ background: var(--bg-tertiary);
520
+ border-radius: 8px;
134
521
  transition: background 0.2s;
135
522
  }
136
523
 
137
- .delete-button:hover {
138
- background: #c0392b;
524
+ .activity-item:hover {
525
+ background: var(--bg-hover);
139
526
  }
140
527
 
141
- .stats {
142
- margin-top: 20px;
143
- padding-top: 20px;
144
- border-top: 2px solid #e0e0e0;
145
- text-align: center;
146
- color: #7f8c8d;
147
- font-size: 0.9em;
528
+ .activity-icon {
529
+ width: 40px;
530
+ height: 40px;
531
+ border-radius: 50%;
532
+ display: flex;
533
+ align-items: center;
534
+ justify-content: center;
535
+ flex-shrink: 0;
148
536
  }
149
537
 
150
- footer {
151
- margin-top: 30px;
152
- padding-top: 20px;
153
- border-top: 2px solid #e0e0e0;
154
- text-align: center;
155
- color: #95a5a6;
156
- font-size: 0.85em;
538
+ .activity-icon.user {
539
+ background: var(--accent-blue-light);
540
+ color: var(--accent-blue);
541
+ }
542
+
543
+ .activity-icon.report {
544
+ background: var(--accent-green-light);
545
+ color: var(--accent-green);
546
+ }
547
+
548
+ .activity-icon.alert {
549
+ background: var(--accent-orange-light);
550
+ color: var(--accent-orange);
551
+ }
552
+
553
+ .activity-content {
554
+ flex: 1;
555
+ min-width: 0;
556
+ }
557
+
558
+ .activity-title {
559
+ font-weight: 500;
560
+ color: var(--text-primary);
561
+ margin-bottom: 4px;
562
+ }
563
+
564
+ .activity-description {
565
+ font-size: 0.9rem;
566
+ color: var(--text-secondary);
567
+ margin-bottom: 6px;
568
+ }
569
+
570
+ .activity-time {
571
+ font-size: 0.85rem;
572
+ color: var(--text-tertiary);
573
+ }
574
+
575
+ /* ============================================
576
+ RESPONSIVE
577
+ ============================================ */
578
+
579
+ @media (max-width: 1024px) {
580
+ .charts-row {
581
+ grid-template-columns: 1fr;
582
+ }
583
+ }
584
+
585
+ @media (max-width: 768px) {
586
+ :root {
587
+ --sidebar-width: 0;
588
+ }
589
+
590
+ .sidebar {
591
+ transform: translateX(-100%);
592
+ }
593
+
594
+ .main-content {
595
+ margin-left: 0;
596
+ }
597
+
598
+ .dashboard-content {
599
+ padding: 20px;
600
+ }
601
+
602
+ .stats-grid {
603
+ grid-template-columns: 1fr;
604
+ }
605
+
606
+ .page-header {
607
+ flex-direction: column;
608
+ align-items: flex-start;
609
+ gap: 16px;
610
+ }
611
+
612
+ .top-bar {
613
+ padding: 0 16px;
614
+ }
615
+
616
+ .search-bar {
617
+ max-width: none;
618
+ }
157
619
  }
158
620
 
159
621
  .empty-state {
@@ -12,6 +12,7 @@ const PORT = 3000;
12
12
  app.use(express.static(path.join(__dirname, 'public')));
13
13
 
14
14
  app.listen(PORT, () => {
15
- console.log(`✓ Task Manager running at http://localhost:${PORT}`);
16
- console.log(`✓ Open your browser and try adding some tasks!`);
15
+ console.log(`✓ Admin Dashboard running at http://localhost:${PORT}`);
16
+ console.log(`✓ Open your browser to see the professional dashboard!`);
17
+ console.log(`💡 Tutorial goal: Add dark theme support`);
17
18
  });