create-bluecopa-react-app 1.0.5 → 1.0.7

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 (117) hide show
  1. package/README.md +47 -10
  2. package/bin/create-bluecopa-react-app.js +257 -51
  3. package/package.json +6 -5
  4. package/templates/latest/Agent.md +254 -0
  5. package/templates/latest/Dockerfile +22 -0
  6. package/templates/latest/README.md +157 -221
  7. package/templates/latest/app/app.css +134 -0
  8. package/templates/latest/app/app.tsx +46 -0
  9. package/templates/latest/app/components/app-sidebar.tsx +174 -0
  10. package/templates/latest/app/components/chart-area-interactive.tsx +290 -0
  11. package/templates/latest/app/components/data-table.tsx +807 -0
  12. package/templates/latest/app/components/nav-documents.tsx +92 -0
  13. package/templates/latest/app/components/nav-main.tsx +56 -0
  14. package/templates/latest/app/components/nav-secondary.tsx +42 -0
  15. package/templates/latest/app/components/nav-user.tsx +112 -0
  16. package/templates/latest/app/components/section-cards.tsx +102 -0
  17. package/templates/latest/app/components/site-header.tsx +19 -0
  18. package/templates/latest/app/components/ui/avatar.tsx +53 -0
  19. package/templates/latest/app/components/ui/badge.tsx +46 -0
  20. package/templates/latest/app/components/ui/breadcrumb.tsx +109 -0
  21. package/templates/latest/app/components/ui/button.tsx +58 -0
  22. package/templates/latest/app/components/ui/card.tsx +92 -0
  23. package/templates/latest/app/components/ui/chart.tsx +352 -0
  24. package/templates/latest/app/components/ui/checkbox.tsx +30 -0
  25. package/templates/latest/app/components/ui/drawer.tsx +139 -0
  26. package/templates/latest/app/components/ui/dropdown-menu.tsx +258 -0
  27. package/templates/latest/app/components/ui/input.tsx +21 -0
  28. package/templates/latest/app/components/ui/label.tsx +24 -0
  29. package/templates/latest/app/components/ui/select.tsx +183 -0
  30. package/templates/latest/app/components/ui/separator.tsx +26 -0
  31. package/templates/latest/app/components/ui/sheet.tsx +139 -0
  32. package/templates/latest/app/components/ui/sidebar.tsx +731 -0
  33. package/templates/latest/app/components/ui/skeleton.tsx +13 -0
  34. package/templates/latest/app/components/ui/sonner.tsx +23 -0
  35. package/templates/latest/app/components/ui/table.tsx +117 -0
  36. package/templates/latest/app/components/ui/tabs.tsx +66 -0
  37. package/templates/latest/app/components/ui/toggle-group.tsx +73 -0
  38. package/templates/latest/app/components/ui/toggle.tsx +47 -0
  39. package/templates/latest/app/components/ui/tooltip.tsx +59 -0
  40. package/templates/latest/app/dashboard/data.json +614 -0
  41. package/templates/latest/app/hooks/use-bluecopa-user.ts +37 -0
  42. package/templates/latest/app/hooks/use-mobile.ts +19 -0
  43. package/templates/latest/{src → app}/lib/utils.ts +1 -1
  44. package/templates/latest/app/main.tsx +12 -0
  45. package/templates/latest/app/routes/home.tsx +40 -0
  46. package/templates/latest/app/routes.tsx +15 -0
  47. package/templates/latest/{src → app}/single-spa.tsx +5 -5
  48. package/templates/latest/components.json +22 -0
  49. package/templates/latest/dist/assets/__federation_expose_App-DsPovvoo.js +147 -0
  50. package/templates/latest/dist/assets/__federation_fn_import-CzfA7kmP.js +438 -0
  51. package/templates/latest/dist/assets/__federation_shared_react-Bp6HVBS4.js +16 -0
  52. package/templates/latest/dist/assets/__federation_shared_react-dom-BCcRGiYp.js +17 -0
  53. package/templates/latest/dist/assets/client-BZh_TW_6.js +12662 -0
  54. package/templates/latest/dist/assets/home-CAuoIW4B.js +54951 -0
  55. package/templates/latest/dist/assets/index-BzNimew1.js +69 -0
  56. package/templates/latest/dist/assets/index-Clg7n7gy.js +60 -0
  57. package/templates/latest/dist/assets/index-DMFtQdNS.js +412 -0
  58. package/templates/latest/dist/assets/remoteEntry.css +3688 -0
  59. package/templates/latest/dist/assets/remoteEntry.js +88 -0
  60. package/templates/latest/dist/avatars/shadcn.svg +6 -0
  61. package/templates/latest/dist/favicon.ico +0 -0
  62. package/templates/latest/dist/index.html +19 -0
  63. package/templates/latest/index.html +1 -1
  64. package/templates/latest/package-lock.json +1227 -3353
  65. package/templates/latest/package.json +47 -43
  66. package/templates/latest/pnpm-lock.yaml +4767 -0
  67. package/templates/latest/preview/index.html +32 -2
  68. package/templates/latest/public/avatars/shadcn.svg +6 -0
  69. package/templates/latest/public/favicon.ico +0 -0
  70. package/templates/latest/tsconfig.json +19 -12
  71. package/templates/latest/vite.config.ts +47 -40
  72. package/templates/latest/.env.example +0 -14
  73. package/templates/latest/.eslintrc.cjs +0 -42
  74. package/templates/latest/AGENT.md +0 -282
  75. package/templates/latest/clean.sh +0 -40
  76. package/templates/latest/postcss.config.cjs +0 -6
  77. package/templates/latest/public/bluecopa-logo.svg +0 -30
  78. package/templates/latest/public/favicon-32x32.png +0 -0
  79. package/templates/latest/public/favicon-96x96.png +0 -0
  80. package/templates/latest/setup.sh +0 -56
  81. package/templates/latest/src/App.tsx +0 -19
  82. package/templates/latest/src/components/charts/AreaChart.tsx +0 -80
  83. package/templates/latest/src/components/charts/DonutChart.tsx +0 -73
  84. package/templates/latest/src/components/charts/SparkAreaChart.tsx +0 -52
  85. package/templates/latest/src/components/layout/dashboard-header.tsx +0 -139
  86. package/templates/latest/src/components/layout/dashboard-layout.tsx +0 -37
  87. package/templates/latest/src/components/layout/navbar.tsx +0 -106
  88. package/templates/latest/src/components/layout/sidebar.tsx +0 -55
  89. package/templates/latest/src/components/page/dashboard/DashboardMetrics.tsx +0 -97
  90. package/templates/latest/src/components/page/dashboard/PaymentMethodsAnalysis.tsx +0 -182
  91. package/templates/latest/src/components/page/dashboard/RevenueAnalytics.tsx +0 -505
  92. package/templates/latest/src/components/page/dashboard/SalesAnalytics.tsx +0 -313
  93. package/templates/latest/src/components/page/dashboard/TransactionsTable.tsx +0 -256
  94. package/templates/latest/src/components/page/dashboard/dashboard-utils.ts +0 -147
  95. package/templates/latest/src/components/page/dashboard/dashboard.tsx +0 -185
  96. package/templates/latest/src/components/tables/data-grid.tsx +0 -439
  97. package/templates/latest/src/components/ui/alert.tsx +0 -59
  98. package/templates/latest/src/components/ui/avatar.tsx +0 -50
  99. package/templates/latest/src/components/ui/badge.tsx +0 -36
  100. package/templates/latest/src/components/ui/bluecopa-logo.tsx +0 -57
  101. package/templates/latest/src/components/ui/button.tsx +0 -58
  102. package/templates/latest/src/components/ui/card.tsx +0 -79
  103. package/templates/latest/src/components/ui/dropdown-menu.tsx +0 -200
  104. package/templates/latest/src/components/ui/input.tsx +0 -24
  105. package/templates/latest/src/components/ui/label.tsx +0 -21
  106. package/templates/latest/src/components/ui/select.tsx +0 -27
  107. package/templates/latest/src/hooks/use-api.ts +0 -55
  108. package/templates/latest/src/index.css +0 -59
  109. package/templates/latest/src/main.tsx +0 -13
  110. package/templates/latest/src/pages/Dashboard.tsx +0 -13
  111. package/templates/latest/src/pages/Home.tsx +0 -622
  112. package/templates/latest/src/providers/query-provider.tsx +0 -48
  113. package/templates/latest/src/types/api.ts +0 -78
  114. package/templates/latest/src/vite-env.d.ts +0 -11
  115. package/templates/latest/tailwind.config.js +0 -87
  116. package/templates/latest/tsconfig.app.json +0 -32
  117. package/templates/latest/tsconfig.node.json +0 -14
package/README.md CHANGED
@@ -20,7 +20,7 @@ A command-line interface for bootstrapping modern React applications with BlueCo
20
20
 
21
21
  ## Version
22
22
 
23
- Current version: 0.1.0
23
+ Current version: 1.0.5
24
24
 
25
25
  ## Installation
26
26
 
@@ -46,35 +46,47 @@ export BLUECOPA_BOILERPLATE_REGISTRY=https://registry.npmjs.org
46
46
 
47
47
  ## Features
48
48
 
49
- - 🚀 **Modern React Stack**: React 18, TypeScript, React Router v6, Vite 7
49
+ - 🚀 **Modern React Stack**: React 18, TypeScript, React Router v7, Vite 6
50
50
  - 🌐 **Microfrontend Support**: Single-spa compatible with module federation
51
51
  - 📊 **Data Visualization**: Recharts integration for charts and analytics
52
- - 🎨 **UI Components**: Radix UI primitives with custom styling
52
+ - 🎨 **UI Components**: shadcn/ui components built on Radix UI primitives
53
53
  - 📡 **BlueCopa React Components**: Pre-configured [`@bluecopa/react`](packages/react:1) package with hooks (includes TanStack Query integration)
54
54
  - 🎯 **Type Safety**: Full TypeScript support
55
- - 📱 **Responsive Design**: Tailwind CSS with mobile-first approach and BlueCopa design system
55
+ - 📱 **Responsive Design**: Tailwind CSS v4 with mobile-first approach and BlueCopa design system
56
56
  - 🛠️ **Development Tools**: ESLint, TypeScript checking, and Vite fast build system
57
57
  - ⚡ **Fast Development**: Hot module replacement with Vite
58
- - 🔄 **Client-side Routing**: React Router v6 for SPA navigation
58
+ - 🔄 **Server-side Rendering**: React Router v7 with SSR support
59
+ - 🌙 **Dark Mode**: Built-in theme switching with next-themes
60
+ - 🗂️ **Data Tables**: TanStack Table with sorting, filtering, and pagination
61
+ - 🎯 **Drag & Drop**: DND Kit integration for interactive interfaces
59
62
 
60
63
  ## Usage
61
64
 
62
65
  ### Creating a New Application
63
66
 
64
67
  ```bash
65
- # Create new app
68
+ # Create new app with default template
66
69
  create-bluecopa-react-app my-dashboard
67
70
 
71
+ # Create new app with shadcn/ui template
72
+ create-bluecopa-react-app my-dashboard --template shadcn
73
+
68
74
  # Or use npx
69
75
  npx create-bluecopa-react-app my-dashboard
76
+ npx create-bluecopa-react-app my-dashboard --template shadcn
70
77
  ```
71
78
 
79
+ ### Available Templates
80
+
81
+ - **Default Template**: Basic React Router setup with essential components
82
+ - **shadcn Template**: Full-featured template with shadcn/ui components, data tables, charts, and dark mode support
83
+
72
84
  ### CLI Options
73
85
 
74
86
  | Option | Description |
75
87
  |--------|-------------|
76
88
  | `--skip-install` | Skip dependency installation |
77
- | `--template` | Specify template version (default: latest) |
89
+ | `--template` | Specify template (default, shadcn) |
78
90
  | `--help` | Show help information |
79
91
 
80
92
  ## API Documentation
@@ -106,6 +118,12 @@ create-bluecopa-react-app my-dashboard
106
118
  create-bluecopa-react-app my-dashboard --skip-install
107
119
  ```
108
120
 
121
+ ### Using npx (Recommended)
122
+
123
+ ```bash
124
+ npx create-bluecopa-react-app my-dashboard
125
+ ```
126
+
109
127
  ## Development
110
128
 
111
129
  ### Available Scripts
@@ -122,11 +140,30 @@ create-bluecopa-react-app my-dashboard --skip-install
122
140
  ### Technologies Used
123
141
 
124
142
  - **React 18** - Modern React with concurrent features
125
- - **React Router v6** - Declarative routing for React SPAs
126
- - **Vite** - Fast build tool and development server
143
+ - **React Router v7** - Modern routing with SSR support
144
+ - **Vite 6** - Fast build tool and development server
127
145
  - **TypeScript** - Full type safety and developer experience
128
146
  - **[`@bluecopa/react`](packages/react:1)** - BlueCopa-specific React components and hooks
147
+ - **shadcn/ui** - Accessible component library built on Radix UI
129
148
  - **Radix UI** - Unstyled, accessible UI primitives
149
+ - **TanStack Table** - Headless table library for React
130
150
  - **Recharts** - Composable charting library for React
131
- - **Tailwind CSS** - Utility-first CSS framework with BlueCopa design system
151
+ - **DND Kit** - Drag and drop toolkit for React
152
+ - **Tailwind CSS v4** - Utility-first CSS framework with BlueCopa design system
153
+ - **next-themes** - Theme switching with dark mode support
132
154
  - **Lucide React** - Beautiful, customizable icons
155
+
156
+ ## Monorepo Integration
157
+
158
+ This CLI tool is part of the BlueCopa UI monorepo and integrates with the following packages:
159
+
160
+ - **[`@bluecopa/react`](packages/react:1)** - BlueCopa-specific React components and hooks
161
+
162
+ ### Standalone Development
163
+
164
+ The generated applications can also be developed independently:
165
+
166
+ 1. **Self-contained**: All dependencies are properly installed
167
+ 2. **Environment setup**: Includes proper environment variable configuration
168
+ 3. **Build optimization**: Uses Vite for fast development and production builds
169
+ 4. **Deployment ready**: Includes Docker configuration and deployment guides
@@ -1,24 +1,49 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { Command } = require('commander');
4
- const path = require('path');
5
- const fs = require('fs-extra');
6
- const chalk = require('chalk');
7
- const inquirer = require('inquirer');
8
- const ora = require('ora');
9
- const { execSync } = require('child_process');
10
- const validatePackageName = require('validate-npm-package-name');
3
+ import { Command } from 'commander';
4
+ import path from 'path';
5
+ import fs from 'fs-extra';
6
+ import chalk from 'chalk';
7
+ import inquirer from 'inquirer';
8
+ import ora from 'ora';
9
+ import { execSync } from 'child_process';
10
+ import validatePackageName from 'validate-npm-package-name';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ // ES module equivalent of __dirname
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
11
16
 
12
17
  const program = new Command();
13
18
 
14
19
  program
15
- .version('1.0.0')
20
+ .version('1.0.5')
16
21
  .name('create-bluecopa-react-app')
17
22
  .description('Create a new Bluecopa React application')
18
23
  .argument('[project-name]', 'Name of the project')
24
+ .option('-t, --template <template>', 'Template to use (latest)', 'latest')
19
25
  .option('--typescript', 'Use TypeScript template', true)
20
26
  .option('--no-typescript', 'Use JavaScript template')
21
27
  .option('--skip-install', 'Skip package installation')
28
+ .option('--package-manager <manager>', 'Package manager to use (npm, yarn, pnpm)', 'auto')
29
+ .option('--git', 'Initialize git repository', true)
30
+ .option('--no-git', 'Skip git initialization')
31
+ .option('--yes', 'Skip all prompts and use defaults')
32
+ .addHelpText('after', `
33
+ Examples:
34
+ $ create-bluecopa-react-app my-dashboard
35
+ $ create-bluecopa-react-app my-app --template latest
36
+ $ create-bluecopa-react-app my-app --package-manager pnpm
37
+ $ create-bluecopa-react-app my-app --skip-install
38
+ $ create-bluecopa-react-app my-app --no-git
39
+ $ create-bluecopa-react-app my-app --yes
40
+
41
+ Templates:
42
+ latest Basic React Router setup with essential components
43
+
44
+ For more information, visit:
45
+ https://github.com/bluecopa/blui/tree/main/packages/boilerplate/react
46
+ `)
22
47
  .action(async (projectName, options) => {
23
48
  try {
24
49
  await createApp(projectName, options);
@@ -30,14 +55,28 @@ program
30
55
 
31
56
  async function createApp(projectName, options) {
32
57
  let appName = projectName;
58
+ let selectedTemplate = options.template;
59
+ let initGit = options.git;
60
+ let packageManager = options.packageManager;
61
+
62
+ // If not using --yes flag, prompt for all options
63
+ if (!options.yes) {
64
+ const prompts = [];
33
65
 
34
- // If no project name provided, prompt for it
35
- if (!appName) {
36
- const answers = await inquirer.prompt([
37
- {
66
+ // 1. Project Name prompt
67
+ if (!appName) {
68
+ // Generate a random default project name
69
+ const adjectives = ['awesome', 'stellar', 'brilliant', 'dynamic', 'epic', 'fantastic', 'incredible', 'magnificent', 'outstanding', 'spectacular'];
70
+ const nouns = ['app', 'dashboard', 'project', 'platform', 'tool', 'system', 'solution', 'interface', 'portal', 'workspace'];
71
+ const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
72
+ const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
73
+ const defaultProjectName = `my-${randomAdjective}-${randomNoun}`;
74
+
75
+ prompts.push({
38
76
  type: 'input',
39
77
  name: 'projectName',
40
78
  message: 'What is your project name?',
79
+ default: defaultProjectName,
41
80
  validate: (input) => {
42
81
  if (!input) return 'Project name is required';
43
82
  const validation = validatePackageName(input);
@@ -46,15 +85,79 @@ async function createApp(projectName, options) {
46
85
  }
47
86
  return true;
48
87
  }
49
- }
50
- ]);
51
- appName = answers.projectName;
88
+ });
89
+ }
90
+
91
+ // 2. Template selection prompt
92
+ prompts.push({
93
+ type: 'list',
94
+ name: 'template',
95
+ message: 'Select a template:',
96
+ choices: [
97
+ { name: 'Latest - Basic React Router setup with essential components', value: 'latest' }
98
+ ],
99
+ default: selectedTemplate
100
+ });
101
+
102
+ // 3. Git initialization prompt
103
+ prompts.push({
104
+ type: 'confirm',
105
+ name: 'initGit',
106
+ message: 'Initialize git repository?',
107
+ default: initGit !== false
108
+ });
109
+
110
+ // 4. Package manager prompt
111
+ prompts.push({
112
+ type: 'list',
113
+ name: 'packageManager',
114
+ message: 'Select package manager:',
115
+ choices: [
116
+ { name: 'pnpm (recommended)', value: 'pnpm' },
117
+ { name: 'npm', value: 'npm' },
118
+ { name: 'Auto-detect', value: 'auto' }
119
+ ],
120
+ default: packageManager === 'auto' ? 'auto' : packageManager
121
+ });
122
+
123
+ // 5. Install dependencies prompt
124
+ prompts.push({
125
+ type: 'confirm',
126
+ name: 'runInstall',
127
+ message: 'Do you want to install dependencies now?',
128
+ default: !options.skipInstall
129
+ });
130
+
131
+ // Execute all prompts
132
+ const answers = await inquirer.prompt(prompts);
133
+
134
+ // Update values from prompts
135
+ if (answers.projectName) appName = answers.projectName;
136
+ selectedTemplate = answers.template;
137
+ initGit = answers.initGit;
138
+ packageManager = answers.packageManager;
139
+ options.skipInstall = !answers.runInstall;
140
+ } else {
141
+ // When using --yes flag, validate required options
142
+ if (!appName) {
143
+ console.error(chalk.red('Project name is required when using --yes flag'));
144
+ process.exit(1);
145
+ }
146
+ }
147
+
148
+ // Validate template
149
+ const validTemplates = ['latest'];
150
+ if (!validTemplates.includes(selectedTemplate)) {
151
+ console.error(chalk.red(`Invalid template: ${selectedTemplate}`));
152
+ console.error(chalk.yellow(`Available templates: ${validTemplates.join(', ')}`));
153
+ process.exit(1);
52
154
  }
53
155
 
54
156
  // Validate project name
55
157
  const validation = validatePackageName(appName);
56
158
  if (!validation.validForNewPackages) {
57
159
  console.error(chalk.red('Invalid project name:'), validation.errors?.[0] || validation.warnings?.[0]);
160
+ console.error(chalk.yellow('Project names must be lowercase, contain no spaces, and follow npm naming conventions.'));
58
161
  process.exit(1);
59
162
  }
60
163
 
@@ -62,37 +165,53 @@ async function createApp(projectName, options) {
62
165
 
63
166
  // Check if directory already exists
64
167
  if (fs.existsSync(targetDir)) {
65
- const answers = await inquirer.prompt([
66
- {
67
- type: 'confirm',
68
- name: 'overwrite',
69
- message: `Directory ${appName} already exists. Overwrite?`,
70
- default: false
168
+ if (options.yes) {
169
+ console.log(chalk.yellow(`Directory ${appName} already exists. Overwriting...`));
170
+ await fs.remove(targetDir);
171
+ } else {
172
+ const answers = await inquirer.prompt([
173
+ {
174
+ type: 'confirm',
175
+ name: 'overwrite',
176
+ message: `Directory ${appName} already exists. Overwrite?`,
177
+ default: false
178
+ }
179
+ ]);
180
+
181
+ if (!answers.overwrite) {
182
+ console.log(chalk.yellow('Operation cancelled.'));
183
+ return;
71
184
  }
72
- ]);
73
185
 
74
- if (!answers.overwrite) {
75
- console.log(chalk.yellow('Operation cancelled.'));
76
- return;
186
+ await fs.remove(targetDir);
77
187
  }
78
-
79
- await fs.remove(targetDir);
80
188
  }
81
189
 
82
190
  console.log(chalk.blue(`Creating a new Bluecopa React app in ${chalk.green(targetDir)}`));
191
+ console.log(chalk.gray(`Template: ${selectedTemplate}`));
83
192
  console.log();
84
193
 
85
194
  // Create app
86
195
  const spinner = ora('Creating project structure...').start();
87
196
 
88
197
  try {
89
- await createProjectStructure(targetDir, appName, options);
198
+ await createProjectStructure(targetDir, appName, { ...options, template: selectedTemplate });
90
199
  spinner.succeed('Project structure created');
91
200
 
92
201
  if (!options.skipInstall) {
93
- spinner.start('Installing dependencies...');
94
- await installDependencies(targetDir);
202
+ const detectedPackageManager = await detectPackageManager(packageManager);
203
+ spinner.start(`Installing dependencies with ${detectedPackageManager}...`);
204
+ await installDependencies(targetDir, detectedPackageManager);
95
205
  spinner.succeed('Dependencies installed');
206
+ } else {
207
+ console.log(chalk.yellow('Skipping dependency installation. You can run it manually later.'));
208
+ }
209
+
210
+ // Post-installation setup
211
+ if (initGit !== false) {
212
+ spinner.start('Initializing git repository...');
213
+ await initializeGit(targetDir, appName);
214
+ spinner.succeed('Git repository initialized');
96
215
  }
97
216
 
98
217
  spinner.succeed(chalk.green('Success! Created ' + appName + ' at ' + targetDir));
@@ -100,30 +219,69 @@ async function createApp(projectName, options) {
100
219
  console.log();
101
220
  console.log('Inside that directory, you can run several commands:');
102
221
  console.log();
103
- console.log(chalk.cyan(' npm run dev'));
222
+
223
+ // Show install command if dependencies weren't installed
224
+ if (options.skipInstall) {
225
+ const detectedPackageManager = await detectPackageManager(packageManager);
226
+ const installCommand = detectedPackageManager === 'yarn' ? 'yarn install' :
227
+ detectedPackageManager === 'pnpm' ? 'pnpm install' :
228
+ 'npm install';
229
+ console.log(chalk.cyan(` ${installCommand}`));
230
+ console.log(' Install dependencies first.');
231
+ console.log();
232
+ }
233
+
234
+ const runCommand = packageManager === 'pnpm' ? 'pnpm run' :
235
+ packageManager === 'yarn' ? 'yarn' :
236
+ 'npm run';
237
+
238
+ console.log(chalk.cyan(` ${runCommand} dev`));
104
239
  console.log(' Starts the development server.');
105
240
  console.log();
106
- console.log(chalk.cyan(' npm run build'));
241
+ console.log(chalk.cyan(` ${runCommand} build`));
107
242
  console.log(' Bundles the app into static files for production.');
108
243
  console.log();
109
- console.log(chalk.cyan(' npm run preview'));
244
+ console.log(chalk.cyan(` ${runCommand} start`));
245
+ console.log(' Start the production build locally.');
246
+ console.log();
247
+ console.log(chalk.cyan(` ${runCommand} preview`));
110
248
  console.log(' Preview the production build locally.');
111
249
  console.log();
112
250
  console.log('We suggest that you begin by typing:');
113
251
  console.log();
114
252
  console.log(chalk.cyan(' cd'), appName);
115
- console.log(chalk.cyan(' npm run dev'));
253
+ if (options.skipInstall) {
254
+ const detectedPackageManager = await detectPackageManager(packageManager);
255
+ const installCommand = detectedPackageManager === 'yarn' ? 'yarn install' :
256
+ detectedPackageManager === 'pnpm' ? 'pnpm install' :
257
+ 'npm install';
258
+ console.log(chalk.cyan(` ${installCommand}`));
259
+ }
260
+ console.log(chalk.cyan(` ${runCommand} dev`));
261
+ console.log();
262
+ console.log('Happy coding! 🚀');
116
263
  console.log();
117
- console.log('Happy coding with Bluecopa! 🚀');
264
+ console.log(chalk.gray('Need help? Check out the documentation:'));
265
+ console.log(chalk.gray(' https://github.com/bluecopa/blui/tree/main/packages/boilerplate/react'));
118
266
 
119
267
  } catch (error) {
120
268
  spinner.fail('Failed to create project');
269
+ // Cleanup on failure
270
+ if (fs.existsSync(targetDir)) {
271
+ console.log(chalk.yellow('Cleaning up...'));
272
+ await fs.remove(targetDir);
273
+ }
121
274
  throw error;
122
275
  }
123
276
  }
124
277
 
125
278
  async function createProjectStructure(targetDir, appName, options) {
126
- const templateDir = path.join(__dirname, '../templates/latest');
279
+ const templateDir = path.join(__dirname, '../templates', options.template);
280
+
281
+ // Validate template directory exists
282
+ if (!await fs.pathExists(templateDir)) {
283
+ throw new Error(`Template '${options.template}' not found at ${templateDir}`);
284
+ }
127
285
 
128
286
  // Create base directory
129
287
  await fs.ensureDir(targetDir);
@@ -133,9 +291,11 @@ async function createProjectStructure(targetDir, appName, options) {
133
291
 
134
292
  // Update package.json with project name
135
293
  const packageJsonPath = path.join(targetDir, 'package.json');
136
- const packageJson = await fs.readJson(packageJsonPath);
137
- packageJson.name = appName;
138
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
294
+ if (await fs.pathExists(packageJsonPath)) {
295
+ const packageJson = await fs.readJson(packageJsonPath);
296
+ packageJson.name = appName;
297
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
298
+ }
139
299
 
140
300
  // Update index.html title if it exists
141
301
  const indexHtmlPath = path.join(targetDir, 'public/index.html');
@@ -144,27 +304,73 @@ async function createProjectStructure(targetDir, appName, options) {
144
304
  indexHtml = indexHtml.replace(/{{APP_NAME}}/g, appName);
145
305
  await fs.writeFile(indexHtmlPath, indexHtml);
146
306
  }
307
+
308
+ // Update root index.html if it exists
309
+ const rootIndexHtmlPath = path.join(targetDir, 'index.html');
310
+ if (await fs.pathExists(rootIndexHtmlPath)) {
311
+ let indexHtml = await fs.readFile(rootIndexHtmlPath, 'utf8');
312
+ indexHtml = indexHtml.replace(/{{APP_NAME}}/g, appName);
313
+ await fs.writeFile(rootIndexHtmlPath, indexHtml);
314
+ }
147
315
  }
148
316
 
149
- async function installDependencies(targetDir) {
317
+ async function detectPackageManager(preferredManager) {
318
+ if (preferredManager !== 'auto') {
319
+ // Validate the preferred manager is available
320
+ try {
321
+ execSync(`${preferredManager} --version`, { stdio: 'ignore' });
322
+ return preferredManager;
323
+ } catch {
324
+ console.log(chalk.yellow(`Warning: ${preferredManager} not found, falling back to auto-detection`));
325
+ }
326
+ }
327
+
328
+ // Auto-detect with preference order: pnpm > yarn > npm
329
+ const managers = ['pnpm', 'yarn', 'npm'];
330
+
331
+ for (const manager of managers) {
332
+ try {
333
+ execSync(`${manager} --version`, { stdio: 'ignore' });
334
+ return manager;
335
+ } catch {
336
+ // Manager not available, try next
337
+ }
338
+ }
339
+
340
+ // Fallback to npm (should always be available)
341
+ return 'npm';
342
+ }
343
+
344
+ async function installDependencies(targetDir, packageManager) {
150
345
  try {
151
346
  // Change to target directory and install
152
347
  process.chdir(targetDir);
153
348
 
154
- // Check if yarn is available, otherwise use npm
155
- let packageManager = 'npm';
156
- try {
157
- execSync('yarn --version', { stdio: 'ignore' });
158
- packageManager = 'yarn';
159
- } catch {
160
- // yarn not available, use npm
161
- }
349
+ const installCommand = packageManager === 'yarn' ? 'yarn install' :
350
+ packageManager === 'pnpm' ? 'pnpm install' :
351
+ 'npm install';
162
352
 
163
- const installCommand = packageManager === 'yarn' ? 'yarn install' : 'npm install';
164
353
  execSync(installCommand, { stdio: 'inherit' });
165
354
 
166
355
  } catch (error) {
167
- throw new Error('Failed to install dependencies: ' + error.message);
356
+ throw new Error(`Failed to install dependencies with ${packageManager}: ${error.message}`);
357
+ }
358
+ }
359
+
360
+ async function initializeGit(targetDir, appName) {
361
+ try {
362
+ process.chdir(targetDir);
363
+
364
+ // Initialize git repository
365
+ execSync('git init', { stdio: 'ignore' });
366
+
367
+ // Create initial commit
368
+ execSync('git add .', { stdio: 'ignore' });
369
+ execSync(`git commit -m "Initial commit: ${appName}"`, { stdio: 'ignore' });
370
+
371
+ } catch (error) {
372
+ // Git initialization is optional, don't fail the whole process
373
+ console.log(chalk.yellow('Warning: Failed to initialize git repository'));
168
374
  }
169
375
  }
170
376
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "create-bluecopa-react-app",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "CLI tool to create bluecopa React applications",
5
+ "type": "module",
5
6
  "main": "./bin/create-bluecopa-react-app.js",
6
7
  "bin": {
7
8
  "create-bluecopa-react-app": "./bin/create-bluecopa-react-app.js"
@@ -19,11 +20,11 @@
19
20
  "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
20
21
  },
21
22
  "dependencies": {
22
- "commander": "^11.1.0",
23
+ "commander": "^12.0.0",
23
24
  "fs-extra": "^11.2.0",
24
- "chalk": "^4.1.2",
25
- "inquirer": "^8.2.6",
26
- "ora": "^5.4.1",
25
+ "chalk": "^5.3.0",
26
+ "inquirer": "^9.2.12",
27
+ "ora": "^8.0.1",
27
28
  "validate-npm-package-name": "^5.0.0"
28
29
  },
29
30
  "devDependencies": {},