create-tina-app 0.0.0-d7c5ec1-20250219020924 → 0.0.0-d9487bf-20251119052214

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,2 +1 @@
1
- export declare const PKG_MANAGERS: string[];
2
1
  export declare function run(): Promise<void>;
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,61 +29,94 @@ 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.6.0",
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: "catalog:",
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, {
32
- PKG_MANAGERS: () => PKG_MANAGERS,
33
97
  run: () => run
34
98
  });
35
99
  module.exports = __toCommonJS(index_exports);
36
100
  var import_metrics = require("@tinacms/metrics");
37
- var import_commander = require("commander");
38
101
  var import_prompts = __toESM(require("prompts"));
39
- var import_node_path = __toESM(require("path"));
40
-
41
- // package.json
42
- var name = "create-tina-app";
43
- var version = "1.3.1";
102
+ var import_node_path = __toESM(require("node:path"));
44
103
 
45
104
  // src/util/fileUtil.ts
46
105
  var import_fs_extra = __toESM(require("fs-extra"));
47
106
  var import_path = __toESM(require("path"));
48
107
 
49
- // src/util/logger.ts
108
+ // src/util/textstyles.ts
50
109
  var import_chalk = __toESM(require("chalk"));
51
110
  var TextStyles = {
52
- link: import_chalk.default.bold.cyan,
53
- 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,
54
114
  info: import_chalk.default.blue,
55
115
  success: import_chalk.default.green,
56
116
  warn: import_chalk.default.yellow,
57
117
  err: import_chalk.default.red,
58
118
  bold: import_chalk.default.bold
59
119
  };
60
- var Logger = class {
61
- log(message) {
62
- console.info(message);
63
- }
64
- debug(message) {
65
- console.debug(TextStyles.info(`[DEBUG] ${message}`));
66
- }
67
- info(message) {
68
- console.info(TextStyles.info(`[INFO] ${message}`));
69
- }
70
- success(message) {
71
- console.log(TextStyles.success(`[SUCCESS] ${message}`));
72
- }
73
- cmd(message) {
74
- console.log(TextStyles.cmd(message));
75
- }
76
- warn(message) {
77
- console.warn(TextStyles.warn(`[WARNING] ${message}`));
78
- }
79
- err(message) {
80
- console.error(TextStyles.err(`[ERROR] ${message}`));
81
- }
82
- };
83
- var log = new Logger();
84
120
 
85
121
  // src/util/fileUtil.ts
86
122
  async function isWriteable(directory) {
@@ -121,24 +157,22 @@ async function setupProjectDirectory(dir) {
121
157
  process.chdir(dir);
122
158
  const conflicts = folderContainsInstallConflicts(dir);
123
159
  if (conflicts.length > 0) {
124
- log.err(
125
- `The directory '${TextStyles.bold(
126
- appName
127
- )}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
128
- );
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
+ ];
129
163
  for (const file of conflicts) {
130
164
  try {
131
165
  const stats = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
132
166
  if (stats.isDirectory()) {
133
- log.log(`- ${TextStyles.info(file)}/`);
167
+ errorMessageLines.push(` - ${TextStyles.info(file)}/`);
134
168
  } else {
135
- log.log(`- ${file}`);
169
+ errorMessageLines.push(` - ${file}`);
136
170
  }
137
171
  } catch {
138
- log.log(`- ${file}`);
172
+ errorMessageLines.push(` - ${file}`);
139
173
  }
140
174
  }
141
- process.exit(1);
175
+ throw new Error(errorMessageLines.join("\n"));
142
176
  }
143
177
  return appName;
144
178
  }
@@ -154,66 +188,31 @@ function updateProjectPackageVersion(dir, version2) {
154
188
  packageJson.version = version2;
155
189
  import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
156
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
+ }
157
204
 
158
205
  // src/util/install.ts
159
206
  var import_cross_spawn = __toESM(require("cross-spawn"));
160
- function install(root, dependencies, { packageManager, isOnline, devDependencies }) {
161
- const npmFlags = [];
162
- const yarnFlags = [];
163
- const pnpmFlags = [];
207
+ function install(packageManager, verboseOutput) {
164
208
  return new Promise((resolve, reject) => {
165
- let args;
166
- const command = packageManager;
167
- if (dependencies == null ? void 0 : dependencies.length) {
168
- switch (packageManager) {
169
- case "yarn":
170
- args = ["add", "--exact"];
171
- if (!isOnline) args.push("--offline");
172
- args.push("--cwd", root);
173
- if (devDependencies) args.push("--dev");
174
- args.push(...dependencies);
175
- break;
176
- case "npm":
177
- args = ["install", "--save-exact"];
178
- args.push(devDependencies ? "--save-dev" : "--save");
179
- args.push(...dependencies);
180
- break;
181
- case "pnpm":
182
- args = ["add"];
183
- if (!isOnline) args.push("--offline");
184
- args.push("--save-exact");
185
- if (devDependencies) args.push("-D");
186
- args.push(...dependencies);
187
- break;
188
- }
189
- } else {
190
- args = ["install"];
191
- if (!isOnline) {
192
- log.warn("You appear to be offline.");
193
- if (packageManager === "yarn") {
194
- log.warn("Falling back to the local Yarn cache.");
195
- args.push("--offline");
196
- }
197
- }
198
- }
199
- switch (packageManager) {
200
- case "yarn":
201
- args.push(...yarnFlags);
202
- break;
203
- case "npm":
204
- args.push(...npmFlags);
205
- break;
206
- case "pnpm":
207
- args.push(...pnpmFlags);
208
- break;
209
- }
210
- const child = (0, import_cross_spawn.default)(command, args, {
211
- stdio: "inherit",
209
+ const child = (0, import_cross_spawn.default)(packageManager, ["install"], {
210
+ stdio: verboseOutput ? "inherit" : "ignore",
212
211
  env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
213
212
  });
214
213
  child.on("close", (code) => {
215
214
  if (code !== 0) {
216
- reject({ command: `${command} ${args.join(" ")}` });
215
+ reject({ command: `${packageManager} install` });
217
216
  return;
218
217
  }
219
218
  resolve();
@@ -253,14 +252,16 @@ function makeFirstCommit(root) {
253
252
  throw err;
254
253
  }
255
254
  }
256
- function initializeGit() {
255
+ function initializeGit(spinner) {
257
256
  (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
258
257
  if (isInGitRepository() || isInMercurialRepository()) {
259
- log.warn("Already in a Git repository, skipping.");
258
+ spinner.warn("Already in a Git repository, skipping.");
260
259
  return false;
261
260
  }
262
261
  if (!import_fs_extra2.default.existsSync(".gitignore")) {
263
- 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
+ );
264
265
  import_fs_extra2.default.writeFileSync(
265
266
  ".gitignore",
266
267
  `node_modules
@@ -276,8 +277,8 @@ function initializeGit() {
276
277
  }
277
278
 
278
279
  // src/util/examples.ts
279
- var import_node_stream = require("stream");
280
- var import_promises = require("stream/promises");
280
+ var import_node_stream = require("node:stream");
281
+ var import_promises = require("node:stream/promises");
281
282
  var import_tar = require("tar");
282
283
  async function getRepoInfo(url, examplePath) {
283
284
  const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
@@ -336,59 +337,71 @@ var import_path3 = __toESM(require("path"));
336
337
  var TEMPLATES = [
337
338
  {
338
339
  title: "\u2B50 NextJS starter",
339
- description: "Kickstart your project with NextJS \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
340
- value: "tina-cloud-starter",
340
+ description: "Kickstart your project with Next.js \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
341
+ value: "tina-nextjs-starter",
341
342
  isInternal: false,
342
- gitURL: "https://github.com/tinacms/tina-cloud-starter"
343
+ gitURL: "https://github.com/tinacms/tina-nextjs-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"
343
353
  },
344
354
  {
345
355
  title: "Astro Starter",
346
356
  description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
347
357
  value: "tina-astro-starter",
348
358
  isInternal: false,
349
- gitURL: "https://github.com/tinacms/tina-astro-starter"
359
+ gitURL: "https://github.com/tinacms/tina-astro-starter",
360
+ devUrl: "http://localhost:4321"
350
361
  },
351
362
  {
352
363
  title: "Hugo Starter",
353
364
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
354
365
  value: "tina-hugo-starter",
355
366
  isInternal: false,
356
- gitURL: "https://github.com/tinacms/tina-hugo-starter"
367
+ gitURL: "https://github.com/tinacms/tina-hugo-starter",
368
+ devUrl: "http://localhost:1313"
357
369
  },
358
370
  {
359
371
  title: "Remix Starter",
360
372
  description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
361
373
  value: "tina-remix-starter",
362
374
  isInternal: false,
363
- gitURL: "https://github.com/tinacms/tina-remix-starter"
375
+ gitURL: "https://github.com/tinacms/tina-remix-starter",
376
+ devUrl: "http://localhost:3000"
364
377
  },
365
378
  {
366
379
  title: "Docusaurus Starter",
367
380
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
368
381
  value: "tinasaurus",
369
382
  isInternal: false,
370
- gitURL: "https://github.com/tinacms/tinasaurus"
383
+ gitURL: "https://github.com/tinacms/tinasaurus",
384
+ devUrl: "http://localhost:3000"
371
385
  },
372
386
  {
373
387
  title: "Bare bones starter",
374
388
  description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity.",
375
389
  value: "basic",
376
390
  isInternal: false,
377
- gitURL: "https://github.com/tinacms/tina-barebones-starter"
391
+ gitURL: "https://github.com/tinacms/tina-barebones-starter",
392
+ devUrl: "http://localhost:3000"
378
393
  }
379
394
  ];
380
- async function downloadTemplate(template, root) {
395
+ async function downloadTemplate(template, root, spinner) {
381
396
  if (template.isInternal === false) {
382
397
  const repoURL = new URL(template.gitURL);
383
398
  const repoInfo = await getRepoInfo(repoURL);
384
399
  if (!repoInfo) {
385
400
  throw new Error("Repository information not found.");
386
401
  }
387
- log.info(
388
- `Downloading files from repo ${TextStyles.link(
389
- `${repoInfo == null ? void 0 : repoInfo.username}/${repoInfo == null ? void 0 : repoInfo.name}`
390
- )}.`
391
- );
402
+ spinner.text = `Downloading files from repo ${TextStyles.tinaOrange(
403
+ `${repoInfo?.username}/${repoInfo?.name}`
404
+ )}`;
392
405
  await downloadAndExtractRepo(root, repoInfo);
393
406
  } else {
394
407
  const templateFile = import_path3.default.join(__dirname, "..", "examples", template.value);
@@ -397,21 +410,21 @@ async function downloadTemplate(template, root) {
397
410
  }
398
411
 
399
412
  // src/util/preRunChecks.ts
400
- var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 18, latest: 22 };
413
+ var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 20, latest: 22 };
401
414
  var SUPPORTED_NODE_VERSION_RANGE = [
402
415
  ...Array(SUPPORTED_NODE_VERSION_BOUNDS.latest).keys()
403
416
  ].map((i) => i + SUPPORTED_NODE_VERSION_BOUNDS.oldest);
404
417
  var isSupported = SUPPORTED_NODE_VERSION_RANGE.some(
405
418
  (version2) => process.version.startsWith(`v${version2}`)
406
419
  );
407
- function preRunChecks() {
408
- checkSupportedNodeVersion();
409
- }
410
- function checkSupportedNodeVersion() {
420
+ function preRunChecks(spinner) {
421
+ spinner.start("Running pre-run checks...");
411
422
  if (!isSupported) {
412
- log.warn(
423
+ spinner.warn(
413
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.`
414
425
  );
426
+ } else {
427
+ spinner.succeed(`Node ${process.version} is supported.`);
415
428
  }
416
429
  }
417
430
 
@@ -434,14 +447,20 @@ async function checkPackageExists(name2) {
434
447
  }
435
448
 
436
449
  // src/index.ts
437
- var import_node_process = require("process");
438
- var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
439
- var PKG_MANAGERS = ["npm", "yarn", "pnpm"];
440
- async function run() {
441
- preRunChecks();
450
+ var import_node_process = require("node:process");
451
+
452
+ // src/util/options.ts
453
+ var import_commander = require("commander");
454
+ var import_package = __toESM(require_package());
455
+
456
+ // src/util/packageManagers.ts
457
+ var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
458
+
459
+ // src/util/options.ts
460
+ function extractOptions(args) {
442
461
  let projectName = "";
443
- const program = new import_commander.Command(name);
444
- program.version(version).option(
462
+ const program = new import_commander.Command(import_package.name);
463
+ program.version(import_package.version).option(
445
464
  "-t, --template <template>",
446
465
  `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
447
466
  (x2) => x2.value
@@ -452,20 +471,82 @@ async function run() {
452
471
  ).option(
453
472
  "-d, --dir <dir>",
454
473
  "Choose which directory to run this script from."
455
- ).option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
474
+ ).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) => {
456
475
  projectName = name2;
457
476
  });
458
- program.parse(process.argv);
477
+ program.parse(args);
459
478
  const opts = program.opts();
460
479
  if (opts.dir) {
461
480
  process.chdir(opts.dir);
462
481
  }
463
- const telemetry = new import_metrics.Telemetry({ disabled: opts == null ? void 0 : opts.noTelemetry });
464
- let template = opts.template;
465
- if (template) {
466
- template = TEMPLATES.find((_template) => _template.value === template);
482
+ if (projectName) {
483
+ opts.projectName = projectName;
484
+ }
485
+ return opts;
486
+ }
487
+
488
+ // src/index.ts
489
+ var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
490
+
491
+ // src/util/asciiArt.ts
492
+ 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 -==- :===- :====. ";
493
+ 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";
494
+
495
+ // src/themes.ts
496
+ var THEMES = [
497
+ {
498
+ title: "Default",
499
+ description: "The default monochromatic theme for your documentation site",
500
+ value: "default"
501
+ },
502
+ {
503
+ title: "Tina",
504
+ description: "The warm color scheme of TinaCMS for your documentation",
505
+ value: "tina"
506
+ },
507
+ {
508
+ title: "Blossom",
509
+ value: "blossom",
510
+ description: "A Blossom theme for your project"
511
+ },
512
+ {
513
+ title: "Lake",
514
+ value: "lake",
515
+ description: "A Lake theme for your project"
516
+ },
517
+ {
518
+ title: "Pine",
519
+ value: "pine",
520
+ description: "A Pine theme for your project"
521
+ },
522
+ {
523
+ title: "Indigo",
524
+ value: "indigo",
525
+ description: "An Indigo theme for your project"
526
+ }
527
+ ];
528
+
529
+ // src/index.ts
530
+ async function run() {
531
+ const ora = (await import("ora")).default;
532
+ let packageManagerInstallationHadError = false;
533
+ if (process.stdout.columns >= 60) {
534
+ console.log(TextStyles.tinaOrange(`${llama}`));
535
+ console.log(TextStyles.tinaOrange(`${tinaCms}`));
536
+ } else {
537
+ console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
538
+ }
539
+ const version2 = require_package().version;
540
+ console.log(`Create Tina App v${version2}`);
541
+ const spinner = ora();
542
+ preRunChecks(spinner);
543
+ const opts = extractOptions(process.argv);
544
+ const telemetry = new import_metrics.Telemetry({ disabled: opts?.noTelemetry });
545
+ let template = null;
546
+ if (opts.template) {
547
+ template = TEMPLATES.find((_template) => _template.value === opts.template);
467
548
  if (!template) {
468
- log.err(
549
+ spinner.fail(
469
550
  `The provided template '${opts.template}' is invalid. Please provide one of the following: ${TEMPLATES.map(
470
551
  (x2) => x2.value
471
552
  )}`
@@ -476,7 +557,7 @@ async function run() {
476
557
  let pkgManager = opts.pkgManager;
477
558
  if (pkgManager) {
478
559
  if (!PKG_MANAGERS.find((_pkgManager) => _pkgManager === pkgManager)) {
479
- log.err(
560
+ spinner.fail(
480
561
  `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
481
562
  );
482
563
  (0, import_node_process.exit)(1);
@@ -490,7 +571,7 @@ async function run() {
490
571
  }
491
572
  }
492
573
  if (installedPkgManagers.length === 0) {
493
- log.err(
574
+ spinner.fail(
494
575
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
495
576
  );
496
577
  (0, import_node_process.exit)(1);
@@ -506,6 +587,7 @@ async function run() {
506
587
  if (!Object.hasOwn(res, "packageManager")) (0, import_node_process.exit)(1);
507
588
  pkgManager = res.packageManager;
508
589
  }
590
+ let projectName = opts.projectName;
509
591
  if (!projectName) {
510
592
  const res = await (0, import_prompts.default)({
511
593
  name: "name",
@@ -533,61 +615,106 @@ async function run() {
533
615
  if (!Object.hasOwn(res, "template")) (0, import_node_process.exit)(1);
534
616
  template = TEMPLATES.find((_template) => _template.value === res.template);
535
617
  }
618
+ let themeChoice;
619
+ if (template.value === "tina-docs") {
620
+ const res = await (0, import_prompts.default)({
621
+ name: "theme",
622
+ type: "select",
623
+ message: "What theme would you like to use?",
624
+ choices: THEMES
625
+ });
626
+ if (!Object.hasOwn(res, "theme")) (0, import_node_process.exit)(1);
627
+ themeChoice = res.theme;
628
+ }
536
629
  await telemetry.submitRecord({
537
630
  event: {
538
631
  name: "create-tina-app:invoke",
539
- template,
632
+ template: template.value,
540
633
  pkgManager
541
634
  }
542
635
  });
543
636
  const rootDir = import_node_path.default.join(process.cwd(), projectName);
544
637
  if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
545
- log.err(
638
+ spinner.fail(
546
639
  "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."
547
640
  );
548
641
  process.exit(1);
549
642
  }
550
- const appName = await setupProjectDirectory(rootDir);
643
+ let appName;
551
644
  try {
552
- await downloadTemplate(template, rootDir);
645
+ appName = await setupProjectDirectory(rootDir);
646
+ } catch (err) {
647
+ spinner.fail(err.message);
648
+ (0, import_node_process.exit)(1);
649
+ }
650
+ try {
651
+ await downloadTemplate(template, rootDir, spinner);
652
+ if (themeChoice) {
653
+ await updateThemeSettings(rootDir, themeChoice);
654
+ }
655
+ spinner.start("Downloading template...");
656
+ await downloadTemplate(template, rootDir, spinner);
657
+ spinner.succeed();
658
+ spinner.start("Updating project metadata...");
553
659
  updateProjectPackageName(rootDir, projectName);
554
660
  updateProjectPackageVersion(rootDir, "0.0.1");
661
+ spinner.succeed();
555
662
  } catch (err) {
556
- log.err(`Failed to download template: ${err.message}`);
663
+ spinner.fail(`Failed to download template: ${err.message}`);
557
664
  (0, import_node_process.exit)(1);
558
665
  }
559
- log.info("Installing packages.");
560
- await install(rootDir, null, { packageManager: pkgManager, isOnline: true });
561
- log.info("Initializing git repository.");
666
+ spinner.start("Installing packages.");
667
+ try {
668
+ await install(pkgManager, opts.verbose);
669
+ spinner.succeed();
670
+ } catch (err) {
671
+ spinner.fail(`Failed to install packages: ${err.message}`);
672
+ packageManagerInstallationHadError = true;
673
+ }
674
+ spinner.start("Initializing git repository.");
562
675
  try {
563
- if (initializeGit()) {
676
+ if (initializeGit(spinner)) {
564
677
  makeFirstCommit(rootDir);
565
- log.info("Initialized git repository.");
678
+ spinner.succeed();
566
679
  }
567
680
  } catch (err) {
568
- log.err("Failed to initialize Git repository, skipping.");
569
- }
570
- log.success("Starter successfully created!");
571
- log.log(TextStyles.bold("\nTo launch your app, run:\n"));
572
- log.cmd(`cd ${appName}
573
- ${pkgManager} run dev`);
574
- log.log(`
575
- Next steps:
576
- \u2022 \u{1F4DD} Edit some content on ${TextStyles.link(
577
- "http://localhost:3000"
578
- )} (See ${TextStyles.link("https://tina.io/docs/using-tina-editor")})
579
- \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}
580
- \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
581
- "https://tina.io/docs/advanced/extending-tina/"
582
- )}
583
- \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
584
- "https://tina.io/docs/tina-cloud/"
585
- )}
586
- `);
681
+ spinner.fail("Failed to initialize Git repository, skipping.");
682
+ }
683
+ spinner.succeed(`Created ${TextStyles.tinaOrange(appName)}
684
+ `);
685
+ if (template.value === "tina-hugo-starter") {
686
+ spinner.warn(
687
+ `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}
688
+ `
689
+ );
690
+ }
691
+ const padCommand = (cmd, width = 20) => TextStyles.cmd(cmd) + " ".repeat(Math.max(0, width - cmd.length));
692
+ spinner.info(`${TextStyles.bold("To get started:")}
693
+
694
+ ${padCommand(`cd ${appName}`)}# move into your project directory${packageManagerInstallationHadError ? `
695
+ ${padCommand(`${pkgManager} install`)}# install dependencies` : ""}
696
+ ${padCommand(`${pkgManager} run dev`)}# start the dev server ${TextStyles.link(template.devUrl)}
697
+ ${padCommand(`${pkgManager} run build`)}# build the app for production
698
+ `);
699
+ console.log("Next steps:");
700
+ console.log(
701
+ ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link("https://tina.io/docs/using-tina-editor")}`
702
+ );
703
+ console.log(
704
+ ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}`
705
+ );
706
+ console.log(
707
+ ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link("https://tina.io/docs/advanced/extending-tina/")}`
708
+ );
709
+ console.log(
710
+ ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link("https://tina.io/docs/tinacloud/")}`
711
+ );
587
712
  }
588
- run();
713
+ run().catch((error) => {
714
+ console.error("Error running create-tina-app:", error);
715
+ process.exit(1);
716
+ });
589
717
  // Annotate the CommonJS export names for ESM import in node:
590
718
  0 && (module.exports = {
591
- PKG_MANAGERS,
592
719
  run
593
720
  });
@@ -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 { PKG_MANAGERS } from '..';
2
- export declare function checkPackageExists(name: (typeof PKG_MANAGERS)[number]): Promise<boolean>;
1
+ import { PackageManager } from './packageManagers';
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,21 +1,7 @@
1
- interface InstallArgs {
2
- /**
3
- * The package manager to use (yarn, npm, pnpm).
4
- */
5
- packageManager: 'yarn' | 'npm' | 'pnpm';
6
- /**
7
- * Indicate whether there is an active Internet connection.
8
- */
9
- isOnline: boolean;
10
- /**
11
- * Indicate whether the given dependencies are devDependencies.
12
- */
13
- devDependencies?: boolean;
14
- }
1
+ import { PackageManager } from './packageManagers';
15
2
  /**
16
- * Spawn a package manager installation with Yarn, NPM, or PNPM.
3
+ * Spawn a package manager installation.
17
4
  *
18
5
  * @returns A Promise that resolves once the installation is finished.
19
6
  */
20
- export declare function install(root: string, dependencies: string[] | null, { packageManager, isOnline, devDependencies }: InstallArgs): Promise<void>;
21
- export {};
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": "0.0.0-d7c5ec1-20250219020924",
3
+ "version": "0.0.0-d9487bf-20251119052214",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",
@@ -35,17 +35,18 @@
35
35
  "@types/prompts": "^2.4.9",
36
36
  "@types/tar": "6.1.13",
37
37
  "typescript": "^5.7.3",
38
- "@tinacms/scripts": "0.0.0-d7c5ec1-20250219020924"
38
+ "@tinacms/scripts": "0.0.0-d9487bf-20251119052214"
39
39
  },
40
40
  "dependencies": {
41
41
  "chalk": "4.1.2",
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",
48
- "@tinacms/metrics": "0.0.0-d7c5ec1-20250219020924"
49
+ "@tinacms/metrics": "1.1.0"
49
50
  },
50
51
  "scripts": {
51
52
  "types": "pnpm tsc",
@@ -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;