build-app-with 2.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.
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/bin/cli.js +18 -0
- package/index.js +3 -0
- package/package.json +80 -0
- package/src/__tests__/core/error-handler.test.js +99 -0
- package/src/__tests__/core/logger.test.js +93 -0
- package/src/__tests__/e2e/cli-integration.test.js +220 -0
- package/src/__tests__/e2e/framework-generation.test.js +249 -0
- package/src/__tests__/setup.js +70 -0
- package/src/config/package-mappings.js +110 -0
- package/src/constants/index.js +42 -0
- package/src/core/error-handler.js +89 -0
- package/src/core/logger.js +89 -0
- package/src/core/package-manager.js +114 -0
- package/src/create-app.js +90 -0
- package/src/generators/express/index.js +52 -0
- package/src/generators/express/project-generator.js +367 -0
- package/src/generators/express/prompts.js +74 -0
- package/src/generators/express/simple-generator.js +275 -0
- package/src/generators/express/templates/app.js +73 -0
- package/src/generators/express/templates/config/database.js +122 -0
- package/src/generators/express/templates/config.js +37 -0
- package/src/generators/express/templates/controllers.js +49 -0
- package/src/generators/express/templates/docker.js +72 -0
- package/src/generators/express/templates/middleware/errorHandler.js +49 -0
- package/src/generators/express/templates/middleware.js +59 -0
- package/src/generators/express/templates/models.js +77 -0
- package/src/generators/express/templates/package-json.js +55 -0
- package/src/generators/express/templates/readme.js +310 -0
- package/src/generators/express/templates/routes.js +36 -0
- package/src/generators/express/templates/server.js +59 -0
- package/src/generators/express/templates/services.js +55 -0
- package/src/generators/express/templates/tests.js +46 -0
- package/src/generators/express/templates/utils/logger.js +54 -0
- package/src/generators/fastify/index.js +46 -0
- package/src/generators/fastify/project-generator.js +373 -0
- package/src/generators/fastify/prompts.js +76 -0
- package/src/generators/fastify/templates/app.js +179 -0
- package/src/generators/fastify/templates/config.js +33 -0
- package/src/generators/fastify/templates/docker.js +73 -0
- package/src/generators/fastify/templates/models.js +77 -0
- package/src/generators/fastify/templates/package-json.js +57 -0
- package/src/generators/fastify/templates/plugins.js +38 -0
- package/src/generators/fastify/templates/readme.js +328 -0
- package/src/generators/fastify/templates/routes.js +32 -0
- package/src/generators/fastify/templates/server.js +71 -0
- package/src/generators/fastify/templates/services.js +50 -0
- package/src/generators/fastify/templates/tests.js +60 -0
- package/src/generators/nextjs/dependency-manager.js +99 -0
- package/src/generators/nextjs/file-generator.js +256 -0
- package/src/generators/nextjs/nextjs-generator.js +177 -0
- package/src/generators/nextjs/nextjs-project-generator.js +896 -0
- package/src/generators/nextjs/package-mappings.js +51 -0
- package/src/generators/nextjs/templates.js +272 -0
- package/src/generators/package-json-generator.js +117 -0
- package/src/generators/vite/components/CreditComponent.jsx +41 -0
- package/src/generators/vite/components/app-component.js +359 -0
- package/src/generators/vite/components/main-file.js +88 -0
- package/src/generators/vite/eslint-config-generator.js +20 -0
- package/src/generators/vite/file-generator.js +796 -0
- package/src/generators/vite/prettier-config-generator.js +10 -0
- package/src/generators/vite/structures/domain-driven-structure.js +465 -0
- package/src/generators/vite/structures/feature-based-structure.js +342 -0
- package/src/generators/vite/structures/simple-structure.js +62 -0
- package/src/generators/vite/styles/index-css.js +130 -0
- package/src/generators/vite/tailwind-config-generator.js +14 -0
- package/src/generators/vite/vite-config-generator.js +22 -0
- package/src/generators/vite/vite-project-generator.js +263 -0
- package/src/generators/vite-project-generator.js +136 -0
- package/src/prompts/index.js +262 -0
- package/src/types/index.js +113 -0
- package/src/utils/answer-helpers.js +24 -0
- package/src/utils/credits.js +192 -0
- package/src/utils/dependencies.js +25 -0
- package/src/utils/messages.js +27 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { generateAppComponent } from '../components/app-component.js';
|
|
4
|
+
import { generateMainFile } from '../components/main-file.js';
|
|
5
|
+
import { generateIndexCSS } from '../styles/index-css.js';
|
|
6
|
+
|
|
7
|
+
export async function generateFeatureBasedStructure(projectPath, answers) {
|
|
8
|
+
const srcPath = path.join(projectPath, 'src');
|
|
9
|
+
await fs.ensureDir(srcPath);
|
|
10
|
+
|
|
11
|
+
// Generate main entry file
|
|
12
|
+
const mainFile = generateMainFile(answers);
|
|
13
|
+
const mainExtension = answers.typescript ? 'tsx' : 'jsx';
|
|
14
|
+
await fs.writeFile(path.join(srcPath, `main.${mainExtension}`), mainFile);
|
|
15
|
+
|
|
16
|
+
// Generate App component
|
|
17
|
+
const appComponent = generateAppComponent(answers);
|
|
18
|
+
const appExtension = answers.typescript ? 'tsx' : 'jsx';
|
|
19
|
+
await fs.writeFile(path.join(srcPath, `App.${appExtension}`), appComponent);
|
|
20
|
+
|
|
21
|
+
// Generate CSS file
|
|
22
|
+
const indexCSS = generateIndexCSS(answers);
|
|
23
|
+
await fs.writeFile(path.join(srcPath, 'index.css'), indexCSS);
|
|
24
|
+
|
|
25
|
+
// Create feature-based directories
|
|
26
|
+
const directories = [
|
|
27
|
+
'components/common',
|
|
28
|
+
'features/auth',
|
|
29
|
+
'features/dashboard',
|
|
30
|
+
'hooks',
|
|
31
|
+
'services',
|
|
32
|
+
'utils',
|
|
33
|
+
'types'
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
for (const dir of directories) {
|
|
37
|
+
await fs.ensureDir(path.join(srcPath, dir));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Generate sample files for each feature
|
|
41
|
+
await generateAuthFeature(srcPath, answers);
|
|
42
|
+
await generateDashboardFeature(srcPath, answers);
|
|
43
|
+
await generateCommonComponents(srcPath, answers);
|
|
44
|
+
await generateHooks(srcPath, answers);
|
|
45
|
+
await generateServices(srcPath, answers);
|
|
46
|
+
await generateUtils(srcPath, answers);
|
|
47
|
+
|
|
48
|
+
if (answers.typescript) {
|
|
49
|
+
await generateTypes(srcPath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function generateAuthFeature(srcPath, answers) {
|
|
54
|
+
const authPath = path.join(srcPath, 'features/auth');
|
|
55
|
+
const ext = answers.typescript ? 'tsx' : 'jsx';
|
|
56
|
+
|
|
57
|
+
const loginComponent = answers.typescript ? `import React from 'react';
|
|
58
|
+
|
|
59
|
+
const Login: React.FC = () => {
|
|
60
|
+
return (
|
|
61
|
+
<div className="login">
|
|
62
|
+
<h2>Login</h2>
|
|
63
|
+
<form>
|
|
64
|
+
<input type="email" placeholder="Email" />
|
|
65
|
+
<input type="password" placeholder="Password" />
|
|
66
|
+
<button type="submit">Login</button>
|
|
67
|
+
</form>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default Login;
|
|
73
|
+
` : `import React from 'react';
|
|
74
|
+
|
|
75
|
+
const Login = () => {
|
|
76
|
+
return (
|
|
77
|
+
<div className="login">
|
|
78
|
+
<h2>Login</h2>
|
|
79
|
+
<form>
|
|
80
|
+
<input type="email" placeholder="Email" />
|
|
81
|
+
<input type="password" placeholder="Password" />
|
|
82
|
+
<button type="submit">Login</button>
|
|
83
|
+
</form>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default Login;
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
await fs.writeFile(path.join(authPath, `Login.${ext}`), loginComponent);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function generateDashboardFeature(srcPath, answers) {
|
|
95
|
+
const dashboardPath = path.join(srcPath, 'features/dashboard');
|
|
96
|
+
const ext = answers.typescript ? 'tsx' : 'jsx';
|
|
97
|
+
|
|
98
|
+
const dashboardComponent = answers.typescript ? `import React from 'react';
|
|
99
|
+
|
|
100
|
+
const Dashboard: React.FC = () => {
|
|
101
|
+
return (
|
|
102
|
+
<div className="dashboard">
|
|
103
|
+
<h1>Dashboard</h1>
|
|
104
|
+
<p>Welcome to your dashboard!</p>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export default Dashboard;
|
|
110
|
+
` : `import React from 'react';
|
|
111
|
+
|
|
112
|
+
const Dashboard = () => {
|
|
113
|
+
return (
|
|
114
|
+
<div className="dashboard">
|
|
115
|
+
<h1>Dashboard</h1>
|
|
116
|
+
<p>Welcome to your dashboard!</p>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export default Dashboard;
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
await fs.writeFile(path.join(dashboardPath, `Dashboard.${ext}`), dashboardComponent);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function generateCommonComponents(srcPath, answers) {
|
|
128
|
+
const commonPath = path.join(srcPath, 'components/common');
|
|
129
|
+
const ext = answers.typescript ? 'tsx' : 'jsx';
|
|
130
|
+
|
|
131
|
+
const headerComponent = answers.typescript ? `import React from 'react';
|
|
132
|
+
|
|
133
|
+
const Header: React.FC = () => {
|
|
134
|
+
return (
|
|
135
|
+
<header className="header">
|
|
136
|
+
<h1>My App</h1>
|
|
137
|
+
<nav>
|
|
138
|
+
<a href="/">Home</a>
|
|
139
|
+
<a href="/about">About</a>
|
|
140
|
+
</nav>
|
|
141
|
+
</header>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export default Header;
|
|
146
|
+
` : `import React from 'react';
|
|
147
|
+
|
|
148
|
+
const Header = () => {
|
|
149
|
+
return (
|
|
150
|
+
<header className="header">
|
|
151
|
+
<h1>My App</h1>
|
|
152
|
+
<nav>
|
|
153
|
+
<a href="/">Home</a>
|
|
154
|
+
<a href="/about">About</a>
|
|
155
|
+
</nav>
|
|
156
|
+
</header>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default Header;
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
await fs.writeFile(path.join(commonPath, `Header.${ext}`), headerComponent);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function generateHooks(srcPath, answers) {
|
|
167
|
+
const hooksPath = path.join(srcPath, 'hooks');
|
|
168
|
+
const ext = answers.typescript ? 'ts' : 'js';
|
|
169
|
+
|
|
170
|
+
const useLocalStorage = answers.typescript ? `import { useState, useEffect } from 'react';
|
|
171
|
+
|
|
172
|
+
export function useLocalStorage<T>(key: string, initialValue: T) {
|
|
173
|
+
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
174
|
+
try {
|
|
175
|
+
const item = window.localStorage.getItem(key);
|
|
176
|
+
return item ? JSON.parse(item) : initialValue;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
return initialValue;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const setValue = (value: T | ((val: T) => T)) => {
|
|
183
|
+
try {
|
|
184
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
185
|
+
setStoredValue(valueToStore);
|
|
186
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error(error);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
return [storedValue, setValue] as const;
|
|
193
|
+
}
|
|
194
|
+
` : `import { useState, useEffect } from 'react';
|
|
195
|
+
|
|
196
|
+
export function useLocalStorage(key, initialValue) {
|
|
197
|
+
const [storedValue, setStoredValue] = useState(() => {
|
|
198
|
+
try {
|
|
199
|
+
const item = window.localStorage.getItem(key);
|
|
200
|
+
return item ? JSON.parse(item) : initialValue;
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return initialValue;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const setValue = (value) => {
|
|
207
|
+
try {
|
|
208
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
209
|
+
setStoredValue(valueToStore);
|
|
210
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error(error);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return [storedValue, setValue];
|
|
217
|
+
}
|
|
218
|
+
`;
|
|
219
|
+
|
|
220
|
+
await fs.writeFile(path.join(hooksPath, `useLocalStorage.${ext}`), useLocalStorage);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function generateServices(srcPath, answers) {
|
|
224
|
+
const servicesPath = path.join(srcPath, 'services');
|
|
225
|
+
const ext = answers.typescript ? 'ts' : 'js';
|
|
226
|
+
|
|
227
|
+
const apiService = answers.typescript ? `const API_BASE_URL = 'https://api.example.com';
|
|
228
|
+
|
|
229
|
+
export class ApiService {
|
|
230
|
+
static async get<T>(endpoint: string): Promise<T> {
|
|
231
|
+
const response = await fetch(\`\${API_BASE_URL}\${endpoint}\`);
|
|
232
|
+
if (!response.ok) {
|
|
233
|
+
throw new Error('Network response was not ok');
|
|
234
|
+
}
|
|
235
|
+
return response.json();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static async post<T>(endpoint: string, data: any): Promise<T> {
|
|
239
|
+
const response = await fetch(\`\${API_BASE_URL}\${endpoint}\`, {
|
|
240
|
+
method: 'POST',
|
|
241
|
+
headers: {
|
|
242
|
+
'Content-Type': 'application/json',
|
|
243
|
+
},
|
|
244
|
+
body: JSON.stringify(data),
|
|
245
|
+
});
|
|
246
|
+
if (!response.ok) {
|
|
247
|
+
throw new Error('Network response was not ok');
|
|
248
|
+
}
|
|
249
|
+
return response.json();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
` : `const API_BASE_URL = 'https://api.example.com';
|
|
253
|
+
|
|
254
|
+
export class ApiService {
|
|
255
|
+
static async get(endpoint) {
|
|
256
|
+
const response = await fetch(\`\${API_BASE_URL}\${endpoint}\`);
|
|
257
|
+
if (!response.ok) {
|
|
258
|
+
throw new Error('Network response was not ok');
|
|
259
|
+
}
|
|
260
|
+
return response.json();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
static async post(endpoint, data) {
|
|
264
|
+
const response = await fetch(\`\${API_BASE_URL}\${endpoint}\`, {
|
|
265
|
+
method: 'POST',
|
|
266
|
+
headers: {
|
|
267
|
+
'Content-Type': 'application/json',
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify(data),
|
|
270
|
+
});
|
|
271
|
+
if (!response.ok) {
|
|
272
|
+
throw new Error('Network response was not ok');
|
|
273
|
+
}
|
|
274
|
+
return response.json();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
`;
|
|
278
|
+
|
|
279
|
+
await fs.writeFile(path.join(servicesPath, `api.${ext}`), apiService);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function generateUtils(srcPath, answers) {
|
|
283
|
+
const utilsPath = path.join(srcPath, 'utils');
|
|
284
|
+
const ext = answers.typescript ? 'ts' : 'js';
|
|
285
|
+
|
|
286
|
+
const helpers = answers.typescript ? `export const formatDate = (date: Date): string => {
|
|
287
|
+
return date.toLocaleDateString('en-US', {
|
|
288
|
+
year: 'numeric',
|
|
289
|
+
month: 'long',
|
|
290
|
+
day: 'numeric'
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
export const debounce = <T extends (...args: any[]) => any>(
|
|
295
|
+
func: T,
|
|
296
|
+
wait: number
|
|
297
|
+
): ((...args: Parameters<T>) => void) => {
|
|
298
|
+
let timeout: NodeJS.Timeout;
|
|
299
|
+
return (...args: Parameters<T>) => {
|
|
300
|
+
clearTimeout(timeout);
|
|
301
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
` : `export const formatDate = (date) => {
|
|
305
|
+
return date.toLocaleDateString('en-US', {
|
|
306
|
+
year: 'numeric',
|
|
307
|
+
month: 'long',
|
|
308
|
+
day: 'numeric'
|
|
309
|
+
});
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export const debounce = (func, wait) => {
|
|
313
|
+
let timeout;
|
|
314
|
+
return (...args) => {
|
|
315
|
+
clearTimeout(timeout);
|
|
316
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
`;
|
|
320
|
+
|
|
321
|
+
await fs.writeFile(path.join(utilsPath, `helpers.${ext}`), helpers);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function generateTypes(srcPath) {
|
|
325
|
+
const typesPath = path.join(srcPath, 'types');
|
|
326
|
+
|
|
327
|
+
const indexTypes = `export interface User {
|
|
328
|
+
id: string;
|
|
329
|
+
name: string;
|
|
330
|
+
email: string;
|
|
331
|
+
createdAt: string;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface ApiResponse<T> {
|
|
335
|
+
data: T;
|
|
336
|
+
message: string;
|
|
337
|
+
success: boolean;
|
|
338
|
+
}
|
|
339
|
+
`;
|
|
340
|
+
|
|
341
|
+
await fs.writeFile(path.join(typesPath, 'index.ts'), indexTypes);
|
|
342
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { generateAppComponent } from '../components/app-component.js';
|
|
4
|
+
import { generateMainFile } from '../components/main-file.js';
|
|
5
|
+
import { generateIndexCSS } from '../styles/index-css.js';
|
|
6
|
+
|
|
7
|
+
export async function generateSimpleStructure(projectPath, answers) {
|
|
8
|
+
const srcPath = path.join(projectPath, 'src');
|
|
9
|
+
await fs.ensureDir(srcPath);
|
|
10
|
+
|
|
11
|
+
// Generate main entry file
|
|
12
|
+
const mainFile = generateMainFile(answers);
|
|
13
|
+
const mainExtension = answers.typescript ? 'tsx' : 'jsx';
|
|
14
|
+
await fs.writeFile(path.join(srcPath, `main.${mainExtension}`), mainFile);
|
|
15
|
+
|
|
16
|
+
// Generate App component
|
|
17
|
+
const appComponent = generateAppComponent(answers);
|
|
18
|
+
const appExtension = answers.typescript ? 'tsx' : 'jsx';
|
|
19
|
+
await fs.writeFile(path.join(srcPath, `App.${appExtension}`), appComponent);
|
|
20
|
+
|
|
21
|
+
// Generate CSS file
|
|
22
|
+
const indexCSS = generateIndexCSS(answers);
|
|
23
|
+
await fs.writeFile(path.join(srcPath, 'index.css'), indexCSS);
|
|
24
|
+
|
|
25
|
+
// Generate a simple components directory
|
|
26
|
+
const componentsPath = path.join(srcPath, 'components');
|
|
27
|
+
await fs.ensureDir(componentsPath);
|
|
28
|
+
|
|
29
|
+
// Create a sample component
|
|
30
|
+
const sampleComponent = answers.typescript ? `import React from 'react';
|
|
31
|
+
|
|
32
|
+
interface WelcomeProps {
|
|
33
|
+
name: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const Welcome: React.FC<WelcomeProps> = ({ name }) => {
|
|
37
|
+
return (
|
|
38
|
+
<div className="welcome">
|
|
39
|
+
<h2>Welcome, {name}!</h2>
|
|
40
|
+
<p>Your React app is ready to go.</p>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default Welcome;
|
|
46
|
+
` : `import React from 'react';
|
|
47
|
+
|
|
48
|
+
const Welcome = ({ name }) => {
|
|
49
|
+
return (
|
|
50
|
+
<div className="welcome">
|
|
51
|
+
<h2>Welcome, {name}!</h2>
|
|
52
|
+
<p>Your React app is ready to go.</p>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default Welcome;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const componentExtension = answers.typescript ? 'tsx' : 'jsx';
|
|
61
|
+
await fs.writeFile(path.join(componentsPath, `Welcome.${componentExtension}`), sampleComponent);
|
|
62
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export function generateIndexCSS(answers) {
|
|
2
|
+
let baseStyles = `:root {
|
|
3
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
4
|
+
line-height: 1.5;
|
|
5
|
+
font-weight: 400;
|
|
6
|
+
|
|
7
|
+
color-scheme: light dark;
|
|
8
|
+
color: rgba(255, 255, 255, 0.87);
|
|
9
|
+
background-color: #242424;
|
|
10
|
+
|
|
11
|
+
font-synthesis: none;
|
|
12
|
+
text-rendering: optimizeLegibility;
|
|
13
|
+
-webkit-font-smoothing: antialiased;
|
|
14
|
+
-moz-osx-font-smoothing: grayscale;
|
|
15
|
+
-webkit-text-size-adjust: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
* {
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
body {
|
|
23
|
+
margin: 0;
|
|
24
|
+
display: flex;
|
|
25
|
+
place-items: center;
|
|
26
|
+
min-width: 320px;
|
|
27
|
+
min-height: 100vh;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#root {
|
|
31
|
+
width: 100%;
|
|
32
|
+
margin: 0 auto;
|
|
33
|
+
text-align: center;
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
// Add Tailwind directives if Tailwind is selected
|
|
38
|
+
if (answers.cssFramework === 'tailwind') {
|
|
39
|
+
baseStyles = `@tailwind base;
|
|
40
|
+
@tailwind components;
|
|
41
|
+
@tailwind utilities;
|
|
42
|
+
|
|
43
|
+
${baseStyles}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Add custom styles based on CSS framework
|
|
47
|
+
if (answers.cssFramework === 'vanilla') {
|
|
48
|
+
baseStyles += `
|
|
49
|
+
.app {
|
|
50
|
+
min-height: 100vh;
|
|
51
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
padding: 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.container {
|
|
59
|
+
background: white;
|
|
60
|
+
border-radius: 20px;
|
|
61
|
+
padding: 40px;
|
|
62
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
63
|
+
max-width: 800px;
|
|
64
|
+
width: 100%;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.container h1 {
|
|
68
|
+
color: #333;
|
|
69
|
+
font-size: 3rem;
|
|
70
|
+
margin-bottom: 1rem;
|
|
71
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
72
|
+
-webkit-background-clip: text;
|
|
73
|
+
-webkit-text-fill-color: transparent;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.container p {
|
|
77
|
+
color: #666;
|
|
78
|
+
font-size: 1.2rem;
|
|
79
|
+
margin-bottom: 2rem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.features {
|
|
83
|
+
display: grid;
|
|
84
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
85
|
+
gap: 20px;
|
|
86
|
+
margin: 30px 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.feature-card {
|
|
90
|
+
padding: 20px;
|
|
91
|
+
border: 1px solid #e1e5e9;
|
|
92
|
+
border-radius: 12px;
|
|
93
|
+
transition: all 0.3s ease;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.feature-card:hover {
|
|
97
|
+
transform: translateY(-5px);
|
|
98
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.feature-icon {
|
|
102
|
+
font-size: 2rem;
|
|
103
|
+
margin-bottom: 10px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.feature-card h3 {
|
|
107
|
+
color: #333;
|
|
108
|
+
margin: 10px 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.feature-card p {
|
|
112
|
+
color: #666;
|
|
113
|
+
font-size: 0.9rem;
|
|
114
|
+
margin: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (max-width: 768px) {
|
|
118
|
+
.container h1 {
|
|
119
|
+
font-size: 2rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.features {
|
|
123
|
+
grid-template-columns: 1fr;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return baseStyles;
|
|
130
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function generateTailwindConfig(answers) {
|
|
2
|
+
return `/** @type {import('tailwindcss').Config} */
|
|
3
|
+
export default {
|
|
4
|
+
content: [
|
|
5
|
+
"./index.html",
|
|
6
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
7
|
+
],
|
|
8
|
+
theme: {
|
|
9
|
+
extend: {},
|
|
10
|
+
},
|
|
11
|
+
plugins: [],
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function generateViteConfig(answers) {
|
|
2
|
+
const imports = [`import { defineConfig } from 'vite'`, `import react from '@vitejs/plugin-react'`];
|
|
3
|
+
const plugins = ['react()'];
|
|
4
|
+
|
|
5
|
+
const config = `${imports.join('\n')}
|
|
6
|
+
|
|
7
|
+
// https://vitejs.dev/config/
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [${plugins.join(', ')}],
|
|
10
|
+
server: {
|
|
11
|
+
port: 3000,
|
|
12
|
+
open: true
|
|
13
|
+
},
|
|
14
|
+
build: {
|
|
15
|
+
outDir: 'dist',
|
|
16
|
+
sourcemap: true
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
return config;
|
|
22
|
+
}
|