create-bearnie 0.4.4 → 0.6.0

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 (2) hide show
  1. package/dist/index.js +132 -29
  2. package/package.json +7 -3
package/dist/index.js CHANGED
@@ -13,6 +13,39 @@ var link = (text, url) => `\x1B]8;;${url}\x07${pc.cyan(text)}\x1B]8;;\x07`;
13
13
  function parseFullArg() {
14
14
  return process.argv.includes("--full");
15
15
  }
16
+ function parseThemeArg() {
17
+ const argv = process.argv;
18
+ for (let i = 2; i < argv.length; i++) {
19
+ if (argv[i].startsWith("--theme=")) {
20
+ return argv[i].slice("--theme=".length) || null;
21
+ }
22
+ if (argv[i] === "--theme") {
23
+ return argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[i + 1] : null;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ function isThemeEntry(name) {
29
+ return name === "styles" || name.startsWith("styles-");
30
+ }
31
+ function composeThemeName(base, accent) {
32
+ if (base === "neutral") return accent;
33
+ if (accent === "default") return base;
34
+ return `${base}-${accent}`;
35
+ }
36
+ function detectPackageManager() {
37
+ const userAgent = process.env.npm_config_user_agent ?? "";
38
+ if (userAgent.startsWith("pnpm")) return "pnpm";
39
+ if (userAgent.startsWith("yarn")) return "yarn";
40
+ if (userAgent.startsWith("bun")) return "bun";
41
+ return "npm";
42
+ }
43
+ var PM_COMMANDS = {
44
+ npm: { install: "npm install", dev: "npm run dev", dlx: "npx" },
45
+ pnpm: { install: "pnpm install", dev: "pnpm dev", dlx: "pnpm dlx" },
46
+ yarn: { install: "yarn", dev: "yarn dev", dlx: "yarn dlx" },
47
+ bun: { install: "bun install", dev: "bun run dev", dlx: "bunx" }
48
+ };
16
49
  var REGISTRY_URL = process.env.BEARNIE_REGISTRY_URL || "https://bearnie.dev/registry";
17
50
  var REGISTRY_PATH = process.env.BEARNIE_REGISTRY_PATH;
18
51
  var BEARNIE_CONFIG = {
@@ -22,15 +55,24 @@ var BEARNIE_CONFIG = {
22
55
  tailwindConfig: "tailwind.config.mjs",
23
56
  typescript: true
24
57
  };
25
- var UTILITY_NAMES = [
58
+ var FALLBACK_UTILITY_NAMES = [
59
+ "cn",
26
60
  "focus-trap",
27
61
  "ui-runtime-loader",
28
- "ui-runtime-boot",
62
+ "ui-runtime-dialog",
29
63
  "ui-runtime-disclosure-triggers",
64
+ "ui-runtime-dropdown-menu",
30
65
  "ui-runtime-popover",
31
66
  "ui-runtime-command",
32
- "ui-runtime-combobox"
67
+ "ui-runtime-combobox",
68
+ "ui-runtime-tabs"
33
69
  ];
70
+ var DEP_VERSIONS = {
71
+ clsx: "^2.1.1",
72
+ "tailwind-merge": "^3.6.0",
73
+ "keen-slider": "^6.8.6",
74
+ "@hugeicons/core-free-icons": "^4.2.3"
75
+ };
34
76
  function resolveInstallPath(targetDir, filePath, type) {
35
77
  if (type === "utility" || filePath.startsWith("utils/")) {
36
78
  return path.join(targetDir, "src/utils", filePath.replace(/^utils\//, ""));
@@ -70,10 +112,12 @@ async function fetchRegistryIndex() {
70
112
  }
71
113
  return await response.json();
72
114
  }
73
- async function writeBearnieConfig(targetDir) {
74
- await fs.writeJson(path.join(targetDir, "bearnie.json"), BEARNIE_CONFIG, {
75
- spaces: 2
76
- });
115
+ async function writeBearnieConfig(targetDir, theme) {
116
+ await fs.writeJson(
117
+ path.join(targetDir, "bearnie.json"),
118
+ { ...BEARNIE_CONFIG, theme },
119
+ { spaces: 2 }
120
+ );
77
121
  }
78
122
  async function writeRegistryFiles(targetDir, entry) {
79
123
  for (const file of entry.files) {
@@ -117,6 +161,54 @@ ${fullInstall ? ` ${pc.dim("Full install: including all components")}
117
161
  }
118
162
  const finalName = projectName;
119
163
  const targetDir = path.resolve(process.cwd(), finalName);
164
+ let availableThemes = ["default"];
165
+ let themeBases = ["neutral"];
166
+ let themeAccents = ["default"];
167
+ try {
168
+ const index = await fetchRegistryIndex();
169
+ if (index.themes?.length) availableThemes = index.themes;
170
+ if (index.themeBases?.length) themeBases = index.themeBases;
171
+ if (index.themeAccents?.length) themeAccents = index.themeAccents;
172
+ } catch {
173
+ }
174
+ let theme = parseThemeArg();
175
+ if (theme && !availableThemes.includes(theme)) {
176
+ console.log(
177
+ `
178
+ ${pc.red("Unknown theme:")} ${theme}
179
+ Themes combine a base and an accent, e.g. ${pc.cyan("slate-blue")}.
180
+ Bases: ${themeBases.join(", ")}
181
+ Accents: ${themeAccents.join(", ")}
182
+ `
183
+ );
184
+ process.exit(1);
185
+ }
186
+ if (!theme && (themeBases.length > 1 || themeAccents.length > 1) && process.stdin.isTTY) {
187
+ const response = await prompts([
188
+ {
189
+ type: "select",
190
+ name: "base",
191
+ message: "Base color (grays and surfaces)",
192
+ choices: themeBases.map((name) => ({ title: name, value: name })),
193
+ initial: 0
194
+ },
195
+ {
196
+ type: "select",
197
+ name: "accent",
198
+ message: "Accent color (buttons, focus rings)",
199
+ choices: themeAccents.map((name) => ({
200
+ title: name === "default" ? "default (neutral)" : name,
201
+ value: name
202
+ })),
203
+ initial: 0
204
+ }
205
+ ]);
206
+ theme = composeThemeName(
207
+ response.base ?? "neutral",
208
+ response.accent ?? "default"
209
+ );
210
+ }
211
+ theme = theme ?? "default";
120
212
  if (fs.existsSync(targetDir)) {
121
213
  const { overwrite } = await prompts({
122
214
  type: "confirm",
@@ -141,39 +233,45 @@ ${fullInstall ? ` ${pc.dim("Full install: including all components")}
141
233
  const pkg = await fs.readJson(pkgPath);
142
234
  pkg.name = finalName;
143
235
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
144
- await writeBearnieConfig(targetDir);
236
+ await writeBearnieConfig(targetDir, theme);
237
+ if (theme !== "default") {
238
+ const themeEntry = await fetchRegistryEntry(`styles-${theme}`);
239
+ if (themeEntry?.files) {
240
+ await writeRegistryFiles(targetDir, themeEntry);
241
+ console.log(` ${pc.green("\u2713")} Applied ${theme} theme`);
242
+ } else {
243
+ console.log(
244
+ ` ${pc.yellow("!")} Couldn't fetch the ${theme} theme \u2014 using default`
245
+ );
246
+ }
247
+ }
145
248
  if (fullInstall) {
146
249
  console.log(`
147
250
  ${pc.dim("Fetching components from registry...")}
148
251
  `);
149
252
  await fs.ensureDir(path.join(targetDir, "src", "components", "bearnie"));
150
253
  await fs.ensureDir(path.join(targetDir, "src", "utils"));
151
- for (const utilityName of UTILITY_NAMES) {
254
+ const registryIndex = await fetchRegistryIndex();
255
+ const npmDependencies = /* @__PURE__ */ new Set(["clsx", "tailwind-merge"]);
256
+ const utilityNames = registryIndex.utilities?.length ? registryIndex.utilities.map((utility) => utility.name) : FALLBACK_UTILITY_NAMES;
257
+ for (const utilityName of utilityNames) {
152
258
  const utility = await fetchRegistryEntry(utilityName);
153
259
  if (utility?.files) {
154
260
  await writeRegistryFiles(targetDir, utility);
261
+ utility.dependencies?.forEach((dep) => npmDependencies.add(dep));
155
262
  console.log(` ${pc.green("\u2713")} Added ${utilityName} utility`);
156
263
  } else {
157
264
  console.log(` ${pc.yellow("!")} Failed to fetch ${utilityName} utility`);
158
265
  }
159
266
  }
160
- const cnContent = `import { clsx, type ClassValue } from "clsx";
161
- import { twMerge } from "tailwind-merge";
162
-
163
- export function cn(...inputs: ClassValue[]) {
164
- return twMerge(clsx(inputs));
165
- }
166
- `;
167
- await fs.writeFile(path.join(targetDir, "src", "utils", "cn.ts"), cnContent);
168
- console.log(` ${pc.green("\u2713")} Added cn utility`);
169
- const registryIndex = await fetchRegistryIndex();
170
- const componentNames = registryIndex.components.map((component) => component.name).filter((name) => name !== "styles" && name !== "barrel");
267
+ const componentNames = registryIndex.components.map((component) => component.name).filter((name) => !isThemeEntry(name) && name !== "barrel");
171
268
  let installed = 0;
172
269
  let failed = 0;
173
270
  for (const componentName of componentNames) {
174
271
  const component = await fetchRegistryEntry(componentName);
175
272
  if (component?.files) {
176
273
  await writeRegistryFiles(targetDir, component);
274
+ component.dependencies?.forEach((dep) => npmDependencies.add(dep));
177
275
  installed++;
178
276
  process.stdout.write(
179
277
  `\r ${pc.green("\u2713")} Installed ${installed}/${componentNames.length} components`
@@ -195,13 +293,17 @@ export function cn(...inputs: ClassValue[]) {
195
293
  }
196
294
  const pkgPath2 = path.join(targetDir, "package.json");
197
295
  const pkg2 = await fs.readJson(pkgPath2);
296
+ const addedDeps = Object.fromEntries(
297
+ [...npmDependencies].sort().map((dep) => [dep, DEP_VERSIONS[dep] ?? "latest"])
298
+ );
198
299
  pkg2.dependencies = {
199
300
  ...pkg2.dependencies,
200
- clsx: "^2.1.1",
201
- "tailwind-merge": "^3.3.0"
301
+ ...addedDeps
202
302
  };
203
303
  await fs.writeJson(pkgPath2, pkg2, { spaces: 2 });
204
- console.log(` ${pc.green("\u2713")} Added component dependencies`);
304
+ console.log(
305
+ ` ${pc.green("\u2713")} Added ${Object.keys(addedDeps).length} npm dependencies (${Object.keys(addedDeps).join(", ")})`
306
+ );
205
307
  }
206
308
  await fs.writeFile(
207
309
  path.join(targetDir, ".gitignore"),
@@ -229,6 +331,7 @@ Thumbs.db
229
331
  `
230
332
  );
231
333
  console.log(` ${pc.green("\u2713")} Created project files`);
334
+ const pmCommands = PM_COMMANDS[detectPackageManager()];
232
335
  if (fullInstall) {
233
336
  console.log(`
234
337
  ${pc.green("Done!")} Your Bearnie project is ready with all components.
@@ -236,8 +339,8 @@ Thumbs.db
236
339
  ${pc.bold("Next steps:")}
237
340
 
238
341
  ${pc.dim("1.")} cd ${pc.cyan(finalName)}
239
- ${pc.dim("2.")} npm install
240
- ${pc.dim("3.")} npm run dev
342
+ ${pc.dim("2.")} ${pmCommands.install}
343
+ ${pc.dim("3.")} ${pmCommands.dev}
241
344
 
242
345
  ${pc.dim("All components are in")} ${pc.cyan("src/components/bearnie/")}
243
346
  ${pc.dim("Import from")} ${pc.cyan("@/components/bearnie")} ${pc.dim("via")} ${pc.cyan("index.ts")}
@@ -253,12 +356,12 @@ Thumbs.db
253
356
  ${pc.bold("Next steps:")}
254
357
 
255
358
  ${pc.dim("1.")} cd ${pc.cyan(finalName)}
256
- ${pc.dim("2.")} npm install
257
- ${pc.dim("3.")} npx bearnie add button card
258
- ${pc.dim("4.")} npm run dev
359
+ ${pc.dim("2.")} ${pmCommands.install}
360
+ ${pc.dim("3.")} ${pmCommands.dlx} bearnie add button card
361
+ ${pc.dim("4.")} ${pmCommands.dev}
259
362
 
260
363
  ${pc.dim("Or use")} ${pc.cyan("--full")} ${pc.dim("to include all components:")}
261
- npx create-bearnie my-app --full
364
+ ${pmCommands.dlx} create-bearnie my-app --full
262
365
 
263
366
  ${pc.dim("Browse components at")} ${link("bearnie.dev/docs/components", "https://bearnie.dev/docs/components")}
264
367
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bearnie",
3
- "version": "0.4.4",
3
+ "version": "0.6.0",
4
4
  "description": "Create a new Astro project with Bearnie UI components",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,13 +23,13 @@
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/fs-extra": "^11.0.4",
26
- "@types/node": "^20.14.9",
26
+ "@types/node": "^22.10.0",
27
27
  "@types/prompts": "^2.4.9",
28
28
  "tsup": "^8.1.0",
29
29
  "typescript": "^5.7.3"
30
30
  },
31
31
  "engines": {
32
- "node": ">=18"
32
+ "node": ">=22.12.0"
33
33
  },
34
34
  "author": "Michael Andreuzza",
35
35
  "repository": {
@@ -37,6 +37,10 @@
37
37
  "url": "https://github.com/michael-andreuzza/bearnie.git",
38
38
  "directory": "packages/create-bearnie"
39
39
  },
40
+ "homepage": "https://bearnie.dev",
41
+ "bugs": {
42
+ "url": "https://github.com/michael-andreuzza/bearnie/issues"
43
+ },
40
44
  "keywords": [
41
45
  "create",
42
46
  "bearnie",