lean-spec 0.2.5 → 0.2.6-dev.20251125010539

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 (85) hide show
  1. package/dist/{chunk-7WXYOHZU.js → chunk-RTEGSMVL.js} +1253 -678
  2. package/dist/chunk-RTEGSMVL.js.map +1 -0
  3. package/dist/cli.js +7 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/mcp-server.js +1 -1
  6. package/package.json +2 -3
  7. package/templates/detailed/AGENTS.md +113 -0
  8. package/templates/detailed/README.md +28 -0
  9. package/templates/detailed/files/DESIGN.md +43 -0
  10. package/templates/detailed/files/PLAN.md +59 -0
  11. package/templates/detailed/files/README.md +30 -0
  12. package/templates/detailed/files/TEST.md +71 -0
  13. package/templates/examples/api-refactor/README.md +81 -0
  14. package/templates/examples/api-refactor/package.json +16 -0
  15. package/templates/examples/api-refactor/src/app.js +40 -0
  16. package/templates/examples/api-refactor/src/services/currencyService.js +43 -0
  17. package/templates/examples/api-refactor/src/services/timezoneService.js +41 -0
  18. package/templates/examples/api-refactor/src/services/weatherService.js +42 -0
  19. package/templates/examples/dark-theme/README.md +66 -0
  20. package/templates/examples/dark-theme/package.json +16 -0
  21. package/templates/examples/dark-theme/src/public/app.js +277 -0
  22. package/templates/examples/dark-theme/src/public/index.html +225 -0
  23. package/templates/examples/dark-theme/src/public/style.css +625 -0
  24. package/templates/examples/dark-theme/src/server.js +18 -0
  25. package/templates/examples/dashboard-widgets/README.md +70 -0
  26. package/templates/examples/dashboard-widgets/index.html +12 -0
  27. package/templates/examples/dashboard-widgets/package.json +22 -0
  28. package/templates/examples/dashboard-widgets/src/App.css +20 -0
  29. package/templates/examples/dashboard-widgets/src/App.jsx +16 -0
  30. package/templates/examples/dashboard-widgets/src/components/Dashboard.css +17 -0
  31. package/templates/examples/dashboard-widgets/src/components/Dashboard.jsx +15 -0
  32. package/templates/examples/dashboard-widgets/src/components/WidgetWrapper.css +23 -0
  33. package/templates/examples/dashboard-widgets/src/components/WidgetWrapper.jsx +16 -0
  34. package/templates/examples/dashboard-widgets/src/components/widgets/ChartWidget.css +33 -0
  35. package/templates/examples/dashboard-widgets/src/components/widgets/ChartWidget.jsx +28 -0
  36. package/templates/examples/dashboard-widgets/src/components/widgets/StatsWidget.css +24 -0
  37. package/templates/examples/dashboard-widgets/src/components/widgets/StatsWidget.jsx +22 -0
  38. package/templates/examples/dashboard-widgets/src/index.css +13 -0
  39. package/templates/examples/dashboard-widgets/src/main.jsx +10 -0
  40. package/templates/examples/dashboard-widgets/src/utils/mockData.js +30 -0
  41. package/templates/examples/dashboard-widgets/vite.config.js +6 -0
  42. package/templates/standard/AGENTS.md +113 -0
  43. package/templates/standard/README.md +4 -2
  44. package/dist/chunk-7WXYOHZU.js.map +0 -1
  45. package/templates/_shared/agents-components/core-rules-base-additions.md +0 -4
  46. package/templates/_shared/agents-components/core-rules-enterprise-additions.md +0 -4
  47. package/templates/_shared/agents-components/core-rules-shared.md +0 -1
  48. package/templates/_shared/agents-components/discovery-commands-enterprise-additions.md +0 -6
  49. package/templates/_shared/agents-components/discovery-commands-minimal-additions.md +0 -0
  50. package/templates/_shared/agents-components/discovery-commands-shared.md +0 -8
  51. package/templates/_shared/agents-components/discovery-commands-standard-additions.md +0 -3
  52. package/templates/_shared/agents-components/enterprise-approval.md +0 -10
  53. package/templates/_shared/agents-components/enterprise-compliance.md +0 -12
  54. package/templates/_shared/agents-components/enterprise-when-required.md +0 -13
  55. package/templates/_shared/agents-components/essential-commands-enterprise-additions.md +0 -29
  56. package/templates/_shared/agents-components/essential-commands-minimal-additions.md +0 -1
  57. package/templates/_shared/agents-components/essential-commands-shared.md +0 -15
  58. package/templates/_shared/agents-components/essential-commands-standard-additions.md +0 -18
  59. package/templates/_shared/agents-components/frontmatter-enterprise.md +0 -33
  60. package/templates/_shared/agents-components/frontmatter-minimal.md +0 -18
  61. package/templates/_shared/agents-components/frontmatter-standard.md +0 -23
  62. package/templates/_shared/agents-components/quality-standards-enterprise-additions.md +0 -4
  63. package/templates/_shared/agents-components/quality-standards-minimal-additions.md +0 -3
  64. package/templates/_shared/agents-components/quality-standards-shared.md +0 -6
  65. package/templates/_shared/agents-components/status-update-triggers.md +0 -14
  66. package/templates/_shared/agents-components/when-to-use-enterprise.md +0 -11
  67. package/templates/_shared/agents-components/when-to-use-minimal.md +0 -9
  68. package/templates/_shared/agents-components/when-to-use-standard.md +0 -9
  69. package/templates/_shared/agents-components/workflow-enterprise.md +0 -11
  70. package/templates/_shared/agents-components/workflow-standard-detailed.md +0 -10
  71. package/templates/_shared/agents-components/workflow-standard.md +0 -8
  72. package/templates/_shared/agents-template.hbs +0 -43
  73. package/templates/enterprise/README.md +0 -25
  74. package/templates/enterprise/agents-config.json +0 -16
  75. package/templates/enterprise/files/AGENTS.md +0 -194
  76. package/templates/enterprise/spec-template.md +0 -80
  77. package/templates/minimal/README.md +0 -18
  78. package/templates/minimal/agents-config.json +0 -13
  79. package/templates/minimal/config.json +0 -15
  80. package/templates/minimal/files/AGENTS.md +0 -116
  81. package/templates/minimal/spec-template.md +0 -25
  82. package/templates/standard/agents-config.json +0 -13
  83. package/templates/standard/files/AGENTS.md +0 -142
  84. /package/templates/{enterprise → detailed}/config.json +0 -0
  85. /package/templates/standard/{spec-template.md → files/README.md} +0 -0
@@ -0,0 +1,625 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
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
+
53
+ body {
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);
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 {
78
+ padding: 20px;
79
+ border-bottom: 1px solid var(--border-color);
80
+ }
81
+
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;
89
+ }
90
+
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;
176
+ }
177
+
178
+ .user-role {
179
+ font-size: 0.8rem;
180
+ color: var(--text-tertiary);
181
+ white-space: nowrap;
182
+ overflow: hidden;
183
+ text-overflow: ellipsis;
184
+ }
185
+
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;
195
+ }
196
+
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);
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ padding: 0 32px;
207
+ gap: 24px;
208
+ z-index: 90;
209
+ }
210
+
211
+ .search-bar {
212
+ flex: 1;
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);
221
+ border-radius: 8px;
222
+ color: var(--text-tertiary);
223
+ }
224
+
225
+ .search-bar input {
226
+ flex: 1;
227
+ border: none;
228
+ background: transparent;
229
+ outline: none;
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;
242
+ }
243
+
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;
310
+ padding: 12px 24px;
311
+ background: var(--accent-blue);
312
+ color: white;
313
+ border: none;
314
+ border-radius: 8px;
315
+ font-weight: 500;
316
+ font-size: 0.95rem;
317
+ cursor: pointer;
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);
326
+ }
327
+
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;
337
+ }
338
+
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;
345
+ }
346
+
347
+ .stat-card:hover {
348
+ box-shadow: var(--shadow-md);
349
+ transform: translateY(-2px);
350
+ }
351
+
352
+ .stat-header {
353
+ display: flex;
354
+ align-items: center;
355
+ justify-content: space-between;
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);
381
+ }
382
+
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;
393
+ }
394
+
395
+ .stat-change.positive {
396
+ color: var(--accent-green);
397
+ background: var(--accent-green-light);
398
+ }
399
+
400
+ .stat-change.negative {
401
+ color: var(--accent-red);
402
+ background: var(--accent-red-light);
403
+ }
404
+
405
+ .stat-content {
406
+ display: flex;
407
+ flex-direction: column;
408
+ }
409
+
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);
420
+ }
421
+
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;
438
+ }
439
+
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 {
454
+ padding: 6px 12px;
455
+ border: 1px solid var(--border-color);
456
+ border-radius: 6px;
457
+ background: var(--bg-tertiary);
458
+ color: var(--text-secondary);
459
+ font-size: 0.85rem;
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;
521
+ transition: background 0.2s;
522
+ }
523
+
524
+ .activity-item:hover {
525
+ background: var(--bg-hover);
526
+ }
527
+
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;
536
+ }
537
+
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
+ }
619
+ }
620
+
621
+ .empty-state {
622
+ text-align: center;
623
+ padding: 40px 20px;
624
+ color: #95a5a6;
625
+ }
@@ -0,0 +1,18 @@
1
+ import express from 'express';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ const app = express();
9
+ const PORT = 3000;
10
+
11
+ // Serve static files from public directory
12
+ app.use(express.static(path.join(__dirname, 'public')));
13
+
14
+ app.listen(PORT, () => {
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`);
18
+ });
@@ -0,0 +1,70 @@
1
+ # Dashboard Widgets Demo
2
+
3
+ > **Tutorial**: [Managing Multiple Features](https://leanspec.dev/docs/tutorials/multiple-features)
4
+
5
+ ## Scenario
6
+
7
+ You're building an analytics dashboard for a SaaS product. The dashboard has some basic widgets (stats cards and a simple chart), but the product team wants to add three new widgets:
8
+ - **Recent Activity Feed** - Show latest user actions
9
+ - **Performance Metrics** - Display system health indicators
10
+ - **Quick Actions Panel** - Common shortcuts for users
11
+
12
+ Each widget needs to be designed, implemented, and integrated into the dashboard grid.
13
+
14
+ ## What's Here
15
+
16
+ A minimal React + Vite dashboard with:
17
+ - Grid layout for widgets
18
+ - Two existing widgets (Stats, Chart)
19
+ - Reusable widget wrapper component
20
+ - Mock data utilities
21
+
22
+ **Files:**
23
+ - `src/App.jsx` - Main dashboard component
24
+ - `src/components/Dashboard.jsx` - Dashboard grid layout
25
+ - `src/components/widgets/` - Existing widgets
26
+ - `src/utils/mockData.js` - Sample data generator
27
+ - `index.html` - Entry point
28
+
29
+ ## Getting Started
30
+
31
+ ```bash
32
+ # Install dependencies
33
+ npm install
34
+
35
+ # Start dev server
36
+ npm run dev
37
+
38
+ # Open http://localhost:5173 in your browser
39
+ ```
40
+
41
+ ## Your Mission
42
+
43
+ Add three new widgets to the dashboard. Follow the tutorial and ask your AI assistant:
44
+
45
+ > "Help me add three new widgets to this dashboard using LeanSpec: Recent Activity Feed, Performance Metrics, and Quick Actions Panel."
46
+
47
+ The AI will guide you through:
48
+ 1. Creating specs for each widget (or one unified spec)
49
+ 2. Designing the widget interfaces
50
+ 3. Implementing components
51
+ 4. Managing dependencies between widgets
52
+ 5. Testing the integrated dashboard
53
+
54
+ ## Current Structure
55
+
56
+ ```
57
+ Dashboard
58
+ ├── StatsWidget (implemented)
59
+ ├── ChartWidget (implemented)
60
+ ├── ActivityWidget (TODO)
61
+ ├── MetricsWidget (TODO)
62
+ └── ActionsWidget (TODO)
63
+ ```
64
+
65
+ ## Tips
66
+
67
+ - Each widget is self-contained with its own component
68
+ - Widgets use the `WidgetWrapper` component for consistent styling
69
+ - Mock data is in `utils/mockData.js` - add new generators as needed
70
+ - Consider which widgets share dependencies (e.g., both might need user data)
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Dashboard Widgets Demo</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.jsx"></script>
11
+ </body>
12
+ </html>