@vue-skuilder/cli 0.1.4 → 0.1.5

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.
@@ -13,7 +13,7 @@ const __dirname = path.dirname(__filename);
13
13
  export async function findStandaloneUiPath(): Promise<string> {
14
14
  // Start from CLI package root and work upward
15
15
  let currentDir = path.join(__dirname, '..', '..');
16
-
16
+
17
17
  while (currentDir !== path.dirname(currentDir)) {
18
18
  const nodeModulesPath = path.join(currentDir, 'node_modules', '@vue-skuilder', 'standalone-ui');
19
19
  if (existsSync(nodeModulesPath)) {
@@ -21,8 +21,10 @@ export async function findStandaloneUiPath(): Promise<string> {
21
21
  }
22
22
  currentDir = path.dirname(currentDir);
23
23
  }
24
-
25
- throw new Error('Could not find @vue-skuilder/standalone-ui package. Please ensure it is installed.');
24
+
25
+ throw new Error(
26
+ 'Could not find @vue-skuilder/standalone-ui package. Please ensure it is installed.'
27
+ );
26
28
  }
27
29
 
28
30
  /**
@@ -34,18 +36,18 @@ export async function copyDirectory(
34
36
  excludePatterns: string[] = ['node_modules', 'dist', '.git', 'cypress']
35
37
  ): Promise<void> {
36
38
  const entries = await fs.readdir(source, { withFileTypes: true });
37
-
39
+
38
40
  await fs.mkdir(destination, { recursive: true });
39
-
41
+
40
42
  for (const entry of entries) {
41
43
  const sourcePath = path.join(source, entry.name);
42
44
  const destPath = path.join(destination, entry.name);
43
-
45
+
44
46
  // Skip excluded patterns
45
- if (excludePatterns.some(pattern => entry.name.includes(pattern))) {
47
+ if (excludePatterns.some((pattern) => entry.name.includes(pattern))) {
46
48
  continue;
47
49
  }
48
-
50
+
49
51
  if (entry.isDirectory()) {
50
52
  await copyDirectory(sourcePath, destPath, excludePatterns);
51
53
  } else {
@@ -64,12 +66,12 @@ export async function transformPackageJson(
64
66
  ): Promise<void> {
65
67
  const content = await fs.readFile(packageJsonPath, 'utf-8');
66
68
  const packageJson = JSON.parse(content);
67
-
69
+
68
70
  // Update basic project info
69
71
  packageJson.name = projectName;
70
72
  packageJson.description = `Skuilder course application: ${projectName}`;
71
73
  packageJson.version = '1.0.0';
72
-
74
+
73
75
  // Transform workspace dependencies to published versions
74
76
  if (packageJson.dependencies) {
75
77
  for (const [depName, version] of Object.entries(packageJson.dependencies)) {
@@ -79,21 +81,21 @@ export async function transformPackageJson(
79
81
  }
80
82
  }
81
83
  }
82
-
84
+
83
85
  // Add missing terser devDependency for build minification
84
86
  if (packageJson.devDependencies && !packageJson.devDependencies['terser']) {
85
87
  packageJson.devDependencies['terser'] = '^5.39.0';
86
88
  }
87
-
89
+
88
90
  // Remove CLI-specific fields that don't belong in generated projects
89
91
  delete packageJson.publishConfig;
90
-
92
+
91
93
  await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
92
94
  }
93
95
 
94
96
  /**
95
97
  * Create a vite.config.ts to work with published packages instead of workspace sources
96
- *
98
+ *
97
99
  * // [ ] This should be revised so that it works from the existing vite.config.ts in standalone-ui. As is, it recreates 95% of the same config.
98
100
  */
99
101
  export async function createViteConfig(viteConfigPath: string): Promise<void> {
@@ -109,7 +111,7 @@ export default defineConfig({
109
111
  alias: {
110
112
  // Alias for internal src paths
111
113
  '@': fileURLToPath(new URL('./src', import.meta.url)),
112
-
114
+
113
115
  // Add events alias if needed (often required by dependencies)
114
116
  events: 'events',
115
117
  },
@@ -156,7 +158,7 @@ export default defineConfig({
156
158
  },
157
159
  });
158
160
  `;
159
-
161
+
160
162
  await fs.writeFile(viteConfigPath, transformedContent);
161
163
  }
162
164
 
@@ -169,21 +171,21 @@ export async function generateSkuilderConfig(
169
171
  ): Promise<void> {
170
172
  const skuilderConfig: SkuilderConfig = {
171
173
  title: config.title,
172
- dataLayerType: config.dataLayerType
174
+ dataLayerType: config.dataLayerType,
173
175
  };
174
-
176
+
175
177
  if (config.course) {
176
178
  skuilderConfig.course = config.course;
177
179
  }
178
-
180
+
179
181
  if (config.couchdbUrl) {
180
182
  skuilderConfig.couchdbUrl = config.couchdbUrl;
181
183
  }
182
-
184
+
183
185
  if (config.theme) {
184
186
  skuilderConfig.theme = config.theme;
185
187
  }
186
-
188
+
187
189
  await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
188
190
  }
189
191
 
@@ -313,14 +315,12 @@ Thumbs.db
313
315
  /**
314
316
  * Generate project README.md
315
317
  */
316
- export async function generateReadme(
317
- readmePath: string,
318
- config: ProjectConfig
319
- ): Promise<void> {
320
- const dataLayerInfo = config.dataLayerType === 'static'
321
- ? 'This project uses a static data layer with JSON files.'
322
- : `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
323
-
318
+ export async function generateReadme(readmePath: string, config: ProjectConfig): Promise<void> {
319
+ const dataLayerInfo =
320
+ config.dataLayerType === 'static'
321
+ ? 'This project uses a static data layer with JSON files.'
322
+ : `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
323
+
324
324
  const readme = `# ${config.title}
325
325
 
326
326
  A Skuilder course application built with Vue 3, Vuetify, and Pinia.
@@ -356,10 +356,42 @@ Course configuration is managed in \`skuilder.config.json\`. You can modify:
356
356
 
357
357
  ## Theme
358
358
 
359
- Current theme: **${config.theme.name}**
360
- - Primary: ${config.theme.colors.primary}
361
- - Secondary: ${config.theme.colors.secondary}
362
- - Accent: ${config.theme.colors.accent}
359
+ Current theme: **${config.theme.name}** (${config.theme.defaultMode} mode)
360
+ - Primary: ${config.theme.light.colors.primary}
361
+ - Secondary: ${config.theme.light.colors.secondary}
362
+ - Accent: ${config.theme.light.colors.accent}
363
+
364
+ This theme includes both light and dark variants. The application will use the ${config.theme.defaultMode} theme by default, but users can toggle between light and dark modes in their settings.
365
+
366
+ ### Theme Customization
367
+
368
+ To customize the theme colors, edit the \`theme\` section in \`skuilder.config.json\`:
369
+
370
+ \`\`\`json
371
+ {
372
+ "theme": {
373
+ "name": "custom",
374
+ "defaultMode": "light",
375
+ "light": {
376
+ "dark": false,
377
+ "colors": {
378
+ "primary": "#your-color",
379
+ "secondary": "#your-color",
380
+ "accent": "#your-color"
381
+ // ... other semantic colors
382
+ }
383
+ },
384
+ "dark": {
385
+ "dark": true,
386
+ "colors": {
387
+ // ... dark variant colors
388
+ }
389
+ }
390
+ }
391
+ }
392
+ \`\`\`
393
+
394
+ The theme system supports all Vuetify semantic colors including error, success, warning, info, background, surface, and text colors. Changes to the configuration file are applied automatically on restart.
363
395
 
364
396
  ## Testing
365
397
 
@@ -391,31 +423,31 @@ export async function processTemplate(
391
423
  ): Promise<void> {
392
424
  console.log(chalk.blue('📦 Locating standalone-ui template...'));
393
425
  const templatePath = await findStandaloneUiPath();
394
-
426
+
395
427
  console.log(chalk.blue('📂 Copying project files...'));
396
428
  await copyDirectory(templatePath, projectPath);
397
-
429
+
398
430
  console.log(chalk.blue('⚙️ Configuring package.json...'));
399
431
  const packageJsonPath = path.join(projectPath, 'package.json');
400
432
  await transformPackageJson(packageJsonPath, config.projectName, cliVersion);
401
-
433
+
402
434
  console.log(chalk.blue('🔧 Creating vite.config.ts...'));
403
435
  const viteConfigPath = path.join(projectPath, 'vite.config.ts');
404
436
  if (existsSync(viteConfigPath)) {
405
437
  await createViteConfig(viteConfigPath);
406
438
  }
407
-
439
+
408
440
  console.log(chalk.blue('🔧 Generating configuration...'));
409
441
  const configPath = path.join(projectPath, 'skuilder.config.json');
410
442
  await generateSkuilderConfig(configPath, config);
411
-
443
+
412
444
  console.log(chalk.blue('📝 Creating README...'));
413
445
  const readmePath = path.join(projectPath, 'README.md');
414
446
  await generateReadme(readmePath, config);
415
-
447
+
416
448
  console.log(chalk.blue('📄 Generating .gitignore...'));
417
449
  const gitignorePath = path.join(projectPath, '.gitignore');
418
450
  await generateGitignore(gitignorePath);
419
-
451
+
420
452
  console.log(chalk.green('✅ Template processing complete!'));
421
- }
453
+ }