@iselect/select 1.0.1 → 1.0.2
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/lib/commands/build.js +129 -49
- package/lib/commands/init.js +219 -149
- package/package.json +1 -1
package/lib/commands/build.js
CHANGED
|
@@ -55,47 +55,112 @@ async function build(target, options) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// ====================
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
// ==================== FRAMEWORK SIGNATURES (Vercel-style) ====================
|
|
59
|
+
const FRAMEWORK_SIGNATURES = {
|
|
60
|
+
// Next.js
|
|
61
|
+
'next.config.js': { name: 'Next.js', build: 'npm run build', output: '.next', icon: '▲' },
|
|
62
|
+
'next.config.mjs': { name: 'Next.js', build: 'npm run build', output: '.next', icon: '▲' },
|
|
63
|
+
'next.config.ts': { name: 'Next.js', build: 'npm run build', output: '.next', icon: '▲' },
|
|
64
|
+
|
|
65
|
+
// Astro
|
|
66
|
+
'astro.config.mjs': { name: 'Astro', build: 'npm run build', output: 'dist', icon: '🚀' },
|
|
67
|
+
'astro.config.js': { name: 'Astro', build: 'npm run build', output: 'dist', icon: '🚀' },
|
|
68
|
+
'astro.config.ts': { name: 'Astro', build: 'npm run build', output: 'dist', icon: '🚀' },
|
|
69
|
+
|
|
70
|
+
// SvelteKit
|
|
71
|
+
'svelte.config.js': { name: 'SvelteKit', build: 'npm run build', output: 'build', icon: '🔶' },
|
|
72
|
+
'svelte.config.ts': { name: 'SvelteKit', build: 'npm run build', output: 'build', icon: '🔶' },
|
|
73
|
+
|
|
74
|
+
// Nuxt
|
|
75
|
+
'nuxt.config.js': { name: 'Nuxt', build: 'npm run build', output: '.nuxt', icon: '💚' },
|
|
76
|
+
'nuxt.config.ts': { name: 'Nuxt', build: 'npm run build', output: '.nuxt', icon: '💚' },
|
|
77
|
+
|
|
78
|
+
// Remix
|
|
79
|
+
'remix.config.js': { name: 'Remix', build: 'npm run build', output: 'build', icon: '💿' },
|
|
80
|
+
|
|
81
|
+
// Gatsby
|
|
82
|
+
'gatsby-config.js': { name: 'Gatsby', build: 'npm run build', output: 'public', icon: '💜' },
|
|
83
|
+
'gatsby-config.ts': { name: 'Gatsby', build: 'npm run build', output: 'public', icon: '💜' },
|
|
84
|
+
|
|
85
|
+
// Vite (generic)
|
|
86
|
+
'vite.config.js': { name: 'Vite', build: 'npm run build', output: 'dist', icon: '⚡' },
|
|
87
|
+
'vite.config.ts': { name: 'Vite', build: 'npm run build', output: 'dist', icon: '⚡' },
|
|
88
|
+
'vite.config.mjs': { name: 'Vite', build: 'npm run build', output: 'dist', icon: '⚡' },
|
|
89
|
+
|
|
90
|
+
// Angular
|
|
91
|
+
'angular.json': { name: 'Angular', build: 'npm run build', output: 'dist', icon: '🅰️' },
|
|
92
|
+
|
|
93
|
+
// Vue CLI
|
|
94
|
+
'vue.config.js': { name: 'Vue CLI', build: 'npm run build', output: 'dist', icon: '💚' },
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Package.json dependency-based detection
|
|
98
|
+
const DEPENDENCY_SIGNATURES = {
|
|
99
|
+
'next': { name: 'Next.js', build: 'npm run build', output: '.next', icon: '▲' },
|
|
100
|
+
'@remix-run/react': { name: 'Remix', build: 'npm run build', output: 'build', icon: '💿' },
|
|
101
|
+
'gatsby': { name: 'Gatsby', build: 'npm run build', output: 'public', icon: '💜' },
|
|
102
|
+
'@angular/core': { name: 'Angular', build: 'npm run build', output: 'dist', icon: '🅰️' },
|
|
103
|
+
'react-scripts': { name: 'Create React App', build: 'npm run build', output: 'build', icon: '⚛️' },
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// ==================== FRAMEWORK DETECTION ====================
|
|
107
|
+
async function detectFramework(projectPath) {
|
|
108
|
+
// 1. Check for framework config files
|
|
109
|
+
for (const [configFile, framework] of Object.entries(FRAMEWORK_SIGNATURES)) {
|
|
110
|
+
if (await fs.pathExists(path.join(projectPath, configFile))) {
|
|
111
|
+
return { ...framework, detected: 'config', configFile };
|
|
112
|
+
}
|
|
76
113
|
}
|
|
77
114
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
115
|
+
// 2. Check package.json dependencies
|
|
116
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
117
|
+
if (await fs.pathExists(pkgPath)) {
|
|
118
|
+
try {
|
|
119
|
+
const pkg = await fs.readJson(pkgPath);
|
|
120
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
82
121
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
122
|
+
for (const [dep, framework] of Object.entries(DEPENDENCY_SIGNATURES)) {
|
|
123
|
+
if (allDeps[dep]) {
|
|
124
|
+
return { ...framework, detected: 'dependency', dependency: dep };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
87
127
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
128
|
+
// Check for generic build script
|
|
129
|
+
if (pkg.scripts?.build) {
|
|
130
|
+
return {
|
|
131
|
+
name: 'Custom',
|
|
132
|
+
build: 'npm run build',
|
|
133
|
+
output: 'dist',
|
|
134
|
+
icon: '📦',
|
|
135
|
+
detected: 'build-script'
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
} catch { }
|
|
91
139
|
}
|
|
92
140
|
|
|
93
|
-
//
|
|
141
|
+
// 3. Static site detection
|
|
142
|
+
const hasIndexHtml = await fs.pathExists(path.join(projectPath, 'index.html'));
|
|
94
143
|
if (hasIndexHtml) {
|
|
95
|
-
return
|
|
144
|
+
return {
|
|
145
|
+
name: 'Static',
|
|
146
|
+
build: null, // No build needed
|
|
147
|
+
output: '.',
|
|
148
|
+
icon: '📄',
|
|
149
|
+
detected: 'static'
|
|
150
|
+
};
|
|
96
151
|
}
|
|
97
152
|
|
|
98
|
-
return
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ==================== PROJECT TYPE DETECTION (legacy wrapper) ====================
|
|
157
|
+
async function detectProjectType(projectPath) {
|
|
158
|
+
const framework = await detectFramework(projectPath);
|
|
159
|
+
|
|
160
|
+
if (!framework) return 'unknown';
|
|
161
|
+
if (framework.detected === 'static') return 'static';
|
|
162
|
+
if (framework.name === 'Vite') return 'vite';
|
|
163
|
+
return 'bundled';
|
|
99
164
|
}
|
|
100
165
|
|
|
101
166
|
// ==================== INLINE BUILD ====================
|
|
@@ -242,40 +307,55 @@ async function buildWeb(config, options) {
|
|
|
242
307
|
return;
|
|
243
308
|
}
|
|
244
309
|
|
|
245
|
-
// Auto-detect
|
|
246
|
-
const
|
|
247
|
-
console.log(chalk.gray(` Detected: ${projectType} project`));
|
|
310
|
+
// Auto-detect framework (Vercel-style)
|
|
311
|
+
const framework = await detectFramework(projectPath);
|
|
248
312
|
|
|
249
|
-
if (
|
|
250
|
-
console.log(chalk.gray(' Mode: Static site (copying files directly)\n'));
|
|
251
|
-
await copyStaticFiles(projectPath, outputDir);
|
|
252
|
-
console.log(chalk.green('\n✅ Static web build complete!'));
|
|
253
|
-
console.log(chalk.gray(` Output: ${outputDir}/\n`));
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (projectType === 'unknown') {
|
|
313
|
+
if (!framework) {
|
|
258
314
|
console.log(chalk.yellow('\n⚠️ Could not detect project type'));
|
|
259
315
|
console.log(chalk.gray(' No index.html or package.json found'));
|
|
260
316
|
console.log(chalk.gray(' Try: slct build web --static\n'));
|
|
261
317
|
process.exit(1);
|
|
262
318
|
}
|
|
263
319
|
|
|
320
|
+
// Display detected framework
|
|
321
|
+
console.log(chalk.cyan(` ${framework.icon} Detected: ${chalk.bold(framework.name)}`));
|
|
322
|
+
if (framework.detected === 'config') {
|
|
323
|
+
console.log(chalk.gray(` via ${framework.configFile}`));
|
|
324
|
+
} else if (framework.detected === 'dependency') {
|
|
325
|
+
console.log(chalk.gray(` via ${framework.dependency} dependency`));
|
|
326
|
+
} else if (framework.detected === 'static') {
|
|
327
|
+
console.log(chalk.gray(' (static HTML/CSS/JS site)'));
|
|
328
|
+
}
|
|
329
|
+
console.log('');
|
|
330
|
+
|
|
331
|
+
// Handle static sites
|
|
332
|
+
if (framework.detected === 'static') {
|
|
333
|
+
await copyStaticFiles(projectPath, outputDir);
|
|
334
|
+
console.log(chalk.green('\n✅ Static web build complete!'));
|
|
335
|
+
console.log(chalk.gray(` Output: ${outputDir}/\n`));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
264
339
|
// Run build command for bundled projects
|
|
265
|
-
|
|
340
|
+
// Priority: select.json config > detected framework > default
|
|
341
|
+
const buildCommand = config.build?.command || framework.build || 'npm run build';
|
|
342
|
+
const finalOutputDir = config.build?.outDir
|
|
343
|
+
? path.resolve(projectPath, config.build.outDir)
|
|
344
|
+
: path.resolve(projectPath, framework.output || 'dist');
|
|
345
|
+
|
|
346
|
+
const spinner = ora(`Running: ${chalk.cyan(buildCommand)}`).start();
|
|
266
347
|
|
|
267
348
|
try {
|
|
268
|
-
const buildCommand = config.build?.command || 'npm run build';
|
|
269
349
|
execSync(buildCommand, {
|
|
270
350
|
stdio: 'inherit',
|
|
271
351
|
cwd: projectPath
|
|
272
352
|
});
|
|
273
|
-
spinner.succeed(
|
|
353
|
+
spinner.succeed(`${framework.icon} ${framework.name} build complete!`);
|
|
274
354
|
|
|
275
355
|
// Validate output
|
|
276
|
-
await validateBuildOutput(
|
|
356
|
+
await validateBuildOutput(finalOutputDir);
|
|
277
357
|
|
|
278
|
-
console.log(chalk.gray(` Output: ${
|
|
358
|
+
console.log(chalk.gray(` Output: ${finalOutputDir}/\n`));
|
|
279
359
|
} catch (error) {
|
|
280
360
|
spinner.fail('Web build failed');
|
|
281
361
|
throw error;
|
package/lib/commands/init.js
CHANGED
|
@@ -5,125 +5,125 @@ const inquirer = require('inquirer');
|
|
|
5
5
|
const ora = require('ora');
|
|
6
6
|
|
|
7
7
|
async function init(name, options) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// If no name provided, ask for it
|
|
11
|
-
if (!name) {
|
|
12
|
-
const answers = await inquirer.prompt([
|
|
13
|
-
{
|
|
14
|
-
type: 'input',
|
|
15
|
-
name: 'name',
|
|
16
|
-
message: 'Project name:',
|
|
17
|
-
default: 'my-select-app',
|
|
18
|
-
validate: (input) => {
|
|
19
|
-
if (/^[a-z0-9-]+$/.test(input)) return true;
|
|
20
|
-
return 'Project name must be lowercase with hyphens only';
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
]);
|
|
24
|
-
name = answers.name;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const projectDir = path.resolve(process.cwd(), name);
|
|
8
|
+
console.log(chalk.bold('\n📦 Initialize Select Project\n'));
|
|
28
9
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
console.log(chalk.red(`\n❌ Directory "${name}" already exists.\n`));
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Ask for project details
|
|
10
|
+
// If no name provided, ask for it
|
|
11
|
+
if (!name) {
|
|
36
12
|
const answers = await inquirer.prompt([
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
],
|
|
46
|
-
default: options.template
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
type: 'checkbox',
|
|
50
|
-
name: 'platforms',
|
|
51
|
-
message: 'Target platforms:',
|
|
52
|
-
choices: [
|
|
53
|
-
{ name: 'Web', value: 'web', checked: true },
|
|
54
|
-
{ name: 'Windows', value: 'windows' },
|
|
55
|
-
{ name: 'macOS', value: 'macos' },
|
|
56
|
-
{ name: 'Linux', value: 'linux' }
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
type: 'list',
|
|
61
|
-
name: 'desktopFramework',
|
|
62
|
-
message: 'Desktop framework:',
|
|
63
|
-
choices: [
|
|
64
|
-
{ name: 'Tauri (Recommended - smaller, faster)', value: 'tauri' },
|
|
65
|
-
{ name: 'Electron (Larger, more compatible)', value: 'electron' }
|
|
66
|
-
],
|
|
67
|
-
when: (ans) => ans.platforms.some(p => ['windows', 'macos', 'linux'].includes(p))
|
|
13
|
+
{
|
|
14
|
+
type: 'input',
|
|
15
|
+
name: 'name',
|
|
16
|
+
message: 'Project name:',
|
|
17
|
+
default: 'my-select-app',
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (/^[a-z0-9-]+$/.test(input)) return true;
|
|
20
|
+
return 'Project name must be lowercase with hyphens only';
|
|
68
21
|
}
|
|
22
|
+
}
|
|
69
23
|
]);
|
|
24
|
+
name = answers.name;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const projectDir = path.resolve(process.cwd(), name);
|
|
28
|
+
|
|
29
|
+
// Check if directory exists
|
|
30
|
+
if (await fs.pathExists(projectDir)) {
|
|
31
|
+
console.log(chalk.red(`\n❌ Directory "${name}" already exists.\n`));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Ask for project details
|
|
36
|
+
const answers = await inquirer.prompt([
|
|
37
|
+
{
|
|
38
|
+
type: 'list',
|
|
39
|
+
name: 'template',
|
|
40
|
+
message: 'Select a template:',
|
|
41
|
+
choices: [
|
|
42
|
+
{ name: 'React + Vite', value: 'react' },
|
|
43
|
+
{ name: 'Vue + Vite', value: 'vue' },
|
|
44
|
+
{ name: 'Vanilla JavaScript', value: 'vanilla' }
|
|
45
|
+
],
|
|
46
|
+
default: options.template
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'checkbox',
|
|
50
|
+
name: 'platforms',
|
|
51
|
+
message: 'Target platforms:',
|
|
52
|
+
choices: [
|
|
53
|
+
{ name: 'Web', value: 'web', checked: true },
|
|
54
|
+
{ name: 'Windows', value: 'windows' },
|
|
55
|
+
{ name: 'macOS', value: 'macos' },
|
|
56
|
+
{ name: 'Linux', value: 'linux' }
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'list',
|
|
61
|
+
name: 'desktopFramework',
|
|
62
|
+
message: 'Desktop framework:',
|
|
63
|
+
choices: [
|
|
64
|
+
{ name: 'Tauri (Recommended - smaller, faster)', value: 'tauri' },
|
|
65
|
+
{ name: 'Electron (Larger, more compatible)', value: 'electron' }
|
|
66
|
+
],
|
|
67
|
+
when: (ans) => ans.platforms.some(p => ['windows', 'macos', 'linux'].includes(p))
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
const spinner = ora('Creating project...').start();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Create project directory
|
|
75
|
+
await fs.ensureDir(projectDir);
|
|
76
|
+
|
|
77
|
+
// Create select.json config
|
|
78
|
+
const selectConfig = {
|
|
79
|
+
name: name,
|
|
80
|
+
version: '1.0.0',
|
|
81
|
+
description: 'A Select app',
|
|
82
|
+
platforms: answers.platforms,
|
|
83
|
+
desktop: {
|
|
84
|
+
framework: answers.desktopFramework || 'tauri'
|
|
85
|
+
},
|
|
86
|
+
build: {
|
|
87
|
+
command: 'npm run build',
|
|
88
|
+
devCommand: 'npm run dev',
|
|
89
|
+
outDir: 'dist'
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
await fs.writeJson(path.join(projectDir, 'select.json'), selectConfig, { spaces: 2 });
|
|
94
|
+
|
|
95
|
+
// Create basic package.json
|
|
96
|
+
const packageJson = {
|
|
97
|
+
name: name,
|
|
98
|
+
version: '1.0.0',
|
|
99
|
+
private: true,
|
|
100
|
+
scripts: {
|
|
101
|
+
dev: 'vite',
|
|
102
|
+
build: 'vite build',
|
|
103
|
+
preview: 'vite preview',
|
|
104
|
+
'slct:build': 'slct build all',
|
|
105
|
+
'slct:deploy': 'slct deploy'
|
|
106
|
+
},
|
|
107
|
+
dependencies: {},
|
|
108
|
+
devDependencies: {
|
|
109
|
+
'vite': '^5.0.0'
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Add template-specific dependencies
|
|
114
|
+
if (answers.template === 'react') {
|
|
115
|
+
packageJson.dependencies['react'] = '^18.2.0';
|
|
116
|
+
packageJson.dependencies['react-dom'] = '^18.2.0';
|
|
117
|
+
packageJson.devDependencies['@vitejs/plugin-react'] = '^4.2.0';
|
|
118
|
+
} else if (answers.template === 'vue') {
|
|
119
|
+
packageJson.dependencies['vue'] = '^3.4.0';
|
|
120
|
+
packageJson.devDependencies['@vitejs/plugin-vue'] = '^4.5.0';
|
|
121
|
+
}
|
|
70
122
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
// Create project directory
|
|
75
|
-
await fs.ensureDir(projectDir);
|
|
76
|
-
|
|
77
|
-
// Create select.json config
|
|
78
|
-
const selectConfig = {
|
|
79
|
-
name: name,
|
|
80
|
-
version: '1.0.0',
|
|
81
|
-
description: 'A Select app',
|
|
82
|
-
platforms: answers.platforms,
|
|
83
|
-
desktop: {
|
|
84
|
-
framework: answers.desktopFramework || 'tauri'
|
|
85
|
-
},
|
|
86
|
-
build: {
|
|
87
|
-
command: 'npm run build',
|
|
88
|
-
devCommand: 'npm run dev',
|
|
89
|
-
outDir: 'dist'
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
await fs.writeJson(path.join(projectDir, 'select.json'), selectConfig, { spaces: 2 });
|
|
94
|
-
|
|
95
|
-
// Create basic package.json
|
|
96
|
-
const packageJson = {
|
|
97
|
-
name: name,
|
|
98
|
-
version: '1.0.0',
|
|
99
|
-
private: true,
|
|
100
|
-
scripts: {
|
|
101
|
-
dev: 'vite',
|
|
102
|
-
build: 'vite build',
|
|
103
|
-
preview: 'vite preview',
|
|
104
|
-
'slct:build': 'slct build all',
|
|
105
|
-
'slct:deploy': 'slct deploy'
|
|
106
|
-
},
|
|
107
|
-
dependencies: {},
|
|
108
|
-
devDependencies: {
|
|
109
|
-
'vite': '^5.0.0'
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// Add template-specific dependencies
|
|
114
|
-
if (answers.template === 'react') {
|
|
115
|
-
packageJson.dependencies['react'] = '^18.2.0';
|
|
116
|
-
packageJson.dependencies['react-dom'] = '^18.2.0';
|
|
117
|
-
packageJson.devDependencies['@vitejs/plugin-react'] = '^4.2.0';
|
|
118
|
-
} else if (answers.template === 'vue') {
|
|
119
|
-
packageJson.dependencies['vue'] = '^3.4.0';
|
|
120
|
-
packageJson.devDependencies['@vitejs/plugin-vue'] = '^4.5.0';
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await fs.writeJson(path.join(projectDir, 'package.json'), packageJson, { spaces: 2 });
|
|
123
|
+
await fs.writeJson(path.join(projectDir, 'package.json'), packageJson, { spaces: 2 });
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
// Create basic index.html
|
|
126
|
+
const indexHtml = `<!DOCTYPE html>
|
|
127
127
|
<html lang="en">
|
|
128
128
|
<head>
|
|
129
129
|
<meta charset="UTF-8">
|
|
@@ -136,21 +136,22 @@ async function init(name, options) {
|
|
|
136
136
|
</body>
|
|
137
137
|
</html>`;
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
await fs.writeFile(path.join(projectDir, 'index.html'), indexHtml);
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
// Create src directory with basic file
|
|
142
|
+
await fs.ensureDir(path.join(projectDir, 'src'));
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
// Create GitHub Actions workflow
|
|
145
|
+
await createGithubWorkflow(projectDir, answers.desktopFramework || 'tauri', name);
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
if (answers.template === 'react') {
|
|
148
|
+
await fs.writeFile(path.join(projectDir, 'src', 'main.jsx'), `import React from 'react'
|
|
149
149
|
import ReactDOM from 'react-dom/client'
|
|
150
|
+
import './style.css'
|
|
150
151
|
|
|
151
152
|
function App() {
|
|
152
153
|
return (
|
|
153
|
-
<div
|
|
154
|
+
<div className="app">
|
|
154
155
|
<h1>Welcome to ${name}</h1>
|
|
155
156
|
<p>Built with Select CLI</p>
|
|
156
157
|
</div>
|
|
@@ -159,19 +160,88 @@ function App() {
|
|
|
159
160
|
|
|
160
161
|
ReactDOM.createRoot(document.getElementById('app')).render(<App />)
|
|
161
162
|
`);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
// Create React style.css
|
|
164
|
+
await fs.writeFile(path.join(projectDir, 'src', 'style.css'), `* {
|
|
165
|
+
margin: 0;
|
|
166
|
+
padding: 0;
|
|
167
|
+
box-sizing: border-box;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
body {
|
|
171
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
172
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
173
|
+
min-height: 100vh;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: center;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.app {
|
|
180
|
+
background: white;
|
|
181
|
+
padding: 3rem 4rem;
|
|
182
|
+
border-radius: 1rem;
|
|
183
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
184
|
+
text-align: center;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
h1 {
|
|
188
|
+
color: #1a202c;
|
|
189
|
+
margin-bottom: 0.5rem;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
p {
|
|
193
|
+
color: #718096;
|
|
194
|
+
}
|
|
195
|
+
`);
|
|
196
|
+
} else {
|
|
197
|
+
// Vanilla JS template
|
|
198
|
+
await fs.writeFile(path.join(projectDir, 'src', 'main.js'), `import './style.css'
|
|
199
|
+
|
|
200
|
+
document.getElementById('app').innerHTML = \`
|
|
201
|
+
<div class="app">
|
|
165
202
|
<h1>Welcome to ${name}</h1>
|
|
166
203
|
<p>Built with Select CLI</p>
|
|
167
204
|
</div>
|
|
168
205
|
\`
|
|
169
206
|
`);
|
|
170
|
-
|
|
207
|
+
// Create style.css for vanilla
|
|
208
|
+
await fs.writeFile(path.join(projectDir, 'src', 'style.css'), `* {
|
|
209
|
+
margin: 0;
|
|
210
|
+
padding: 0;
|
|
211
|
+
box-sizing: border-box;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
body {
|
|
215
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
216
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
217
|
+
min-height: 100vh;
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
justify-content: center;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.app {
|
|
224
|
+
background: white;
|
|
225
|
+
padding: 3rem 4rem;
|
|
226
|
+
border-radius: 1rem;
|
|
227
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
228
|
+
text-align: center;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
h1 {
|
|
232
|
+
color: #1a202c;
|
|
233
|
+
margin-bottom: 0.5rem;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
p {
|
|
237
|
+
color: #718096;
|
|
238
|
+
}
|
|
239
|
+
`);
|
|
240
|
+
}
|
|
171
241
|
|
|
172
|
-
|
|
242
|
+
spinner.succeed('Project created successfully!');
|
|
173
243
|
|
|
174
|
-
|
|
244
|
+
console.log(chalk.green(`
|
|
175
245
|
✅ Project "${name}" created!
|
|
176
246
|
|
|
177
247
|
Next steps:
|
|
@@ -181,33 +251,33 @@ Next steps:
|
|
|
181
251
|
|
|
182
252
|
`));
|
|
183
253
|
|
|
184
|
-
|
|
185
|
-
|
|
254
|
+
// Check for required dependencies
|
|
255
|
+
await checkDependencies(answers);
|
|
186
256
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
257
|
+
} catch (error) {
|
|
258
|
+
spinner.fail('Failed to create project');
|
|
259
|
+
console.error(chalk.red(error.message));
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
192
262
|
}
|
|
193
263
|
|
|
194
264
|
async function checkDependencies(answers) {
|
|
195
|
-
|
|
265
|
+
const hasDesktop = answers.platforms?.some(p => ['windows', 'macos', 'linux'].includes(p));
|
|
196
266
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
267
|
+
if (hasDesktop && answers.desktopFramework === 'tauri') {
|
|
268
|
+
console.log(chalk.yellow('\n⚠️ Tauri Requirements:'));
|
|
269
|
+
console.log(chalk.gray(' Run "slct build desktop" for detailed setup instructions.\n'));
|
|
270
|
+
}
|
|
201
271
|
}
|
|
202
272
|
|
|
203
273
|
async function createGithubWorkflow(projectDir, framework, name) {
|
|
204
|
-
|
|
205
|
-
|
|
274
|
+
const workflowDir = path.join(projectDir, '.github', 'workflows');
|
|
275
|
+
await fs.ensureDir(workflowDir);
|
|
206
276
|
|
|
207
|
-
|
|
277
|
+
let workflowContent = '';
|
|
208
278
|
|
|
209
|
-
|
|
210
|
-
|
|
279
|
+
if (framework === 'tauri') {
|
|
280
|
+
workflowContent = `name: Build Apps
|
|
211
281
|
on:
|
|
212
282
|
push:
|
|
213
283
|
branches: [ main ]
|
|
@@ -253,9 +323,9 @@ jobs:
|
|
|
253
323
|
releaseDraft: true
|
|
254
324
|
prerelease: false
|
|
255
325
|
`;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
326
|
+
} else {
|
|
327
|
+
// Electron Workflow
|
|
328
|
+
workflowContent = `name: Build Apps
|
|
259
329
|
on:
|
|
260
330
|
push:
|
|
261
331
|
branches: [ main ]
|
|
@@ -287,9 +357,9 @@ jobs:
|
|
|
287
357
|
env:
|
|
288
358
|
GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
289
359
|
`;
|
|
290
|
-
|
|
360
|
+
}
|
|
291
361
|
|
|
292
|
-
|
|
362
|
+
await fs.writeFile(path.join(workflowDir, 'build.yml'), workflowContent);
|
|
293
363
|
}
|
|
294
364
|
|
|
295
365
|
module.exports = init;
|