@seip/blue-bird 0.3.3 → 0.3.4
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 +23 -13
- package/LICENSE +21 -21
- package/README.md +79 -79
- package/backend/index.js +12 -12
- package/backend/routes/api.js +34 -34
- package/backend/routes/frontend.js +1 -8
- package/core/app.js +359 -359
- package/core/auth.js +69 -69
- package/core/cache.js +35 -35
- package/core/cli/component.js +42 -42
- package/core/cli/init.js +120 -118
- package/core/cli/react.js +383 -411
- package/core/cli/route.js +42 -42
- package/core/cli/scaffolding-auth.js +967 -0
- package/core/config.js +41 -41
- package/core/debug.js +248 -248
- package/core/logger.js +80 -80
- package/core/middleware.js +27 -27
- package/core/router.js +134 -134
- package/core/swagger.js +24 -24
- package/core/template.js +288 -288
- package/core/upload.js +76 -76
- package/core/validate.js +291 -290
- package/frontend/index.html +28 -22
- package/frontend/resources/js/App.jsx +28 -42
- package/frontend/resources/js/Main.jsx +17 -17
- package/frontend/resources/js/blue-bird/components/Button.jsx +67 -0
- package/frontend/resources/js/blue-bird/components/Card.jsx +17 -0
- package/frontend/resources/js/blue-bird/components/DataTable.jsx +126 -0
- package/frontend/resources/js/blue-bird/components/Input.jsx +21 -0
- package/frontend/resources/js/blue-bird/components/Label.jsx +12 -0
- package/frontend/resources/js/blue-bird/components/Modal.jsx +27 -0
- package/frontend/resources/js/blue-bird/components/Translate.jsx +12 -0
- package/frontend/resources/js/blue-bird/components/Typography.jsx +25 -0
- package/frontend/resources/js/blue-bird/contexts/LanguageContext.jsx +29 -0
- package/frontend/resources/js/blue-bird/contexts/SnackbarContext.jsx +38 -0
- package/frontend/resources/js/blue-bird/contexts/ThemeContext.jsx +49 -0
- package/frontend/resources/js/blue-bird/locales/en.json +30 -0
- package/frontend/resources/js/blue-bird/locales/es.json +30 -0
- package/frontend/resources/js/pages/About.jsx +33 -15
- package/frontend/resources/js/pages/Home.jsx +93 -68
- package/package.json +56 -55
- package/vite.config.js +21 -21
package/core/cli/react.js
CHANGED
|
@@ -1,411 +1,383 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { execSync } from "node:child_process";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import Config from "../config.js";
|
|
6
|
-
|
|
7
|
-
const __dirname = Config.dirname();
|
|
8
|
-
const props = Config.props();
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Scaffolding class for setting up React and Vite in the project.
|
|
12
|
-
*/
|
|
13
|
-
class ReactScaffold {
|
|
14
|
-
/**
|
|
15
|
-
* Initializes the Scaffolder with the base application directory.
|
|
16
|
-
*/
|
|
17
|
-
constructor() {
|
|
18
|
-
this.appDir = __dirname;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Executes the installation process.
|
|
23
|
-
*/
|
|
24
|
-
async install() {
|
|
25
|
-
console.log(chalk.cyan("Initializing React + Vite setup..."));
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
this.createStructure();
|
|
29
|
-
this.updatePackageJson();
|
|
30
|
-
this.createViteConfig();
|
|
31
|
-
this.createAppjs();
|
|
32
|
-
this.createMainJs();
|
|
33
|
-
this.createPagesJs();
|
|
34
|
-
this.updateGitIgnore();
|
|
35
|
-
this.npmInstall();
|
|
36
|
-
|
|
37
|
-
console.log(chalk.green("React scaffolding created successfully!"));
|
|
38
|
-
console.log(chalk.cyan("\nNext steps:"));
|
|
39
|
-
console.log(chalk.white(" 1. Run (Blue Bird Server): ") + chalk.bold("npm run dev"));
|
|
40
|
-
console.log(chalk.white(" 2. Run (React Vite Dev): ") + chalk.bold("npm run vite:dev"));
|
|
41
|
-
console.log(chalk.blue("\nBlue Bird React setup completed!"));
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error(chalk.red("Fatal error during scaffolding:"), error.message);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Creates the necessary directory structure for React resources.
|
|
49
|
-
*/
|
|
50
|
-
createStructure() {
|
|
51
|
-
const dirs = [
|
|
52
|
-
'frontend/resources/js/pages'
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
dirs.forEach(dir => {
|
|
56
|
-
const fullPath = path.join(this.appDir, dir);
|
|
57
|
-
if (!fs.existsSync(fullPath)) {
|
|
58
|
-
fs.mkdirSync(fullPath, { recursive: true });
|
|
59
|
-
console.log(chalk.gray(`Created directory: ${dir}`));
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Updates the project's package.json with React and Vite dependencies and scripts.
|
|
66
|
-
*/
|
|
67
|
-
updatePackageJson() {
|
|
68
|
-
const packagePath = path.join(this.appDir, 'package.json');
|
|
69
|
-
if (!fs.existsSync(packagePath)) {
|
|
70
|
-
console.warn(chalk.yellow("package.json not found. Initializing with npm init..."));
|
|
71
|
-
execSync('npm init -y', { cwd: this.appDir });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
75
|
-
|
|
76
|
-
pkg.scripts = pkg.scripts || {};
|
|
77
|
-
pkg.scripts["vite:dev"] = "vite";
|
|
78
|
-
pkg.scripts["vite:build"] = "vite build";
|
|
79
|
-
|
|
80
|
-
pkg.devDependencies = pkg.devDependencies || {};
|
|
81
|
-
|
|
82
|
-
pkg.devDependencies["vite"] = "^7.3.1";
|
|
83
|
-
pkg.devDependencies["@vitejs/plugin-react"] = "^4.3.4";
|
|
84
|
-
|
|
85
|
-
pkg.dependencies = pkg.dependencies || {};
|
|
86
|
-
pkg.dependencies["react"] = "^19.2.4";
|
|
87
|
-
pkg.dependencies["react-dom"] = "^19.2.4";
|
|
88
|
-
pkg.dependencies["react-router-dom"] = "^7.2.0";
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2));
|
|
92
|
-
console.log(chalk.gray("Updated package.json dependencies and scripts."));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Creates the vite.config.js file with appropriate root and outDir settings.
|
|
97
|
-
*/
|
|
98
|
-
createViteConfig() {
|
|
99
|
-
const file = path.join(this.appDir, 'vite.config.js');
|
|
100
|
-
if (fs.existsSync(file)) {
|
|
101
|
-
console.warn(chalk.yellow("vite.config.js already exists. Skipping."));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// We use props.static.path to determine where the build goes
|
|
106
|
-
const outDir = path.join(props.static.path, 'build');
|
|
107
|
-
|
|
108
|
-
const content = `import { defineConfig } from 'vite';
|
|
109
|
-
import react from '@vitejs/plugin-react';
|
|
110
|
-
import path from 'path';
|
|
111
|
-
|
|
112
|
-
export default defineConfig({
|
|
113
|
-
plugins: [react()],
|
|
114
|
-
root: path.resolve(__dirname, 'frontend/resources/js'),
|
|
115
|
-
base: '/build/',
|
|
116
|
-
build: {
|
|
117
|
-
outDir: path.resolve(__dirname, '${outDir.replace(/\\/g, '/')}'),
|
|
118
|
-
emptyOutDir: true,
|
|
119
|
-
manifest: true,
|
|
120
|
-
rollupOptions: {
|
|
121
|
-
input: path.resolve(__dirname, 'frontend/resources/js/Main.jsx'),
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
server: {
|
|
125
|
-
origin: 'http://localhost:5173',
|
|
126
|
-
strictPort: true,
|
|
127
|
-
cors: true,
|
|
128
|
-
},
|
|
129
|
-
});`;
|
|
130
|
-
fs.writeFileSync(file, content);
|
|
131
|
-
console.log(chalk.gray("Created vite.config.js"));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
createPagesJs() {
|
|
135
|
-
const file = path.join(this.appDir, 'frontend/resources/js/pages/Home.jsx');
|
|
136
|
-
if (fs.existsSync(file)) {
|
|
137
|
-
console.warn(chalk.yellow("Home.jsx already exists. Skipping."));
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const content = `import React, { useEffect } from 'react';
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
</
|
|
177
|
-
</
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
};`;
|
|
347
|
-
fs.writeFileSync(file, content);
|
|
348
|
-
console.log(chalk.gray("Created frontend/resources/js/
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
updateGitIgnore() {
|
|
385
|
-
const file = path.join(this.appDir, '.gitignore');
|
|
386
|
-
const entry = "\nnode_modules\ndist\nfrontend/public/build\n";
|
|
387
|
-
|
|
388
|
-
if (fs.existsSync(file)) {
|
|
389
|
-
const content = fs.readFileSync(file, 'utf8');
|
|
390
|
-
if (!content.includes('node_modules')) {
|
|
391
|
-
fs.appendFileSync(file, entry);
|
|
392
|
-
console.log(chalk.gray("Updated .gitignore"));
|
|
393
|
-
}
|
|
394
|
-
} else {
|
|
395
|
-
fs.writeFileSync(file, entry);
|
|
396
|
-
console.log(chalk.gray("Created .gitignore"));
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
npmInstall() {
|
|
400
|
-
try {
|
|
401
|
-
execSync('npm install', { cwd: this.appDir });
|
|
402
|
-
console.log(chalk.gray("Installed dependencies"));
|
|
403
|
-
} catch (error) {
|
|
404
|
-
console.error(chalk.red("Error installing dependencies:"), error.message);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const scaffold = new ReactScaffold();
|
|
411
|
-
scaffold.install();
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import Config from "../config.js";
|
|
6
|
+
|
|
7
|
+
const __dirname = Config.dirname();
|
|
8
|
+
const props = Config.props();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Scaffolding class for setting up React and Vite in the project.
|
|
12
|
+
*/
|
|
13
|
+
class ReactScaffold {
|
|
14
|
+
/**
|
|
15
|
+
* Initializes the Scaffolder with the base application directory.
|
|
16
|
+
*/
|
|
17
|
+
constructor() {
|
|
18
|
+
this.appDir = __dirname;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Executes the installation process.
|
|
23
|
+
*/
|
|
24
|
+
async install() {
|
|
25
|
+
console.log(chalk.cyan("Initializing React + Vite setup..."));
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
this.createStructure();
|
|
29
|
+
this.updatePackageJson();
|
|
30
|
+
this.createViteConfig();
|
|
31
|
+
this.createAppjs();
|
|
32
|
+
this.createMainJs();
|
|
33
|
+
this.createPagesJs();
|
|
34
|
+
this.updateGitIgnore();
|
|
35
|
+
this.npmInstall();
|
|
36
|
+
|
|
37
|
+
console.log(chalk.green("React scaffolding created successfully!"));
|
|
38
|
+
console.log(chalk.cyan("\nNext steps:"));
|
|
39
|
+
console.log(chalk.white(" 1. Run (Blue Bird Server): ") + chalk.bold("npm run dev"));
|
|
40
|
+
console.log(chalk.white(" 2. Run (React Vite Dev): ") + chalk.bold("npm run vite:dev"));
|
|
41
|
+
console.log(chalk.blue("\nBlue Bird React setup completed!"));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(chalk.red("Fatal error during scaffolding:"), error.message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates the necessary directory structure for React resources.
|
|
49
|
+
*/
|
|
50
|
+
createStructure() {
|
|
51
|
+
const dirs = [
|
|
52
|
+
'frontend/resources/js/pages'
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
dirs.forEach(dir => {
|
|
56
|
+
const fullPath = path.join(this.appDir, dir);
|
|
57
|
+
if (!fs.existsSync(fullPath)) {
|
|
58
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
59
|
+
console.log(chalk.gray(`Created directory: ${dir}`));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Updates the project's package.json with React and Vite dependencies and scripts.
|
|
66
|
+
*/
|
|
67
|
+
updatePackageJson() {
|
|
68
|
+
const packagePath = path.join(this.appDir, 'package.json');
|
|
69
|
+
if (!fs.existsSync(packagePath)) {
|
|
70
|
+
console.warn(chalk.yellow("package.json not found. Initializing with npm init..."));
|
|
71
|
+
execSync('npm init -y', { cwd: this.appDir });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
75
|
+
|
|
76
|
+
pkg.scripts = pkg.scripts || {};
|
|
77
|
+
pkg.scripts["vite:dev"] = "vite";
|
|
78
|
+
pkg.scripts["vite:build"] = "vite build";
|
|
79
|
+
|
|
80
|
+
pkg.devDependencies = pkg.devDependencies || {};
|
|
81
|
+
|
|
82
|
+
pkg.devDependencies["vite"] = "^7.3.1";
|
|
83
|
+
pkg.devDependencies["@vitejs/plugin-react"] = "^4.3.4";
|
|
84
|
+
|
|
85
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
86
|
+
pkg.dependencies["react"] = "^19.2.4";
|
|
87
|
+
pkg.dependencies["react-dom"] = "^19.2.4";
|
|
88
|
+
pkg.dependencies["react-router-dom"] = "^7.2.0";
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2));
|
|
92
|
+
console.log(chalk.gray("Updated package.json dependencies and scripts."));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates the vite.config.js file with appropriate root and outDir settings.
|
|
97
|
+
*/
|
|
98
|
+
createViteConfig() {
|
|
99
|
+
const file = path.join(this.appDir, 'vite.config.js');
|
|
100
|
+
if (fs.existsSync(file)) {
|
|
101
|
+
console.warn(chalk.yellow("vite.config.js already exists. Skipping."));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// We use props.static.path to determine where the build goes
|
|
106
|
+
const outDir = path.join(props.static.path, 'build');
|
|
107
|
+
|
|
108
|
+
const content = `import { defineConfig } from 'vite';
|
|
109
|
+
import react from '@vitejs/plugin-react';
|
|
110
|
+
import path from 'path';
|
|
111
|
+
|
|
112
|
+
export default defineConfig({
|
|
113
|
+
plugins: [react()],
|
|
114
|
+
root: path.resolve(__dirname, 'frontend/resources/js'),
|
|
115
|
+
base: '/build/',
|
|
116
|
+
build: {
|
|
117
|
+
outDir: path.resolve(__dirname, '${outDir.replace(/\\/g, '/')}'),
|
|
118
|
+
emptyOutDir: true,
|
|
119
|
+
manifest: true,
|
|
120
|
+
rollupOptions: {
|
|
121
|
+
input: path.resolve(__dirname, 'frontend/resources/js/Main.jsx'),
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
server: {
|
|
125
|
+
origin: 'http://localhost:5173',
|
|
126
|
+
strictPort: true,
|
|
127
|
+
cors: true,
|
|
128
|
+
},
|
|
129
|
+
});`;
|
|
130
|
+
fs.writeFileSync(file, content);
|
|
131
|
+
console.log(chalk.gray("Created vite.config.js"));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
createPagesJs() {
|
|
135
|
+
const file = path.join(this.appDir, 'frontend/resources/js/pages/Home.jsx');
|
|
136
|
+
if (fs.existsSync(file)) {
|
|
137
|
+
console.warn(chalk.yellow("Home.jsx already exists. Skipping."));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const content = `import React, { useEffect } from 'react';
|
|
142
|
+
import { Link } from 'react-router-dom';
|
|
143
|
+
import Card from '../blue-bird/components/Card';
|
|
144
|
+
|
|
145
|
+
export default function Home() {
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
// Example API call to the backend
|
|
148
|
+
fetch("http://localhost:3000/login", {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: {
|
|
151
|
+
"Content-Type": "application/json",
|
|
152
|
+
},
|
|
153
|
+
body: JSON.stringify({
|
|
154
|
+
email: "example@example.com",
|
|
155
|
+
password: "myPassword123"
|
|
156
|
+
}),
|
|
157
|
+
})
|
|
158
|
+
.then((response) => response.json())
|
|
159
|
+
.then((data) => console.log('Backend response:', data))
|
|
160
|
+
.catch((error) => console.error('Error fetching from backend:', error));
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div
|
|
165
|
+
className="bg-white text-gray-900"
|
|
166
|
+
>
|
|
167
|
+
<nav
|
|
168
|
+
className='bg-white text-gray-900 border border-gray-200 px-4 py-4 flex justify-between items-center gap-4 sticky top-0 z-10'
|
|
169
|
+
>
|
|
170
|
+
<div className='font-bold text-xl text-blue-600'>
|
|
171
|
+
Blue Bird
|
|
172
|
+
</div>
|
|
173
|
+
<div className='flex justify-between items-center gap-4'>
|
|
174
|
+
<Link to="/" className='text-gray-500 hover:text-gray-900'>Home</Link>
|
|
175
|
+
<Link to="/about" className='text-gray-500 hover:text-gray-900'>About</Link>
|
|
176
|
+
</div>
|
|
177
|
+
</nav>
|
|
178
|
+
<main className='max-w-7xl mx-auto'>
|
|
179
|
+
<div className='text-center p-4'>
|
|
180
|
+
<header className='mb-4'>
|
|
181
|
+
<h1 className='text-3xl font-bold bg-gradient-to-r from-blue-500 to-blue-600 bg-clip-text text-transparent mb-4'>
|
|
182
|
+
Welcome to Blue Bird
|
|
183
|
+
</h1>
|
|
184
|
+
<p className='text-gray-500 max-w-600px mx-auto'>
|
|
185
|
+
The elegant, fast, and weightless framework for modern web development.
|
|
186
|
+
</p>
|
|
187
|
+
</header>
|
|
188
|
+
|
|
189
|
+
<Card title={" Documentation (Eng)"} className='mt-8 border-none shadow-none'>
|
|
190
|
+
<div className='flex gap-4 justify-center mb-8'>
|
|
191
|
+
<a
|
|
192
|
+
href="https://seip25.github.io/Blue-bird/en.html"
|
|
193
|
+
target="_blank"
|
|
194
|
+
rel="noopener noreferrer"
|
|
195
|
+
className='bg-blue-600 text-white px-4 py-2 rounded-lg font-semibold transition-colors hover:bg-blue-400'
|
|
196
|
+
>
|
|
197
|
+
Documentation(Eng)
|
|
198
|
+
</a>
|
|
199
|
+
<a
|
|
200
|
+
href="https://seip25.github.io/Blue-bird/"
|
|
201
|
+
target="_blank"
|
|
202
|
+
rel="noopener noreferrer"
|
|
203
|
+
className='bg-blue-50 text-blue-500 px-4 py-2 rounded-lg font-semibold transition-colors hover:bg-blue-100 '
|
|
204
|
+
>
|
|
205
|
+
Documentación (Esp)
|
|
206
|
+
|
|
207
|
+
</a>
|
|
208
|
+
</div>
|
|
209
|
+
</Card>
|
|
210
|
+
|
|
211
|
+
<Card className='mt-8 border-none shadow-none'>
|
|
212
|
+
<div className='mt-8 grid grid-cols-1 md:grid-cols-3 gap-4 max-w-1000px mx-auto'>
|
|
213
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
214
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>Lightweight</h3>
|
|
215
|
+
<p>Built with performance and simplicity in mind.</p>
|
|
216
|
+
</div>
|
|
217
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
218
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>React Powered</h3>
|
|
219
|
+
<p>Full React + Vite integration .</p>
|
|
220
|
+
</div>
|
|
221
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
222
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>Express Backend</h3>
|
|
223
|
+
<p>Robust and scalable backend architecture.</p>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</Card>
|
|
227
|
+
|
|
228
|
+
</div>
|
|
229
|
+
</main>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
`;
|
|
236
|
+
fs.writeFileSync(file, content);
|
|
237
|
+
console.log(chalk.gray("Created frontend/resources/js/pages/Home.jsx"));
|
|
238
|
+
|
|
239
|
+
const file2 = path.join(this.appDir, 'frontend/resources/js/pages/About.jsx');
|
|
240
|
+
if (fs.existsSync(file2)) {
|
|
241
|
+
console.warn(chalk.yellow("About.jsx already exists. Skipping."));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const content2 = `import React from 'react';
|
|
246
|
+
import { Link } from 'react-router-dom';
|
|
247
|
+
|
|
248
|
+
export default function About() {
|
|
249
|
+
return (
|
|
250
|
+
<div
|
|
251
|
+
className="bg-white text-gray-900"
|
|
252
|
+
>
|
|
253
|
+
<nav
|
|
254
|
+
className='bg-white text-gray-900 border border-gray-200 px-4 py-4 flex justify-between items-center gap-4 sticky top-0 z-10'
|
|
255
|
+
>
|
|
256
|
+
<div className='font-bold text-xl text-blue-600'>
|
|
257
|
+
Blue Bird
|
|
258
|
+
</div>
|
|
259
|
+
<div className='flex justify-between items-center gap-4'>
|
|
260
|
+
<Link to="/" className='text-gray-500 hover:text-gray-900'>Home</Link>
|
|
261
|
+
<Link to="/about" className='text-gray-500 hover:text-gray-900'>About</Link>
|
|
262
|
+
</div>
|
|
263
|
+
</nav>
|
|
264
|
+
<main className='max-w-7xl mx-auto'>
|
|
265
|
+
<div className='p-4'>
|
|
266
|
+
<h1 className='text-xl font-bold text-gray-900 mb-4'>About Blue Bird</h1>
|
|
267
|
+
<p className='text-gray-500 leading-1.6'>
|
|
268
|
+
Blue Bird is a modern framework designed to bridge the gap between backend routing and frontend interactivity.
|
|
269
|
+
It provides a seamless developer experience for building fast, reactive web applications.
|
|
270
|
+
</p>
|
|
271
|
+
<p className='text-red-500 text-xl mt-8 '>
|
|
272
|
+
Check your console JS
|
|
273
|
+
</p>
|
|
274
|
+
</div>
|
|
275
|
+
</main>
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
}`;
|
|
279
|
+
fs.writeFileSync(file2, content2);
|
|
280
|
+
console.log(chalk.gray("Created frontend/resources/js/pages/About.jsx"));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Creates the main entry point for React (main.jsx) which handles island hydration.
|
|
285
|
+
*/
|
|
286
|
+
createAppjs() {
|
|
287
|
+
const file = path.join(this.appDir, 'frontend/resources/js/App.jsx');
|
|
288
|
+
if (fs.existsSync(file)) {
|
|
289
|
+
console.warn(chalk.yellow("App.jsx already exists. Skipping."));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const content = `import React from 'react';
|
|
294
|
+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
|
295
|
+
import Home from './pages/Home';
|
|
296
|
+
import About from './pages/About';
|
|
297
|
+
|
|
298
|
+
export default function App(_props) {
|
|
299
|
+
const {
|
|
300
|
+
component,
|
|
301
|
+
props
|
|
302
|
+
} = _props;
|
|
303
|
+
|
|
304
|
+
console.log('Check props and component ')
|
|
305
|
+
console.log('Component:'+component)
|
|
306
|
+
console.log(props)
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<Router>
|
|
310
|
+
<Routes>
|
|
311
|
+
<Route path="/" element={<Home />} />
|
|
312
|
+
<Route path="/about" element={<About />} />
|
|
313
|
+
</Routes>
|
|
314
|
+
</Router>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
`;
|
|
319
|
+
fs.writeFileSync(file, content);
|
|
320
|
+
console.log(chalk.gray("Created frontend/resources/js/App.jsx"));
|
|
321
|
+
}
|
|
322
|
+
createMainJs() {
|
|
323
|
+
const file = path.join(this.appDir, 'frontend/resources/js/Main.jsx');
|
|
324
|
+
if (fs.existsSync(file)) {
|
|
325
|
+
console.warn(chalk.yellow("Main.jsx already exists. Skipping."));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const content = `import React from 'react';
|
|
330
|
+
import { createRoot } from 'react-dom/client';
|
|
331
|
+
import App from './App';
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
335
|
+
document.querySelectorAll('[data-react-component]').forEach(el => {
|
|
336
|
+
const component = {
|
|
337
|
+
component:el.dataset.reactComponent
|
|
338
|
+
};
|
|
339
|
+
const props = JSON.parse(el.dataset.props || '{}');
|
|
340
|
+
const allProps={
|
|
341
|
+
...props,
|
|
342
|
+
...component
|
|
343
|
+
}
|
|
344
|
+
createRoot(el).render(<App {...allProps} />);
|
|
345
|
+
});
|
|
346
|
+
});`;
|
|
347
|
+
fs.writeFileSync(file, content);
|
|
348
|
+
console.log(chalk.gray("Created frontend/resources/js/Main.jsx"));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Ensures node_modules and other build artifacts are ignored by Git.
|
|
355
|
+
*/
|
|
356
|
+
updateGitIgnore() {
|
|
357
|
+
const file = path.join(this.appDir, '.gitignore');
|
|
358
|
+
const entry = "\nnode_modules\ndist\nfrontend/public/build\n";
|
|
359
|
+
|
|
360
|
+
if (fs.existsSync(file)) {
|
|
361
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
362
|
+
if (!content.includes('node_modules')) {
|
|
363
|
+
fs.appendFileSync(file, entry);
|
|
364
|
+
console.log(chalk.gray("Updated .gitignore"));
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
fs.writeFileSync(file, entry);
|
|
368
|
+
console.log(chalk.gray("Created .gitignore"));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
npmInstall() {
|
|
372
|
+
try {
|
|
373
|
+
execSync('npm install', { cwd: this.appDir });
|
|
374
|
+
console.log(chalk.gray("Installed dependencies"));
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error(chalk.red("Error installing dependencies:"), error.message);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
const scaffold = new ReactScaffold();
|
|
383
|
+
scaffold.install();
|