create-nextjs-cms 0.5.32 → 0.5.34

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/index.js CHANGED
@@ -5,10 +5,11 @@ import { fileURLToPath } from 'node:url';
5
5
  import { randomBytes } from 'node:crypto';
6
6
  import path, { dirname, resolve, relative, basename } from 'node:path';
7
7
  import { Command } from 'commander';
8
- import prompts from 'prompts';
8
+ import { text, confirm, spinner, log } from '@clack/prompts';
9
9
  import { expandHome, isValidPkgName, isEmptyDir, detectPackageManager, validateTemplate } from './lib/utils.js';
10
10
  import { readFileSync } from 'node:fs';
11
11
  import chalk from 'chalk';
12
+ import { renderTitle } from './lib/render-title.js';
12
13
  /** Resolve __dirname for ESM */
13
14
  const __filename = fileURLToPath(import.meta.url);
14
15
  const __dirname = dirname(__filename);
@@ -22,15 +23,6 @@ const templateDir = fileURLToPath(new URL('../templates/default/', import.meta.u
22
23
  const handleSigTerm = () => process.exit(0);
23
24
  process.on('SIGINT', handleSigTerm);
24
25
  process.on('SIGTERM', handleSigTerm);
25
- const onPromptState = (state) => {
26
- if (state.aborted) {
27
- // If we don't re-enable the terminal cursor before exiting
28
- // the program, the cursor will remain hidden
29
- process.stdout.write('\x1B[?25h');
30
- process.stdout.write('\n');
31
- process.exit(1);
32
- }
33
- };
34
26
  /**
35
27
  * Creates a blog section file in the sections folder
36
28
  */
@@ -39,7 +31,7 @@ async function createBlogSection(targetDir) {
39
31
  const blogSectionPath = path.join(sectionsDir, 'blog.section.ts');
40
32
  // Ensure sections directory exists
41
33
  await fs.ensureDir(sectionsDir);
42
- const blogSectionContent = `import { dateField, photoField, richTextField, textField } from 'nextjs-cms/core/fields'
34
+ const blogSectionContent = `import { photoField, richTextField, textField, tagsField } from 'nextjs-cms/core/fields'
43
35
  import { hasItemsSection } from 'nextjs-cms/core/sections'
44
36
 
45
37
  const title = textField({
@@ -49,67 +41,27 @@ const title = textField({
49
41
  order: 1,
50
42
  })
51
43
 
52
- const slug = textField({
53
- name: 'slug',
54
- label: 'Slug',
55
- required: false,
56
- order: 2,
57
- })
58
-
59
44
  const coverPhotoField = photoField({
60
45
  name: 'coverphoto',
61
46
  label: 'Cover Photo',
62
- watermark: false,
63
47
  required: true,
64
- order: 3,
65
- size: {
66
- width: 1200,
67
- height: 628,
68
- crop: true,
69
- },
70
- thumbnail: {
71
- width: 400,
72
- height: 209,
73
- crop: true,
74
- quality: 80,
75
- },
48
+ order: 2,
76
49
  fileType: ['jpg', 'jpeg', 'png', 'webp'],
77
50
  })
78
51
 
79
- const excerpt = textField({
80
- name: 'excerpt',
81
- label: 'Excerpt',
82
- required: false,
83
- order: 4,
84
- })
85
-
86
52
  const content = richTextField({
87
53
  name: 'content',
88
54
  label: 'Content',
89
55
  required: true,
90
- order: 5,
91
- allowMedia: true
56
+ order: 3,
92
57
  })
93
58
 
94
- const publishedAt = dateField({
95
- name: 'published_at',
96
- label: 'Published At',
97
- required: false,
98
- order: 6,
99
- })
100
59
 
101
- const metaDescription = textField({
102
- name: 'meta_description',
103
- label: 'Meta Description',
60
+ const keywords = tagsField({
61
+ name: 'keywords',
62
+ label: 'Keywords',
104
63
  required: false,
105
- order: 7,
106
- })
107
-
108
- const metaKeywords = textField({
109
- name: 'meta_keywords',
110
- label: 'Meta Keywords',
111
- required: false,
112
- order: 8,
64
+ order: 4,
113
65
  })
114
66
 
115
67
  export default hasItemsSection({
@@ -133,39 +85,17 @@ export default hasItemsSection({
133
85
  },
134
86
  db: {
135
87
  table: 'blog',
136
- fulltext: [
137
- {
138
- columns: [title],
139
- name: 'title_fulltext',
140
- },
141
- {
142
- columns: [content],
143
- name: 'content_fulltext',
144
- },
145
- ],
146
- unique: [
147
- {
148
- columns: [slug],
149
- name: 'slug_unique',
150
- },
151
- ],
152
- index: [
153
- {
154
- columns: [publishedAt],
155
- name: 'published_at_index',
156
- },
157
- ],
158
88
  },
159
89
  search: {
160
- searchFields: [title, content],
90
+ searchFields: [title],
161
91
  },
162
92
  coverPhotoField: coverPhotoField,
163
93
  generateQR: false,
164
- fields: [title, slug, coverPhotoField, excerpt, content, publishedAt, metaDescription, metaKeywords],
94
+ fields: [title, coverPhotoField, content, keywords],
165
95
  })
166
96
  `;
167
97
  await fs.writeFile(blogSectionPath, blogSectionContent, 'utf-8');
168
- console.log('Blog section created successfully!');
98
+ log.success('Blog section created successfully!');
169
99
  }
170
100
  /**
171
101
  * Generates a random secret string using crypto.randomBytes
@@ -179,7 +109,7 @@ function generateSecret() {
179
109
  async function updateEnvSecrets(targetDir) {
180
110
  const envPath = path.join(targetDir, '.env');
181
111
  if (!(await fs.pathExists(envPath))) {
182
- console.warn('⚠️ No .env file found; skipping secret generation.');
112
+ log.warn('No .env file found; skipping secret generation.');
183
113
  return;
184
114
  }
185
115
  try {
@@ -191,16 +121,17 @@ async function updateEnvSecrets(targetDir) {
191
121
  envContent = envContent.replace(/ACCESS_TOKEN_EXPIRATION=.*/, 'ACCESS_TOKEN_EXPIRATION=2h');
192
122
  envContent = envContent.replace(/REFRESH_TOKEN_EXPIRATION=.*/, 'REFRESH_TOKEN_EXPIRATION=1y');
193
123
  await fs.writeFile(envPath, envContent, 'utf-8');
194
- console.log('🔐 Generated random secrets and set token expirations in .env file');
124
+ log.step('Generated random secrets and set token expirations in .env file');
195
125
  }
196
126
  catch (e) {
197
- console.warn('⚠️ Could not update .env secrets automatically.');
198
- console.warn(` Error: ${e instanceof Error ? e.message : 'Unknown error'}`);
127
+ log.warn('Could not update .env secrets automatically.');
128
+ log.error(` Error: ${e instanceof Error ? e.message : 'Unknown error'}`);
199
129
  }
200
130
  }
201
131
  async function createNextjsCms() {
202
- console.log('🚀 Welcome to NextJS CMS!');
203
- console.log('Creating your new CMS project...\n');
132
+ renderTitle();
133
+ log.info('🚀 Welcome to NextJS CMS!');
134
+ log.message('Creating your new CMS project...\n');
204
135
  let projectPath = '';
205
136
  const program = new Command(packageJson.name)
206
137
  .version(packageJson.version, '-v, --version', 'Output the current version of create-nextjs-cms.')
@@ -227,34 +158,31 @@ async function createNextjsCms() {
227
158
  try {
228
159
  // Ensure template folder is present in the published package
229
160
  if (!(await fs.pathExists(templateDir))) {
230
- console.error('Template directory not found in the published package.');
231
- console.error(' Make sure "templates/" is included in package.json#files and actually published.');
161
+ log.error('Template directory not found in the published package.');
162
+ log.message(' Make sure "templates/" is included in package.json#files and actually published.');
232
163
  process.exit(1);
233
164
  }
234
165
  // Validate template structure
235
166
  await validateTemplate(templateDir);
236
167
  // If no directory was provided, prompt for project name
237
168
  if (!projectPath) {
238
- const res = await prompts({
239
- onState: onPromptState,
240
- type: 'text',
241
- name: 'path',
169
+ const res = await text({
242
170
  message: 'What is your project named?',
243
- initial: 'my-cms-app',
171
+ defaultValue: 'my-cms-app',
244
172
  validate: (name) => {
245
173
  const validation = isValidPkgName(basename(resolve(name)));
246
174
  if (validation) {
247
- return true;
175
+ return;
248
176
  }
249
177
  return 'Invalid project name: Project name can only contain letters, numbers, hyphens, and underscores.';
250
178
  },
251
179
  });
252
- if (typeof res.path === 'string') {
253
- projectPath = res.path.trim();
180
+ if (typeof res === 'string') {
181
+ projectPath = res.trim();
254
182
  }
255
183
  }
256
184
  if (!projectPath) {
257
- console.log('\nPlease specify the project directory:\n' +
185
+ log.error('\nPlease specify the project directory:\n' +
258
186
  ` ${chalk.cyan(program.name())} ${chalk.green('<project-directory>')}\n` +
259
187
  'For example:\n' +
260
188
  ` ${chalk.cyan(program.name())} ${chalk.green('my-cms-app')}\n\n` +
@@ -268,8 +196,8 @@ async function createNextjsCms() {
268
196
  options.projectName = basename(options.targetDir);
269
197
  // Validate name
270
198
  if (!isValidPkgName(options.projectName)) {
271
- console.error(`Could not create a project called ${chalk.red(`"${options.projectName}"`)} because of npm naming restrictions:`);
272
- console.error(` ${chalk.red('*')} Project name can only contain letters, numbers, hyphens, and underscores.`);
199
+ log.error(`Could not create a project called ${chalk.red(`"${options.projectName}"`)} because of npm naming restrictions:`);
200
+ log.message(` ${chalk.red('*')} Project name can only contain letters, numbers, hyphens, and underscores.`);
273
201
  process.exit(1);
274
202
  }
275
203
  targetIsCwd = path.normalize(options.targetDir) === path.normalize(process.cwd());
@@ -279,34 +207,36 @@ async function createNextjsCms() {
279
207
  await fs.ensureDir(options.targetDir);
280
208
  }
281
209
  else if (!(await isEmptyDir(options.targetDir))) {
282
- console.error('Current directory is not empty. Choose an empty folder or a new directory name.');
283
- console.error(' Tip: pnpm create nextjs-cms my-app');
210
+ log.error('Current directory is not empty. Choose an empty folder or a new directory name.');
211
+ log.message(chalk.gray('Tip: You can also specify a directory name like this: \n') +
212
+ chalk.green('pnpm create nextjs-cms ') +
213
+ chalk.italic.magenta('my-app'));
214
+ log.message(' ');
284
215
  process.exit(1);
285
216
  }
286
217
  }
287
218
  else {
288
219
  if (await fs.pathExists(options.targetDir)) {
289
- console.error(`❌ Directory "${options.targetDir}" already exists.`);
290
- process.exit(1);
220
+ if (!(await isEmptyDir(options.targetDir))) {
221
+ log.error(`Directory "${options.targetDir}" is not empty.`);
222
+ log.message('Please choose an empty directory or a different directory name.');
223
+ process.exit(1);
224
+ }
225
+ }
226
+ else {
227
+ await fs.ensureDir(options.targetDir);
291
228
  }
292
- await fs.ensureDir(options.targetDir);
293
229
  }
294
230
  // Ask if user wants to add blog section
295
- const blogRes = await prompts({
296
- onState: onPromptState,
297
- type: 'toggle',
298
- name: 'addBlogSection',
231
+ const blogRes = await confirm({
299
232
  message: 'Would you like to add a default blog section config?',
300
- initial: false,
301
- active: 'Yes',
302
- inactive: 'No',
233
+ initialValue: false,
303
234
  });
304
- if (typeof blogRes.addBlogSection === 'boolean') {
305
- options.addBlogSection = Boolean(blogRes.addBlogSection);
306
- }
307
- console.log(`📁 Creating project in: ${options.targetDir}`);
235
+ options.addBlogSection = Boolean(blogRes);
236
+ log.step(`Creating project in: ${options.targetDir}`);
308
237
  // Copy template → project dir with a filter to skip build/cache artifacts
309
- console.log('📁 Copying template files...');
238
+ const copySpinner = spinner();
239
+ copySpinner.start('Copying template files...');
310
240
  await fs.copy(options.templateDir, options.targetDir, {
311
241
  filter: (src) => {
312
242
  const rel = relative(options.templateDir, src);
@@ -322,7 +252,7 @@ async function createNextjsCms() {
322
252
  overwrite: true,
323
253
  errorOnExist: false,
324
254
  });
325
- console.log('✅ Template copied successfully!');
255
+ copySpinner.stop('✅ Template copied successfully!');
326
256
  // Generate random secrets for .env file
327
257
  await updateEnvSecrets(options.targetDir);
328
258
  // npm excludes .gitignore from packages, so we rename it back from _gitignore
@@ -330,11 +260,11 @@ async function createNextjsCms() {
330
260
  const gitignorePath = path.join(options.targetDir, '.gitignore');
331
261
  if (await fs.pathExists(gitignoreTemplatePath)) {
332
262
  await fs.move(gitignoreTemplatePath, gitignorePath);
333
- console.log('📝 Restored .gitignore file');
263
+ log.step('Restored .gitignore file');
334
264
  }
335
265
  // Create blog section if requested
336
266
  if (options.addBlogSection) {
337
- console.log('📝 Creating blog section...');
267
+ log.info('Creating blog section...');
338
268
  await createBlogSection(options.targetDir);
339
269
  }
340
270
  // Update package.json name (if template contains package.json)
@@ -344,45 +274,48 @@ async function createNextjsCms() {
344
274
  const pkg = (await fs.readJson(packageJsonPath));
345
275
  pkg.name = options.projectName;
346
276
  await fs.writeJson(packageJsonPath, pkg, { spaces: 2 });
347
- console.log(`📝 Updated package.json name to: ${options.projectName}`);
277
+ log.step(`Updated package.json name to: ${options.projectName}`);
348
278
  }
349
279
  catch (e) {
350
- console.warn('⚠️ Could not update package.json name automatically.');
351
- console.warn(` Error: ${e instanceof Error ? e.message : 'Unknown error'}`);
280
+ log.warn('Could not update package.json name automatically.');
281
+ log.error(` Error: ${e instanceof Error ? e.message : 'Unknown error'}`);
352
282
  }
353
283
  }
354
284
  else {
355
- console.warn('⚠️ No package.json found in template root; skipping name update.');
285
+ log.warn('No package.json found in template root; skipping name update.');
356
286
  }
357
- console.log('📦 Installing dependencies...');
287
+ log.info('Installing dependencies...');
358
288
  process.chdir(options.targetDir);
289
+ const installSpinner = spinner();
290
+ installSpinner.start('Installing dependencies...');
359
291
  const preferredPM = detectPackageManager();
292
+ log.step(`Using ${chalk.green(preferredPM)} as the package manager...`);
360
293
  let installed = false;
361
294
  // Try preferred package manager first
362
295
  try {
363
296
  if (preferredPM === 'pnpm') {
364
297
  execSync('pnpm install', { stdio: 'inherit' });
365
298
  installed = true;
366
- console.log('✅ Dependencies installed with pnpm!');
299
+ installSpinner.stop('✅ Dependencies installed with pnpm!');
367
300
  }
368
301
  else if (preferredPM === 'yarn') {
369
302
  execSync('yarn install', { stdio: 'inherit' });
370
303
  installed = true;
371
- console.log('✅ Dependencies installed with yarn!');
304
+ installSpinner.stop('✅ Dependencies installed with yarn!');
372
305
  }
373
306
  else if (preferredPM === 'bun') {
374
307
  execSync('bun install', { stdio: 'inherit' });
375
308
  installed = true;
376
- console.log('✅ Dependencies installed with bun!');
309
+ installSpinner.stop('✅ Dependencies installed with bun!');
377
310
  }
378
311
  else {
379
312
  execSync('npm install', { stdio: 'inherit' });
380
313
  installed = true;
381
- console.log('✅ Dependencies installed with npm!');
314
+ installSpinner.stop('✅ Dependencies installed with npm!');
382
315
  }
383
316
  }
384
317
  catch {
385
- console.error(`❌ ${preferredPM} install failed. Trying alternatives...`);
318
+ installSpinner.message(`❌ ${preferredPM} install failed. Trying alternatives...`);
386
319
  // Fallback to other package managers
387
320
  const fallbacks = preferredPM === 'pnpm'
388
321
  ? ['npm', 'yarn', 'bun']
@@ -393,49 +326,50 @@ async function createNextjsCms() {
393
326
  try {
394
327
  execSync(`${pm} install`, { stdio: 'inherit' });
395
328
  installed = true;
396
- console.log(`✅ Dependencies installed with ${pm}!`);
329
+ installSpinner.stop(`✅ Dependencies installed with ${pm}!`);
397
330
  break;
398
331
  }
399
332
  catch {
400
- console.error(`❌ ${pm} install failed.`);
333
+ installSpinner.message(`❌ ${pm} install failed.`);
401
334
  }
402
335
  }
403
336
  if (!installed) {
404
- console.error('❌ Failed to install dependencies automatically.');
405
- console.error(' Please run "pnpm install", "npm install", "yarn install", or "bun install" manually.');
337
+ installSpinner.stop('❌ Failed to install dependencies automatically.');
338
+ log.error(' Please run "pnpm install", "npm install", "yarn install", or "bun install" manually.');
406
339
  }
407
340
  }
408
341
  // Run CMS setup
409
- console.log('🔧 Running CMS setup...');
342
+ const setupSpinner = spinner();
343
+ setupSpinner.start('Running CMS setup...');
410
344
  try {
411
345
  execSync('pnpm next-cms-kit:dev setup', { stdio: 'inherit' });
412
- console.log('✅ CMS setup completed successfully!');
346
+ setupSpinner.stop('✅ CMS setup completed successfully!');
413
347
  }
414
348
  catch (error) {
415
- console.warn('⚠️ CMS setup failed. You may need to run it manually:');
416
- console.warn(' pnpm next-cms-kit:dev setup');
417
- console.warn(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
349
+ setupSpinner.stop('⚠️ CMS setup failed. You may need to run it manually:');
350
+ log.warn(' pnpm next-cms-kit:dev setup');
351
+ log.error(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
418
352
  }
419
- console.log('\n🎉 Your NextJS CMS project has been created successfully!');
420
- console.log('\nNext steps:');
421
- console.log(` cd ${options.projectName}`);
422
- console.log(installed
353
+ log.success('\n🎉 Your NextJS CMS project has been created successfully!');
354
+ log.message('\nNext steps:');
355
+ log.message(` cd ${options.projectName}`);
356
+ log.message(installed
423
357
  ? ` ${preferredPM} dev # or: npm run dev`
424
358
  : ` ${preferredPM} install && ${preferredPM} dev # or: npm install && npm run dev`);
425
- console.log('\nHappy coding! 🚀');
359
+ log.message('\nHappy coding! 🚀');
426
360
  }
427
361
  catch (error) {
428
- console.error('❌ Failed to create project:', error);
362
+ log.error(`❌ Failed to create project: ${error instanceof Error ? error.message : 'Unknown error'}`);
429
363
  // Clean up partial installation on error
430
364
  if ((await fs.pathExists(options.targetDir)) && !targetIsCwd) {
431
- console.log('🧹 Cleaning up partial installation...');
365
+ log.info('🧹 Cleaning up partial installation...');
432
366
  try {
433
367
  await fs.remove(options.targetDir);
434
- console.log('✅ Cleanup completed.');
368
+ log.success('✅ Cleanup completed.');
435
369
  }
436
370
  catch {
437
- console.error('⚠️ Could not clean up partial installation.');
438
- console.error(` Please manually remove: ${options.targetDir}`);
371
+ log.error('⚠️ Could not clean up partial installation.');
372
+ log.message(` Please manually remove: ${options.targetDir}`);
439
373
  }
440
374
  }
441
375
  process.exit(1);
@@ -0,0 +1,2 @@
1
+ export declare const renderTitle: () => void;
2
+ //# sourceMappingURL=render-title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-title.d.ts","sourceRoot":"","sources":["../../src/lib/render-title.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,WAAW,YASvB,CAAA"}
@@ -0,0 +1,21 @@
1
+ import gradient from 'gradient-string';
2
+ import { TITLE_TEXT } from './utils.js';
3
+ import { detectPackageManager } from './utils.js';
4
+ // colors brought in from vscode poimandres theme
5
+ const poimandresTheme = {
6
+ blue: '#add7ff',
7
+ cyan: '#89ddff',
8
+ green: '#5de4c7',
9
+ magenta: '#fae4fc',
10
+ red: '#d0679d',
11
+ yellow: '#fffac2',
12
+ };
13
+ export const renderTitle = () => {
14
+ const titleGradient = gradient(Object.values(poimandresTheme));
15
+ // resolves weird behavior where the ascii is offset
16
+ const pkgManager = detectPackageManager();
17
+ if (pkgManager === 'yarn' || pkgManager === 'pnpm') {
18
+ console.log('');
19
+ }
20
+ console.log(titleGradient.multiline(TITLE_TEXT));
21
+ };
@@ -1,3 +1,4 @@
1
+ export declare const TITLE_TEXT = "\n _\n ___ _ __ ___ __ _| |_ ___\n / __| '__/ _ \\/ _\\` | __/ _ \\\n | (__| | | __/ (_| | || __/\n \\___|_| \\___|\\__,_|\\__\\___|\n _ _\n _ __ _____ _| |_ (_)___\n | '_ \\ / _ \\ \\/ / __|| / __|\n | | | | __/> <| |_ | \\__ \\\n |_| |_|\\___/_/\\_\\__|/ |___/\n |__/\n ___ _ __ ___ ___\n / __| '_ \\` _ \\/ __|\n | (__| | | | | \\__ \\\n \\___|_| |_| |_|___/\n";
1
2
  /** Expand ~ to home */
2
3
  export declare function expandHome(p: string): string;
3
4
  /** Validate npm package name (simple rule) */
@@ -5,6 +6,7 @@ export declare function isValidPkgName(name: string): boolean;
5
6
  /** Check if a directory is empty */
6
7
  export declare function isEmptyDir(dir: string): Promise<boolean>;
7
8
  /** Detect preferred package manager */
9
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
8
10
  export declare function detectPackageManager(): 'pnpm' | 'npm' | 'yarn' | 'bun';
9
11
  /** Validate template structure */
10
12
  export declare function validateTemplate(templateDir: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAIA,uBAAuB;AACvB,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,oCAAoC;AACpC,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9D;AAED,uCAAuC;AACvC,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAMtE;AAED,kCAAkC;AAClC,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAczE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,4jBAgBtB,CAAA;AAED,uBAAuB;AACvB,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,oCAAoC;AACpC,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9D;AAED,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAC5D,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAkBtE;AAED,kCAAkC;AAClC,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAczE"}
package/dist/lib/utils.js CHANGED
@@ -1,6 +1,23 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'node:path';
3
3
  import os from 'node:os';
4
+ export const TITLE_TEXT = `
5
+ _
6
+ ___ _ __ ___ __ _| |_ ___
7
+ / __| '__/ _ \\/ _\\\` | __/ _ \\
8
+ | (__| | | __/ (_| | || __/
9
+ \\___|_| \\___|\\__,_|\\__\\___|
10
+ _ _
11
+ _ __ _____ _| |_ (_)___
12
+ | '_ \\ / _ \\ \\/ / __|| / __|
13
+ | | | | __/> <| |_ | \\__ \\
14
+ |_| |_|\\___/_/\\_\\__|/ |___/
15
+ |__/
16
+ ___ _ __ ___ ___
17
+ / __| '_ \\\` _ \\/ __|
18
+ | (__| | | | | \\__ \\
19
+ \\___|_| |_| |_|___/
20
+ `;
4
21
  /** Expand ~ to home */
5
22
  export function expandHome(p) {
6
23
  if (p.startsWith('~'))
@@ -21,16 +38,27 @@ export async function isEmptyDir(dir) {
21
38
  return true;
22
39
  }
23
40
  }
24
- /** Detect preferred package manager */
25
41
  export function detectPackageManager() {
42
+ // This environment variable is set by npm and yarn but pnpm seems less consistent
26
43
  const userAgent = process.env.npm_config_user_agent;
27
- if (userAgent?.includes('pnpm'))
28
- return 'pnpm';
29
- if (userAgent?.includes('yarn'))
30
- return 'yarn';
31
- if (userAgent?.includes('bun'))
32
- return 'bun';
33
- return 'npm';
44
+ if (userAgent) {
45
+ if (userAgent.startsWith('yarn')) {
46
+ return 'yarn';
47
+ }
48
+ else if (userAgent.startsWith('pnpm')) {
49
+ return 'pnpm';
50
+ }
51
+ else if (userAgent.startsWith('bun')) {
52
+ return 'bun';
53
+ }
54
+ else {
55
+ return 'npm';
56
+ }
57
+ }
58
+ else {
59
+ // If no user agent is set, assume npm
60
+ return 'npm';
61
+ }
34
62
  }
35
63
  /** Validate template structure */
36
64
  export async function validateTemplate(templateDir) {
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "create-nextjs-cms",
3
- "version": "0.5.32",
3
+ "version": "0.5.34",
4
4
  "private": false,
5
+ "type": "module",
5
6
  "bin": {
6
7
  "create-nextjs-cms": "./dist/index.js"
7
8
  },
@@ -10,17 +11,17 @@
10
11
  "templates"
11
12
  ],
12
13
  "dependencies": {
14
+ "@clack/prompts": "^0.11.0",
13
15
  "chalk": "^5.4.1",
14
16
  "commander": "^14.0.2",
15
17
  "fs-extra": "^11.3.3",
16
18
  "glob": "^11.0.3",
17
- "js-yaml": "^4.1.1",
18
- "prompts": "^2.4.2"
19
+ "gradient-string": "^3.0.0",
20
+ "js-yaml": "^4.1.1"
19
21
  },
20
22
  "devDependencies": {
21
23
  "@types/fs-extra": "^11.0.4",
22
24
  "@types/js-yaml": "^4.0.9",
23
- "@types/prompts": "^2.4.9",
24
25
  "eslint": "^9.12.0",
25
26
  "prettier": "^3.3.3",
26
27
  "tsx": "^4.20.6",
@@ -31,7 +32,7 @@
31
32
  },
32
33
  "prettier": "@lzcms/prettier-config",
33
34
  "scripts": {
34
- "dev": "tsc",
35
+ "dev": "tsc --watch",
35
36
  "prebuild": "tsx scripts/build.ts",
36
37
  "build": "pnpm prebuild && tsc",
37
38
  "clean": "git clean -xdf .cache .turbo dist node_modules templates",
@@ -70,7 +70,7 @@
70
70
  "nanoid": "^5.1.2",
71
71
  "next": "^15.5.5",
72
72
  "next-themes": "^0.4.6",
73
- "nextjs-cms": "0.5.32",
73
+ "nextjs-cms": "0.5.34",
74
74
  "plaiceholder": "^3.0.0",
75
75
  "prettier-plugin-tailwindcss": "^0.7.2",
76
76
  "qrcode": "^1.5.4",
@@ -103,7 +103,7 @@
103
103
  "eslint-config-prettier": "^10.0.1",
104
104
  "eslint-plugin-prettier": "^5.2.3",
105
105
  "fs-extra": "^11.3.3",
106
- "nextjs-cms-kit": "0.5.32",
106
+ "nextjs-cms-kit": "0.5.34",
107
107
  "postcss": "^8.5.1",
108
108
  "prettier": "3.5.0",
109
109
  "tailwindcss": "^4.1.18",