popeye-cli 1.0.1 → 1.2.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.
- package/.env.example +24 -1
- package/CONTRIBUTING.md +275 -0
- package/OPEN_SOURCE_MANIFESTO.md +172 -0
- package/README.md +832 -123
- package/dist/adapters/claude.d.ts +19 -4
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/claude.js +908 -42
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/gemini.d.ts +55 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +318 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/grok.d.ts +73 -0
- package/dist/adapters/grok.d.ts.map +1 -0
- package/dist/adapters/grok.js +430 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +47 -8
- package/dist/adapters/openai.js.map +1 -1
- package/dist/auth/claude.d.ts +11 -9
- package/dist/auth/claude.d.ts.map +1 -1
- package/dist/auth/claude.js +107 -71
- package/dist/auth/claude.js.map +1 -1
- package/dist/auth/gemini.d.ts +58 -0
- package/dist/auth/gemini.d.ts.map +1 -0
- package/dist/auth/gemini.js +172 -0
- package/dist/auth/gemini.js.map +1 -0
- package/dist/auth/grok.d.ts +73 -0
- package/dist/auth/grok.d.ts.map +1 -0
- package/dist/auth/grok.js +211 -0
- package/dist/auth/grok.js.map +1 -0
- package/dist/auth/index.d.ts +14 -7
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +41 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/keychain.d.ts +20 -7
- package/dist/auth/keychain.d.ts.map +1 -1
- package/dist/auth/keychain.js +85 -29
- package/dist/auth/keychain.js.map +1 -1
- package/dist/auth/openai.d.ts +2 -2
- package/dist/auth/openai.d.ts.map +1 -1
- package/dist/auth/openai.js +30 -32
- package/dist/auth/openai.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +79 -8
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +15 -4
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +1494 -114
- package/dist/cli/interactive.js.map +1 -1
- package/dist/config/defaults.d.ts +9 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +19 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +19 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +33 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +47 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +29 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/generators/fullstack.d.ts +32 -0
- package/dist/generators/fullstack.d.ts.map +1 -0
- package/dist/generators/fullstack.js +497 -0
- package/dist/generators/fullstack.js.map +1 -0
- package/dist/generators/index.d.ts +4 -3
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +15 -1
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/python.d.ts +17 -1
- package/dist/generators/python.d.ts.map +1 -1
- package/dist/generators/python.js +34 -20
- package/dist/generators/python.js.map +1 -1
- package/dist/generators/templates/fullstack.d.ts +113 -0
- package/dist/generators/templates/fullstack.d.ts.map +1 -0
- package/dist/generators/templates/fullstack.js +1004 -0
- package/dist/generators/templates/fullstack.js.map +1 -0
- package/dist/generators/typescript.d.ts +19 -1
- package/dist/generators/typescript.d.ts.map +1 -1
- package/dist/generators/typescript.js +37 -20
- package/dist/generators/typescript.js.map +1 -1
- package/dist/state/index.d.ts +108 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +551 -4
- package/dist/state/index.js.map +1 -1
- package/dist/state/registry.d.ts +52 -0
- package/dist/state/registry.d.ts.map +1 -0
- package/dist/state/registry.js +215 -0
- package/dist/state/registry.js.map +1 -0
- package/dist/types/cli.d.ts +8 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js.map +1 -1
- package/dist/types/consensus.d.ts +186 -4
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js +35 -3
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/project.d.ts +76 -0
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +1 -1
- package/dist/types/project.js.map +1 -1
- package/dist/types/workflow.d.ts +217 -16
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +40 -1
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/auto-fix.d.ts +45 -0
- package/dist/workflow/auto-fix.d.ts.map +1 -0
- package/dist/workflow/auto-fix.js +274 -0
- package/dist/workflow/auto-fix.js.map +1 -0
- package/dist/workflow/consensus.d.ts +70 -2
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js +872 -17
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/execution-mode.d.ts +10 -4
- package/dist/workflow/execution-mode.d.ts.map +1 -1
- package/dist/workflow/execution-mode.js +547 -58
- package/dist/workflow/execution-mode.js.map +1 -1
- package/dist/workflow/index.d.ts +14 -2
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +69 -6
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/milestone-workflow.d.ts +34 -0
- package/dist/workflow/milestone-workflow.d.ts.map +1 -0
- package/dist/workflow/milestone-workflow.js +414 -0
- package/dist/workflow/milestone-workflow.js.map +1 -0
- package/dist/workflow/plan-mode.d.ts +80 -3
- package/dist/workflow/plan-mode.d.ts.map +1 -1
- package/dist/workflow/plan-mode.js +767 -49
- package/dist/workflow/plan-mode.js.map +1 -1
- package/dist/workflow/plan-storage.d.ts +386 -0
- package/dist/workflow/plan-storage.d.ts.map +1 -0
- package/dist/workflow/plan-storage.js +878 -0
- package/dist/workflow/plan-storage.js.map +1 -0
- package/dist/workflow/project-verification.d.ts +37 -0
- package/dist/workflow/project-verification.d.ts.map +1 -0
- package/dist/workflow/project-verification.js +381 -0
- package/dist/workflow/project-verification.js.map +1 -0
- package/dist/workflow/task-workflow.d.ts +37 -0
- package/dist/workflow/task-workflow.d.ts.map +1 -0
- package/dist/workflow/task-workflow.js +386 -0
- package/dist/workflow/task-workflow.js.map +1 -0
- package/dist/workflow/test-runner.d.ts +9 -0
- package/dist/workflow/test-runner.d.ts.map +1 -1
- package/dist/workflow/test-runner.js +101 -5
- package/dist/workflow/test-runner.js.map +1 -1
- package/dist/workflow/ui-designer.d.ts +82 -0
- package/dist/workflow/ui-designer.d.ts.map +1 -0
- package/dist/workflow/ui-designer.js +234 -0
- package/dist/workflow/ui-designer.js.map +1 -0
- package/dist/workflow/ui-setup.d.ts +58 -0
- package/dist/workflow/ui-setup.d.ts.map +1 -0
- package/dist/workflow/ui-setup.js +685 -0
- package/dist/workflow/ui-setup.js.map +1 -0
- package/dist/workflow/ui-verification.d.ts +114 -0
- package/dist/workflow/ui-verification.d.ts.map +1 -0
- package/dist/workflow/ui-verification.js +258 -0
- package/dist/workflow/ui-verification.js.map +1 -0
- package/dist/workflow/workflow-logger.d.ts +110 -0
- package/dist/workflow/workflow-logger.d.ts.map +1 -0
- package/dist/workflow/workflow-logger.js +267 -0
- package/dist/workflow/workflow-logger.js.map +1 -0
- package/dist/workflow/workspace-manager.d.ts +342 -0
- package/dist/workflow/workspace-manager.d.ts.map +1 -0
- package/dist/workflow/workspace-manager.js +733 -0
- package/dist/workflow/workspace-manager.js.map +1 -0
- package/package.json +2 -2
- package/src/adapters/claude.ts +1067 -47
- package/src/adapters/gemini.ts +373 -0
- package/src/adapters/grok.ts +492 -0
- package/src/adapters/openai.ts +48 -9
- package/src/auth/claude.ts +120 -78
- package/src/auth/gemini.ts +207 -0
- package/src/auth/grok.ts +255 -0
- package/src/auth/index.ts +47 -9
- package/src/auth/keychain.ts +95 -28
- package/src/auth/openai.ts +29 -36
- package/src/cli/commands/auth.ts +89 -10
- package/src/cli/commands/create.ts +13 -4
- package/src/cli/interactive.ts +1774 -142
- package/src/config/defaults.ts +19 -2
- package/src/config/index.ts +36 -1
- package/src/config/schema.ts +30 -1
- package/src/generators/fullstack.ts +551 -0
- package/src/generators/index.ts +25 -1
- package/src/generators/python.ts +65 -20
- package/src/generators/templates/fullstack.ts +1047 -0
- package/src/generators/typescript.ts +69 -20
- package/src/state/index.ts +713 -4
- package/src/state/registry.ts +278 -0
- package/src/types/cli.ts +8 -0
- package/src/types/consensus.ts +197 -6
- package/src/types/project.ts +82 -1
- package/src/types/workflow.ts +90 -1
- package/src/workflow/auto-fix.ts +340 -0
- package/src/workflow/consensus.ts +1180 -16
- package/src/workflow/execution-mode.ts +673 -74
- package/src/workflow/index.ts +95 -6
- package/src/workflow/milestone-workflow.ts +576 -0
- package/src/workflow/plan-mode.ts +924 -50
- package/src/workflow/plan-storage.ts +1282 -0
- package/src/workflow/project-verification.ts +471 -0
- package/src/workflow/task-workflow.ts +528 -0
- package/src/workflow/test-runner.ts +120 -5
- package/src/workflow/ui-designer.ts +337 -0
- package/src/workflow/ui-setup.ts +797 -0
- package/src/workflow/ui-verification.ts +357 -0
- package/src/workflow/workflow-logger.ts +353 -0
- package/src/workflow/workspace-manager.ts +912 -0
- package/tests/config/config.test.ts +1 -1
- package/tests/types/consensus.test.ts +3 -3
- package/tests/workflow/plan-mode.test.ts +213 -0
- package/tests/workflow/test-runner.test.ts +5 -3
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Setup Module
|
|
3
|
+
* Automatically sets up component libraries, design systems, and styling
|
|
4
|
+
* for a polished, professional UI without manual configuration
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { promises as fs } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { exec } from 'node:child_process';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
|
|
12
|
+
const execAsync = promisify(exec);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Design theme configuration
|
|
16
|
+
*/
|
|
17
|
+
export interface DesignTheme {
|
|
18
|
+
name: string;
|
|
19
|
+
colors: {
|
|
20
|
+
primary: string;
|
|
21
|
+
primaryForeground: string;
|
|
22
|
+
secondary: string;
|
|
23
|
+
secondaryForeground: string;
|
|
24
|
+
accent: string;
|
|
25
|
+
accentForeground: string;
|
|
26
|
+
background: string;
|
|
27
|
+
foreground: string;
|
|
28
|
+
card: string;
|
|
29
|
+
cardForeground: string;
|
|
30
|
+
muted: string;
|
|
31
|
+
mutedForeground: string;
|
|
32
|
+
destructive: string;
|
|
33
|
+
destructiveForeground: string;
|
|
34
|
+
border: string;
|
|
35
|
+
input: string;
|
|
36
|
+
ring: string;
|
|
37
|
+
};
|
|
38
|
+
borderRadius: string;
|
|
39
|
+
fontFamily: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Pre-defined professional themes
|
|
44
|
+
*/
|
|
45
|
+
export const THEMES: Record<string, DesignTheme> = {
|
|
46
|
+
modern: {
|
|
47
|
+
name: 'Modern Blue',
|
|
48
|
+
colors: {
|
|
49
|
+
primary: '221.2 83.2% 53.3%',
|
|
50
|
+
primaryForeground: '210 40% 98%',
|
|
51
|
+
secondary: '210 40% 96.1%',
|
|
52
|
+
secondaryForeground: '222.2 47.4% 11.2%',
|
|
53
|
+
accent: '210 40% 96.1%',
|
|
54
|
+
accentForeground: '222.2 47.4% 11.2%',
|
|
55
|
+
background: '0 0% 100%',
|
|
56
|
+
foreground: '222.2 84% 4.9%',
|
|
57
|
+
card: '0 0% 100%',
|
|
58
|
+
cardForeground: '222.2 84% 4.9%',
|
|
59
|
+
muted: '210 40% 96.1%',
|
|
60
|
+
mutedForeground: '215.4 16.3% 46.9%',
|
|
61
|
+
destructive: '0 84.2% 60.2%',
|
|
62
|
+
destructiveForeground: '210 40% 98%',
|
|
63
|
+
border: '214.3 31.8% 91.4%',
|
|
64
|
+
input: '214.3 31.8% 91.4%',
|
|
65
|
+
ring: '221.2 83.2% 53.3%',
|
|
66
|
+
},
|
|
67
|
+
borderRadius: '0.5rem',
|
|
68
|
+
fontFamily: 'Inter, system-ui, sans-serif',
|
|
69
|
+
},
|
|
70
|
+
elegant: {
|
|
71
|
+
name: 'Elegant Dark',
|
|
72
|
+
colors: {
|
|
73
|
+
primary: '262.1 83.3% 57.8%',
|
|
74
|
+
primaryForeground: '210 20% 98%',
|
|
75
|
+
secondary: '220 14.3% 95.9%',
|
|
76
|
+
secondaryForeground: '220.9 39.3% 11%',
|
|
77
|
+
accent: '220 14.3% 95.9%',
|
|
78
|
+
accentForeground: '220.9 39.3% 11%',
|
|
79
|
+
background: '0 0% 100%',
|
|
80
|
+
foreground: '224 71.4% 4.1%',
|
|
81
|
+
card: '0 0% 100%',
|
|
82
|
+
cardForeground: '224 71.4% 4.1%',
|
|
83
|
+
muted: '220 14.3% 95.9%',
|
|
84
|
+
mutedForeground: '220 8.9% 46.1%',
|
|
85
|
+
destructive: '0 84.2% 60.2%',
|
|
86
|
+
destructiveForeground: '210 20% 98%',
|
|
87
|
+
border: '220 13% 91%',
|
|
88
|
+
input: '220 13% 91%',
|
|
89
|
+
ring: '262.1 83.3% 57.8%',
|
|
90
|
+
},
|
|
91
|
+
borderRadius: '0.75rem',
|
|
92
|
+
fontFamily: 'Plus Jakarta Sans, system-ui, sans-serif',
|
|
93
|
+
},
|
|
94
|
+
minimal: {
|
|
95
|
+
name: 'Minimal Clean',
|
|
96
|
+
colors: {
|
|
97
|
+
primary: '240 5.9% 10%',
|
|
98
|
+
primaryForeground: '0 0% 98%',
|
|
99
|
+
secondary: '240 4.8% 95.9%',
|
|
100
|
+
secondaryForeground: '240 5.9% 10%',
|
|
101
|
+
accent: '240 4.8% 95.9%',
|
|
102
|
+
accentForeground: '240 5.9% 10%',
|
|
103
|
+
background: '0 0% 100%',
|
|
104
|
+
foreground: '240 10% 3.9%',
|
|
105
|
+
card: '0 0% 100%',
|
|
106
|
+
cardForeground: '240 10% 3.9%',
|
|
107
|
+
muted: '240 4.8% 95.9%',
|
|
108
|
+
mutedForeground: '240 3.8% 46.1%',
|
|
109
|
+
destructive: '0 84.2% 60.2%',
|
|
110
|
+
destructiveForeground: '0 0% 98%',
|
|
111
|
+
border: '240 5.9% 90%',
|
|
112
|
+
input: '240 5.9% 90%',
|
|
113
|
+
ring: '240 5.9% 10%',
|
|
114
|
+
},
|
|
115
|
+
borderRadius: '0.375rem',
|
|
116
|
+
fontFamily: 'system-ui, sans-serif',
|
|
117
|
+
},
|
|
118
|
+
vibrant: {
|
|
119
|
+
name: 'Vibrant Gradient',
|
|
120
|
+
colors: {
|
|
121
|
+
primary: '339 89.6% 51%',
|
|
122
|
+
primaryForeground: '0 0% 100%',
|
|
123
|
+
secondary: '217.2 91.2% 59.8%',
|
|
124
|
+
secondaryForeground: '0 0% 100%',
|
|
125
|
+
accent: '47.9 95.8% 53.1%',
|
|
126
|
+
accentForeground: '0 0% 9%',
|
|
127
|
+
background: '0 0% 100%',
|
|
128
|
+
foreground: '222.2 84% 4.9%',
|
|
129
|
+
card: '0 0% 100%',
|
|
130
|
+
cardForeground: '222.2 84% 4.9%',
|
|
131
|
+
muted: '210 40% 96.1%',
|
|
132
|
+
mutedForeground: '215.4 16.3% 46.9%',
|
|
133
|
+
destructive: '0 84.2% 60.2%',
|
|
134
|
+
destructiveForeground: '0 0% 100%',
|
|
135
|
+
border: '214.3 31.8% 91.4%',
|
|
136
|
+
input: '214.3 31.8% 91.4%',
|
|
137
|
+
ring: '339 89.6% 51%',
|
|
138
|
+
},
|
|
139
|
+
borderRadius: '1rem',
|
|
140
|
+
fontFamily: 'Poppins, system-ui, sans-serif',
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* UI Setup result
|
|
146
|
+
*/
|
|
147
|
+
export interface UISetupResult {
|
|
148
|
+
success: boolean;
|
|
149
|
+
theme: string;
|
|
150
|
+
componentsInstalled: string[];
|
|
151
|
+
error?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate globals.css with theme
|
|
156
|
+
*/
|
|
157
|
+
function generateGlobalsCss(theme: DesignTheme): string {
|
|
158
|
+
return `@tailwind base;
|
|
159
|
+
@tailwind components;
|
|
160
|
+
@tailwind utilities;
|
|
161
|
+
|
|
162
|
+
@layer base {
|
|
163
|
+
:root {
|
|
164
|
+
--background: ${theme.colors.background};
|
|
165
|
+
--foreground: ${theme.colors.foreground};
|
|
166
|
+
--card: ${theme.colors.card};
|
|
167
|
+
--card-foreground: ${theme.colors.cardForeground};
|
|
168
|
+
--popover: ${theme.colors.card};
|
|
169
|
+
--popover-foreground: ${theme.colors.cardForeground};
|
|
170
|
+
--primary: ${theme.colors.primary};
|
|
171
|
+
--primary-foreground: ${theme.colors.primaryForeground};
|
|
172
|
+
--secondary: ${theme.colors.secondary};
|
|
173
|
+
--secondary-foreground: ${theme.colors.secondaryForeground};
|
|
174
|
+
--muted: ${theme.colors.muted};
|
|
175
|
+
--muted-foreground: ${theme.colors.mutedForeground};
|
|
176
|
+
--accent: ${theme.colors.accent};
|
|
177
|
+
--accent-foreground: ${theme.colors.accentForeground};
|
|
178
|
+
--destructive: ${theme.colors.destructive};
|
|
179
|
+
--destructive-foreground: ${theme.colors.destructiveForeground};
|
|
180
|
+
--border: ${theme.colors.border};
|
|
181
|
+
--input: ${theme.colors.input};
|
|
182
|
+
--ring: ${theme.colors.ring};
|
|
183
|
+
--radius: ${theme.borderRadius};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.dark {
|
|
187
|
+
--background: 222.2 84% 4.9%;
|
|
188
|
+
--foreground: 210 40% 98%;
|
|
189
|
+
--card: 222.2 84% 4.9%;
|
|
190
|
+
--card-foreground: 210 40% 98%;
|
|
191
|
+
--popover: 222.2 84% 4.9%;
|
|
192
|
+
--popover-foreground: 210 40% 98%;
|
|
193
|
+
--primary: ${theme.colors.primary};
|
|
194
|
+
--primary-foreground: ${theme.colors.primaryForeground};
|
|
195
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
196
|
+
--secondary-foreground: 210 40% 98%;
|
|
197
|
+
--muted: 217.2 32.6% 17.5%;
|
|
198
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
199
|
+
--accent: 217.2 32.6% 17.5%;
|
|
200
|
+
--accent-foreground: 210 40% 98%;
|
|
201
|
+
--destructive: 0 62.8% 30.6%;
|
|
202
|
+
--destructive-foreground: 210 40% 98%;
|
|
203
|
+
--border: 217.2 32.6% 17.5%;
|
|
204
|
+
--input: 217.2 32.6% 17.5%;
|
|
205
|
+
--ring: ${theme.colors.ring};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@layer base {
|
|
210
|
+
* {
|
|
211
|
+
@apply border-border;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
body {
|
|
215
|
+
@apply bg-background text-foreground;
|
|
216
|
+
font-family: ${theme.fontFamily};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Custom utility classes */
|
|
221
|
+
@layer utilities {
|
|
222
|
+
.text-balance {
|
|
223
|
+
text-wrap: balance;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.glass {
|
|
227
|
+
@apply bg-white/80 backdrop-blur-lg border border-white/20;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.glass-dark {
|
|
231
|
+
@apply bg-black/40 backdrop-blur-lg border border-white/10;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Animation utilities */
|
|
236
|
+
@layer utilities {
|
|
237
|
+
.animate-in {
|
|
238
|
+
animation: animateIn 0.3s ease-out;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.animate-out {
|
|
242
|
+
animation: animateOut 0.2s ease-in;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@keyframes animateIn {
|
|
246
|
+
from {
|
|
247
|
+
opacity: 0;
|
|
248
|
+
transform: translateY(-10px);
|
|
249
|
+
}
|
|
250
|
+
to {
|
|
251
|
+
opacity: 1;
|
|
252
|
+
transform: translateY(0);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@keyframes animateOut {
|
|
257
|
+
from {
|
|
258
|
+
opacity: 1;
|
|
259
|
+
transform: translateY(0);
|
|
260
|
+
}
|
|
261
|
+
to {
|
|
262
|
+
opacity: 0;
|
|
263
|
+
transform: translateY(-10px);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Generate Tailwind config for shadcn
|
|
272
|
+
*/
|
|
273
|
+
function generateTailwindConfig(theme: DesignTheme): string {
|
|
274
|
+
return `import type { Config } from "tailwindcss";
|
|
275
|
+
|
|
276
|
+
const config: Config = {
|
|
277
|
+
darkMode: ["class"],
|
|
278
|
+
content: [
|
|
279
|
+
"./index.html",
|
|
280
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
281
|
+
],
|
|
282
|
+
theme: {
|
|
283
|
+
container: {
|
|
284
|
+
center: true,
|
|
285
|
+
padding: "2rem",
|
|
286
|
+
screens: {
|
|
287
|
+
"2xl": "1400px",
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
extend: {
|
|
291
|
+
fontFamily: {
|
|
292
|
+
sans: ["${theme.fontFamily.split(',')[0]}", "system-ui", "sans-serif"],
|
|
293
|
+
},
|
|
294
|
+
colors: {
|
|
295
|
+
border: "hsl(var(--border))",
|
|
296
|
+
input: "hsl(var(--input))",
|
|
297
|
+
ring: "hsl(var(--ring))",
|
|
298
|
+
background: "hsl(var(--background))",
|
|
299
|
+
foreground: "hsl(var(--foreground))",
|
|
300
|
+
primary: {
|
|
301
|
+
DEFAULT: "hsl(var(--primary))",
|
|
302
|
+
foreground: "hsl(var(--primary-foreground))",
|
|
303
|
+
},
|
|
304
|
+
secondary: {
|
|
305
|
+
DEFAULT: "hsl(var(--secondary))",
|
|
306
|
+
foreground: "hsl(var(--secondary-foreground))",
|
|
307
|
+
},
|
|
308
|
+
destructive: {
|
|
309
|
+
DEFAULT: "hsl(var(--destructive))",
|
|
310
|
+
foreground: "hsl(var(--destructive-foreground))",
|
|
311
|
+
},
|
|
312
|
+
muted: {
|
|
313
|
+
DEFAULT: "hsl(var(--muted))",
|
|
314
|
+
foreground: "hsl(var(--muted-foreground))",
|
|
315
|
+
},
|
|
316
|
+
accent: {
|
|
317
|
+
DEFAULT: "hsl(var(--accent))",
|
|
318
|
+
foreground: "hsl(var(--accent-foreground))",
|
|
319
|
+
},
|
|
320
|
+
popover: {
|
|
321
|
+
DEFAULT: "hsl(var(--popover))",
|
|
322
|
+
foreground: "hsl(var(--popover-foreground))",
|
|
323
|
+
},
|
|
324
|
+
card: {
|
|
325
|
+
DEFAULT: "hsl(var(--card))",
|
|
326
|
+
foreground: "hsl(var(--card-foreground))",
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
borderRadius: {
|
|
330
|
+
lg: "var(--radius)",
|
|
331
|
+
md: "calc(var(--radius) - 2px)",
|
|
332
|
+
sm: "calc(var(--radius) - 4px)",
|
|
333
|
+
},
|
|
334
|
+
keyframes: {
|
|
335
|
+
"accordion-down": {
|
|
336
|
+
from: { height: "0" },
|
|
337
|
+
to: { height: "var(--radix-accordion-content-height)" },
|
|
338
|
+
},
|
|
339
|
+
"accordion-up": {
|
|
340
|
+
from: { height: "var(--radix-accordion-content-height)" },
|
|
341
|
+
to: { height: "0" },
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
animation: {
|
|
345
|
+
"accordion-down": "accordion-down 0.2s ease-out",
|
|
346
|
+
"accordion-up": "accordion-up 0.2s ease-out",
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
plugins: [require("tailwindcss-animate")],
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export default config;
|
|
354
|
+
`;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Components to install based on project type
|
|
359
|
+
*/
|
|
360
|
+
const COMPONENT_SETS: Record<string, string[]> = {
|
|
361
|
+
dashboard: [
|
|
362
|
+
'button', 'card', 'input', 'label', 'select', 'table', 'tabs',
|
|
363
|
+
'dialog', 'dropdown-menu', 'avatar', 'badge', 'skeleton',
|
|
364
|
+
'tooltip', 'separator', 'scroll-area', 'sheet', 'toast',
|
|
365
|
+
],
|
|
366
|
+
kanban: [
|
|
367
|
+
'button', 'card', 'input', 'label', 'select', 'dialog',
|
|
368
|
+
'dropdown-menu', 'avatar', 'badge', 'skeleton', 'tooltip',
|
|
369
|
+
'separator', 'scroll-area', 'sheet', 'toast', 'popover',
|
|
370
|
+
'context-menu', 'command',
|
|
371
|
+
],
|
|
372
|
+
ecommerce: [
|
|
373
|
+
'button', 'card', 'input', 'label', 'select', 'dialog',
|
|
374
|
+
'carousel', 'avatar', 'badge', 'skeleton', 'tooltip',
|
|
375
|
+
'separator', 'scroll-area', 'sheet', 'toast', 'accordion',
|
|
376
|
+
'tabs', 'slider',
|
|
377
|
+
],
|
|
378
|
+
blog: [
|
|
379
|
+
'button', 'card', 'input', 'label', 'textarea', 'dialog',
|
|
380
|
+
'avatar', 'badge', 'skeleton', 'separator', 'scroll-area',
|
|
381
|
+
'toast', 'navigation-menu',
|
|
382
|
+
],
|
|
383
|
+
default: [
|
|
384
|
+
'button', 'card', 'input', 'label', 'select', 'dialog',
|
|
385
|
+
'dropdown-menu', 'avatar', 'badge', 'skeleton', 'tooltip',
|
|
386
|
+
'separator', 'toast',
|
|
387
|
+
],
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Detect project type from idea/specification
|
|
392
|
+
*/
|
|
393
|
+
export function detectProjectType(idea: string): string {
|
|
394
|
+
const lowerIdea = idea.toLowerCase();
|
|
395
|
+
|
|
396
|
+
if (lowerIdea.includes('kanban') || lowerIdea.includes('project manage') || lowerIdea.includes('task')) {
|
|
397
|
+
return 'kanban';
|
|
398
|
+
}
|
|
399
|
+
if (lowerIdea.includes('dashboard') || lowerIdea.includes('analytics') || lowerIdea.includes('admin')) {
|
|
400
|
+
return 'dashboard';
|
|
401
|
+
}
|
|
402
|
+
if (lowerIdea.includes('shop') || lowerIdea.includes('store') || lowerIdea.includes('ecommerce') || lowerIdea.includes('product')) {
|
|
403
|
+
return 'ecommerce';
|
|
404
|
+
}
|
|
405
|
+
if (lowerIdea.includes('blog') || lowerIdea.includes('article') || lowerIdea.includes('content')) {
|
|
406
|
+
return 'blog';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return 'default';
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Setup complete UI system for a project
|
|
414
|
+
*/
|
|
415
|
+
export async function setupUI(
|
|
416
|
+
projectDir: string,
|
|
417
|
+
options: {
|
|
418
|
+
theme?: string;
|
|
419
|
+
projectType?: string;
|
|
420
|
+
idea?: string;
|
|
421
|
+
} = {},
|
|
422
|
+
onProgress?: (message: string) => void
|
|
423
|
+
): Promise<UISetupResult> {
|
|
424
|
+
const frontendDir = path.join(projectDir, 'packages', 'frontend');
|
|
425
|
+
const componentsInstalled: string[] = [];
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
// Determine theme
|
|
429
|
+
const themeName = options.theme || 'modern';
|
|
430
|
+
const theme = THEMES[themeName] || THEMES.modern;
|
|
431
|
+
onProgress?.(`Using theme: ${theme.name}`);
|
|
432
|
+
|
|
433
|
+
// Determine project type
|
|
434
|
+
const projectType = options.projectType || (options.idea ? detectProjectType(options.idea) : 'default');
|
|
435
|
+
onProgress?.(`Detected project type: ${projectType}`);
|
|
436
|
+
|
|
437
|
+
// Check if frontend exists
|
|
438
|
+
const frontendExists = await fs.access(frontendDir).then(() => true).catch(() => false);
|
|
439
|
+
if (!frontendExists) {
|
|
440
|
+
return {
|
|
441
|
+
success: false,
|
|
442
|
+
theme: themeName,
|
|
443
|
+
componentsInstalled: [],
|
|
444
|
+
error: 'Frontend directory not found',
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Step 1: Install Tailwind and dependencies
|
|
449
|
+
onProgress?.('Installing Tailwind CSS and dependencies...');
|
|
450
|
+
await execAsync(
|
|
451
|
+
'npm install -D tailwindcss postcss autoprefixer tailwindcss-animate @tailwindcss/postcss',
|
|
452
|
+
{ cwd: frontendDir, timeout: 120000 }
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
// Step 2: Install shadcn/ui dependencies
|
|
456
|
+
onProgress?.('Installing UI component dependencies...');
|
|
457
|
+
await execAsync(
|
|
458
|
+
'npm install class-variance-authority clsx tailwind-merge lucide-react @radix-ui/react-slot',
|
|
459
|
+
{ cwd: frontendDir, timeout: 120000 }
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
// Step 3: Create lib/utils.ts
|
|
463
|
+
onProgress?.('Creating utility functions...');
|
|
464
|
+
const libDir = path.join(frontendDir, 'src', 'lib');
|
|
465
|
+
await fs.mkdir(libDir, { recursive: true });
|
|
466
|
+
await fs.writeFile(
|
|
467
|
+
path.join(libDir, 'utils.ts'),
|
|
468
|
+
`import { type ClassValue, clsx } from "clsx";
|
|
469
|
+
import { twMerge } from "tailwind-merge";
|
|
470
|
+
|
|
471
|
+
export function cn(...inputs: ClassValue[]) {
|
|
472
|
+
return twMerge(clsx(inputs));
|
|
473
|
+
}
|
|
474
|
+
`
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
// Step 4: Create Tailwind config
|
|
478
|
+
onProgress?.('Configuring Tailwind CSS...');
|
|
479
|
+
await fs.writeFile(
|
|
480
|
+
path.join(frontendDir, 'tailwind.config.ts'),
|
|
481
|
+
generateTailwindConfig(theme)
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
// Step 5: Create PostCSS config
|
|
485
|
+
await fs.writeFile(
|
|
486
|
+
path.join(frontendDir, 'postcss.config.js'),
|
|
487
|
+
`export default {
|
|
488
|
+
plugins: {
|
|
489
|
+
tailwindcss: {},
|
|
490
|
+
autoprefixer: {},
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
`
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// Step 6: Create globals.css
|
|
497
|
+
onProgress?.('Setting up theme and styles...');
|
|
498
|
+
await fs.writeFile(
|
|
499
|
+
path.join(frontendDir, 'src', 'index.css'),
|
|
500
|
+
generateGlobalsCss(theme)
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
// Step 7: Create components directory structure
|
|
504
|
+
const componentsDir = path.join(frontendDir, 'src', 'components', 'ui');
|
|
505
|
+
await fs.mkdir(componentsDir, { recursive: true });
|
|
506
|
+
|
|
507
|
+
// Step 8: Install base components
|
|
508
|
+
const components = COMPONENT_SETS[projectType] || COMPONENT_SETS.default;
|
|
509
|
+
onProgress?.(`Installing ${components.length} UI components...`);
|
|
510
|
+
|
|
511
|
+
// Create button component (always needed)
|
|
512
|
+
await fs.writeFile(
|
|
513
|
+
path.join(componentsDir, 'button.tsx'),
|
|
514
|
+
generateButtonComponent()
|
|
515
|
+
);
|
|
516
|
+
componentsInstalled.push('button');
|
|
517
|
+
|
|
518
|
+
// Create card component
|
|
519
|
+
await fs.writeFile(
|
|
520
|
+
path.join(componentsDir, 'card.tsx'),
|
|
521
|
+
generateCardComponent()
|
|
522
|
+
);
|
|
523
|
+
componentsInstalled.push('card');
|
|
524
|
+
|
|
525
|
+
// Create input component
|
|
526
|
+
await fs.writeFile(
|
|
527
|
+
path.join(componentsDir, 'input.tsx'),
|
|
528
|
+
generateInputComponent()
|
|
529
|
+
);
|
|
530
|
+
componentsInstalled.push('input');
|
|
531
|
+
|
|
532
|
+
// Create badge component
|
|
533
|
+
await fs.writeFile(
|
|
534
|
+
path.join(componentsDir, 'badge.tsx'),
|
|
535
|
+
generateBadgeComponent()
|
|
536
|
+
);
|
|
537
|
+
componentsInstalled.push('badge');
|
|
538
|
+
|
|
539
|
+
// Create skeleton component
|
|
540
|
+
await fs.writeFile(
|
|
541
|
+
path.join(componentsDir, 'skeleton.tsx'),
|
|
542
|
+
generateSkeletonComponent()
|
|
543
|
+
);
|
|
544
|
+
componentsInstalled.push('skeleton');
|
|
545
|
+
|
|
546
|
+
// Step 9: Update main.tsx to import CSS
|
|
547
|
+
onProgress?.('Updating application entry point...');
|
|
548
|
+
const mainTsxPath = path.join(frontendDir, 'src', 'main.tsx');
|
|
549
|
+
let mainTsx = await fs.readFile(mainTsxPath, 'utf-8');
|
|
550
|
+
|
|
551
|
+
if (!mainTsx.includes("import './index.css'")) {
|
|
552
|
+
// Add CSS import at the top
|
|
553
|
+
mainTsx = `import './index.css';\n${mainTsx}`;
|
|
554
|
+
await fs.writeFile(mainTsxPath, mainTsx);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
onProgress?.(`UI setup complete! Theme: ${theme.name}, Components: ${componentsInstalled.length}`);
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
success: true,
|
|
561
|
+
theme: themeName,
|
|
562
|
+
componentsInstalled,
|
|
563
|
+
};
|
|
564
|
+
} catch (error) {
|
|
565
|
+
return {
|
|
566
|
+
success: false,
|
|
567
|
+
theme: options.theme || 'modern',
|
|
568
|
+
componentsInstalled,
|
|
569
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Component generators
|
|
575
|
+
function generateButtonComponent(): string {
|
|
576
|
+
return `import * as React from "react";
|
|
577
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
578
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
579
|
+
import { cn } from "@/lib/utils";
|
|
580
|
+
|
|
581
|
+
const buttonVariants = cva(
|
|
582
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
583
|
+
{
|
|
584
|
+
variants: {
|
|
585
|
+
variant: {
|
|
586
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
587
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
588
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
589
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
590
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
591
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
592
|
+
},
|
|
593
|
+
size: {
|
|
594
|
+
default: "h-10 px-4 py-2",
|
|
595
|
+
sm: "h-9 rounded-md px-3",
|
|
596
|
+
lg: "h-11 rounded-md px-8",
|
|
597
|
+
icon: "h-10 w-10",
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
defaultVariants: {
|
|
601
|
+
variant: "default",
|
|
602
|
+
size: "default",
|
|
603
|
+
},
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
export interface ButtonProps
|
|
608
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
609
|
+
VariantProps<typeof buttonVariants> {
|
|
610
|
+
asChild?: boolean;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
614
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
615
|
+
const Comp = asChild ? Slot : "button";
|
|
616
|
+
return (
|
|
617
|
+
<Comp
|
|
618
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
619
|
+
ref={ref}
|
|
620
|
+
{...props}
|
|
621
|
+
/>
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
Button.displayName = "Button";
|
|
626
|
+
|
|
627
|
+
export { Button, buttonVariants };
|
|
628
|
+
`;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function generateCardComponent(): string {
|
|
632
|
+
return `import * as React from "react";
|
|
633
|
+
import { cn } from "@/lib/utils";
|
|
634
|
+
|
|
635
|
+
const Card = React.forwardRef<
|
|
636
|
+
HTMLDivElement,
|
|
637
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
638
|
+
>(({ className, ...props }, ref) => (
|
|
639
|
+
<div
|
|
640
|
+
ref={ref}
|
|
641
|
+
className={cn(
|
|
642
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
643
|
+
className
|
|
644
|
+
)}
|
|
645
|
+
{...props}
|
|
646
|
+
/>
|
|
647
|
+
));
|
|
648
|
+
Card.displayName = "Card";
|
|
649
|
+
|
|
650
|
+
const CardHeader = React.forwardRef<
|
|
651
|
+
HTMLDivElement,
|
|
652
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
653
|
+
>(({ className, ...props }, ref) => (
|
|
654
|
+
<div
|
|
655
|
+
ref={ref}
|
|
656
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
657
|
+
{...props}
|
|
658
|
+
/>
|
|
659
|
+
));
|
|
660
|
+
CardHeader.displayName = "CardHeader";
|
|
661
|
+
|
|
662
|
+
const CardTitle = React.forwardRef<
|
|
663
|
+
HTMLParagraphElement,
|
|
664
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
665
|
+
>(({ className, ...props }, ref) => (
|
|
666
|
+
<h3
|
|
667
|
+
ref={ref}
|
|
668
|
+
className={cn(
|
|
669
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
670
|
+
className
|
|
671
|
+
)}
|
|
672
|
+
{...props}
|
|
673
|
+
/>
|
|
674
|
+
));
|
|
675
|
+
CardTitle.displayName = "CardTitle";
|
|
676
|
+
|
|
677
|
+
const CardDescription = React.forwardRef<
|
|
678
|
+
HTMLParagraphElement,
|
|
679
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
680
|
+
>(({ className, ...props }, ref) => (
|
|
681
|
+
<p
|
|
682
|
+
ref={ref}
|
|
683
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
684
|
+
{...props}
|
|
685
|
+
/>
|
|
686
|
+
));
|
|
687
|
+
CardDescription.displayName = "CardDescription";
|
|
688
|
+
|
|
689
|
+
const CardContent = React.forwardRef<
|
|
690
|
+
HTMLDivElement,
|
|
691
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
692
|
+
>(({ className, ...props }, ref) => (
|
|
693
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
694
|
+
));
|
|
695
|
+
CardContent.displayName = "CardContent";
|
|
696
|
+
|
|
697
|
+
const CardFooter = React.forwardRef<
|
|
698
|
+
HTMLDivElement,
|
|
699
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
700
|
+
>(({ className, ...props }, ref) => (
|
|
701
|
+
<div
|
|
702
|
+
ref={ref}
|
|
703
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
704
|
+
{...props}
|
|
705
|
+
/>
|
|
706
|
+
));
|
|
707
|
+
CardFooter.displayName = "CardFooter";
|
|
708
|
+
|
|
709
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
|
710
|
+
`;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function generateInputComponent(): string {
|
|
714
|
+
return `import * as React from "react";
|
|
715
|
+
import { cn } from "@/lib/utils";
|
|
716
|
+
|
|
717
|
+
export interface InputProps
|
|
718
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
719
|
+
|
|
720
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
721
|
+
({ className, type, ...props }, ref) => {
|
|
722
|
+
return (
|
|
723
|
+
<input
|
|
724
|
+
type={type}
|
|
725
|
+
className={cn(
|
|
726
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
727
|
+
className
|
|
728
|
+
)}
|
|
729
|
+
ref={ref}
|
|
730
|
+
{...props}
|
|
731
|
+
/>
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
);
|
|
735
|
+
Input.displayName = "Input";
|
|
736
|
+
|
|
737
|
+
export { Input };
|
|
738
|
+
`;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function generateBadgeComponent(): string {
|
|
742
|
+
return `import * as React from "react";
|
|
743
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
744
|
+
import { cn } from "@/lib/utils";
|
|
745
|
+
|
|
746
|
+
const badgeVariants = cva(
|
|
747
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
748
|
+
{
|
|
749
|
+
variants: {
|
|
750
|
+
variant: {
|
|
751
|
+
default:
|
|
752
|
+
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
753
|
+
secondary:
|
|
754
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
755
|
+
destructive:
|
|
756
|
+
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
757
|
+
outline: "text-foreground",
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
defaultVariants: {
|
|
761
|
+
variant: "default",
|
|
762
|
+
},
|
|
763
|
+
}
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
export interface BadgeProps
|
|
767
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
768
|
+
VariantProps<typeof badgeVariants> {}
|
|
769
|
+
|
|
770
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
771
|
+
return (
|
|
772
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
export { Badge, badgeVariants };
|
|
777
|
+
`;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function generateSkeletonComponent(): string {
|
|
781
|
+
return `import { cn } from "@/lib/utils";
|
|
782
|
+
|
|
783
|
+
function Skeleton({
|
|
784
|
+
className,
|
|
785
|
+
...props
|
|
786
|
+
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
787
|
+
return (
|
|
788
|
+
<div
|
|
789
|
+
className={cn("animate-pulse rounded-md bg-muted", className)}
|
|
790
|
+
{...props}
|
|
791
|
+
/>
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
export { Skeleton };
|
|
796
|
+
`;
|
|
797
|
+
}
|