@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.
- package/dist/cli.js +7 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +41 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pack.d.ts +3 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +124 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/types.d.ts +24 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +192 -16
- package/dist/types.js.map +1 -1
- package/dist/utils/prompts.d.ts +5 -2
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +67 -52
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +39 -7
- package/dist/utils/template.js.map +1 -1
- package/package.json +5 -3
- package/src/cli.ts +8 -12
- package/src/commands/init.ts +71 -21
- package/src/commands/pack.ts +163 -0
- package/src/types.ts +224 -18
- package/src/utils/prompts.ts +81 -54
- package/src/utils/template.ts +73 -41
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import PouchDB from 'pouchdb';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { CouchDBToStaticPacker } from '@vue-skuilder/db/packer';
|
|
7
|
+
|
|
8
|
+
export function createPackCommand(): Command {
|
|
9
|
+
return new Command('pack')
|
|
10
|
+
.description('Pack a CouchDB course into static files')
|
|
11
|
+
.argument('<courseId>', 'Course ID to pack')
|
|
12
|
+
.option('-s, --server <url>', 'CouchDB server URL', 'http://localhost:5984')
|
|
13
|
+
.option('-u, --username <username>', 'CouchDB username')
|
|
14
|
+
.option('-p, --password <password>', 'CouchDB password')
|
|
15
|
+
.option('-o, --output <dir>', 'Output directory', './static-courses')
|
|
16
|
+
.option('-c, --chunk-size <size>', 'Documents per chunk', '1000')
|
|
17
|
+
.option('--no-attachments', 'Exclude attachments')
|
|
18
|
+
.action(packCourse);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PackOptions {
|
|
22
|
+
server: string;
|
|
23
|
+
username?: string;
|
|
24
|
+
password?: string;
|
|
25
|
+
output: string;
|
|
26
|
+
chunkSize: string;
|
|
27
|
+
noAttachments: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function packCourse(courseId: string, options: PackOptions) {
|
|
31
|
+
try {
|
|
32
|
+
console.log(chalk.cyan(`š§ Packing course: ${courseId}`));
|
|
33
|
+
|
|
34
|
+
// Validate courseId
|
|
35
|
+
if (!courseId || courseId.trim() === '') {
|
|
36
|
+
throw new Error('Course ID is required');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Connect to CouchDB
|
|
40
|
+
const dbUrl = `${options.server}/coursedb-${courseId}`;
|
|
41
|
+
const dbOptions: Record<string, unknown> = {};
|
|
42
|
+
|
|
43
|
+
if (options.username && options.password) {
|
|
44
|
+
dbOptions.auth = {
|
|
45
|
+
username: options.username,
|
|
46
|
+
password: options.password,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(chalk.gray(`š” Connecting to: ${dbUrl}`));
|
|
51
|
+
const sourceDB = new PouchDB(dbUrl, dbOptions);
|
|
52
|
+
|
|
53
|
+
// Test connection
|
|
54
|
+
try {
|
|
55
|
+
await sourceDB.info();
|
|
56
|
+
console.log(chalk.green('ā
Connected to database'));
|
|
57
|
+
} catch (error: unknown) {
|
|
58
|
+
let errorMessage = 'Unknown error';
|
|
59
|
+
if (error instanceof Error) {
|
|
60
|
+
errorMessage = error.message;
|
|
61
|
+
} else if (typeof error === 'string') {
|
|
62
|
+
errorMessage = error;
|
|
63
|
+
} else if (error && typeof error === 'object' && 'message' in error) {
|
|
64
|
+
errorMessage = String((error as { message: unknown }).message);
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`Failed to connect to database: ${errorMessage}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Configure packer (data transformation only)
|
|
70
|
+
const packerConfig = {
|
|
71
|
+
chunkSize: parseInt(options.chunkSize),
|
|
72
|
+
includeAttachments: !options.noAttachments,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
console.log(chalk.gray(`š¦ Chunk size: ${packerConfig.chunkSize} documents`));
|
|
76
|
+
console.log(chalk.gray(`š Include attachments: ${packerConfig.includeAttachments}`));
|
|
77
|
+
|
|
78
|
+
// Pack the course (data transformation)
|
|
79
|
+
console.log(chalk.cyan('š Processing course data...'));
|
|
80
|
+
const packer = new CouchDBToStaticPacker(packerConfig);
|
|
81
|
+
const packedData = await packer.packCourse(sourceDB, courseId);
|
|
82
|
+
|
|
83
|
+
// Create output directory
|
|
84
|
+
const outputDir = path.resolve(options.output, courseId);
|
|
85
|
+
await fs.ensureDir(outputDir);
|
|
86
|
+
console.log(chalk.gray(`š Output directory: ${outputDir}`));
|
|
87
|
+
|
|
88
|
+
// Write files
|
|
89
|
+
await writePackedData(packedData, outputDir);
|
|
90
|
+
|
|
91
|
+
// Success summary
|
|
92
|
+
console.log(chalk.green('\nā
Successfully packed course!'));
|
|
93
|
+
console.log(chalk.white(`š Course: ${packedData.manifest.courseName}`));
|
|
94
|
+
console.log(chalk.white(`š Documents: ${packedData.manifest.documentCount}`));
|
|
95
|
+
console.log(chalk.white(`šļø Chunks: ${packedData.manifest.chunks.length}`));
|
|
96
|
+
console.log(chalk.white(`šļø Indices: ${packedData.manifest.indices.length}`));
|
|
97
|
+
console.log(chalk.white(`š Location: ${outputDir}`));
|
|
98
|
+
|
|
99
|
+
} catch (error: unknown) {
|
|
100
|
+
console.error(chalk.red('\nā Packing failed:'));
|
|
101
|
+
let errorMessage = 'Unknown error';
|
|
102
|
+
if (error instanceof Error) {
|
|
103
|
+
errorMessage = error.message;
|
|
104
|
+
} else if (typeof error === 'string') {
|
|
105
|
+
errorMessage = error;
|
|
106
|
+
} else if (error && typeof error === 'object' && 'message' in error) {
|
|
107
|
+
errorMessage = String((error as { message: unknown }).message);
|
|
108
|
+
}
|
|
109
|
+
console.error(chalk.red(errorMessage));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface PackedData {
|
|
115
|
+
manifest: {
|
|
116
|
+
version: string;
|
|
117
|
+
courseId: string;
|
|
118
|
+
courseName: string;
|
|
119
|
+
lastUpdated: string;
|
|
120
|
+
documentCount: number;
|
|
121
|
+
chunks: unknown[];
|
|
122
|
+
indices: unknown[];
|
|
123
|
+
designDocs: unknown[];
|
|
124
|
+
};
|
|
125
|
+
chunks: Map<string, unknown[]>;
|
|
126
|
+
indices: Map<string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function writePackedData(
|
|
130
|
+
packedData: PackedData,
|
|
131
|
+
outputDir: string
|
|
132
|
+
) {
|
|
133
|
+
console.log(chalk.cyan('š¾ Writing files...'));
|
|
134
|
+
|
|
135
|
+
// Write manifest
|
|
136
|
+
const manifestPath = path.join(outputDir, 'manifest.json');
|
|
137
|
+
await fs.writeJson(manifestPath, packedData.manifest, { spaces: 2 });
|
|
138
|
+
console.log(chalk.gray(`š Wrote manifest: ${manifestPath}`));
|
|
139
|
+
|
|
140
|
+
// Create directories
|
|
141
|
+
const chunksDir = path.join(outputDir, 'chunks');
|
|
142
|
+
const indicesDir = path.join(outputDir, 'indices');
|
|
143
|
+
await fs.ensureDir(chunksDir);
|
|
144
|
+
await fs.ensureDir(indicesDir);
|
|
145
|
+
|
|
146
|
+
// Write chunks
|
|
147
|
+
let chunkCount = 0;
|
|
148
|
+
for (const [chunkId, chunkData] of packedData.chunks) {
|
|
149
|
+
const chunkPath = path.join(chunksDir, `${chunkId}.json`);
|
|
150
|
+
await fs.writeJson(chunkPath, chunkData);
|
|
151
|
+
chunkCount++;
|
|
152
|
+
}
|
|
153
|
+
console.log(chalk.gray(`š¦ Wrote ${chunkCount} chunks`));
|
|
154
|
+
|
|
155
|
+
// Write indices
|
|
156
|
+
let indexCount = 0;
|
|
157
|
+
for (const [indexName, indexData] of packedData.indices) {
|
|
158
|
+
const indexPath = path.join(indicesDir, `${indexName}.json`);
|
|
159
|
+
await fs.writeJson(indexPath, indexData, { spaces: 2 });
|
|
160
|
+
indexCount++;
|
|
161
|
+
}
|
|
162
|
+
console.log(chalk.gray(`šļø Wrote ${indexCount} indices`));
|
|
163
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -15,15 +15,45 @@ export interface ProjectConfig {
|
|
|
15
15
|
theme: ThemeConfig;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export interface
|
|
19
|
-
|
|
18
|
+
export interface VuetifyThemeDefinition {
|
|
19
|
+
dark: boolean;
|
|
20
20
|
colors: {
|
|
21
|
+
// Core semantic colors
|
|
21
22
|
primary: string;
|
|
22
23
|
secondary: string;
|
|
23
24
|
accent: string;
|
|
25
|
+
error: string;
|
|
26
|
+
info: string;
|
|
27
|
+
success: string;
|
|
28
|
+
warning: string;
|
|
29
|
+
|
|
30
|
+
// Surface colors
|
|
31
|
+
background: string;
|
|
32
|
+
surface: string;
|
|
33
|
+
'surface-bright': string;
|
|
34
|
+
'surface-light': string;
|
|
35
|
+
'surface-variant': string;
|
|
36
|
+
'on-surface-variant': string;
|
|
37
|
+
|
|
38
|
+
// Derived colors
|
|
39
|
+
'primary-darken-1': string;
|
|
40
|
+
'secondary-darken-1': string;
|
|
41
|
+
|
|
42
|
+
// Text colors
|
|
43
|
+
'on-primary': string;
|
|
44
|
+
'on-secondary': string;
|
|
45
|
+
'on-background': string;
|
|
46
|
+
'on-surface': string;
|
|
24
47
|
};
|
|
25
48
|
}
|
|
26
49
|
|
|
50
|
+
export interface ThemeConfig {
|
|
51
|
+
name: string;
|
|
52
|
+
light: VuetifyThemeDefinition;
|
|
53
|
+
dark: VuetifyThemeDefinition;
|
|
54
|
+
defaultMode: 'light' | 'dark';
|
|
55
|
+
}
|
|
56
|
+
|
|
27
57
|
export interface SkuilderConfig {
|
|
28
58
|
title: string;
|
|
29
59
|
course?: string;
|
|
@@ -39,34 +69,210 @@ export interface InitCommandOptions extends CliOptions {
|
|
|
39
69
|
export const PREDEFINED_THEMES: Record<string, ThemeConfig> = {
|
|
40
70
|
default: {
|
|
41
71
|
name: 'default',
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
defaultMode: 'light',
|
|
73
|
+
light: {
|
|
74
|
+
dark: false,
|
|
75
|
+
colors: {
|
|
76
|
+
primary: '#1976D2',
|
|
77
|
+
secondary: '#424242',
|
|
78
|
+
accent: '#82B1FF',
|
|
79
|
+
error: '#F44336',
|
|
80
|
+
info: '#2196F3',
|
|
81
|
+
success: '#4CAF50',
|
|
82
|
+
warning: '#FF9800',
|
|
83
|
+
background: '#FFFFFF',
|
|
84
|
+
surface: '#FFFFFF',
|
|
85
|
+
'surface-bright': '#FFFFFF',
|
|
86
|
+
'surface-light': '#EEEEEE',
|
|
87
|
+
'surface-variant': '#E3F2FD',
|
|
88
|
+
'on-surface-variant': '#1976D2',
|
|
89
|
+
'primary-darken-1': '#1565C0',
|
|
90
|
+
'secondary-darken-1': '#212121',
|
|
91
|
+
'on-primary': '#FFFFFF',
|
|
92
|
+
'on-secondary': '#FFFFFF',
|
|
93
|
+
'on-background': '#212121',
|
|
94
|
+
'on-surface': '#212121',
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
dark: {
|
|
98
|
+
dark: true,
|
|
99
|
+
colors: {
|
|
100
|
+
primary: '#2196F3',
|
|
101
|
+
secondary: '#90A4AE',
|
|
102
|
+
accent: '#82B1FF',
|
|
103
|
+
error: '#FF5252',
|
|
104
|
+
info: '#2196F3',
|
|
105
|
+
success: '#4CAF50',
|
|
106
|
+
warning: '#FFC107',
|
|
107
|
+
background: '#121212',
|
|
108
|
+
surface: '#1E1E1E',
|
|
109
|
+
'surface-bright': '#2C2C2C',
|
|
110
|
+
'surface-light': '#2C2C2C',
|
|
111
|
+
'surface-variant': '#1A237E',
|
|
112
|
+
'on-surface-variant': '#82B1FF',
|
|
113
|
+
'primary-darken-1': '#1976D2',
|
|
114
|
+
'secondary-darken-1': '#546E7A',
|
|
115
|
+
'on-primary': '#000000',
|
|
116
|
+
'on-secondary': '#000000',
|
|
117
|
+
'on-background': '#FFFFFF',
|
|
118
|
+
'on-surface': '#FFFFFF',
|
|
119
|
+
}
|
|
46
120
|
}
|
|
47
121
|
},
|
|
48
122
|
medical: {
|
|
49
123
|
name: 'medical',
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
124
|
+
defaultMode: 'light',
|
|
125
|
+
light: {
|
|
126
|
+
dark: false,
|
|
127
|
+
colors: {
|
|
128
|
+
primary: '#2E7D32',
|
|
129
|
+
secondary: '#558B2F',
|
|
130
|
+
accent: '#66BB6A',
|
|
131
|
+
error: '#D32F2F',
|
|
132
|
+
info: '#1976D2',
|
|
133
|
+
success: '#388E3C',
|
|
134
|
+
warning: '#F57C00',
|
|
135
|
+
background: '#FAFAFA',
|
|
136
|
+
surface: '#FFFFFF',
|
|
137
|
+
'surface-bright': '#FFFFFF',
|
|
138
|
+
'surface-light': '#F5F5F5',
|
|
139
|
+
'surface-variant': '#E8F5E8',
|
|
140
|
+
'on-surface-variant': '#2E7D32',
|
|
141
|
+
'primary-darken-1': '#1B5E20',
|
|
142
|
+
'secondary-darken-1': '#33691E',
|
|
143
|
+
'on-primary': '#FFFFFF',
|
|
144
|
+
'on-secondary': '#FFFFFF',
|
|
145
|
+
'on-background': '#212121',
|
|
146
|
+
'on-surface': '#212121',
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
dark: {
|
|
150
|
+
dark: true,
|
|
151
|
+
colors: {
|
|
152
|
+
primary: '#4CAF50',
|
|
153
|
+
secondary: '#8BC34A',
|
|
154
|
+
accent: '#81C784',
|
|
155
|
+
error: '#F44336',
|
|
156
|
+
info: '#2196F3',
|
|
157
|
+
success: '#4CAF50',
|
|
158
|
+
warning: '#FF9800',
|
|
159
|
+
background: '#121212',
|
|
160
|
+
surface: '#1E1E1E',
|
|
161
|
+
'surface-bright': '#2C2C2C',
|
|
162
|
+
'surface-light': '#2C2C2C',
|
|
163
|
+
'surface-variant': '#1B2E1B',
|
|
164
|
+
'on-surface-variant': '#81C784',
|
|
165
|
+
'primary-darken-1': '#388E3C',
|
|
166
|
+
'secondary-darken-1': '#689F38',
|
|
167
|
+
'on-primary': '#000000',
|
|
168
|
+
'on-secondary': '#000000',
|
|
169
|
+
'on-background': '#FFFFFF',
|
|
170
|
+
'on-surface': '#FFFFFF',
|
|
171
|
+
}
|
|
54
172
|
}
|
|
55
173
|
},
|
|
56
174
|
educational: {
|
|
57
175
|
name: 'educational',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
176
|
+
defaultMode: 'light',
|
|
177
|
+
light: {
|
|
178
|
+
dark: false,
|
|
179
|
+
colors: {
|
|
180
|
+
primary: '#F57C00',
|
|
181
|
+
secondary: '#FF9800',
|
|
182
|
+
accent: '#FFB74D',
|
|
183
|
+
error: '#F44336',
|
|
184
|
+
info: '#2196F3',
|
|
185
|
+
success: '#4CAF50',
|
|
186
|
+
warning: '#FF9800',
|
|
187
|
+
background: '#FFFEF7',
|
|
188
|
+
surface: '#FFFFFF',
|
|
189
|
+
'surface-bright': '#FFFFFF',
|
|
190
|
+
'surface-light': '#FFF8E1',
|
|
191
|
+
'surface-variant': '#FFF3E0',
|
|
192
|
+
'on-surface-variant': '#F57C00',
|
|
193
|
+
'primary-darken-1': '#E65100',
|
|
194
|
+
'secondary-darken-1': '#F57C00',
|
|
195
|
+
'on-primary': '#FFFFFF',
|
|
196
|
+
'on-secondary': '#000000',
|
|
197
|
+
'on-background': '#212121',
|
|
198
|
+
'on-surface': '#212121',
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
dark: {
|
|
202
|
+
dark: true,
|
|
203
|
+
colors: {
|
|
204
|
+
primary: '#FF9800',
|
|
205
|
+
secondary: '#FFB74D',
|
|
206
|
+
accent: '#FFCC02',
|
|
207
|
+
error: '#FF5252',
|
|
208
|
+
info: '#2196F3',
|
|
209
|
+
success: '#4CAF50',
|
|
210
|
+
warning: '#FF9800',
|
|
211
|
+
background: '#121212',
|
|
212
|
+
surface: '#1E1E1E',
|
|
213
|
+
'surface-bright': '#2C2C2C',
|
|
214
|
+
'surface-light': '#2C2C2C',
|
|
215
|
+
'surface-variant': '#2E1A00',
|
|
216
|
+
'on-surface-variant': '#FFCC02',
|
|
217
|
+
'primary-darken-1': '#F57C00',
|
|
218
|
+
'secondary-darken-1': '#FF9800',
|
|
219
|
+
'on-primary': '#000000',
|
|
220
|
+
'on-secondary': '#000000',
|
|
221
|
+
'on-background': '#FFFFFF',
|
|
222
|
+
'on-surface': '#FFFFFF',
|
|
223
|
+
}
|
|
62
224
|
}
|
|
63
225
|
},
|
|
64
226
|
corporate: {
|
|
65
227
|
name: 'corporate',
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
228
|
+
defaultMode: 'light',
|
|
229
|
+
light: {
|
|
230
|
+
dark: false,
|
|
231
|
+
colors: {
|
|
232
|
+
primary: '#37474F',
|
|
233
|
+
secondary: '#546E7A',
|
|
234
|
+
accent: '#78909C',
|
|
235
|
+
error: '#F44336',
|
|
236
|
+
info: '#2196F3',
|
|
237
|
+
success: '#4CAF50',
|
|
238
|
+
warning: '#FF9800',
|
|
239
|
+
background: '#FAFAFA',
|
|
240
|
+
surface: '#FFFFFF',
|
|
241
|
+
'surface-bright': '#FFFFFF',
|
|
242
|
+
'surface-light': '#F5F5F5',
|
|
243
|
+
'surface-variant': '#ECEFF1',
|
|
244
|
+
'on-surface-variant': '#37474F',
|
|
245
|
+
'primary-darken-1': '#263238',
|
|
246
|
+
'secondary-darken-1': '#455A64',
|
|
247
|
+
'on-primary': '#FFFFFF',
|
|
248
|
+
'on-secondary': '#FFFFFF',
|
|
249
|
+
'on-background': '#212121',
|
|
250
|
+
'on-surface': '#212121',
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
dark: {
|
|
254
|
+
dark: true,
|
|
255
|
+
colors: {
|
|
256
|
+
primary: '#607D8B',
|
|
257
|
+
secondary: '#78909C',
|
|
258
|
+
accent: '#90A4AE',
|
|
259
|
+
error: '#FF5252',
|
|
260
|
+
info: '#2196F3',
|
|
261
|
+
success: '#4CAF50',
|
|
262
|
+
warning: '#FFC107',
|
|
263
|
+
background: '#121212',
|
|
264
|
+
surface: '#1E1E1E',
|
|
265
|
+
'surface-bright': '#2C2C2C',
|
|
266
|
+
'surface-light': '#2C2C2C',
|
|
267
|
+
'surface-variant': '#1C2429',
|
|
268
|
+
'on-surface-variant': '#90A4AE',
|
|
269
|
+
'primary-darken-1': '#455A64',
|
|
270
|
+
'secondary-darken-1': '#546E7A',
|
|
271
|
+
'on-primary': '#FFFFFF',
|
|
272
|
+
'on-secondary': '#FFFFFF',
|
|
273
|
+
'on-background': '#FFFFFF',
|
|
274
|
+
'on-surface': '#FFFFFF',
|
|
275
|
+
}
|
|
70
276
|
}
|
|
71
277
|
}
|
|
72
278
|
};
|
package/src/utils/prompts.ts
CHANGED
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { CliOptions, ProjectConfig, PREDEFINED_THEMES
|
|
3
|
+
import { CliOptions, ProjectConfig, PREDEFINED_THEMES } from '../types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert hex color to closest ANSI color code
|
|
7
|
+
*/
|
|
8
|
+
function hexToAnsi(hex: string): string {
|
|
9
|
+
// Remove # if present
|
|
10
|
+
hex = hex.replace('#', '');
|
|
11
|
+
|
|
12
|
+
// Convert hex to RGB
|
|
13
|
+
const r = parseInt(hex.substr(0, 2), 16);
|
|
14
|
+
const g = parseInt(hex.substr(2, 2), 16);
|
|
15
|
+
const b = parseInt(hex.substr(4, 2), 16);
|
|
16
|
+
|
|
17
|
+
// Convert to 256-color ANSI
|
|
18
|
+
const ansiCode = 16 + (36 * Math.round(r / 255 * 5)) + (6 * Math.round(g / 255 * 5)) + Math.round(b / 255 * 5);
|
|
19
|
+
return `\x1b[48;5;${ansiCode}m`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a color swatch for terminal display
|
|
24
|
+
*/
|
|
25
|
+
function createColorSwatch(hex: string, label: string): string {
|
|
26
|
+
const colorCode = hexToAnsi(hex);
|
|
27
|
+
const reset = '\x1b[0m';
|
|
28
|
+
return `${colorCode} ${reset} ${label}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create theme preview with color swatches
|
|
33
|
+
*/
|
|
34
|
+
function createThemePreview(themeName: string): string {
|
|
35
|
+
const theme = PREDEFINED_THEMES[themeName];
|
|
36
|
+
const lightColors = theme.light.colors;
|
|
37
|
+
|
|
38
|
+
const primarySwatch = createColorSwatch(lightColors.primary, 'Primary');
|
|
39
|
+
const secondarySwatch = createColorSwatch(lightColors.secondary, 'Secondary');
|
|
40
|
+
const accentSwatch = createColorSwatch(lightColors.accent, 'Accent');
|
|
41
|
+
|
|
42
|
+
return `${primarySwatch} ${secondarySwatch} ${accentSwatch}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Display comprehensive theme preview after selection
|
|
47
|
+
*/
|
|
48
|
+
export function displayThemePreview(themeName: string): void {
|
|
49
|
+
const theme = PREDEFINED_THEMES[themeName];
|
|
50
|
+
|
|
51
|
+
console.log(chalk.cyan('\nšØ Theme Color Palette:'));
|
|
52
|
+
console.log(chalk.white(` ${theme.name.toUpperCase()} THEME`));
|
|
53
|
+
|
|
54
|
+
// Light theme colors
|
|
55
|
+
console.log(chalk.white('\n Light Mode:'));
|
|
56
|
+
const lightColors = theme.light.colors;
|
|
57
|
+
console.log(` ${createColorSwatch(lightColors.primary, `Primary: ${lightColors.primary}`)}`);
|
|
58
|
+
console.log(` ${createColorSwatch(lightColors.secondary, `Secondary: ${lightColors.secondary}`)}`);
|
|
59
|
+
console.log(` ${createColorSwatch(lightColors.accent, `Accent: ${lightColors.accent}`)}`);
|
|
60
|
+
console.log(` ${createColorSwatch(lightColors.success, `Success: ${lightColors.success}`)}`);
|
|
61
|
+
console.log(` ${createColorSwatch(lightColors.warning, `Warning: ${lightColors.warning}`)}`);
|
|
62
|
+
console.log(` ${createColorSwatch(lightColors.error, `Error: ${lightColors.error}`)}`);
|
|
63
|
+
|
|
64
|
+
// Dark theme colors
|
|
65
|
+
console.log(chalk.white('\n Dark Mode:'));
|
|
66
|
+
const darkColors = theme.dark.colors;
|
|
67
|
+
console.log(` ${createColorSwatch(darkColors.primary, `Primary: ${darkColors.primary}`)}`);
|
|
68
|
+
console.log(` ${createColorSwatch(darkColors.secondary, `Secondary: ${darkColors.secondary}`)}`);
|
|
69
|
+
console.log(` ${createColorSwatch(darkColors.accent, `Accent: ${darkColors.accent}`)}`);
|
|
70
|
+
console.log(` ${createColorSwatch(darkColors.success, `Success: ${darkColors.success}`)}`);
|
|
71
|
+
console.log(` ${createColorSwatch(darkColors.warning, `Warning: ${darkColors.warning}`)}`);
|
|
72
|
+
console.log(` ${createColorSwatch(darkColors.error, `Error: ${darkColors.error}`)}`);
|
|
73
|
+
|
|
74
|
+
console.log(chalk.gray(`\n Default mode: ${theme.defaultMode}`));
|
|
75
|
+
}
|
|
4
76
|
|
|
5
77
|
export async function gatherProjectConfig(
|
|
6
78
|
projectName: string,
|
|
@@ -65,19 +137,19 @@ export async function gatherProjectConfig(
|
|
|
65
137
|
message: 'Select theme:',
|
|
66
138
|
choices: [
|
|
67
139
|
{
|
|
68
|
-
name:
|
|
140
|
+
name: `Default (Material Blue) ${createThemePreview('default')}`,
|
|
69
141
|
value: 'default'
|
|
70
142
|
},
|
|
71
143
|
{
|
|
72
|
-
name:
|
|
144
|
+
name: `Medical (Healthcare Green) ${createThemePreview('medical')}`,
|
|
73
145
|
value: 'medical'
|
|
74
146
|
},
|
|
75
147
|
{
|
|
76
|
-
name:
|
|
148
|
+
name: `Educational (Academic Orange) ${createThemePreview('educational')}`,
|
|
77
149
|
value: 'educational'
|
|
78
150
|
},
|
|
79
151
|
{
|
|
80
|
-
name:
|
|
152
|
+
name: `Corporate (Professional Gray) ${createThemePreview('corporate')}`,
|
|
81
153
|
value: 'corporate'
|
|
82
154
|
}
|
|
83
155
|
],
|
|
@@ -93,6 +165,9 @@ export async function gatherProjectConfig(
|
|
|
93
165
|
course: answers.courseId,
|
|
94
166
|
theme: PREDEFINED_THEMES[answers.themeName]
|
|
95
167
|
};
|
|
168
|
+
|
|
169
|
+
// Show comprehensive theme preview
|
|
170
|
+
displayThemePreview(answers.themeName);
|
|
96
171
|
} else {
|
|
97
172
|
// Non-interactive mode: use provided options
|
|
98
173
|
config = {
|
|
@@ -130,7 +205,7 @@ export async function confirmProjectCreation(
|
|
|
130
205
|
console.log(` Course ID: ${chalk.white(config.course)}`);
|
|
131
206
|
}
|
|
132
207
|
|
|
133
|
-
console.log(` Theme: ${chalk.white(config.theme.name)}`);
|
|
208
|
+
console.log(` Theme: ${chalk.white(config.theme.name)} ${createThemePreview(config.theme.name)}`);
|
|
134
209
|
console.log(` Directory: ${chalk.white(projectPath)}`);
|
|
135
210
|
|
|
136
211
|
const { confirmed } = await inquirer.prompt([
|
|
@@ -145,48 +220,7 @@ export async function confirmProjectCreation(
|
|
|
145
220
|
return confirmed;
|
|
146
221
|
}
|
|
147
222
|
|
|
148
|
-
export async function promptForCustomTheme(): Promise<ThemeConfig> {
|
|
149
|
-
console.log(chalk.cyan('\nšØ Custom Theme Configuration\n'));
|
|
150
|
-
|
|
151
|
-
const answers = await inquirer.prompt([
|
|
152
|
-
{
|
|
153
|
-
type: 'input',
|
|
154
|
-
name: 'name',
|
|
155
|
-
message: 'Theme name:',
|
|
156
|
-
validate: (input: string) => input.trim().length > 0 || 'Theme name is required'
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
type: 'input',
|
|
160
|
-
name: 'primary',
|
|
161
|
-
message: 'Primary color (hex):',
|
|
162
|
-
default: '#1976D2',
|
|
163
|
-
validate: validateHexColor
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
type: 'input',
|
|
167
|
-
name: 'secondary',
|
|
168
|
-
message: 'Secondary color (hex):',
|
|
169
|
-
default: '#424242',
|
|
170
|
-
validate: validateHexColor
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
type: 'input',
|
|
174
|
-
name: 'accent',
|
|
175
|
-
message: 'Accent color (hex):',
|
|
176
|
-
default: '#82B1FF',
|
|
177
|
-
validate: validateHexColor
|
|
178
|
-
}
|
|
179
|
-
]);
|
|
180
223
|
|
|
181
|
-
return {
|
|
182
|
-
name: answers.name,
|
|
183
|
-
colors: {
|
|
184
|
-
primary: answers.primary,
|
|
185
|
-
secondary: answers.secondary,
|
|
186
|
-
accent: answers.accent
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
224
|
|
|
191
225
|
function formatProjectName(projectName: string): string {
|
|
192
226
|
return projectName
|
|
@@ -195,10 +229,3 @@ function formatProjectName(projectName: string): string {
|
|
|
195
229
|
.join(' ');
|
|
196
230
|
}
|
|
197
231
|
|
|
198
|
-
function validateHexColor(input: string): boolean | string {
|
|
199
|
-
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
|
|
200
|
-
if (!hexColorRegex.test(input)) {
|
|
201
|
-
return 'Please enter a valid hex color (e.g., #1976D2)';
|
|
202
|
-
}
|
|
203
|
-
return true;
|
|
204
|
-
}
|