zerozeeker 2.2.3 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +178 -87
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
6
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
7
7
|
import { join, dirname } from "path";
|
|
8
|
-
import readline from "readline";
|
|
8
|
+
import * as readline from "readline/promises";
|
|
9
9
|
import ora from "ora";
|
|
10
10
|
import chalk from "chalk";
|
|
11
11
|
var REGISTRY_URL = "https://www.zerozeeker.com/r";
|
|
@@ -18,12 +18,24 @@ var COMPONENTS = [
|
|
|
18
18
|
"circle-reveal-button",
|
|
19
19
|
"index"
|
|
20
20
|
];
|
|
21
|
-
async function fetchRegistry(url) {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
async function fetchRegistry(url, retries = 3) {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
26
|
+
clearTimeout(timeoutId);
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
throw new Error(`Failed to fetch registry: ${response.statusText}`);
|
|
29
|
+
}
|
|
30
|
+
return response.json();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
clearTimeout(timeoutId);
|
|
33
|
+
if (retries > 0 && error instanceof Error && error.name !== "AbortError") {
|
|
34
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
35
|
+
return fetchRegistry(url, retries - 1);
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
25
38
|
}
|
|
26
|
-
return response.json();
|
|
27
39
|
}
|
|
28
40
|
function ensureDir(filePath) {
|
|
29
41
|
const dir = dirname(filePath);
|
|
@@ -33,7 +45,8 @@ function ensureDir(filePath) {
|
|
|
33
45
|
}
|
|
34
46
|
function findProjectRoot() {
|
|
35
47
|
let currentDir = process.cwd();
|
|
36
|
-
|
|
48
|
+
const root = dirname(currentDir);
|
|
49
|
+
while (currentDir !== root) {
|
|
37
50
|
if (existsSync(join(currentDir, "package.json"))) {
|
|
38
51
|
return currentDir;
|
|
39
52
|
}
|
|
@@ -41,40 +54,73 @@ function findProjectRoot() {
|
|
|
41
54
|
}
|
|
42
55
|
throw new Error("Could not find project root (no package.json found)");
|
|
43
56
|
}
|
|
57
|
+
function detectPackageManager() {
|
|
58
|
+
const projectRoot = process.cwd();
|
|
59
|
+
if (existsSync(join(projectRoot, "bun.lockb"))) return "bun";
|
|
60
|
+
if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
61
|
+
if (existsSync(join(projectRoot, "yarn.lock"))) return "yarn";
|
|
62
|
+
return "npm";
|
|
63
|
+
}
|
|
64
|
+
function getInstallCommand(deps) {
|
|
65
|
+
const pm = detectPackageManager();
|
|
66
|
+
const depsStr = deps.join(" ");
|
|
67
|
+
switch (pm) {
|
|
68
|
+
case "bun":
|
|
69
|
+
return `bun add ${depsStr}`;
|
|
70
|
+
case "pnpm":
|
|
71
|
+
return `pnpm add ${depsStr}`;
|
|
72
|
+
case "yarn":
|
|
73
|
+
return `yarn add ${depsStr}`;
|
|
74
|
+
default:
|
|
75
|
+
return `npm install ${depsStr}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
44
78
|
function installDependencies(deps) {
|
|
45
79
|
if (deps.length === 0) return;
|
|
80
|
+
const command = getInstallCommand(deps);
|
|
46
81
|
console.log(chalk.dim(` Installing dependencies: ${deps.join(", ")}`));
|
|
47
82
|
try {
|
|
48
|
-
execSync(
|
|
83
|
+
execSync(command, {
|
|
49
84
|
stdio: "pipe",
|
|
50
85
|
encoding: "utf-8"
|
|
51
86
|
});
|
|
52
87
|
} catch {
|
|
53
|
-
console.warn(chalk.yellow(` [!] Failed to auto-install dependencies. Install manually:
|
|
88
|
+
console.warn(chalk.yellow(` [!] Failed to auto-install dependencies. Install manually: ${command}`));
|
|
54
89
|
}
|
|
55
90
|
}
|
|
56
91
|
async function askYesNo(question, defaultYes = false) {
|
|
57
|
-
const rl = readline.createInterface({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
rl.close();
|
|
61
|
-
const a = answer.trim().toLowerCase();
|
|
62
|
-
if (a === "") return resolve(defaultYes);
|
|
63
|
-
if (["y", "yes"].includes(a)) return resolve(true);
|
|
64
|
-
return resolve(false);
|
|
65
|
-
});
|
|
92
|
+
const rl = readline.createInterface({
|
|
93
|
+
input: process.stdin,
|
|
94
|
+
output: process.stdout
|
|
66
95
|
});
|
|
96
|
+
try {
|
|
97
|
+
const answer = await rl.question(`${question} (${defaultYes ? "Y/n" : "y/N"}): `);
|
|
98
|
+
const normalized = answer.trim().toLowerCase();
|
|
99
|
+
if (normalized === "") return defaultYes;
|
|
100
|
+
return ["y", "yes"].includes(normalized);
|
|
101
|
+
} finally {
|
|
102
|
+
rl.close();
|
|
103
|
+
}
|
|
67
104
|
}
|
|
68
105
|
async function installRegistryDependencies(deps, projectRoot, installed = /* @__PURE__ */ new Set()) {
|
|
69
106
|
const allFiles = [];
|
|
70
107
|
const allNpmDeps = [];
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
try {
|
|
108
|
+
const results = await Promise.allSettled(
|
|
109
|
+
deps.filter((dep) => !installed.has(dep)).map(async (dep) => {
|
|
110
|
+
installed.add(dep);
|
|
111
|
+
const url = `${REGISTRY_URL}/${dep}.json`;
|
|
76
112
|
const registry = await fetchRegistry(url);
|
|
77
|
-
|
|
113
|
+
return { dep, registry };
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
for (const result of results) {
|
|
117
|
+
if (result.status === "rejected") {
|
|
118
|
+
console.warn(chalk.yellow(` [!] Could not fetch registry dependency`));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const { dep, registry } = result.value;
|
|
122
|
+
try {
|
|
123
|
+
if (registry.registryDependencies?.length) {
|
|
78
124
|
const nested = await installRegistryDependencies(
|
|
79
125
|
registry.registryDependencies,
|
|
80
126
|
projectRoot,
|
|
@@ -83,13 +129,11 @@ async function installRegistryDependencies(deps, projectRoot, installed = /* @__
|
|
|
83
129
|
allFiles.push(...nested.files);
|
|
84
130
|
allNpmDeps.push(...nested.npmDeps);
|
|
85
131
|
}
|
|
86
|
-
if (registry.files
|
|
132
|
+
if (registry.files?.length) {
|
|
87
133
|
for (const file of registry.files) {
|
|
88
134
|
const targetPath = file.target || file.path;
|
|
89
135
|
const fullPath = join(projectRoot, targetPath);
|
|
90
|
-
if (existsSync(fullPath))
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
136
|
+
if (existsSync(fullPath)) continue;
|
|
93
137
|
ensureDir(fullPath);
|
|
94
138
|
writeFileSync(fullPath, file.content, "utf-8");
|
|
95
139
|
allFiles.push(targetPath);
|
|
@@ -104,27 +148,33 @@ async function installRegistryDependencies(deps, projectRoot, installed = /* @__
|
|
|
104
148
|
}
|
|
105
149
|
return { files: allFiles, npmDeps: allNpmDeps };
|
|
106
150
|
}
|
|
151
|
+
function parseJsonFile(filePath) {
|
|
152
|
+
try {
|
|
153
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
107
158
|
function checkTypeScriptConfig(projectRoot) {
|
|
108
159
|
const tsconfigPath = join(projectRoot, "tsconfig.json");
|
|
109
160
|
if (!existsSync(tsconfigPath)) {
|
|
110
161
|
return { name: "TypeScript", passed: false, message: "tsconfig.json not found" };
|
|
111
162
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const paths = tsconfig.compilerOptions?.paths || {};
|
|
115
|
-
const hasComponentsAlias = paths["@/components/*"] || paths["@/components"];
|
|
116
|
-
const hasLibAlias = paths["@/lib/*"] || paths["@/lib"];
|
|
117
|
-
if (hasComponentsAlias && hasLibAlias) {
|
|
118
|
-
return { name: "TypeScript paths", passed: true };
|
|
119
|
-
}
|
|
120
|
-
return {
|
|
121
|
-
name: "TypeScript paths",
|
|
122
|
-
passed: false,
|
|
123
|
-
message: "Missing @/components or @/lib path aliases"
|
|
124
|
-
};
|
|
125
|
-
} catch {
|
|
163
|
+
const tsconfig = parseJsonFile(tsconfigPath);
|
|
164
|
+
if (!tsconfig) {
|
|
126
165
|
return { name: "TypeScript config", passed: false, message: "Invalid tsconfig.json" };
|
|
127
166
|
}
|
|
167
|
+
const paths = tsconfig.compilerOptions?.paths ?? {};
|
|
168
|
+
const hasComponentsAlias = "@/components/*" in paths || "@/components" in paths;
|
|
169
|
+
const hasLibAlias = "@/lib/*" in paths || "@/lib" in paths;
|
|
170
|
+
if (hasComponentsAlias && hasLibAlias) {
|
|
171
|
+
return { name: "TypeScript paths", passed: true };
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
name: "TypeScript paths",
|
|
175
|
+
passed: false,
|
|
176
|
+
message: "Missing @/components or @/lib path aliases"
|
|
177
|
+
};
|
|
128
178
|
}
|
|
129
179
|
function checkTailwindConfig(projectRoot) {
|
|
130
180
|
const tailwindConfigs = [
|
|
@@ -137,63 +187,105 @@ function checkTailwindConfig(projectRoot) {
|
|
|
137
187
|
return hasTailwind ? { name: "Tailwind CSS", passed: true } : { name: "Tailwind CSS", passed: false, message: "Config file not found" };
|
|
138
188
|
}
|
|
139
189
|
function checkFramework(projectRoot) {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (deps.next) {
|
|
144
|
-
return { name: "Next.js", passed: true };
|
|
145
|
-
}
|
|
146
|
-
if (deps.react) {
|
|
147
|
-
return { name: "React", passed: true };
|
|
190
|
+
const packageJson = parseJsonFile(join(projectRoot, "package.json"));
|
|
191
|
+
if (!packageJson) {
|
|
192
|
+
return { name: "React/Next.js", passed: false, message: "Could not read package.json" };
|
|
148
193
|
}
|
|
194
|
+
const deps = {
|
|
195
|
+
...packageJson.dependencies ?? {},
|
|
196
|
+
...packageJson.devDependencies ?? {}
|
|
197
|
+
};
|
|
198
|
+
if (deps.next) return { name: "Next.js", passed: true };
|
|
199
|
+
if (deps.react) return { name: "React", passed: true };
|
|
149
200
|
return { name: "React/Next.js", passed: false, message: "Not found in dependencies" };
|
|
150
201
|
}
|
|
151
202
|
function displaySetupHelp(checks) {
|
|
152
|
-
const tsCheck = checks.find((c) => c.name
|
|
203
|
+
const tsCheck = checks.find((c) => c.name.startsWith("TypeScript"));
|
|
153
204
|
const tailwindCheck = checks.find((c) => c.name === "Tailwind CSS");
|
|
205
|
+
const pm = detectPackageManager();
|
|
154
206
|
if (tsCheck && !tsCheck.passed) {
|
|
155
207
|
console.log(chalk.dim("Install TypeScript:"));
|
|
156
|
-
console.log(chalk.white("
|
|
208
|
+
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D typescript @types/node @types/react`));
|
|
157
209
|
console.log(chalk.dim("\nCreate tsconfig.json with path aliases:"));
|
|
158
210
|
console.log(chalk.white(" npx tsc --init"));
|
|
159
211
|
}
|
|
160
212
|
if (tailwindCheck && !tailwindCheck.passed) {
|
|
161
213
|
console.log(chalk.dim("\nInstall Tailwind CSS:"));
|
|
162
|
-
console.log(chalk.white("
|
|
214
|
+
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D tailwindcss postcss autoprefixer`));
|
|
163
215
|
console.log(chalk.white(" npx tailwindcss init -p"));
|
|
164
216
|
}
|
|
165
217
|
console.log(chalk.dim("\nOr create a new Next.js project:"));
|
|
166
218
|
console.log(chalk.white(" npx create-next-app@latest --typescript --tailwind\n"));
|
|
167
219
|
}
|
|
168
220
|
async function autoFixSetup(projectRoot, needsTypeScript, needsTailwind, spinner) {
|
|
221
|
+
const pm = detectPackageManager();
|
|
222
|
+
const installCmd = pm === "npm" ? "install" : "add";
|
|
169
223
|
if (needsTypeScript) {
|
|
170
224
|
spinner.text = "Installing TypeScript and types...";
|
|
171
|
-
execSync(
|
|
225
|
+
execSync(`${pm} ${installCmd} -D typescript @types/node @types/react`, { stdio: "inherit" });
|
|
172
226
|
}
|
|
173
227
|
const tsconfigPath = join(projectRoot, "tsconfig.json");
|
|
174
|
-
|
|
175
|
-
if (existsSync(tsconfigPath)) {
|
|
176
|
-
try {
|
|
177
|
-
tsconfig = JSON.parse(readFileSync(tsconfigPath, "utf-8"));
|
|
178
|
-
} catch {
|
|
179
|
-
tsconfig = {};
|
|
180
|
-
}
|
|
181
|
-
} else {
|
|
228
|
+
const tsconfig = parseJsonFile(tsconfigPath) ?? { compilerOptions: {} };
|
|
229
|
+
if (!existsSync(tsconfigPath)) {
|
|
182
230
|
spinner.text = "Creating tsconfig.json...";
|
|
183
|
-
tsconfig = { compilerOptions: {} };
|
|
184
231
|
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
185
232
|
}
|
|
186
|
-
tsconfig.compilerOptions
|
|
187
|
-
tsconfig.compilerOptions.baseUrl
|
|
188
|
-
tsconfig.compilerOptions.paths
|
|
233
|
+
tsconfig.compilerOptions ??= {};
|
|
234
|
+
tsconfig.compilerOptions.baseUrl ??= ".";
|
|
235
|
+
tsconfig.compilerOptions.paths ??= {};
|
|
189
236
|
tsconfig.compilerOptions.paths["@/components/*"] = ["components/*"];
|
|
190
237
|
tsconfig.compilerOptions.paths["@/lib/*"] = ["lib/*"];
|
|
191
238
|
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
192
239
|
if (needsTailwind) {
|
|
193
240
|
spinner.text = "Installing Tailwind CSS...";
|
|
194
|
-
execSync(
|
|
241
|
+
execSync(`${pm} ${installCmd} -D tailwindcss postcss autoprefixer`, { stdio: "inherit" });
|
|
195
242
|
spinner.text = "Initializing Tailwind config...";
|
|
196
|
-
|
|
243
|
+
try {
|
|
244
|
+
execSync("npx tailwindcss init -p", { stdio: "inherit" });
|
|
245
|
+
} catch {
|
|
246
|
+
console.warn(chalk.yellow("\nWarning: `npx tailwindcss init -p` failed. Creating default config files instead."));
|
|
247
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
248
|
+
export default {
|
|
249
|
+
content: [
|
|
250
|
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
251
|
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
252
|
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}'
|
|
253
|
+
],
|
|
254
|
+
theme: {
|
|
255
|
+
extend: {},
|
|
256
|
+
},
|
|
257
|
+
plugins: [],
|
|
258
|
+
};
|
|
259
|
+
`;
|
|
260
|
+
const postcssConfig = `export default {
|
|
261
|
+
plugins: {
|
|
262
|
+
tailwindcss: {},
|
|
263
|
+
autoprefixer: {},
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
`;
|
|
267
|
+
const globalsCssDir = join(projectRoot, "app");
|
|
268
|
+
const globalsCssPath = join(globalsCssDir, "globals.css");
|
|
269
|
+
try {
|
|
270
|
+
writeFileSync(join(projectRoot, "tailwind.config.js"), tailwindConfig, "utf-8");
|
|
271
|
+
writeFileSync(join(projectRoot, "postcss.config.js"), postcssConfig, "utf-8");
|
|
272
|
+
if (!existsSync(globalsCssDir)) {
|
|
273
|
+
mkdirSync(globalsCssDir, { recursive: true });
|
|
274
|
+
}
|
|
275
|
+
if (!existsSync(globalsCssPath)) {
|
|
276
|
+
const globals = `@tailwind base;
|
|
277
|
+
@tailwind components;
|
|
278
|
+
@tailwind utilities;
|
|
279
|
+
`;
|
|
280
|
+
writeFileSync(globalsCssPath, globals, "utf-8");
|
|
281
|
+
}
|
|
282
|
+
console.log(chalk.green("Created tailwind.config.js, postcss.config.js, and app/globals.css"));
|
|
283
|
+
} catch (writeErr) {
|
|
284
|
+
const errorMessage = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
285
|
+
console.warn(chalk.yellow(`Failed to write fallback Tailwind files: ${errorMessage}`));
|
|
286
|
+
throw writeErr;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
197
289
|
}
|
|
198
290
|
}
|
|
199
291
|
var COMPONENT_DESCRIPTIONS = {
|
|
@@ -205,7 +297,7 @@ var COMPONENT_DESCRIPTIONS = {
|
|
|
205
297
|
"circle-reveal-button": "Icon to pill expansion - the element of surprise"
|
|
206
298
|
};
|
|
207
299
|
var program = new Command();
|
|
208
|
-
program.name("zerozeeker").description("CLI for installing ZeroZeeker UI components - because life is too short for boring interfaces").version("2.
|
|
300
|
+
program.name("zerozeeker").description("CLI for installing ZeroZeeker UI components - because life is too short for boring interfaces").version("2.3.0");
|
|
209
301
|
program.command("init").description("Initialize ZeroZeeker in your project").action(async () => {
|
|
210
302
|
const spinner = ora("Checking project setup...").start();
|
|
211
303
|
try {
|
|
@@ -236,9 +328,7 @@ program.command("init").description("Initialize ZeroZeeker in your project").act
|
|
|
236
328
|
}
|
|
237
329
|
console.log(chalk.yellow("\n[!] Some setup issues detected\n"));
|
|
238
330
|
displaySetupHelp(checks);
|
|
239
|
-
const needsTypeScript = !checks.find(
|
|
240
|
-
(c) => c.name === "TypeScript" || c.name === "TypeScript paths" || c.name === "TypeScript config"
|
|
241
|
-
)?.passed;
|
|
331
|
+
const needsTypeScript = !checks.find((c) => c.name.startsWith("TypeScript"))?.passed;
|
|
242
332
|
const needsTailwind = !checks.find((c) => c.name === "Tailwind CSS")?.passed;
|
|
243
333
|
const doAuto = await askYesNo("Would you like ZeroZeeker to try to automatically fix these issues now?", true);
|
|
244
334
|
if (!doAuto) {
|
|
@@ -267,7 +357,7 @@ program.command("init").description("Initialize ZeroZeeker in your project").act
|
|
|
267
357
|
process.exit(1);
|
|
268
358
|
}
|
|
269
359
|
});
|
|
270
|
-
program.command("add <component>").description("Add a component from ZeroZeeker registry").action(async (component) => {
|
|
360
|
+
program.command("add <component>").description("Add a component from ZeroZeeker registry").option("-f, --force", "Overwrite existing files").action(async (component, options) => {
|
|
271
361
|
if (!COMPONENTS.includes(component)) {
|
|
272
362
|
console.error(chalk.red(`[x] Component "${component}" does not exist in this dimension.`));
|
|
273
363
|
console.log(chalk.dim("\nHere are the components that actually exist:"));
|
|
@@ -284,9 +374,9 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
284
374
|
spinner.text = `Fetching ${chalk.cyan(component)} from registry...`;
|
|
285
375
|
const registry = await fetchRegistry(url);
|
|
286
376
|
const filesInstalled = [];
|
|
287
|
-
const allDependencies = [...registry.dependencies
|
|
288
|
-
if (registry.registryDependencies
|
|
289
|
-
spinner.text =
|
|
377
|
+
const allDependencies = [...registry.dependencies ?? []];
|
|
378
|
+
if (registry.registryDependencies?.length) {
|
|
379
|
+
spinner.text = "Installing registry dependencies...";
|
|
290
380
|
const registryResult = await installRegistryDependencies(
|
|
291
381
|
registry.registryDependencies,
|
|
292
382
|
projectRoot
|
|
@@ -294,18 +384,18 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
294
384
|
filesInstalled.push(...registryResult.files);
|
|
295
385
|
allDependencies.push(...registryResult.npmDeps);
|
|
296
386
|
}
|
|
297
|
-
if (registry.files
|
|
387
|
+
if (registry.files?.length) {
|
|
298
388
|
spinner.text = `Installing ${chalk.cyan(component)} files...`;
|
|
299
389
|
for (const file of registry.files) {
|
|
300
390
|
const targetPath = file.target || file.path;
|
|
301
391
|
const fullPath = join(projectRoot, targetPath);
|
|
302
|
-
if (existsSync(fullPath)) {
|
|
392
|
+
if (existsSync(fullPath) && !options.force) {
|
|
303
393
|
spinner.stop();
|
|
304
394
|
console.warn(chalk.yellow(`
|
|
305
395
|
[!] File already exists: ${targetPath}`));
|
|
306
396
|
console.log(chalk.dim(" Skipping to avoid overwriting your changes."));
|
|
307
|
-
console.log(chalk.dim(
|
|
308
|
-
|
|
397
|
+
console.log(chalk.dim(" Use --force flag to overwrite existing files.\n"));
|
|
398
|
+
spinner.start();
|
|
309
399
|
continue;
|
|
310
400
|
}
|
|
311
401
|
ensureDir(fullPath);
|
|
@@ -323,15 +413,15 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
323
413
|
[+] Successfully installed ${component}`));
|
|
324
414
|
if (filesInstalled.length > 0) {
|
|
325
415
|
console.log(chalk.dim("\n Files added:"));
|
|
326
|
-
|
|
416
|
+
for (const f of filesInstalled) {
|
|
327
417
|
console.log(chalk.cyan(` ${f}`));
|
|
328
|
-
}
|
|
418
|
+
}
|
|
329
419
|
}
|
|
330
420
|
if (uniqueDeps.length > 0) {
|
|
331
421
|
console.log(chalk.dim("\n Dependencies installed:"));
|
|
332
|
-
|
|
422
|
+
for (const d of uniqueDeps) {
|
|
333
423
|
console.log(chalk.cyan(` ${d}`));
|
|
334
|
-
}
|
|
424
|
+
}
|
|
335
425
|
}
|
|
336
426
|
console.log(chalk.dim("\n Now go make something beautiful.\n"));
|
|
337
427
|
} catch (error) {
|
|
@@ -341,7 +431,7 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
341
431
|
if (error instanceof Error) {
|
|
342
432
|
if (error.message.includes("package.json")) {
|
|
343
433
|
console.log(chalk.dim("\n Make sure you're in a React/Next.js project directory."));
|
|
344
|
-
} else if (error.message.includes("fetch")) {
|
|
434
|
+
} else if (error.message.includes("fetch") || error.name === "AbortError") {
|
|
345
435
|
console.log(chalk.dim("\n Check your internet connection and try again."));
|
|
346
436
|
} else {
|
|
347
437
|
console.log(chalk.dim(`
|
|
@@ -355,11 +445,12 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
355
445
|
program.command("list").description("List all available components").action(() => {
|
|
356
446
|
console.log(chalk.bold("\nZeroZeeker UI Components\n"));
|
|
357
447
|
console.log(chalk.dim("Modern, polished components that make users actually want to interact.\n"));
|
|
358
|
-
|
|
448
|
+
for (const component of COMPONENTS) {
|
|
449
|
+
if (component === "index") continue;
|
|
359
450
|
console.log(chalk.cyan(` ${component}`));
|
|
360
451
|
console.log(chalk.dim(` ${COMPONENT_DESCRIPTIONS[component]}
|
|
361
452
|
`));
|
|
362
|
-
}
|
|
453
|
+
}
|
|
363
454
|
console.log(chalk.dim("Install any component with: ") + chalk.white("npx zerozeeker add <component>"));
|
|
364
455
|
console.log(chalk.dim("More components coming soon. Ship fast. Look good doing it.\n"));
|
|
365
456
|
});
|