@mohammad-irfan/create-dashboard-kit 1.0.0

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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +153 -0
  3. package/bin/create-dashboard.js +12 -0
  4. package/dist/cli.d.ts +7 -0
  5. package/dist/cli.js +223 -0
  6. package/dist/configBuilder.d.ts +8 -0
  7. package/dist/configBuilder.js +573 -0
  8. package/dist/generator.d.ts +9 -0
  9. package/dist/generator.js +223 -0
  10. package/dist/presets.d.ts +8 -0
  11. package/dist/presets.js +72 -0
  12. package/dist/prompts.d.ts +2 -0
  13. package/dist/prompts.js +121 -0
  14. package/dist/templateEngine.d.ts +3 -0
  15. package/dist/templateEngine.js +31 -0
  16. package/dist/types.d.ts +54 -0
  17. package/dist/types.js +1 -0
  18. package/dist/validation.d.ts +16 -0
  19. package/dist/validation.js +73 -0
  20. package/package.json +56 -0
  21. package/templates/source/components/controls/Button.tsx +69 -0
  22. package/templates/source/components/controls/Input.tsx +59 -0
  23. package/templates/source/components/controls/SearchBar.tsx +44 -0
  24. package/templates/source/components/controls/Select.tsx +61 -0
  25. package/templates/source/components/controls/ThemeToggle.tsx +23 -0
  26. package/templates/source/components/feedback/NotificationCenter.tsx +151 -0
  27. package/templates/source/components/feedback/Skeleton.tsx +22 -0
  28. package/templates/source/components/feedback/StatusBadge.tsx +35 -0
  29. package/templates/source/components/feedback/statusBadgeStyles.ts +28 -0
  30. package/templates/source/components/icons/IconSet.tsx +235 -0
  31. package/templates/source/components/layout/AppShell.tsx +70 -0
  32. package/templates/source/components/layout/Header.tsx +90 -0
  33. package/templates/source/components/layout/PageHeader.tsx +27 -0
  34. package/templates/source/components/layout/Sidebar.tsx +202 -0
  35. package/templates/source/components/metrics/MetricRow.tsx +61 -0
  36. package/templates/source/components/metrics/StatCard.tsx +49 -0
  37. package/templates/source/components/navigation/NavItem.tsx +75 -0
  38. package/templates/source/components/navigation/ShortcutPill.tsx +39 -0
  39. package/templates/source/components/surfaces/EmptyState.tsx +36 -0
  40. package/templates/source/components/surfaces/HeroSurface.tsx +64 -0
  41. package/templates/source/components/surfaces/Panel.tsx +43 -0
  42. package/templates/source/components/surfaces/PriorityCard.tsx +75 -0
  43. package/templates/source/components/surfaces/QuietListCard.tsx +146 -0
  44. package/templates/source/design-system/animations.css +25 -0
  45. package/templates/source/design-system/tokens.css +74 -0
  46. package/templates/source/design-system/typography.css +34 -0
  47. package/templates/source/theme/ThemeContext.tsx +82 -0
  48. package/templates/source/theme/useTheme.ts +10 -0
@@ -0,0 +1,573 @@
1
+ import { resolvePresetTokens } from './presets.js';
2
+ export function buildDashboardConfigFile(options) {
3
+ const tokens = resolvePresetTokens(options.preset, options.primaryColor, options.accentColor);
4
+ const cardRadiusMap = {
5
+ small: 'rounded-lg',
6
+ medium: 'rounded-xl',
7
+ large: 'rounded-2xl',
8
+ };
9
+ const canvasRadiusMap = {
10
+ small: 'sm',
11
+ medium: 'md',
12
+ large: 'lg',
13
+ };
14
+ const cardRadiusClass = cardRadiusMap[options.cardRadius] || 'rounded-2xl';
15
+ const canvasRadiusClass = canvasRadiusMap[options.cardRadius] || 'lg';
16
+ const demoNav = options.preset === 'cafe'
17
+ ? `[
18
+ { id: 'orders', label: 'Active Orders', to: '/orders', icon: 'coffee', badge: 8 },
19
+ { id: 'kitchen', label: 'Kitchen KDS', to: '/kitchen', icon: 'clipboard', badge: 'Live' },
20
+ { id: 'menu', label: 'Menu & Recipes', to: '/menu', icon: 'clock' },
21
+ { id: 'inventory', label: 'Bean & Milk Stock', to: '/inventory', icon: 'check' },
22
+ { id: 'staff', label: 'Staff Roster', to: '/staff', icon: 'users' },
23
+ { id: 'sales', label: 'Daily Takings', to: '/sales', icon: 'dollar' },
24
+ { id: 'settings', label: 'Store Config', to: '/settings', icon: 'settings' },
25
+ ]`
26
+ : `[
27
+ { id: 'overview', label: 'Overview', to: '/dashboard', icon: 'dashboard' },
28
+ { id: 'projects', label: 'Projects', to: '/projects', icon: 'folder', badge: 12 },
29
+ { id: 'tasks', label: 'Tasks', to: '/tasks', icon: 'check', badge: 4 },
30
+ { id: 'team', label: 'Team', to: '/team', icon: 'users' },
31
+ { id: 'billing', label: 'Billing', to: '/billing', icon: 'dollar' },
32
+ { id: 'settings', label: 'Settings', to: '/settings', icon: 'settings' },
33
+ ]`;
34
+ const demoShortcuts = options.preset === 'cafe'
35
+ ? `[
36
+ { id: 'new-ticket', label: 'Quick Order', to: '/orders/new', icon: 'plus' },
37
+ { id: 'brew-log', label: 'Calibrate Grinder', to: '/equipment', icon: 'coffee' },
38
+ { id: 'close-shift', label: 'Z-Report', to: '/reports', icon: 'dollar' },
39
+ ]`
40
+ : `[
41
+ { id: 'new-project', label: 'New Project', to: '/projects/new', icon: 'plus' },
42
+ { id: 'ai-summary', label: 'AI Summary', to: '/insights', icon: 'sparkles' },
43
+ { id: 'team-invite', label: 'Invite Member', to: '/team/invite', icon: 'users' },
44
+ ]`;
45
+ const demoUser = options.preset === 'cafe'
46
+ ? `{
47
+ name: 'Matteo Rossi',
48
+ email: 'headbarista@roastery.cafe',
49
+ initials: 'MR',
50
+ profileRoute: '/settings',
51
+ }`
52
+ : `{
53
+ name: 'Alex Morgan',
54
+ email: 'alex.morgan@workspace.local',
55
+ initials: 'AM',
56
+ profileRoute: '/settings',
57
+ }`;
58
+ return `// ============================================================================
59
+ // ${options.brandName} — Dashboard Configuration
60
+ // ============================================================================
61
+ // Edit this file to customize navigation, branding, colors, and layout shapes.
62
+ // No core components need to be modified.
63
+
64
+ import type { ComponentType, SVGProps } from 'react'
65
+
66
+ export type CanvasRadius = 'none' | 'sm' | 'md' | 'lg' | 'full'
67
+ export type ButtonShape = 'square' | 'rounded' | 'pill'
68
+
69
+ export interface NavItemConfig {
70
+ id: string
71
+ label: string
72
+ to: string
73
+ icon?: string | ComponentType<SVGProps<SVGSVGElement>>
74
+ badge?: string | number
75
+ end?: boolean
76
+ }
77
+
78
+ export interface ShortcutConfig {
79
+ id: string
80
+ label: string
81
+ to: string
82
+ icon?: string | ComponentType<SVGProps<SVGSVGElement>>
83
+ }
84
+
85
+ export interface UserMenuConfig {
86
+ name: string
87
+ email?: string
88
+ avatarUrl?: string
89
+ initials?: string
90
+ profileRoute: string
91
+ onLogout?: () => void
92
+ }
93
+
94
+ export interface DashboardConfig {
95
+ branding: {
96
+ name: string
97
+ logoUrl?: string
98
+ logoIcon?: ComponentType<SVGProps<SVGSVGElement>>
99
+ tagline?: string
100
+ homeRoute: string
101
+ }
102
+ colors: {
103
+ primary: { light: string; dark: string }
104
+ primaryForeground: { light: string; dark: string }
105
+ background: { light: string; dark: string }
106
+ canvas: { light: string; dark: string }
107
+ surface: { light: string; dark: string }
108
+ surfaceElevated: { light: string; dark: string }
109
+ border: { light: string; dark: string }
110
+ accent: { light: string; dark: string }
111
+ }
112
+ shapes: {
113
+ canvasRadius: CanvasRadius
114
+ cardRadius: string
115
+ buttonShape: ButtonShape
116
+ }
117
+ navigation: NavItemConfig[]
118
+ shortcuts?: ShortcutConfig[]
119
+ userMenu: UserMenuConfig
120
+ }
121
+
122
+ export const dashboardConfig: DashboardConfig = {
123
+ branding: {
124
+ name: '${options.brandName.replace(/'/g, "\\'")}',
125
+ tagline: '${(options.tagline || tokens.taglineDefault).replace(/'/g, "\\'")}',
126
+ homeRoute: '/dashboard',
127
+ logoUrl: '/assets/logo.svg',
128
+ },
129
+ colors: {
130
+ primary: {
131
+ light: '${tokens.primaryLight}',
132
+ dark: '${tokens.primaryDark}',
133
+ },
134
+ primaryForeground: {
135
+ light: '#ffffff',
136
+ dark: '#ffffff',
137
+ },
138
+ background: {
139
+ light: '${tokens.backgroundLight}',
140
+ dark: '${tokens.backgroundDark}',
141
+ },
142
+ canvas: {
143
+ light: '${tokens.canvasLight}',
144
+ dark: '${tokens.canvasDark}',
145
+ },
146
+ surface: {
147
+ light: '${tokens.surfaceLight}',
148
+ dark: '${tokens.surfaceDark}',
149
+ },
150
+ surfaceElevated: {
151
+ light: '${tokens.surfaceElevatedLight}',
152
+ dark: '${tokens.surfaceElevatedDark}',
153
+ },
154
+ border: {
155
+ light: '${tokens.borderLight}',
156
+ dark: '${tokens.borderDark}',
157
+ },
158
+ accent: {
159
+ light: '${tokens.accentLight}',
160
+ dark: '${tokens.accentDark}',
161
+ },
162
+ },
163
+ shapes: {
164
+ canvasRadius: '${canvasRadiusClass}',
165
+ cardRadius: '${cardRadiusClass}',
166
+ buttonShape: '${options.buttonShape}',
167
+ },
168
+ navigation: ${demoNav},
169
+ shortcuts: ${demoShortcuts},
170
+ userMenu: ${demoUser},
171
+ }
172
+
173
+ export function getCanvasRadiusClass(radius: CanvasRadius): string {
174
+ switch (radius) {
175
+ case 'none':
176
+ return 'rounded-none'
177
+ case 'sm':
178
+ return 'sm:rounded-tl-[16px] lg:rounded-tl-[20px]'
179
+ case 'md':
180
+ return 'sm:rounded-tl-[24px] lg:rounded-tl-[32px]'
181
+ case 'lg':
182
+ return 'sm:rounded-tl-[36px] lg:rounded-tl-[48px]'
183
+ case 'full':
184
+ return 'sm:rounded-tl-[60px] lg:rounded-tl-[72px]'
185
+ default:
186
+ return 'sm:rounded-tl-[36px] lg:rounded-tl-[48px]'
187
+ }
188
+ }
189
+
190
+ export function getButtonShapeClass(shape: ButtonShape): string {
191
+ switch (shape) {
192
+ case 'pill':
193
+ return 'rounded-full'
194
+ case 'rounded':
195
+ return 'rounded-xl'
196
+ case 'square':
197
+ return 'rounded-md'
198
+ default:
199
+ return 'rounded-full'
200
+ }
201
+ }
202
+ `;
203
+ }
204
+ export function buildTokensCssFile(options) {
205
+ const tokens = resolvePresetTokens(options.preset, options.primaryColor, options.accentColor);
206
+ return `/* ============================================================================
207
+ * ${options.brandName} — Design Tokens
208
+ * ============================================================================
209
+ * Generated semantic design tokens for Light & Dark mode.
210
+ */
211
+
212
+ :root,
213
+ [data-theme="light"] {
214
+ --background: ${tokens.backgroundLight};
215
+ --foreground: #0f172a;
216
+ --muted-foreground: #64748b;
217
+ --surface: ${tokens.surfaceLight};
218
+ --surface-elevated: ${tokens.surfaceElevatedLight};
219
+ --muted: #eef1f4;
220
+ --border: ${tokens.borderLight};
221
+ --input: #ffffff;
222
+ --canvas-background: ${tokens.canvasLight};
223
+
224
+ /* Brand Primary */
225
+ --primary: ${tokens.primaryLight};
226
+ --primary-foreground: #ffffff;
227
+ --ring: ${tokens.primaryLight};
228
+
229
+ /* Semantic Feedback */
230
+ --success: ${tokens.accentLight};
231
+ --success-fg: ${tokens.accentLight};
232
+ --success-bg: #ecfdf5;
233
+ --warning: #d97706;
234
+ --warning-fg: #b45309;
235
+ --warning-bg: #fffbeb;
236
+ --danger: #dc2626;
237
+ --danger-fg: #b91c1c;
238
+ --danger-bg: #fef2f2;
239
+ --info: #0284c7;
240
+ --info-fg: #0369a1;
241
+ --info-bg: #f0f9ff;
242
+
243
+ color-scheme: light;
244
+ }
245
+
246
+ [data-theme="dark"] {
247
+ --background: ${tokens.backgroundDark};
248
+ --foreground: #f3f5f7;
249
+ --muted-foreground: #9aa4b2;
250
+ --surface: ${tokens.surfaceDark};
251
+ --surface-elevated: ${tokens.surfaceElevatedDark};
252
+ --muted: #22262b;
253
+ --border: ${tokens.borderDark};
254
+ --input: #1a1a1a;
255
+ --canvas-background: ${tokens.canvasDark};
256
+
257
+ /* Brand Primary */
258
+ --primary: ${tokens.primaryDark};
259
+ --primary-foreground: #ffffff;
260
+ --ring: ${tokens.primaryDark};
261
+
262
+ /* Semantic Feedback */
263
+ --success: ${tokens.accentDark};
264
+ --success-fg: ${tokens.accentDark};
265
+ --success-bg: rgba(16, 185, 129, 0.15);
266
+ --warning: #f59e0b;
267
+ --warning-fg: #f59e0b;
268
+ --warning-bg: rgba(245, 158, 11, 0.15);
269
+ --danger: #ef4444;
270
+ --danger-fg: #ef4444;
271
+ --danger-bg: rgba(239, 68, 68, 0.15);
272
+ --info: #38bdf8;
273
+ --info-fg: #38bdf8;
274
+ --info-bg: rgba(56, 189, 248, 0.15);
275
+
276
+ color-scheme: dark;
277
+ }
278
+ `;
279
+ }
280
+ export function buildIndexHtml(options) {
281
+ const storageKey = `${options.projectName.replace(/[^a-zA-Z0-9]/g, '_')}_theme`;
282
+ return `<!doctype html>
283
+ <html lang="en">
284
+ <head>
285
+ <meta charset="UTF-8" />
286
+ <link rel="icon" type="image/svg+xml" href="/assets/logo.svg" />
287
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
288
+ <title>${options.brandName}</title>
289
+ <script>
290
+ (function () {
291
+ try {
292
+ var stored = localStorage.getItem('${storageKey}')
293
+ var theme =
294
+ stored === 'light' || stored === 'dark'
295
+ ? stored
296
+ : window.matchMedia('(prefers-color-scheme: dark)').matches
297
+ ? 'dark'
298
+ : '${options.defaultMode === 'system' ? 'light' : options.defaultMode}'
299
+ document.documentElement.setAttribute('data-theme', theme)
300
+ } catch (e) {
301
+ document.documentElement.setAttribute('data-theme', 'light')
302
+ }
303
+ })()
304
+ </script>
305
+ </head>
306
+ <body class="dashboard-font-base bg-background text-foreground antialiased selection:bg-primary/20">
307
+ <div id="root"></div>
308
+ <script type="module" src="/src/main.tsx"></script>
309
+ </body>
310
+ </html>
311
+ `;
312
+ }
313
+ export function buildLogoSvg(options) {
314
+ const initial = options.brandName.charAt(0).toUpperCase() || 'D';
315
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
316
+ <defs>
317
+ <linearGradient id="brandGrad" x1="0%" y1="0%" x2="100%" y2="100%">
318
+ <stop offset="0%" stop-color="${options.primaryColor || '#2563eb'}" />
319
+ <stop offset="100%" stop-color="${options.accentColor || '#059669'}" />
320
+ </linearGradient>
321
+ </defs>
322
+ <rect width="48" height="48" rx="14" fill="url(#brandGrad)" />
323
+ <text x="50%" y="54%" dominant-baseline="middle" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-weight="bold" font-size="24" fill="#ffffff">${initial}</text>
324
+ </svg>
325
+ `;
326
+ }
327
+ export function buildAppTsx(options) {
328
+ const storageKey = `${options.projectName.replace(/[^a-zA-Z0-9]/g, '_')}_theme`;
329
+ const defaultTheme = options.defaultMode === 'system' ? 'light' : options.defaultMode;
330
+ if (!options.includeDemo) {
331
+ return `import { useState } from 'react'
332
+ import { ThemeProvider } from './theme/ThemeContext.tsx'
333
+ import { AppShell } from './components/layout/AppShell.tsx'
334
+ import { PageHeader } from './components/layout/PageHeader.tsx'
335
+ import { Panel } from './components/surfaces/Panel.tsx'
336
+ import { EmptyState } from './components/surfaces/EmptyState.tsx'
337
+ import { Button } from './components/controls/Button.tsx'
338
+ import { dashboardConfig } from './config/dashboard.config.ts'
339
+
340
+ export function App() {
341
+ const [currentPath, setCurrentPath] = useState('/dashboard')
342
+
343
+ return (
344
+ <ThemeProvider defaultTheme="${defaultTheme}" storageKey="${storageKey}">
345
+ <AppShell
346
+ config={dashboardConfig}
347
+ currentPath={currentPath}
348
+ onNavigate={(to) => setCurrentPath(to)}
349
+ headerActions={
350
+ <Button variant="primary" size="sm" shape="${options.buttonShape}">
351
+ Create New
352
+ </Button>
353
+ }
354
+ >
355
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
356
+ <PageHeader
357
+ title="Overview"
358
+ description="${options.brandName} is ready for your product components."
359
+ actions={
360
+ <Button variant="outline" size="sm" shape="${options.buttonShape}">
361
+ Settings
362
+ </Button>
363
+ }
364
+ />
365
+
366
+ <Panel title="Welcome to your new Dashboard" subtitle="Extracted from JobTrack's signature visual system.">
367
+ <EmptyState
368
+ title="No records yet"
369
+ description="Start building out your domain surfaces, forms, and metric views using the prebuilt components."
370
+ actionLabel="Add First Item"
371
+ onAction={() => alert('Add your business logic here!')}
372
+ />
373
+ </Panel>
374
+ </div>
375
+ </AppShell>
376
+ </ThemeProvider>
377
+ )
378
+ }
379
+
380
+ export default App
381
+ `;
382
+ }
383
+ // With Demo Mode
384
+ return `import { useState } from 'react'
385
+ import { ThemeProvider } from './theme/ThemeContext.tsx'
386
+ import { AppShell } from './components/layout/AppShell.tsx'
387
+ import { HeroSurface } from './components/surfaces/HeroSurface.tsx'
388
+ import { PriorityCard } from './components/surfaces/PriorityCard.tsx'
389
+ import { Panel } from './components/surfaces/Panel.tsx'
390
+ import { QuietListCard } from './components/surfaces/QuietListCard.tsx'
391
+ import { MetricRow, type MetricItem } from './components/metrics/MetricRow.tsx'
392
+ import { StatusBadge } from './components/feedback/StatusBadge.tsx'
393
+ import { NotificationCenter } from './components/feedback/NotificationCenter.tsx'
394
+ import { Button } from './components/controls/Button.tsx'
395
+ import { dashboardConfig } from './config/dashboard.config.ts'
396
+
397
+ const DEMO_METRICS: MetricItem[] = ${options.preset === 'cafe'
398
+ ? `[
399
+ { id: '1', label: 'Active Orders', value: '24' },
400
+ { id: '2', label: 'Daily Takings', value: '$3,420' },
401
+ { id: '3', label: 'Bean Stock', value: '142kg' },
402
+ { id: '4', label: 'Open Kitchen Tickets', value: '6' },
403
+ ]`
404
+ : `[
405
+ { id: '1', label: 'Active Projects', value: '18' },
406
+ { id: '2', label: 'Sprint Velocity', value: '94%' },
407
+ { id: '3', label: 'Open Tasks', value: '42' },
408
+ { id: '4', label: 'Team Members', value: '28' },
409
+ ]`}
410
+
411
+ export function App() {
412
+ const [currentPath, setCurrentPath] = useState('/dashboard')
413
+
414
+ return (
415
+ <ThemeProvider defaultTheme="${defaultTheme}" storageKey="${storageKey}">
416
+ <AppShell
417
+ config={dashboardConfig}
418
+ currentPath={currentPath}
419
+ onNavigate={(to) => setCurrentPath(to)}
420
+ headerActions={
421
+ <div className="flex items-center gap-2">
422
+ <NotificationCenter
423
+ notifications={[
424
+ { id: '1', title: 'System initialized', message: 'Ready for operations', timestamp: 'Just now', read: false },
425
+ { id: '2', title: 'Weekly summary', message: 'Report compiled', timestamp: '1h ago', read: true },
426
+ ]}
427
+ />
428
+ <Button variant="primary" size="sm" shape="${options.buttonShape}">
429
+ + Action
430
+ </Button>
431
+ </div>
432
+ }
433
+ >
434
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
435
+ <HeroSurface
436
+ greeting="${options.preset === 'cafe' ? 'Good Morning' : 'Welcome back'}"
437
+ title="${options.preset === 'cafe' ? 'Matteo Rossi' : 'Alex Morgan'}"
438
+ description="${options.preset === 'cafe' ? 'Artisan roast service is live. 6 tickets currently open in kitchen.' : 'Your team is tracking 18 active deliverables across 4 workstreams.'}"
439
+ statusContext={
440
+ <div className="flex gap-2">
441
+ <StatusBadge variant="info">${options.preset === 'cafe' ? 'Morning Rush' : 'Sprint 42'}</StatusBadge>
442
+ <StatusBadge variant="success">${options.preset === 'cafe' ? 'Optimal Flow' : '94% On Track'}</StatusBadge>
443
+ </div>
444
+ }
445
+ actions={
446
+ <div className="flex items-center gap-2">
447
+ <Button variant="secondary" size="sm" shape="${options.buttonShape}">
448
+ View Reports
449
+ </Button>
450
+ <Button variant="primary" size="sm" shape="${options.buttonShape}">
451
+ New Entry
452
+ </Button>
453
+ </div>
454
+ }
455
+ />
456
+
457
+ <MetricRow metrics={DEMO_METRICS} />
458
+
459
+ <PriorityCard
460
+ heading="Next Best Action"
461
+ badgeText="Priority"
462
+ title="${options.preset === 'cafe' ? 'Calibrate Espresso Grinders' : 'Quarterly Executive Review'}"
463
+ description="${options.preset === 'cafe' ? 'Morning ambient humidity changed by 8%. Check extraction time for single origin batch.' : 'Review sprint burn-down chart and update customer satisfaction metrics.'}"
464
+ action={
465
+ <Button variant="primary" size="sm" shape="${options.buttonShape}">
466
+ ${options.preset === 'cafe' ? 'Open Calibration Log' : 'Review Deck'}
467
+ </Button>
468
+ }
469
+ />
470
+
471
+ <Panel
472
+ title="${options.preset === 'cafe' ? 'Live Kitchen Tickets' : 'Recent Project Deliverables'}"
473
+ action={<Button variant="ghost" size="sm">View All</Button>}
474
+ >
475
+ <QuietListCard
476
+ title="${options.preset === 'cafe' ? 'Kitchen Queue' : 'Deliverables'}"
477
+ items={[
478
+ {
479
+ id: '1',
480
+ title: '${options.preset === 'cafe' ? 'Table 4 • 2x Oat Flat White, 1x Croissant' : 'Core Architecture Redesign'}',
481
+ subtitle: '${options.preset === 'cafe' ? 'Barista Station • 3 mins ago' : 'Updated by Sarah • 12 mins ago'}',
482
+ avatarText: '${options.preset === 'cafe' ? 'T4' : 'CA'}',
483
+ statusBadge: <StatusBadge variant="info" dot>${options.preset === 'cafe' ? 'Brewing' : 'In Progress'}</StatusBadge>,
484
+ action: <Button variant="outline" size="sm" shape="${options.buttonShape}">Details</Button>,
485
+ },
486
+ {
487
+ id: '2',
488
+ title: '${options.preset === 'cafe' ? 'Takeaway • 1x Cold Brew, 1x Bag Colombia' : 'Auth Migration to Passkeys'}',
489
+ subtitle: '${options.preset === 'cafe' ? 'Front Counter • 8 mins ago' : 'Reviewed by David • 1h ago'}',
490
+ avatarText: '${options.preset === 'cafe' ? 'TA' : 'AM'}',
491
+ statusBadge: <StatusBadge variant="success" dot>${options.preset === 'cafe' ? 'Ready' : 'Completed'}</StatusBadge>,
492
+ action: <Button variant="outline" size="sm" shape="${options.buttonShape}">Details</Button>,
493
+ },
494
+ ]}
495
+ />
496
+ </Panel>
497
+ </div>
498
+ </AppShell>
499
+ </ThemeProvider>
500
+ )
501
+ }
502
+
503
+ export default App
504
+ `;
505
+ }
506
+ export function buildPackageJson(options) {
507
+ const pkgName = options.projectName.split(/[\\/]/).filter(Boolean).pop() || options.projectName;
508
+ return JSON.stringify({
509
+ name: pkgName,
510
+ private: true,
511
+ version: '0.1.0',
512
+ type: 'module',
513
+ scripts: {
514
+ dev: 'vite',
515
+ build: 'tsc -b && vite build',
516
+ preview: 'vite preview',
517
+ test: 'node --test',
518
+ },
519
+ dependencies: {
520
+ '@tailwindcss/vite': '^4.3.3',
521
+ react: '^19.2.8',
522
+ 'react-dom': '^19.2.8',
523
+ tailwindcss: '^4.3.3',
524
+ },
525
+ devDependencies: {
526
+ '@types/node': '^24.13.3',
527
+ '@types/react': '^19.2.18',
528
+ '@types/react-dom': '^19.2.4',
529
+ '@vitejs/plugin-react': '^6.1.0',
530
+ typescript: '~6.0.2',
531
+ vite: '^8.2.2',
532
+ },
533
+ }, null, 2);
534
+ }
535
+ export function buildProjectReadme(options) {
536
+ return `# ${options.brandName}
537
+
538
+ Modern dashboard application built with React, TypeScript, and Tailwind CSS, based on the JobTrack design system.
539
+
540
+ ---
541
+
542
+ ## Getting Started
543
+
544
+ ### 1. Install Dependencies
545
+ \`\`\`bash
546
+ npm install
547
+ \`\`\`
548
+
549
+ ### 2. Run Development Server
550
+ \`\`\`bash
551
+ npm run dev
552
+ \`\`\`
553
+
554
+ ### 3. Build for Production
555
+ \`\`\`bash
556
+ npm run build
557
+ \`\`\`
558
+
559
+ ---
560
+
561
+ ## Customizing Your Dashboard
562
+
563
+ All configuration is centralized in:
564
+ \`\`\`
565
+ src/config/dashboard.config.ts
566
+ \`\`\`
567
+
568
+ - **Navigation**: Update the \`navigation\` array with your product routes and icons.
569
+ - **Branding**: Change \`branding.name\` and \`branding.logoUrl\`.
570
+ - **Colors**: Customize \`colors.primary\` and \`colors.accent\`.
571
+ - **Shapes**: Toggle \`shapes.canvasRadius\` (\`'sm'\` | \`'md'\` | \`'lg'\`) and \`shapes.buttonShape\` (\`'pill'\` | \`'rounded'\` | \`'square'\`).
572
+ `;
573
+ }
@@ -0,0 +1,9 @@
1
+ import type { GeneratorOptions } from './types.js';
2
+ /**
3
+ * Finds the source directory containing the generic dashboard starter kit components.
4
+ */
5
+ export declare function resolveStarterKitSrc(): string;
6
+ export declare function generateProject(options: GeneratorOptions): {
7
+ success: boolean;
8
+ targetDir: string;
9
+ };