create-zenith 1.3.19 → 1.3.20

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.
Files changed (40) hide show
  1. package/README.md +7 -0
  2. package/dist/cli.js +178 -18
  3. package/dist/index.js +178 -18
  4. package/package.json +4 -4
  5. package/templates/basic/LICENSE +21 -0
  6. package/templates/basic/README.md +11 -0
  7. package/templates/basic/package.json +18 -0
  8. package/templates/basic/src/layouts/DefaultLayout.zen +20 -0
  9. package/templates/basic/src/pages/index.zen +24 -0
  10. package/templates/basic/src/public/logo.svg +601 -0
  11. package/templates/basic/src/styles/global.css +61 -0
  12. package/templates/basic/tsconfig.json +30 -0
  13. package/templates/basic/zenith.config.js +5 -0
  14. package/templates/css/LICENSE +21 -0
  15. package/templates/css/README.md +11 -0
  16. package/templates/css/package.json +18 -0
  17. package/templates/css/src/layouts/DefaultLayout.zen +26 -0
  18. package/templates/css/src/pages/about.zen +19 -0
  19. package/templates/css/src/pages/blog.zen +19 -0
  20. package/templates/css/src/pages/docs.zen +19 -0
  21. package/templates/css/src/pages/index.zen +26 -0
  22. package/templates/css/src/public/logo.svg +601 -0
  23. package/templates/css/src/styles/global.css +66 -0
  24. package/templates/css/tsconfig.json +30 -0
  25. package/templates/css/zenith.config.js +4 -0
  26. package/templates/features/eslint/eslint.config.js +30 -0
  27. package/templates/features/prettier/.prettierignore +3 -0
  28. package/templates/features/prettier/.prettierrc +7 -0
  29. package/templates/tailwind/LICENSE +21 -0
  30. package/templates/tailwind/README.md +11 -0
  31. package/templates/tailwind/package.json +20 -0
  32. package/templates/tailwind/src/layouts/DefaultLayout.zen +28 -0
  33. package/templates/tailwind/src/pages/about.zen +20 -0
  34. package/templates/tailwind/src/pages/blog.zen +19 -0
  35. package/templates/tailwind/src/pages/docs.zen +19 -0
  36. package/templates/tailwind/src/pages/index.zen +31 -0
  37. package/templates/tailwind/src/public/logo.svg +601 -0
  38. package/templates/tailwind/src/styles/globals.css +3 -0
  39. package/templates/tailwind/tsconfig.json +30 -0
  40. package/templates/tailwind/zenith.config.js +4 -0
package/README.md CHANGED
@@ -17,6 +17,7 @@ The official CLI for scaffolding new Zenith applications. Fast, animated, and de
17
17
  - **Interactive UX**: Built with `@clack/prompts` for intuitive arrow-key navigation and clear visual indicators.
18
18
  - **Reliable Fallbacks**: Automatically detects CI environments and non-TTY pipes to provide clean, static output.
19
19
  - **Smart Detection**: automatically detects your preferred package manager (Bun, pnpm, Yarn, or npm).
20
+ - **Template Authority**: Scaffold generation now reads only from `templates/` (`basic`, `css`, `tailwind`), which is the single source of truth for starter projects.
20
21
  - **Tool-Agnostic Output**: ESLint, Prettier, and TypeScript path aliases are opt-in. If you answer `No`, the generated project contains no scripts, dependencies, config files, or ignore files for that tool.
21
22
 
22
23
  ## Quick Start
@@ -65,9 +66,15 @@ If you see version mismatches after install, delete `node_modules` and `package-
65
66
 
66
67
  - Generated apps now depend on `@zenithbuild/core@latest` so new installs track the current stable framework release.
67
68
  - Template downloads now resolve from `zenithbuild/framework`, which is the active monorepo source of truth.
69
+ - Starter templates now live under `templates/`, and the scaffolder no longer depends on `examples/`.
68
70
  - ESLint and Prettier are now feature overlays, so opting out leaves no stray config or dependency references in the scaffolded app.
69
71
  - Verified scaffold → install → build coverage lives in `tests/template-regression.spec.mjs`.
70
72
 
73
+ ## Templates vs Examples
74
+
75
+ - `templates/` is authoritative for scaffolding.
76
+ - `examples/` is demo-only when present and is not part of the scaffold source of truth.
77
+
71
78
  ## Development
72
79
 
73
80
  ```bash
package/dist/cli.js CHANGED
@@ -2553,6 +2553,33 @@ class dD extends x {
2553
2553
  }
2554
2554
  var A;
2555
2555
  A = new WeakMap;
2556
+ var OD = Object.defineProperty;
2557
+ var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
2558
+ var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
2559
+
2560
+ class LD extends x {
2561
+ constructor(u) {
2562
+ super(u, false), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
2563
+ switch (t) {
2564
+ case "left":
2565
+ case "up":
2566
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
2567
+ break;
2568
+ case "down":
2569
+ case "right":
2570
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
2571
+ break;
2572
+ }
2573
+ this.changeValue();
2574
+ });
2575
+ }
2576
+ get _value() {
2577
+ return this.options[this.cursor];
2578
+ }
2579
+ changeValue() {
2580
+ this.value = this._value.value;
2581
+ }
2582
+ }
2556
2583
  class RD extends x {
2557
2584
  get valueWithCursor() {
2558
2585
  if (this.state === "submit")
@@ -2615,6 +2642,16 @@ var b2 = (t) => {
2615
2642
  return import_picocolors3.default.green(C);
2616
2643
  }
2617
2644
  };
2645
+ var G2 = (t) => {
2646
+ const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
2647
+ let l2 = 0;
2648
+ n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
2649
+ const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
2650
+ return r2.slice(l2, l2 + a).map((p2, v2, f) => {
2651
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
2652
+ return j2 || E ? import_picocolors3.default.dim("...") : i(p2, v2 + l2 === n);
2653
+ });
2654
+ };
2618
2655
  var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
2619
2656
  const n = `${import_picocolors3.default.gray(o)}
2620
2657
  ${b2(this.state)} ${t.message}
@@ -2655,6 +2692,38 @@ ${import_picocolors3.default.cyan(d2)}
2655
2692
  }
2656
2693
  } }).prompt();
2657
2694
  };
2695
+ var ve = (t) => {
2696
+ const n = (r2, i) => {
2697
+ const s = r2.label ?? String(r2.value);
2698
+ switch (i) {
2699
+ case "selected":
2700
+ return `${import_picocolors3.default.dim(s)}`;
2701
+ case "active":
2702
+ return `${import_picocolors3.default.green(k2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}`;
2703
+ case "cancelled":
2704
+ return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
2705
+ default:
2706
+ return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
2707
+ }
2708
+ };
2709
+ return new LD({ options: t.options, initialValue: t.initialValue, render() {
2710
+ const r2 = `${import_picocolors3.default.gray(o)}
2711
+ ${b2(this.state)} ${t.message}
2712
+ `;
2713
+ switch (this.state) {
2714
+ case "submit":
2715
+ return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
2716
+ case "cancel":
2717
+ return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
2718
+ ${import_picocolors3.default.gray(o)}`;
2719
+ default:
2720
+ return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
2721
+ ${import_picocolors3.default.cyan(o)} `)}
2722
+ ${import_picocolors3.default.cyan(d2)}
2723
+ `;
2724
+ }
2725
+ } }).prompt();
2726
+ };
2658
2727
  var xe = (t = "") => {
2659
2728
  process.stdout.write(`${import_picocolors3.default.gray(d2)} ${import_picocolors3.default.red(t)}
2660
2729
 
@@ -2687,7 +2756,7 @@ var M2 = { message: (t = "", { symbol: n = import_picocolors3.default.gray(o) }
2687
2756
  }, error: (t) => {
2688
2757
  M2.message(t, { symbol: import_picocolors3.default.red(K2) });
2689
2758
  } };
2690
- var J = `${import_picocolors3.default.gray(o)} `;
2759
+ var J2 = `${import_picocolors3.default.gray(o)} `;
2691
2760
  var Y2 = ({ indicator: t = "dots" } = {}) => {
2692
2761
  const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
2693
2762
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
@@ -2777,6 +2846,12 @@ async function confirm(opts) {
2777
2846
  initialValue: opts.initialValue ?? true
2778
2847
  });
2779
2848
  }
2849
+ async function select(opts) {
2850
+ if (!isTTY()) {
2851
+ return opts.initialValue || opts.options[0]?.value;
2852
+ }
2853
+ return await ve(opts);
2854
+ }
2780
2855
  function isCancel(value) {
2781
2856
  return pD(value);
2782
2857
  }
@@ -2885,10 +2960,58 @@ function applyPackageFeatures(manifest, options) {
2885
2960
  return nextManifest;
2886
2961
  }
2887
2962
 
2963
+ // src/templates.ts
2964
+ var DEFAULT_TEMPLATE = "css";
2965
+ var TEMPLATE_DEFINITIONS = {
2966
+ basic: {
2967
+ name: "basic",
2968
+ label: "Basic",
2969
+ hint: "Blank starter with a single page and minimal CSS",
2970
+ templatePath: "templates/basic",
2971
+ usesTailwind: false
2972
+ },
2973
+ css: {
2974
+ name: "css",
2975
+ label: "CSS",
2976
+ hint: "Multi-page starter with a small curated CSS setup",
2977
+ templatePath: "templates/css",
2978
+ usesTailwind: false
2979
+ },
2980
+ tailwind: {
2981
+ name: "tailwind",
2982
+ label: "Tailwind",
2983
+ hint: "Multi-page starter with Tailwind enabled",
2984
+ templatePath: "templates/tailwind",
2985
+ usesTailwind: true
2986
+ }
2987
+ };
2988
+ var TEMPLATE_ALIASES = {
2989
+ starter: "css",
2990
+ "starter-tailwindcss": "tailwind"
2991
+ };
2992
+ function resolveTemplateName(value) {
2993
+ const normalized = String(value || "").trim().toLowerCase();
2994
+ if (!normalized) {
2995
+ return null;
2996
+ }
2997
+ if (normalized in TEMPLATE_DEFINITIONS) {
2998
+ return normalized;
2999
+ }
3000
+ return TEMPLATE_ALIASES[normalized] || null;
3001
+ }
3002
+ function getTemplateDefinition(templateName) {
3003
+ return TEMPLATE_DEFINITIONS[templateName];
3004
+ }
3005
+ function templateSelectOptions() {
3006
+ return Object.values(TEMPLATE_DEFINITIONS).map((definition) => ({
3007
+ value: definition.name,
3008
+ label: definition.label,
3009
+ hint: definition.hint
3010
+ }));
3011
+ }
3012
+
2888
3013
  // src/index.ts
2889
3014
  var GITHUB_REPO = "zenithbuild/framework";
2890
- var DEFAULT_TEMPLATE = "examples/starter";
2891
- var TAILWIND_TEMPLATE = "examples/starter-tailwindcss";
2892
3015
  var __filename2 = fileURLToPath(import.meta.url);
2893
3016
  var __dirname2 = path.dirname(__filename2);
2894
3017
  function getCliVersion() {
@@ -3011,10 +3134,23 @@ function readOptionOverride(name) {
3011
3134
  }
3012
3135
  return flagEnabled2(value);
3013
3136
  }
3014
- async function gatherOptions(providedName, withTailwind) {
3137
+ function readTemplateOverride(name) {
3138
+ const value = process.env[name];
3139
+ if (value == null || value.trim() === "") {
3140
+ return;
3141
+ }
3142
+ const templateName = resolveTemplateName(value);
3143
+ if (!templateName) {
3144
+ throw new Error(`Unsupported template "${value}". Use basic, css, or tailwind.`);
3145
+ }
3146
+ return templateName;
3147
+ }
3148
+ async function gatherOptions(providedName, requestedTemplate) {
3015
3149
  const eslintOverride = readOptionOverride("CREATE_ZENITH_ESLINT");
3016
3150
  const prettierOverride = readOptionOverride("CREATE_ZENITH_PRETTIER");
3017
3151
  const pathAliasOverride = readOptionOverride("CREATE_ZENITH_PATH_ALIAS");
3152
+ const templateOverride = readTemplateOverride("CREATE_ZENITH_TEMPLATE");
3153
+ const selectedTemplate = requestedTemplate || templateOverride || DEFAULT_TEMPLATE;
3018
3154
  let name = providedName;
3019
3155
  if (!name) {
3020
3156
  const nameResult = await text({
@@ -3055,15 +3191,17 @@ async function gatherOptions(providedName, withTailwind) {
3055
3191
  eslint: eslintOverride ?? true,
3056
3192
  prettier: prettierOverride ?? true,
3057
3193
  pathAlias: pathAliasOverride ?? true,
3058
- tailwind: withTailwind ?? false
3194
+ template: selectedTemplate
3059
3195
  };
3060
3196
  }
3061
- const tailwindResult = withTailwind !== undefined ? withTailwind : await confirm({
3062
- message: "Add Tailwind CSS for styling?",
3063
- initialValue: true
3197
+ const templateResult = requestedTemplate ?? templateOverride ?? await select({
3198
+ message: "Choose a starter template",
3199
+ options: templateSelectOptions(),
3200
+ initialValue: DEFAULT_TEMPLATE
3064
3201
  });
3065
- if (isCancel(tailwindResult))
3202
+ if (requestedTemplate === undefined && templateOverride === undefined && isCancel(templateResult)) {
3066
3203
  handleCancel();
3204
+ }
3067
3205
  const eslintResult = eslintOverride ?? await confirm({
3068
3206
  message: "Add ESLint for code linting?",
3069
3207
  initialValue: true
@@ -3087,12 +3225,12 @@ async function gatherOptions(providedName, withTailwind) {
3087
3225
  eslint: eslintResult,
3088
3226
  prettier: prettierResult,
3089
3227
  pathAlias: pathAliasResult,
3090
- tailwind: tailwindResult
3228
+ template: templateResult
3091
3229
  };
3092
3230
  }
3093
3231
  async function createProject(options) {
3094
3232
  const targetDir = path.resolve(process.cwd(), options.name);
3095
- const templatePath = options.tailwind ? TAILWIND_TEMPLATE : DEFAULT_TEMPLATE;
3233
+ const templatePath = getTemplateDefinition(options.template).templatePath;
3096
3234
  const templateFeaturePaths = selectedTemplateFeaturePaths(options);
3097
3235
  await downloadTemplate(targetDir, [templatePath, ...templateFeaturePaths]);
3098
3236
  const pkgPath = path.join(targetDir, "package.json");
@@ -3117,10 +3255,10 @@ async function createProject(options) {
3117
3255
  fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 4));
3118
3256
  }
3119
3257
  }
3120
- async function create(appName, withTailwind) {
3258
+ async function create(appName, requestedTemplate) {
3121
3259
  await intro();
3122
- const options = await gatherOptions(appName, withTailwind);
3123
- const templateLabel = options.tailwind ? "starter-tailwindcss" : "starter";
3260
+ const options = await gatherOptions(appName, requestedTemplate);
3261
+ const templateLabel = getTemplateDefinition(options.template).name;
3124
3262
  showScaffoldSummary(options.name, templateLabel);
3125
3263
  console.log("");
3126
3264
  log.step(`Creating ${bold(options.name)}...`);
@@ -3165,7 +3303,8 @@ if (args.includes("--help") || args.includes("-h")) {
3165
3303
  console.log("Options:");
3166
3304
  console.log(" -h, --help Show this help message");
3167
3305
  console.log(" -v, --version Show version number");
3168
- console.log(" --with-tailwind Initialize with Tailwind CSS v4 template");
3306
+ console.log(" --template <name> Choose template: basic, css, or tailwind");
3307
+ console.log(" --with-tailwind Alias for --template tailwind");
3169
3308
  console.log("");
3170
3309
  console.log("Examples:");
3171
3310
  console.log(" npx create-zenith my-app");
@@ -3178,9 +3317,30 @@ if (args.includes("--version") || args.includes("-v")) {
3178
3317
  console.log(`create-zenith ${VERSION}`);
3179
3318
  process.exit(0);
3180
3319
  }
3181
- var projectName = args.find((arg) => !arg.startsWith("-"));
3182
- var withTailwind = args.includes("--with-tailwind") ? true : undefined;
3183
- create(projectName, withTailwind).catch((err) => {
3320
+ var projectName;
3321
+ var requestedTemplate;
3322
+ for (let index = 0;index < args.length; index += 1) {
3323
+ const arg = args[index];
3324
+ if (arg === "--with-tailwind") {
3325
+ requestedTemplate = "tailwind";
3326
+ continue;
3327
+ }
3328
+ if (arg === "--template") {
3329
+ const templateValue = args[index + 1];
3330
+ const templateName = resolveTemplateName(templateValue);
3331
+ if (!templateName) {
3332
+ error(`Unsupported template "${templateValue || ""}". Use basic, css, or tailwind.`);
3333
+ process.exit(1);
3334
+ }
3335
+ requestedTemplate = templateName;
3336
+ index += 1;
3337
+ continue;
3338
+ }
3339
+ if (!arg.startsWith("-") && !projectName) {
3340
+ projectName = arg;
3341
+ }
3342
+ }
3343
+ create(projectName, requestedTemplate).catch((err) => {
3184
3344
  const mode = getUiMode(process);
3185
3345
  if (mode.plain) {
3186
3346
  console.log("ERROR: SCAFFOLD_ERROR");
package/dist/index.js CHANGED
@@ -2552,6 +2552,33 @@ class dD extends x {
2552
2552
  }
2553
2553
  var A;
2554
2554
  A = new WeakMap;
2555
+ var OD = Object.defineProperty;
2556
+ var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
2557
+ var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
2558
+
2559
+ class LD extends x {
2560
+ constructor(u) {
2561
+ super(u, false), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
2562
+ switch (t) {
2563
+ case "left":
2564
+ case "up":
2565
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
2566
+ break;
2567
+ case "down":
2568
+ case "right":
2569
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
2570
+ break;
2571
+ }
2572
+ this.changeValue();
2573
+ });
2574
+ }
2575
+ get _value() {
2576
+ return this.options[this.cursor];
2577
+ }
2578
+ changeValue() {
2579
+ this.value = this._value.value;
2580
+ }
2581
+ }
2555
2582
  class RD extends x {
2556
2583
  get valueWithCursor() {
2557
2584
  if (this.state === "submit")
@@ -2614,6 +2641,16 @@ var b2 = (t) => {
2614
2641
  return import_picocolors3.default.green(C);
2615
2642
  }
2616
2643
  };
2644
+ var G2 = (t) => {
2645
+ const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
2646
+ let l2 = 0;
2647
+ n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
2648
+ const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
2649
+ return r2.slice(l2, l2 + a).map((p2, v2, f) => {
2650
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
2651
+ return j2 || E ? import_picocolors3.default.dim("...") : i(p2, v2 + l2 === n);
2652
+ });
2653
+ };
2617
2654
  var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
2618
2655
  const n = `${import_picocolors3.default.gray(o)}
2619
2656
  ${b2(this.state)} ${t.message}
@@ -2654,6 +2691,38 @@ ${import_picocolors3.default.cyan(d2)}
2654
2691
  }
2655
2692
  } }).prompt();
2656
2693
  };
2694
+ var ve = (t) => {
2695
+ const n = (r2, i) => {
2696
+ const s = r2.label ?? String(r2.value);
2697
+ switch (i) {
2698
+ case "selected":
2699
+ return `${import_picocolors3.default.dim(s)}`;
2700
+ case "active":
2701
+ return `${import_picocolors3.default.green(k2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}`;
2702
+ case "cancelled":
2703
+ return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
2704
+ default:
2705
+ return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
2706
+ }
2707
+ };
2708
+ return new LD({ options: t.options, initialValue: t.initialValue, render() {
2709
+ const r2 = `${import_picocolors3.default.gray(o)}
2710
+ ${b2(this.state)} ${t.message}
2711
+ `;
2712
+ switch (this.state) {
2713
+ case "submit":
2714
+ return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
2715
+ case "cancel":
2716
+ return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
2717
+ ${import_picocolors3.default.gray(o)}`;
2718
+ default:
2719
+ return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
2720
+ ${import_picocolors3.default.cyan(o)} `)}
2721
+ ${import_picocolors3.default.cyan(d2)}
2722
+ `;
2723
+ }
2724
+ } }).prompt();
2725
+ };
2657
2726
  var xe = (t = "") => {
2658
2727
  process.stdout.write(`${import_picocolors3.default.gray(d2)} ${import_picocolors3.default.red(t)}
2659
2728
 
@@ -2686,7 +2755,7 @@ var M2 = { message: (t = "", { symbol: n = import_picocolors3.default.gray(o) }
2686
2755
  }, error: (t) => {
2687
2756
  M2.message(t, { symbol: import_picocolors3.default.red(K2) });
2688
2757
  } };
2689
- var J = `${import_picocolors3.default.gray(o)} `;
2758
+ var J2 = `${import_picocolors3.default.gray(o)} `;
2690
2759
  var Y2 = ({ indicator: t = "dots" } = {}) => {
2691
2760
  const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
2692
2761
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
@@ -2776,6 +2845,12 @@ async function confirm(opts) {
2776
2845
  initialValue: opts.initialValue ?? true
2777
2846
  });
2778
2847
  }
2848
+ async function select(opts) {
2849
+ if (!isTTY()) {
2850
+ return opts.initialValue || opts.options[0]?.value;
2851
+ }
2852
+ return await ve(opts);
2853
+ }
2779
2854
  function isCancel(value) {
2780
2855
  return pD(value);
2781
2856
  }
@@ -2884,10 +2959,58 @@ function applyPackageFeatures(manifest, options) {
2884
2959
  return nextManifest;
2885
2960
  }
2886
2961
 
2962
+ // src/templates.ts
2963
+ var DEFAULT_TEMPLATE = "css";
2964
+ var TEMPLATE_DEFINITIONS = {
2965
+ basic: {
2966
+ name: "basic",
2967
+ label: "Basic",
2968
+ hint: "Blank starter with a single page and minimal CSS",
2969
+ templatePath: "templates/basic",
2970
+ usesTailwind: false
2971
+ },
2972
+ css: {
2973
+ name: "css",
2974
+ label: "CSS",
2975
+ hint: "Multi-page starter with a small curated CSS setup",
2976
+ templatePath: "templates/css",
2977
+ usesTailwind: false
2978
+ },
2979
+ tailwind: {
2980
+ name: "tailwind",
2981
+ label: "Tailwind",
2982
+ hint: "Multi-page starter with Tailwind enabled",
2983
+ templatePath: "templates/tailwind",
2984
+ usesTailwind: true
2985
+ }
2986
+ };
2987
+ var TEMPLATE_ALIASES = {
2988
+ starter: "css",
2989
+ "starter-tailwindcss": "tailwind"
2990
+ };
2991
+ function resolveTemplateName(value) {
2992
+ const normalized = String(value || "").trim().toLowerCase();
2993
+ if (!normalized) {
2994
+ return null;
2995
+ }
2996
+ if (normalized in TEMPLATE_DEFINITIONS) {
2997
+ return normalized;
2998
+ }
2999
+ return TEMPLATE_ALIASES[normalized] || null;
3000
+ }
3001
+ function getTemplateDefinition(templateName) {
3002
+ return TEMPLATE_DEFINITIONS[templateName];
3003
+ }
3004
+ function templateSelectOptions() {
3005
+ return Object.values(TEMPLATE_DEFINITIONS).map((definition) => ({
3006
+ value: definition.name,
3007
+ label: definition.label,
3008
+ hint: definition.hint
3009
+ }));
3010
+ }
3011
+
2887
3012
  // src/index.ts
2888
3013
  var GITHUB_REPO = "zenithbuild/framework";
2889
- var DEFAULT_TEMPLATE = "examples/starter";
2890
- var TAILWIND_TEMPLATE = "examples/starter-tailwindcss";
2891
3014
  var __filename2 = fileURLToPath(import.meta.url);
2892
3015
  var __dirname2 = path.dirname(__filename2);
2893
3016
  function getCliVersion() {
@@ -3010,10 +3133,23 @@ function readOptionOverride(name) {
3010
3133
  }
3011
3134
  return flagEnabled2(value);
3012
3135
  }
3013
- async function gatherOptions(providedName, withTailwind) {
3136
+ function readTemplateOverride(name) {
3137
+ const value = process.env[name];
3138
+ if (value == null || value.trim() === "") {
3139
+ return;
3140
+ }
3141
+ const templateName = resolveTemplateName(value);
3142
+ if (!templateName) {
3143
+ throw new Error(`Unsupported template "${value}". Use basic, css, or tailwind.`);
3144
+ }
3145
+ return templateName;
3146
+ }
3147
+ async function gatherOptions(providedName, requestedTemplate) {
3014
3148
  const eslintOverride = readOptionOverride("CREATE_ZENITH_ESLINT");
3015
3149
  const prettierOverride = readOptionOverride("CREATE_ZENITH_PRETTIER");
3016
3150
  const pathAliasOverride = readOptionOverride("CREATE_ZENITH_PATH_ALIAS");
3151
+ const templateOverride = readTemplateOverride("CREATE_ZENITH_TEMPLATE");
3152
+ const selectedTemplate = requestedTemplate || templateOverride || DEFAULT_TEMPLATE;
3017
3153
  let name = providedName;
3018
3154
  if (!name) {
3019
3155
  const nameResult = await text({
@@ -3054,15 +3190,17 @@ async function gatherOptions(providedName, withTailwind) {
3054
3190
  eslint: eslintOverride ?? true,
3055
3191
  prettier: prettierOverride ?? true,
3056
3192
  pathAlias: pathAliasOverride ?? true,
3057
- tailwind: withTailwind ?? false
3193
+ template: selectedTemplate
3058
3194
  };
3059
3195
  }
3060
- const tailwindResult = withTailwind !== undefined ? withTailwind : await confirm({
3061
- message: "Add Tailwind CSS for styling?",
3062
- initialValue: true
3196
+ const templateResult = requestedTemplate ?? templateOverride ?? await select({
3197
+ message: "Choose a starter template",
3198
+ options: templateSelectOptions(),
3199
+ initialValue: DEFAULT_TEMPLATE
3063
3200
  });
3064
- if (isCancel(tailwindResult))
3201
+ if (requestedTemplate === undefined && templateOverride === undefined && isCancel(templateResult)) {
3065
3202
  handleCancel();
3203
+ }
3066
3204
  const eslintResult = eslintOverride ?? await confirm({
3067
3205
  message: "Add ESLint for code linting?",
3068
3206
  initialValue: true
@@ -3086,12 +3224,12 @@ async function gatherOptions(providedName, withTailwind) {
3086
3224
  eslint: eslintResult,
3087
3225
  prettier: prettierResult,
3088
3226
  pathAlias: pathAliasResult,
3089
- tailwind: tailwindResult
3227
+ template: templateResult
3090
3228
  };
3091
3229
  }
3092
3230
  async function createProject(options) {
3093
3231
  const targetDir = path.resolve(process.cwd(), options.name);
3094
- const templatePath = options.tailwind ? TAILWIND_TEMPLATE : DEFAULT_TEMPLATE;
3232
+ const templatePath = getTemplateDefinition(options.template).templatePath;
3095
3233
  const templateFeaturePaths = selectedTemplateFeaturePaths(options);
3096
3234
  await downloadTemplate(targetDir, [templatePath, ...templateFeaturePaths]);
3097
3235
  const pkgPath = path.join(targetDir, "package.json");
@@ -3116,10 +3254,10 @@ async function createProject(options) {
3116
3254
  fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 4));
3117
3255
  }
3118
3256
  }
3119
- async function create(appName, withTailwind) {
3257
+ async function create(appName, requestedTemplate) {
3120
3258
  await intro();
3121
- const options = await gatherOptions(appName, withTailwind);
3122
- const templateLabel = options.tailwind ? "starter-tailwindcss" : "starter";
3259
+ const options = await gatherOptions(appName, requestedTemplate);
3260
+ const templateLabel = getTemplateDefinition(options.template).name;
3123
3261
  showScaffoldSummary(options.name, templateLabel);
3124
3262
  console.log("");
3125
3263
  log.step(`Creating ${bold(options.name)}...`);
@@ -3164,7 +3302,8 @@ if (args.includes("--help") || args.includes("-h")) {
3164
3302
  console.log("Options:");
3165
3303
  console.log(" -h, --help Show this help message");
3166
3304
  console.log(" -v, --version Show version number");
3167
- console.log(" --with-tailwind Initialize with Tailwind CSS v4 template");
3305
+ console.log(" --template <name> Choose template: basic, css, or tailwind");
3306
+ console.log(" --with-tailwind Alias for --template tailwind");
3168
3307
  console.log("");
3169
3308
  console.log("Examples:");
3170
3309
  console.log(" npx create-zenith my-app");
@@ -3177,9 +3316,30 @@ if (args.includes("--version") || args.includes("-v")) {
3177
3316
  console.log(`create-zenith ${VERSION}`);
3178
3317
  process.exit(0);
3179
3318
  }
3180
- var projectName = args.find((arg) => !arg.startsWith("-"));
3181
- var withTailwind = args.includes("--with-tailwind") ? true : undefined;
3182
- create(projectName, withTailwind).catch((err) => {
3319
+ var projectName;
3320
+ var requestedTemplate;
3321
+ for (let index = 0;index < args.length; index += 1) {
3322
+ const arg = args[index];
3323
+ if (arg === "--with-tailwind") {
3324
+ requestedTemplate = "tailwind";
3325
+ continue;
3326
+ }
3327
+ if (arg === "--template") {
3328
+ const templateValue = args[index + 1];
3329
+ const templateName = resolveTemplateName(templateValue);
3330
+ if (!templateName) {
3331
+ error(`Unsupported template "${templateValue || ""}". Use basic, css, or tailwind.`);
3332
+ process.exit(1);
3333
+ }
3334
+ requestedTemplate = templateName;
3335
+ index += 1;
3336
+ continue;
3337
+ }
3338
+ if (!arg.startsWith("-") && !projectName) {
3339
+ projectName = arg;
3340
+ }
3341
+ }
3342
+ create(projectName, requestedTemplate).catch((err) => {
3183
3343
  const mode = getUiMode(process);
3184
3344
  if (mode.plain) {
3185
3345
  console.log("ERROR: SCAFFOLD_ERROR");
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "create-zenith",
3
- "version": "1.3.19",
3
+ "version": "1.3.20",
4
4
  "description": "Create a new Zenith application - the modern reactive web framework",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "create-zenith": "dist/cli.js"
8
8
  },
9
9
  "files": [
10
- "dist/**"
10
+ "dist/**",
11
+ "templates/**"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "bun build src/index.ts --outdir dist --target node --format esm && node -e \"const fs=require('fs');const c=fs.readFileSync('dist/index.js','utf8');fs.writeFileSync('dist/cli.js','#!/usr/bin/env node\\n'+c);fs.chmodSync('dist/cli.js','755')\"",
14
15
  "prepublishOnly": "npm run build",
15
16
  "create": "bun src/index.ts",
16
- "example": "rm -rf examples/test-template && bun src/index.ts test-template && mv test-template examples/",
17
- "test": "node --test tests/*.spec.mjs",
17
+ "test": "bun run build && node --test tests/*.spec.mjs",
18
18
  "release": "bun run scripts/release.ts",
19
19
  "release:dry": "bun run scripts/release.ts --dry-run",
20
20
  "release:patch": "bun run scripts/release.ts --bump=patch",
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zenith Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ # Zenith Basic Starter
2
+
3
+ Minimal single-page Zenith starter scaffolded from `create-zenith`.
4
+
5
+ ## Scripts
6
+
7
+ ```bash
8
+ npm run dev
9
+ npm run build
10
+ npm run preview
11
+ ```