create-tina-app 1.4.0 → 1.5.1

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/README.md CHANGED
@@ -6,6 +6,6 @@ Create Tina App is a powerful command-line interface (CLI) tool designed to kick
6
6
 
7
7
  To get started, you need to first build the code - see [contributing](https://github.com/tinacms/tinacms/blob/main/CONTRIBUTING.md).
8
8
 
9
- 1. run `pnpm link create-tina-app`
9
+ 1. run `pnpm link --global`
10
10
  1. Test your changes by running `npx create-tina-app`
11
11
  1. Run `pnpm unlink` when done to unlink the local build
package/dist/index.d.ts CHANGED
@@ -1,9 +1 @@
1
- /**
2
- * The available package managers a user can use.
3
- * To add a new supported package manager, add the usage command to this list.
4
- * The `PackageManager` type will be automatically updated as a result.
5
- */
6
- declare const PKG_MANAGERS: readonly ["npm", "yarn", "pnpm", "bun"];
7
- export type PackageManager = (typeof PKG_MANAGERS)[number];
8
1
  export declare function run(): Promise<void>;
9
- export {};
package/dist/index.js CHANGED
@@ -4,6 +4,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
7
10
  var __export = (target, all) => {
8
11
  for (var name2 in all)
9
12
  __defProp(target, name2, { get: all[name2], enumerable: true });
@@ -26,6 +29,68 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
29
  ));
27
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
31
 
32
+ // package.json
33
+ var require_package = __commonJS({
34
+ "package.json"(exports2, module2) {
35
+ module2.exports = {
36
+ name: "create-tina-app",
37
+ version: "1.5.1",
38
+ main: "dist/index.js",
39
+ files: [
40
+ "dist",
41
+ "examples",
42
+ "bin/*"
43
+ ],
44
+ bin: "bin/create-tina-app",
45
+ typings: "dist/index.d.ts",
46
+ license: "Apache-2.0",
47
+ buildConfig: {
48
+ entryPoints: [
49
+ {
50
+ name: "src/index.ts",
51
+ target: "node"
52
+ }
53
+ ]
54
+ },
55
+ engines: {
56
+ node: ">=18.18.0"
57
+ },
58
+ scripts: {
59
+ types: "pnpm tsc",
60
+ build: "tinacms-scripts build",
61
+ "test-run-bin": "pnpm create-tina-app"
62
+ },
63
+ publishConfig: {
64
+ registry: "https://registry.npmjs.org"
65
+ },
66
+ repository: {
67
+ url: "https://github.com/tinacms/tinacms.git",
68
+ directory: "packages/create-tina-app"
69
+ },
70
+ devDependencies: {
71
+ "@tinacms/scripts": "workspace:*",
72
+ "@types/cross-spawn": "catalog:",
73
+ "@types/fs-extra": "^11.0.4",
74
+ "@types/node": "^22.13.1",
75
+ "@types/prompts": "catalog:",
76
+ "@types/tar": "catalog:",
77
+ typescript: "^5.7.3"
78
+ },
79
+ dependencies: {
80
+ "@tinacms/metrics": "workspace:*",
81
+ chalk: "4.1.2",
82
+ commander: "^12.1.0",
83
+ "cross-spawn": "catalog:",
84
+ "fs-extra": "catalog:",
85
+ ora: "^8.2.0",
86
+ prompts: "catalog:",
87
+ tar: "catalog:",
88
+ "validate-npm-package-name": "catalog:"
89
+ }
90
+ };
91
+ }
92
+ });
93
+
29
94
  // src/index.ts
30
95
  var index_exports = {};
31
96
  __export(index_exports, {
@@ -33,53 +98,25 @@ __export(index_exports, {
33
98
  });
34
99
  module.exports = __toCommonJS(index_exports);
35
100
  var import_metrics = require("@tinacms/metrics");
36
- var import_commander = require("commander");
37
101
  var import_prompts = __toESM(require("prompts"));
38
102
  var import_node_path = __toESM(require("node:path"));
39
103
 
40
- // package.json
41
- var name = "create-tina-app";
42
- var version = "1.4.0";
43
-
44
104
  // src/util/fileUtil.ts
45
105
  var import_fs_extra = __toESM(require("fs-extra"));
46
106
  var import_path = __toESM(require("path"));
47
107
 
48
- // src/util/logger.ts
108
+ // src/util/textstyles.ts
49
109
  var import_chalk = __toESM(require("chalk"));
50
110
  var TextStyles = {
51
- link: import_chalk.default.bold.cyan,
52
- cmd: import_chalk.default.inverse,
111
+ tinaOrange: import_chalk.default.hex("#EC4816"),
112
+ link: (url) => `\x1B]8;;${url}\x07${import_chalk.default.cyan.underline(url)}\x1B]8;;\x07`,
113
+ cmd: import_chalk.default.bgBlackBright.bold.white,
53
114
  info: import_chalk.default.blue,
54
115
  success: import_chalk.default.green,
55
116
  warn: import_chalk.default.yellow,
56
117
  err: import_chalk.default.red,
57
118
  bold: import_chalk.default.bold
58
119
  };
59
- var Logger = class {
60
- log(message) {
61
- console.info(message);
62
- }
63
- debug(message) {
64
- console.debug(TextStyles.info(`[DEBUG] ${message}`));
65
- }
66
- info(message) {
67
- console.info(TextStyles.info(`[INFO] ${message}`));
68
- }
69
- success(message) {
70
- console.log(TextStyles.success(`[SUCCESS] ${message}`));
71
- }
72
- cmd(message) {
73
- console.log(TextStyles.cmd(message));
74
- }
75
- warn(message) {
76
- console.warn(TextStyles.warn(`[WARNING] ${message}`));
77
- }
78
- err(message) {
79
- console.error(TextStyles.err(`[ERROR] ${message}`));
80
- }
81
- };
82
- var log = new Logger();
83
120
 
84
121
  // src/util/fileUtil.ts
85
122
  async function isWriteable(directory) {
@@ -120,24 +157,22 @@ async function setupProjectDirectory(dir) {
120
157
  process.chdir(dir);
121
158
  const conflicts = folderContainsInstallConflicts(dir);
122
159
  if (conflicts.length > 0) {
123
- log.err(
124
- `The directory '${TextStyles.bold(
125
- appName
126
- )}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
127
- );
160
+ const errorMessageLines = [
161
+ `The directory '${TextStyles.bold(appName)}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
162
+ ];
128
163
  for (const file of conflicts) {
129
164
  try {
130
165
  const stats = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
131
166
  if (stats.isDirectory()) {
132
- log.log(`- ${TextStyles.info(file)}/`);
167
+ errorMessageLines.push(` - ${TextStyles.info(file)}/`);
133
168
  } else {
134
- log.log(`- ${file}`);
169
+ errorMessageLines.push(` - ${file}`);
135
170
  }
136
171
  } catch {
137
- log.log(`- ${file}`);
172
+ errorMessageLines.push(` - ${file}`);
138
173
  }
139
174
  }
140
- process.exit(1);
175
+ throw new Error(errorMessageLines.join("\n"));
141
176
  }
142
177
  return appName;
143
178
  }
@@ -153,13 +188,26 @@ function updateProjectPackageVersion(dir, version2) {
153
188
  packageJson.version = version2;
154
189
  import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
155
190
  }
191
+ async function updateThemeSettings(dir, selectedTheme) {
192
+ const settingsDir = import_path.default.join(dir, "content", "settings");
193
+ const configPath = import_path.default.join(settingsDir, "config.json");
194
+ await import_fs_extra.default.mkdirp(settingsDir);
195
+ let config = {};
196
+ try {
197
+ const existingConfig = await import_fs_extra.default.readFile(configPath, "utf8");
198
+ config = JSON.parse(existingConfig);
199
+ } catch (error) {
200
+ }
201
+ config.selectedTheme = selectedTheme;
202
+ await import_fs_extra.default.writeFile(configPath, JSON.stringify(config, null, 2));
203
+ }
156
204
 
157
205
  // src/util/install.ts
158
206
  var import_cross_spawn = __toESM(require("cross-spawn"));
159
- function install(packageManager) {
207
+ function install(packageManager, verboseOutput) {
160
208
  return new Promise((resolve, reject) => {
161
209
  const child = (0, import_cross_spawn.default)(packageManager, ["install"], {
162
- stdio: "inherit",
210
+ stdio: verboseOutput ? "inherit" : "ignore",
163
211
  env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
164
212
  });
165
213
  child.on("close", (code) => {
@@ -204,14 +252,16 @@ function makeFirstCommit(root) {
204
252
  throw err;
205
253
  }
206
254
  }
207
- function initializeGit() {
255
+ function initializeGit(spinner) {
208
256
  (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
209
257
  if (isInGitRepository() || isInMercurialRepository()) {
210
- log.warn("Already in a Git repository, skipping.");
258
+ spinner.warn("Already in a Git repository, skipping.");
211
259
  return false;
212
260
  }
213
261
  if (!import_fs_extra2.default.existsSync(".gitignore")) {
214
- log.warn("There is no .gitignore file in this repository, creating one...");
262
+ spinner.warn(
263
+ "There is no .gitignore file in this repository, creating one..."
264
+ );
215
265
  import_fs_extra2.default.writeFileSync(
216
266
  ".gitignore",
217
267
  `node_modules
@@ -290,56 +340,68 @@ var TEMPLATES = [
290
340
  description: "Kickstart your project with NextJS \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
291
341
  value: "tina-cloud-starter",
292
342
  isInternal: false,
293
- gitURL: "https://github.com/tinacms/tina-cloud-starter"
343
+ gitURL: "https://github.com/tinacms/tina-cloud-starter",
344
+ devUrl: "http://localhost:3000"
345
+ },
346
+ {
347
+ title: "\u2B50\uFE0F TinaDocs",
348
+ description: "Get your documentation site up and running with TinaCMS and Next.JS in minutes.",
349
+ value: "tina-docs",
350
+ isInternal: false,
351
+ gitURL: "https://github.com/tinacms/tina-docs",
352
+ devUrl: "http://localhost:3000"
294
353
  },
295
354
  {
296
355
  title: "Astro Starter",
297
356
  description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
298
357
  value: "tina-astro-starter",
299
358
  isInternal: false,
300
- gitURL: "https://github.com/tinacms/tina-astro-starter"
359
+ gitURL: "https://github.com/tinacms/tina-astro-starter",
360
+ devUrl: "http://localhost:4321"
301
361
  },
302
362
  {
303
363
  title: "Hugo Starter",
304
364
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
305
365
  value: "tina-hugo-starter",
306
366
  isInternal: false,
307
- gitURL: "https://github.com/tinacms/tina-hugo-starter"
367
+ gitURL: "https://github.com/tinacms/tina-hugo-starter",
368
+ devUrl: "http://localhost:1313"
308
369
  },
309
370
  {
310
371
  title: "Remix Starter",
311
372
  description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
312
373
  value: "tina-remix-starter",
313
374
  isInternal: false,
314
- gitURL: "https://github.com/tinacms/tina-remix-starter"
375
+ gitURL: "https://github.com/tinacms/tina-remix-starter",
376
+ devUrl: "http://localhost:3000"
315
377
  },
316
378
  {
317
379
  title: "Docusaurus Starter",
318
380
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
319
381
  value: "tinasaurus",
320
382
  isInternal: false,
321
- gitURL: "https://github.com/tinacms/tinasaurus"
383
+ gitURL: "https://github.com/tinacms/tinasaurus",
384
+ devUrl: "http://localhost:3000"
322
385
  },
323
386
  {
324
387
  title: "Bare bones starter",
325
388
  description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity.",
326
389
  value: "basic",
327
390
  isInternal: false,
328
- gitURL: "https://github.com/tinacms/tina-barebones-starter"
391
+ gitURL: "https://github.com/tinacms/tina-barebones-starter",
392
+ devUrl: "http://localhost:3000"
329
393
  }
330
394
  ];
331
- async function downloadTemplate(template, root) {
395
+ async function downloadTemplate(template, root, spinner) {
332
396
  if (template.isInternal === false) {
333
397
  const repoURL = new URL(template.gitURL);
334
398
  const repoInfo = await getRepoInfo(repoURL);
335
399
  if (!repoInfo) {
336
400
  throw new Error("Repository information not found.");
337
401
  }
338
- log.info(
339
- `Downloading files from repo ${TextStyles.link(
340
- `${repoInfo?.username}/${repoInfo?.name}`
341
- )}.`
342
- );
402
+ spinner.text = `Downloading files from repo ${TextStyles.tinaOrange(
403
+ `${repoInfo?.username}/${repoInfo?.name}`
404
+ )}`;
343
405
  await downloadAndExtractRepo(root, repoInfo);
344
406
  } else {
345
407
  const templateFile = import_path3.default.join(__dirname, "..", "examples", template.value);
@@ -348,21 +410,21 @@ async function downloadTemplate(template, root) {
348
410
  }
349
411
 
350
412
  // src/util/preRunChecks.ts
351
- var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 18, latest: 22 };
413
+ var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 20, latest: 22 };
352
414
  var SUPPORTED_NODE_VERSION_RANGE = [
353
415
  ...Array(SUPPORTED_NODE_VERSION_BOUNDS.latest).keys()
354
416
  ].map((i) => i + SUPPORTED_NODE_VERSION_BOUNDS.oldest);
355
417
  var isSupported = SUPPORTED_NODE_VERSION_RANGE.some(
356
418
  (version2) => process.version.startsWith(`v${version2}`)
357
419
  );
358
- function preRunChecks() {
359
- checkSupportedNodeVersion();
360
- }
361
- function checkSupportedNodeVersion() {
420
+ function preRunChecks(spinner) {
421
+ spinner.start("Running pre-run checks...");
362
422
  if (!isSupported) {
363
- log.warn(
423
+ spinner.warn(
364
424
  `Node ${process.version} is not supported by create-tina-app. Please update to be within v${SUPPORTED_NODE_VERSION_BOUNDS.oldest}-v${SUPPORTED_NODE_VERSION_BOUNDS.latest}. See https://nodejs.org/en/download/ for more details.`
365
425
  );
426
+ } else {
427
+ spinner.succeed(`Node ${process.version} is supported.`);
366
428
  }
367
429
  }
368
430
 
@@ -386,13 +448,20 @@ async function checkPackageExists(name2) {
386
448
 
387
449
  // src/index.ts
388
450
  var import_node_process = require("node:process");
389
- var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
451
+ var import_ora = __toESM(require("ora"));
452
+
453
+ // src/util/options.ts
454
+ var import_commander = require("commander");
455
+ var import_package = __toESM(require_package());
456
+
457
+ // src/util/packageManagers.ts
390
458
  var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
391
- async function run() {
392
- preRunChecks();
459
+
460
+ // src/util/options.ts
461
+ function extractOptions(args) {
393
462
  let projectName = "";
394
- const program = new import_commander.Command(name);
395
- program.version(version).option(
463
+ const program = new import_commander.Command(import_package.name);
464
+ program.version(import_package.version).option(
396
465
  "-t, --template <template>",
397
466
  `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
398
467
  (x2) => x2.value
@@ -403,20 +472,80 @@ async function run() {
403
472
  ).option(
404
473
  "-d, --dir <dir>",
405
474
  "Choose which directory to run this script from."
406
- ).option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
475
+ ).option("-v, --verbose", "Enable verbose output.").option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
407
476
  projectName = name2;
408
477
  });
409
- program.parse(process.argv);
478
+ program.parse(args);
410
479
  const opts = program.opts();
411
480
  if (opts.dir) {
412
481
  process.chdir(opts.dir);
413
482
  }
483
+ if (projectName) {
484
+ opts.projectName = projectName;
485
+ }
486
+ return opts;
487
+ }
488
+
489
+ // src/index.ts
490
+ var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
491
+
492
+ // src/util/asciiArt.ts
493
+ var llama = " :--=: \n :-===- \n -=====- \n -=======. \n .=========-. \n :===========--:\n -=============.\n .==========-:. \n :=========-. \n -=========- \n .==========- \n -==========- \n :===========- \n -=============. \n :==============: \n :===============- \n .:-================- \n ..::---==================== \n ....::::::::::-------============================. \n .---=================================================: \n .-=====================================================- \n:=======================================================. \n .-====================================================. \n .-=================================================. \n :=============================================- \n -============================================. \n .============-:. -==========- \n :=========-: .. -==========. \n -========: :-=- -=========- \n .========. .-==== :=========: \n -=======: :=====. -========: \n -======- -====- -=======: \n -=====: -====: :======. \n .=====. -====. .-====- \n :==== -===- -====: \n -==- :===- :====. ";
494
+ var tinaCms = "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\n \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D";
495
+
496
+ // src/themes.ts
497
+ var THEMES = [
498
+ {
499
+ title: "Default",
500
+ description: "The default monochromatic theme for your documentation site",
501
+ value: "default"
502
+ },
503
+ {
504
+ title: "Tina",
505
+ description: "The warm color scheme of TinaCMS for your documentation",
506
+ value: "tina"
507
+ },
508
+ {
509
+ title: "Blossom",
510
+ value: "blossom",
511
+ description: "A Blossom theme for your project"
512
+ },
513
+ {
514
+ title: "Lake",
515
+ value: "lake",
516
+ description: "A Lake theme for your project"
517
+ },
518
+ {
519
+ title: "Pine",
520
+ value: "pine",
521
+ description: "A Pine theme for your project"
522
+ },
523
+ {
524
+ title: "Indigo",
525
+ value: "indigo",
526
+ description: "An Indigo theme for your project"
527
+ }
528
+ ];
529
+
530
+ // src/index.ts
531
+ async function run() {
532
+ if (process.stdout.columns >= 60) {
533
+ console.log(TextStyles.tinaOrange(`${llama}`));
534
+ console.log(TextStyles.tinaOrange(`${tinaCms}`));
535
+ } else {
536
+ console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
537
+ }
538
+ const version2 = require_package().version;
539
+ console.log(`Create Tina App v${version2}`);
540
+ const spinner = (0, import_ora.default)();
541
+ preRunChecks(spinner);
542
+ const opts = extractOptions(process.argv);
414
543
  const telemetry = new import_metrics.Telemetry({ disabled: opts?.noTelemetry });
415
- let template = opts.template;
416
- if (template) {
417
- template = TEMPLATES.find((_template) => _template.value === template);
544
+ let template = null;
545
+ if (opts.template) {
546
+ template = TEMPLATES.find((_template) => _template.value === opts.template);
418
547
  if (!template) {
419
- log.err(
548
+ spinner.fail(
420
549
  `The provided template '${opts.template}' is invalid. Please provide one of the following: ${TEMPLATES.map(
421
550
  (x2) => x2.value
422
551
  )}`
@@ -427,7 +556,7 @@ async function run() {
427
556
  let pkgManager = opts.pkgManager;
428
557
  if (pkgManager) {
429
558
  if (!PKG_MANAGERS.find((_pkgManager) => _pkgManager === pkgManager)) {
430
- log.err(
559
+ spinner.fail(
431
560
  `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
432
561
  );
433
562
  (0, import_node_process.exit)(1);
@@ -441,7 +570,7 @@ async function run() {
441
570
  }
442
571
  }
443
572
  if (installedPkgManagers.length === 0) {
444
- log.err(
573
+ spinner.fail(
445
574
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
446
575
  );
447
576
  (0, import_node_process.exit)(1);
@@ -457,6 +586,7 @@ async function run() {
457
586
  if (!Object.hasOwn(res, "packageManager")) (0, import_node_process.exit)(1);
458
587
  pkgManager = res.packageManager;
459
588
  }
589
+ let projectName = opts.projectName;
460
590
  if (!projectName) {
461
591
  const res = await (0, import_prompts.default)({
462
592
  name: "name",
@@ -484,61 +614,99 @@ async function run() {
484
614
  if (!Object.hasOwn(res, "template")) (0, import_node_process.exit)(1);
485
615
  template = TEMPLATES.find((_template) => _template.value === res.template);
486
616
  }
617
+ let themeChoice;
618
+ if (template.value === "tina-docs") {
619
+ const res = await (0, import_prompts.default)({
620
+ name: "theme",
621
+ type: "select",
622
+ message: "What theme would you like to use?",
623
+ choices: THEMES
624
+ });
625
+ if (!Object.hasOwn(res, "theme")) (0, import_node_process.exit)(1);
626
+ themeChoice = res.theme;
627
+ }
487
628
  await telemetry.submitRecord({
488
629
  event: {
489
630
  name: "create-tina-app:invoke",
490
- template,
631
+ template: template.value,
491
632
  pkgManager
492
633
  }
493
634
  });
494
635
  const rootDir = import_node_path.default.join(process.cwd(), projectName);
495
636
  if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
496
- log.err(
637
+ spinner.fail(
497
638
  "The application path is not writable, please check folder permissions and try again. It is likely you do not have write permissions for this folder."
498
639
  );
499
640
  process.exit(1);
500
641
  }
501
- const appName = await setupProjectDirectory(rootDir);
642
+ let appName;
643
+ try {
644
+ appName = await setupProjectDirectory(rootDir);
645
+ } catch (err) {
646
+ spinner.fail(err.message);
647
+ (0, import_node_process.exit)(1);
648
+ }
502
649
  try {
503
- await downloadTemplate(template, rootDir);
650
+ await downloadTemplate(template, rootDir, spinner);
651
+ if (themeChoice) {
652
+ await updateThemeSettings(rootDir, themeChoice);
653
+ }
654
+ spinner.start("Downloading template...");
655
+ await downloadTemplate(template, rootDir, spinner);
656
+ spinner.succeed();
657
+ spinner.start("Updating project metadata...");
504
658
  updateProjectPackageName(rootDir, projectName);
505
659
  updateProjectPackageVersion(rootDir, "0.0.1");
660
+ spinner.succeed();
661
+ } catch (err) {
662
+ spinner.fail(`Failed to download template: ${err.message}`);
663
+ (0, import_node_process.exit)(1);
664
+ }
665
+ spinner.start("Installing packages.");
666
+ try {
667
+ await install(pkgManager, opts.verbose);
668
+ spinner.succeed();
506
669
  } catch (err) {
507
- log.err(`Failed to download template: ${err.message}`);
670
+ spinner.fail(`Failed to install packages: ${err.message}`);
508
671
  (0, import_node_process.exit)(1);
509
672
  }
510
- log.info("Installing packages.");
511
- await install(pkgManager);
512
- log.info("Initializing git repository.");
673
+ spinner.start("Initializing git repository.");
513
674
  try {
514
- if (initializeGit()) {
675
+ if (initializeGit(spinner)) {
515
676
  makeFirstCommit(rootDir);
516
- log.info("Initialized git repository.");
677
+ spinner.succeed();
517
678
  }
518
679
  } catch (err) {
519
- log.err("Failed to initialize Git repository, skipping.");
680
+ spinner.fail("Failed to initialize Git repository, skipping.");
520
681
  }
521
- log.success("Starter successfully created!");
522
- if (template.value === "tina-hugo-starter")
523
- log.warn(
524
- `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}.`
682
+ spinner.succeed(`Created ${TextStyles.tinaOrange(appName)}
683
+ `);
684
+ if (template.value === "tina-hugo-starter") {
685
+ spinner.warn(
686
+ `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}
687
+ `
525
688
  );
526
- log.log(TextStyles.bold("\nTo launch your app, run:\n"));
527
- log.cmd(`cd ${appName}
528
- ${pkgManager} run dev`);
529
- log.log(`
530
- Next steps:
531
- \u2022 \u{1F4DD} Edit some content on ${TextStyles.link(
532
- "http://localhost:3000"
533
- )} (See ${TextStyles.link("https://tina.io/docs/using-tina-editor")})
534
- \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}
535
- \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
536
- "https://tina.io/docs/advanced/extending-tina/"
537
- )}
538
- \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
539
- "https://tina.io/docs/tina-cloud/"
540
- )}
541
- `);
689
+ }
690
+ const padCommand = (cmd, width = 20) => TextStyles.cmd(cmd) + " ".repeat(Math.max(0, width - cmd.length));
691
+ spinner.info(`${TextStyles.bold("To get started:")}
692
+
693
+ ${padCommand(`cd ${appName}`)}# move into your project directory
694
+ ${padCommand(`${pkgManager} run dev`)}# start the dev server ${TextStyles.link(template.devUrl)}
695
+ ${padCommand(`${pkgManager} run build`)}# build the app for production
696
+ `);
697
+ console.log("Next steps:");
698
+ console.log(
699
+ ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link("https://tina.io/docs/using-tina-editor")}`
700
+ );
701
+ console.log(
702
+ ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}`
703
+ );
704
+ console.log(
705
+ ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link("https://tina.io/docs/advanced/extending-tina/")}`
706
+ );
707
+ console.log(
708
+ ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link("https://tina.io/docs/tina-cloud/")}`
709
+ );
542
710
  }
543
711
  run();
544
712
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,7 +1,9 @@
1
- type BaseExample = {
1
+ import { Ora } from 'ora';
2
+ export type BaseExample = {
2
3
  title: string;
3
4
  description?: string;
4
5
  value: string;
6
+ devUrl: string;
5
7
  };
6
8
  export type InternalTemplate = BaseExample & {
7
9
  isInternal: true;
@@ -12,5 +14,4 @@ export type ExternalTemplate = BaseExample & {
12
14
  };
13
15
  export type Template = InternalTemplate | ExternalTemplate;
14
16
  export declare const TEMPLATES: Template[];
15
- export declare function downloadTemplate(template: Template, root: string): Promise<void>;
16
- export {};
17
+ export declare function downloadTemplate(template: Template, root: string, spinner: Ora): Promise<void>;
@@ -0,0 +1,7 @@
1
+ type TinaDocsTheme = {
2
+ title: string;
3
+ value: string;
4
+ description: string;
5
+ };
6
+ export declare const THEMES: TinaDocsTheme[];
7
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const llama: string;
2
+ export declare const tinaCms: string;
@@ -1,2 +1,2 @@
1
- import { PackageManager } from '..';
1
+ import { PackageManager } from './packageManagers';
2
2
  export declare function checkPackageExists(name: PackageManager): Promise<boolean>;
@@ -3,3 +3,4 @@ export declare function folderContainsInstallConflicts(root: string): string[];
3
3
  export declare function setupProjectDirectory(dir: string): Promise<string>;
4
4
  export declare function updateProjectPackageName(dir: string, name: string): void;
5
5
  export declare function updateProjectPackageVersion(dir: string, version: string): void;
6
+ export declare function updateThemeSettings(dir: string, selectedTheme: string): Promise<void>;
@@ -1,2 +1,3 @@
1
+ import { Ora } from 'ora';
1
2
  export declare function makeFirstCommit(root: string): void;
2
- export declare function initializeGit(): boolean;
3
+ export declare function initializeGit(spinner: Ora): boolean;
@@ -1,7 +1,7 @@
1
- import { PackageManager } from '..';
1
+ import { PackageManager } from './packageManagers';
2
2
  /**
3
3
  * Spawn a package manager installation.
4
4
  *
5
5
  * @returns A Promise that resolves once the installation is finished.
6
6
  */
7
- export declare function install(packageManager: PackageManager): Promise<void>;
7
+ export declare function install(packageManager: PackageManager, verboseOutput: boolean): Promise<void>;
@@ -0,0 +1,9 @@
1
+ export interface CreateOptions {
2
+ template: string;
3
+ pkgManager: string;
4
+ dir: string;
5
+ noTelemetry: boolean;
6
+ projectName: string;
7
+ verbose: boolean;
8
+ }
9
+ export declare function extractOptions(args: string[]): CreateOptions;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The available package managers a user can use.
3
+ * To add a new supported package manager, add the usage command to this list.
4
+ * The `PackageManager` type will be automatically updated as a result.
5
+ */
6
+ export declare const PKG_MANAGERS: readonly ["npm", "yarn", "pnpm", "bun"];
7
+ export type PackageManager = (typeof PKG_MANAGERS)[number];
@@ -1 +1,2 @@
1
- export declare function preRunChecks(): void;
1
+ import { Ora } from 'ora';
2
+ export declare function preRunChecks(spinner: Ora): void;
@@ -0,0 +1,11 @@
1
+ import chalk from 'chalk';
2
+ export declare const TextStyles: {
3
+ tinaOrange: chalk.Chalk;
4
+ link: (url: string) => string;
5
+ cmd: chalk.Chalk;
6
+ info: chalk.Chalk;
7
+ success: chalk.Chalk;
8
+ warn: chalk.Chalk;
9
+ err: chalk.Chalk;
10
+ bold: chalk.Chalk;
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-tina-app",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",
@@ -42,6 +42,7 @@
42
42
  "commander": "^12.1.0",
43
43
  "cross-spawn": "^7.0.6",
44
44
  "fs-extra": "^11.3.0",
45
+ "ora": "^8.2.0",
45
46
  "prompts": "^2.4.2",
46
47
  "tar": "7.4.0",
47
48
  "validate-npm-package-name": "^5.0.1",
@@ -1,20 +0,0 @@
1
- import chalk from 'chalk';
2
- export declare const TextStyles: {
3
- link: chalk.Chalk;
4
- cmd: chalk.Chalk;
5
- info: chalk.Chalk;
6
- success: chalk.Chalk;
7
- warn: chalk.Chalk;
8
- err: chalk.Chalk;
9
- bold: chalk.Chalk;
10
- };
11
- export declare class Logger {
12
- log(message: string): void;
13
- debug(message: string): void;
14
- info(message: string): void;
15
- success(message: string): void;
16
- cmd(message: string): void;
17
- warn(message: string): void;
18
- err(message: string): void;
19
- }
20
- export declare const log: Logger;