zerozeeker 2.2.6 → 2.2.7
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 +18 -4
- package/dist/index.js +22 -499
- package/package.json +7 -10
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# ZeroZeeker Components
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
**No setup required. Just install and go.**
|
|
3
|
+
Official CLI for installing production-ready UI components into your React or Next.js projects.
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/zerozeeker)
|
|
8
6
|
[](https://www.typescriptlang.org/)
|
|
@@ -92,8 +90,17 @@ Before using ZeroZeeker components, ensure you have:
|
|
|
92
90
|
|
|
93
91
|
- Node.js 18 or higher
|
|
94
92
|
- An existing React or Next.js project
|
|
93
|
+
- shadcn/ui initialized in your project
|
|
95
94
|
- Tailwind CSS configured
|
|
96
95
|
|
|
96
|
+
### Setup shadcn/ui
|
|
97
|
+
|
|
98
|
+
If you haven't initialized shadcn/ui yet:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx shadcn-ui@latest init
|
|
102
|
+
```
|
|
103
|
+
|
|
97
104
|
---
|
|
98
105
|
|
|
99
106
|
## How to Use Installed Components
|
|
@@ -112,7 +119,7 @@ export default function App() {
|
|
|
112
119
|
}
|
|
113
120
|
```
|
|
114
121
|
|
|
115
|
-
All components follow
|
|
122
|
+
All components follow shadcn/ui conventions. Import from `@/components/ui/<component-name>`.
|
|
116
123
|
|
|
117
124
|
---
|
|
118
125
|
|
|
@@ -151,6 +158,13 @@ Use the full npx command:
|
|
|
151
158
|
npx zerozeeker list
|
|
152
159
|
```
|
|
153
160
|
|
|
161
|
+
### shadcn/ui not initialized
|
|
162
|
+
|
|
163
|
+
Initialize shadcn/ui first:
|
|
164
|
+
```bash
|
|
165
|
+
npx shadcn-ui@latest init
|
|
166
|
+
```
|
|
167
|
+
|
|
154
168
|
### Component won't install
|
|
155
169
|
|
|
156
170
|
Verify the exact component name:
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
// index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
7
|
-
import { join, dirname } from "path";
|
|
8
|
-
import * as readline from "readline/promises";
|
|
9
6
|
import ora from "ora";
|
|
10
7
|
import chalk from "chalk";
|
|
11
8
|
var REGISTRY_URL = "https://www.zerozeeker.com/r";
|
|
@@ -18,433 +15,11 @@ var COMPONENTS = [
|
|
|
18
15
|
"circle-reveal-button",
|
|
19
16
|
"index"
|
|
20
17
|
];
|
|
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;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function ensureDir(filePath) {
|
|
41
|
-
const dir = dirname(filePath);
|
|
42
|
-
if (!existsSync(dir)) {
|
|
43
|
-
mkdirSync(dir, { recursive: true });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function findProjectRoot() {
|
|
47
|
-
let currentDir = process.cwd();
|
|
48
|
-
const root = dirname(currentDir);
|
|
49
|
-
while (currentDir !== root) {
|
|
50
|
-
if (existsSync(join(currentDir, "package.json"))) {
|
|
51
|
-
return currentDir;
|
|
52
|
-
}
|
|
53
|
-
currentDir = dirname(currentDir);
|
|
54
|
-
}
|
|
55
|
-
throw new Error("Could not find project root (no package.json found)");
|
|
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
|
-
}
|
|
78
|
-
function installDependencies(deps) {
|
|
79
|
-
if (deps.length === 0) return;
|
|
80
|
-
const command = getInstallCommand(deps);
|
|
81
|
-
console.log(chalk.dim(` Installing dependencies: ${deps.join(", ")}`));
|
|
82
|
-
try {
|
|
83
|
-
execSync(command, {
|
|
84
|
-
stdio: "pipe",
|
|
85
|
-
encoding: "utf-8"
|
|
86
|
-
});
|
|
87
|
-
} catch {
|
|
88
|
-
console.warn(chalk.yellow(` [!] Failed to auto-install dependencies. Install manually: ${command}`));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async function askYesNo(question, defaultYes = false) {
|
|
92
|
-
const rl = readline.createInterface({
|
|
93
|
-
input: process.stdin,
|
|
94
|
-
output: process.stdout
|
|
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
|
-
}
|
|
104
|
-
}
|
|
105
|
-
async function installRegistryDependencies(deps, projectRoot, installed = /* @__PURE__ */ new Set()) {
|
|
106
|
-
const allFiles = [];
|
|
107
|
-
const allNpmDeps = [];
|
|
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`;
|
|
112
|
-
const registry = await fetchRegistry(url);
|
|
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) {
|
|
124
|
-
const nested = await installRegistryDependencies(
|
|
125
|
-
registry.registryDependencies,
|
|
126
|
-
projectRoot,
|
|
127
|
-
installed
|
|
128
|
-
);
|
|
129
|
-
allFiles.push(...nested.files);
|
|
130
|
-
allNpmDeps.push(...nested.npmDeps);
|
|
131
|
-
}
|
|
132
|
-
if (registry.files?.length) {
|
|
133
|
-
for (const file of registry.files) {
|
|
134
|
-
const targetPath = file.target || file.path;
|
|
135
|
-
const fullPath = join(projectRoot, targetPath);
|
|
136
|
-
if (existsSync(fullPath)) continue;
|
|
137
|
-
ensureDir(fullPath);
|
|
138
|
-
writeFileSync(fullPath, file.content, "utf-8");
|
|
139
|
-
allFiles.push(targetPath);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (registry.dependencies) {
|
|
143
|
-
allNpmDeps.push(...registry.dependencies);
|
|
144
|
-
}
|
|
145
|
-
} catch {
|
|
146
|
-
console.warn(chalk.yellow(` [!] Could not install registry dependency "${dep}"`));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return { files: allFiles, npmDeps: allNpmDeps };
|
|
150
|
-
}
|
|
151
|
-
function parseJsonFile(filePath) {
|
|
152
|
-
try {
|
|
153
|
-
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
154
|
-
} catch {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
function checkTypeScriptConfig(projectRoot) {
|
|
159
|
-
const tsconfigPath = join(projectRoot, "tsconfig.json");
|
|
160
|
-
if (!existsSync(tsconfigPath)) {
|
|
161
|
-
return { name: "TypeScript", passed: false, message: "tsconfig.json not found" };
|
|
162
|
-
}
|
|
163
|
-
const tsconfig = parseJsonFile(tsconfigPath);
|
|
164
|
-
if (!tsconfig) {
|
|
165
|
-
return { name: "TypeScript config", passed: false, message: "Invalid tsconfig.json" };
|
|
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
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function checkTailwindConfig(projectRoot) {
|
|
180
|
-
const cssFileLocations = [
|
|
181
|
-
"app/globals.css",
|
|
182
|
-
"src/app/globals.css",
|
|
183
|
-
"styles/globals.css",
|
|
184
|
-
"src/styles/globals.css",
|
|
185
|
-
"app/global.css",
|
|
186
|
-
"src/app/global.css",
|
|
187
|
-
"styles/global.css",
|
|
188
|
-
"src/styles/global.css",
|
|
189
|
-
"app/index.css",
|
|
190
|
-
"src/index.css",
|
|
191
|
-
"index.css"
|
|
192
|
-
];
|
|
193
|
-
for (const cssPath of cssFileLocations) {
|
|
194
|
-
const fullPath = join(projectRoot, cssPath);
|
|
195
|
-
if (existsSync(fullPath)) {
|
|
196
|
-
try {
|
|
197
|
-
const content = readFileSync(fullPath, "utf-8");
|
|
198
|
-
if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'") || content.includes("@theme")) {
|
|
199
|
-
return { name: "Tailwind CSS v4", passed: true };
|
|
200
|
-
}
|
|
201
|
-
if (content.includes("@tailwind base") || content.includes("@tailwind components") || content.includes("@tailwind utilities")) {
|
|
202
|
-
return { name: "Tailwind CSS v3", passed: true };
|
|
203
|
-
}
|
|
204
|
-
} catch {
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
const tailwindConfigs = [
|
|
209
|
-
"tailwind.config.ts",
|
|
210
|
-
"tailwind.config.js",
|
|
211
|
-
"tailwind.config.mjs",
|
|
212
|
-
"tailwind.config.cjs"
|
|
213
|
-
];
|
|
214
|
-
const hasTailwindConfig = tailwindConfigs.some((config) => existsSync(join(projectRoot, config)));
|
|
215
|
-
if (hasTailwindConfig) {
|
|
216
|
-
return { name: "Tailwind CSS", passed: true };
|
|
217
|
-
}
|
|
218
|
-
const packageJson = parseJsonFile(join(projectRoot, "package.json"));
|
|
219
|
-
if (packageJson) {
|
|
220
|
-
const deps = {
|
|
221
|
-
...packageJson.dependencies ?? {},
|
|
222
|
-
...packageJson.devDependencies ?? {}
|
|
223
|
-
};
|
|
224
|
-
if (deps.tailwindcss) {
|
|
225
|
-
return {
|
|
226
|
-
name: "Tailwind CSS",
|
|
227
|
-
passed: true,
|
|
228
|
-
message: "Installed but config not detected - may need setup"
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return { name: "Tailwind CSS", passed: false, message: "Config file not found" };
|
|
233
|
-
}
|
|
234
|
-
function checkFramework(projectRoot) {
|
|
235
|
-
const packageJson = parseJsonFile(join(projectRoot, "package.json"));
|
|
236
|
-
if (!packageJson) {
|
|
237
|
-
return { name: "React/Next.js", passed: false, message: "Could not read package.json" };
|
|
238
|
-
}
|
|
239
|
-
const deps = {
|
|
240
|
-
...packageJson.dependencies ?? {},
|
|
241
|
-
...packageJson.devDependencies ?? {}
|
|
242
|
-
};
|
|
243
|
-
if (deps.next) return { name: "Next.js", passed: true };
|
|
244
|
-
if (deps.react) return { name: "React", passed: true };
|
|
245
|
-
return { name: "React/Next.js", passed: false, message: "Not found in dependencies" };
|
|
246
|
-
}
|
|
247
|
-
function displaySetupHelp(checks) {
|
|
248
|
-
const tsCheck = checks.find((c) => c.name.startsWith("TypeScript"));
|
|
249
|
-
const tailwindCheck = checks.find((c) => c.name.startsWith("Tailwind"));
|
|
250
|
-
const pm = detectPackageManager();
|
|
251
|
-
if (tsCheck && !tsCheck.passed) {
|
|
252
|
-
console.log(chalk.dim("Install TypeScript:"));
|
|
253
|
-
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D typescript @types/node @types/react`));
|
|
254
|
-
console.log(chalk.dim("\nCreate tsconfig.json with path aliases:"));
|
|
255
|
-
console.log(chalk.white(" npx tsc --init"));
|
|
256
|
-
}
|
|
257
|
-
if (tailwindCheck && !tailwindCheck.passed) {
|
|
258
|
-
console.log(chalk.dim("\nInstall Tailwind CSS v4:"));
|
|
259
|
-
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D tailwindcss @tailwindcss/postcss postcss`));
|
|
260
|
-
console.log(chalk.dim("\nOr for Tailwind CSS v3:"));
|
|
261
|
-
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D tailwindcss postcss autoprefixer`));
|
|
262
|
-
console.log(chalk.white(" npx tailwindcss init -p"));
|
|
263
|
-
}
|
|
264
|
-
console.log(chalk.dim("\nOr create a new Next.js project:"));
|
|
265
|
-
console.log(chalk.white(" npx create-next-app@latest --typescript --tailwind\n"));
|
|
266
|
-
}
|
|
267
|
-
async function autoFixSetup(projectRoot, needsTypeScript, needsTailwind, spinner) {
|
|
268
|
-
const pm = detectPackageManager();
|
|
269
|
-
const installCmd = pm === "npm" ? "install" : "add";
|
|
270
|
-
if (needsTypeScript) {
|
|
271
|
-
spinner.text = "Installing TypeScript and types...";
|
|
272
|
-
execSync(`${pm} ${installCmd} -D typescript @types/node @types/react`, { stdio: "inherit" });
|
|
273
|
-
}
|
|
274
|
-
const tsconfigPath = join(projectRoot, "tsconfig.json");
|
|
275
|
-
const tsconfig = parseJsonFile(tsconfigPath) ?? { compilerOptions: {} };
|
|
276
|
-
if (!existsSync(tsconfigPath)) {
|
|
277
|
-
spinner.text = "Creating tsconfig.json...";
|
|
278
|
-
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
279
|
-
}
|
|
280
|
-
tsconfig.compilerOptions ??= {};
|
|
281
|
-
tsconfig.compilerOptions.baseUrl ??= ".";
|
|
282
|
-
tsconfig.compilerOptions.paths ??= {};
|
|
283
|
-
tsconfig.compilerOptions.paths["@/components/*"] = ["components/*"];
|
|
284
|
-
tsconfig.compilerOptions.paths["@/lib/*"] = ["lib/*"];
|
|
285
|
-
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
286
|
-
if (needsTailwind) {
|
|
287
|
-
spinner.text = "Installing Tailwind CSS v4...";
|
|
288
|
-
try {
|
|
289
|
-
execSync(`${pm} ${installCmd} -D tailwindcss @tailwindcss/postcss postcss`, { stdio: "inherit" });
|
|
290
|
-
} catch {
|
|
291
|
-
console.warn(chalk.yellow("\nWarning: Tailwind CSS v4 packages not available. Installing v3 instead."));
|
|
292
|
-
execSync(`${pm} ${installCmd} -D tailwindcss postcss autoprefixer`, { stdio: "inherit" });
|
|
293
|
-
}
|
|
294
|
-
spinner.text = "Creating Tailwind CSS configuration...";
|
|
295
|
-
try {
|
|
296
|
-
const postcssConfig = `export default {
|
|
297
|
-
plugins: {
|
|
298
|
-
"@tailwindcss/postcss": {},
|
|
299
|
-
},
|
|
300
|
-
};
|
|
301
|
-
`;
|
|
302
|
-
const appDir = join(projectRoot, "app");
|
|
303
|
-
const srcAppDir = join(projectRoot, "src", "app");
|
|
304
|
-
let globalsCssPath;
|
|
305
|
-
if (existsSync(srcAppDir)) {
|
|
306
|
-
globalsCssPath = join(srcAppDir, "globals.css");
|
|
307
|
-
} else if (existsSync(appDir)) {
|
|
308
|
-
globalsCssPath = join(appDir, "globals.css");
|
|
309
|
-
} else {
|
|
310
|
-
globalsCssPath = join(appDir, "globals.css");
|
|
311
|
-
mkdirSync(appDir, { recursive: true });
|
|
312
|
-
}
|
|
313
|
-
const globals = `@import "tailwindcss";
|
|
314
|
-
|
|
315
|
-
/*
|
|
316
|
-
* Tailwind CSS v4 uses CSS-first configuration.
|
|
317
|
-
* Customize your theme using the @theme directive:
|
|
318
|
-
*
|
|
319
|
-
* @theme {
|
|
320
|
-
* --color-primary: oklch(0.7 0.15 200);
|
|
321
|
-
* --font-display: "Satoshi", sans-serif;
|
|
322
|
-
* }
|
|
323
|
-
*
|
|
324
|
-
* Learn more: https://tailwindcss.com/docs/v4-beta
|
|
325
|
-
*/
|
|
326
|
-
`;
|
|
327
|
-
writeFileSync(join(projectRoot, "postcss.config.mjs"), postcssConfig, "utf-8");
|
|
328
|
-
if (!existsSync(globalsCssPath)) {
|
|
329
|
-
writeFileSync(globalsCssPath, globals, "utf-8");
|
|
330
|
-
console.log(chalk.green(`Created postcss.config.mjs and ${globalsCssPath.replace(projectRoot, "")}`));
|
|
331
|
-
} else {
|
|
332
|
-
const existingContent = readFileSync(globalsCssPath, "utf-8");
|
|
333
|
-
if (!existingContent.includes('@import "tailwindcss"') && !existingContent.includes("@import 'tailwindcss'") && !existingContent.includes("@tailwind")) {
|
|
334
|
-
writeFileSync(globalsCssPath, `@import "tailwindcss";
|
|
335
|
-
|
|
336
|
-
${existingContent}`, "utf-8");
|
|
337
|
-
console.log(chalk.green(`Created postcss.config.mjs and added Tailwind import to ${globalsCssPath.replace(projectRoot, "")}`));
|
|
338
|
-
} else {
|
|
339
|
-
console.log(chalk.green("Created postcss.config.mjs"));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
} catch (writeErr) {
|
|
343
|
-
const errorMessage = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
344
|
-
console.warn(chalk.yellow(`Failed to write Tailwind config files: ${errorMessage}`));
|
|
345
|
-
console.log(chalk.dim("Attempting fallback to Tailwind v3 configuration..."));
|
|
346
|
-
try {
|
|
347
|
-
execSync("npx tailwindcss init -p", { stdio: "inherit" });
|
|
348
|
-
} catch {
|
|
349
|
-
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
350
|
-
export default {
|
|
351
|
-
content: [
|
|
352
|
-
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
353
|
-
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
354
|
-
'./pages/**/*.{js,ts,jsx,tsx,mdx}'
|
|
355
|
-
],
|
|
356
|
-
theme: {
|
|
357
|
-
extend: {},
|
|
358
|
-
},
|
|
359
|
-
plugins: [],
|
|
360
|
-
};
|
|
361
|
-
`;
|
|
362
|
-
const postcssConfig = `export default {
|
|
363
|
-
plugins: {
|
|
364
|
-
tailwindcss: {},
|
|
365
|
-
autoprefixer: {},
|
|
366
|
-
},
|
|
367
|
-
};
|
|
368
|
-
`;
|
|
369
|
-
writeFileSync(join(projectRoot, "tailwind.config.js"), tailwindConfig, "utf-8");
|
|
370
|
-
writeFileSync(join(projectRoot, "postcss.config.js"), postcssConfig, "utf-8");
|
|
371
|
-
console.log(chalk.green("Created tailwind.config.js and postcss.config.js (v3 fallback)"));
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
var COMPONENT_DESCRIPTIONS = {
|
|
377
|
-
"rainbow-button": "Animated rainbow gradient border - for when one color just will not cut it",
|
|
378
|
-
"shimmer-button": "Moving border glow effect - subtle flex, maximum impact",
|
|
379
|
-
"magnetic-button": "Cursor-following magnetic effect - it literally chases your mouse",
|
|
380
|
-
"expand-button": "Expanding pill animation - small to big, just like your startup",
|
|
381
|
-
"flip-button": "3D flip card effect - because flat is boring",
|
|
382
|
-
"circle-reveal-button": "Icon to pill expansion - the element of surprise"
|
|
383
|
-
};
|
|
384
18
|
var program = new Command();
|
|
385
|
-
program.name("zerozeeker").description("CLI for installing ZeroZeeker UI components - because life is too short for boring interfaces").version("
|
|
386
|
-
program.command("
|
|
387
|
-
const spinner = ora("Checking project setup...").start();
|
|
388
|
-
try {
|
|
389
|
-
const projectRoot = findProjectRoot();
|
|
390
|
-
const checks = [
|
|
391
|
-
checkTypeScriptConfig(projectRoot),
|
|
392
|
-
checkTailwindConfig(projectRoot),
|
|
393
|
-
checkFramework(projectRoot)
|
|
394
|
-
];
|
|
395
|
-
spinner.stop();
|
|
396
|
-
console.log(chalk.bold("\n[*] Project Setup Check\n"));
|
|
397
|
-
let allPassed = true;
|
|
398
|
-
for (const check of checks) {
|
|
399
|
-
if (check.passed) {
|
|
400
|
-
console.log(chalk.green(` [+] ${check.name}`));
|
|
401
|
-
} else {
|
|
402
|
-
console.log(chalk.red(` [x] ${check.name}${check.message ? `: ${check.message}` : ""}`));
|
|
403
|
-
allPassed = false;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (allPassed) {
|
|
407
|
-
console.log(chalk.green("\n[*] Your project is ready for ZeroZeeker!\n"));
|
|
408
|
-
console.log(chalk.dim("Get started:"));
|
|
409
|
-
console.log(chalk.cyan(" npx zerozeeker add rainbow-button"));
|
|
410
|
-
console.log(chalk.dim("\nList all components:"));
|
|
411
|
-
console.log(chalk.cyan(" npx zerozeeker list\n"));
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
console.log(chalk.yellow("\n[!] Some setup issues detected\n"));
|
|
415
|
-
displaySetupHelp(checks);
|
|
416
|
-
const needsTypeScript = !checks.find((c) => c.name.startsWith("TypeScript"))?.passed;
|
|
417
|
-
const needsTailwind = !checks.find((c) => c.name.startsWith("Tailwind"))?.passed;
|
|
418
|
-
const doAuto = await askYesNo("Would you like ZeroZeeker to try to automatically fix these issues now?", true);
|
|
419
|
-
if (!doAuto) {
|
|
420
|
-
process.exit(1);
|
|
421
|
-
}
|
|
422
|
-
spinner.start();
|
|
423
|
-
try {
|
|
424
|
-
await autoFixSetup(projectRoot, needsTypeScript, needsTailwind, spinner);
|
|
425
|
-
spinner.stop();
|
|
426
|
-
console.log(chalk.green("\n[+] Auto-fix complete. Re-run `npx zerozeeker init` to re-check, or proceed to install components."));
|
|
427
|
-
process.exit(0);
|
|
428
|
-
} catch {
|
|
429
|
-
spinner.stop();
|
|
430
|
-
console.error(chalk.red("\n[x] Auto-fix failed. See errors above."));
|
|
431
|
-
process.exit(1);
|
|
432
|
-
}
|
|
433
|
-
} catch (error) {
|
|
434
|
-
spinner.stop();
|
|
435
|
-
console.error(chalk.red("\n[x] Initialization failed\n"));
|
|
436
|
-
if (error instanceof Error && error.message.includes("package.json")) {
|
|
437
|
-
console.log(chalk.dim("Make sure you're in a React/Next.js project directory.\n"));
|
|
438
|
-
} else {
|
|
439
|
-
console.log(chalk.dim(`${error instanceof Error ? error.message : "Unknown error"}
|
|
440
|
-
`));
|
|
441
|
-
}
|
|
442
|
-
process.exit(1);
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
program.command("add <component>").description("Add a component from ZeroZeeker registry").option("-f, --force", "Overwrite existing files").action(async (component, options) => {
|
|
19
|
+
program.name("zerozeeker").description("CLI for installing ZeroZeeker UI components - because life is too short for boring interfaces").version("1.0.0");
|
|
20
|
+
program.command("add <component>").description("Add a component from ZeroZeeker registry").action((component) => {
|
|
446
21
|
if (!COMPONENTS.includes(component)) {
|
|
447
|
-
console.error(chalk.red(`
|
|
22
|
+
console.error(chalk.red(`Component "${component}" does not exist in this dimension.`));
|
|
448
23
|
console.log(chalk.dim("\nHere are the components that actually exist:"));
|
|
449
24
|
COMPONENTS.filter((c) => c !== "index").forEach((c) => {
|
|
450
25
|
console.log(chalk.cyan(` - ${c}`));
|
|
@@ -453,89 +28,37 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
453
28
|
process.exit(1);
|
|
454
29
|
}
|
|
455
30
|
const url = `${REGISTRY_URL}/${component}.json`;
|
|
456
|
-
const spinner = ora(`Installing ${chalk.cyan(component)}
|
|
31
|
+
const spinner = ora(`Installing ${chalk.cyan(component)}... hold tight`).start();
|
|
457
32
|
try {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const allDependencies = [...registry.dependencies ?? []];
|
|
463
|
-
if (registry.registryDependencies?.length) {
|
|
464
|
-
spinner.text = "Installing registry dependencies...";
|
|
465
|
-
const registryResult = await installRegistryDependencies(
|
|
466
|
-
registry.registryDependencies,
|
|
467
|
-
projectRoot
|
|
468
|
-
);
|
|
469
|
-
filesInstalled.push(...registryResult.files);
|
|
470
|
-
allDependencies.push(...registryResult.npmDeps);
|
|
471
|
-
}
|
|
472
|
-
if (registry.files?.length) {
|
|
473
|
-
spinner.text = `Installing ${chalk.cyan(component)} files...`;
|
|
474
|
-
for (const file of registry.files) {
|
|
475
|
-
const targetPath = file.target || file.path;
|
|
476
|
-
const fullPath = join(projectRoot, targetPath);
|
|
477
|
-
if (existsSync(fullPath) && !options.force) {
|
|
478
|
-
spinner.stop();
|
|
479
|
-
console.warn(chalk.yellow(`
|
|
480
|
-
[!] File already exists: ${targetPath}`));
|
|
481
|
-
console.log(chalk.dim(" Skipping to avoid overwriting your changes."));
|
|
482
|
-
console.log(chalk.dim(" Use --force flag to overwrite existing files.\n"));
|
|
483
|
-
spinner.start();
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
ensureDir(fullPath);
|
|
487
|
-
writeFileSync(fullPath, file.content, "utf-8");
|
|
488
|
-
filesInstalled.push(targetPath);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
const uniqueDeps = [...new Set(allDependencies)];
|
|
492
|
-
if (uniqueDeps.length > 0) {
|
|
493
|
-
spinner.text = "Installing npm dependencies...";
|
|
494
|
-
installDependencies(uniqueDeps);
|
|
495
|
-
}
|
|
33
|
+
execSync(`npx shadcn@latest add ${url}`, {
|
|
34
|
+
stdio: "inherit",
|
|
35
|
+
encoding: "utf-8"
|
|
36
|
+
});
|
|
496
37
|
spinner.stop();
|
|
497
|
-
console.log(chalk.green(`
|
|
498
|
-
[+] Successfully installed ${component}`));
|
|
499
|
-
if (filesInstalled.length > 0) {
|
|
500
|
-
console.log(chalk.dim("\n Files added:"));
|
|
501
|
-
for (const f of filesInstalled) {
|
|
502
|
-
console.log(chalk.cyan(` ${f}`));
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
if (uniqueDeps.length > 0) {
|
|
506
|
-
console.log(chalk.dim("\n Dependencies installed:"));
|
|
507
|
-
for (const d of uniqueDeps) {
|
|
508
|
-
console.log(chalk.cyan(` ${d}`));
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
console.log(chalk.dim("\n Now go make something beautiful.\n"));
|
|
38
|
+
console.log(chalk.green(`Successfully installed ${component}. Now go make something beautiful.`));
|
|
512
39
|
} catch (error) {
|
|
513
40
|
spinner.stop();
|
|
514
|
-
console.error(chalk.red(`
|
|
515
|
-
|
|
516
|
-
if (error instanceof Error) {
|
|
517
|
-
if (error.message.includes("package.json")) {
|
|
518
|
-
console.log(chalk.dim("\n Make sure you're in a React/Next.js project directory."));
|
|
519
|
-
} else if (error.message.includes("fetch") || error.name === "AbortError") {
|
|
520
|
-
console.log(chalk.dim("\n Check your internet connection and try again."));
|
|
521
|
-
} else {
|
|
522
|
-
console.log(chalk.dim(`
|
|
523
|
-
${error.message}`));
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
console.log(chalk.dim("\n Need help? https://www.zerozeeker.com/docs\n"));
|
|
41
|
+
console.error(chalk.red(`Failed to install ${component}. The internet might be having a bad day.`));
|
|
42
|
+
console.log(chalk.dim("Try again, or check your network connection."));
|
|
527
43
|
process.exit(1);
|
|
528
44
|
}
|
|
529
45
|
});
|
|
530
46
|
program.command("list").description("List all available components").action(() => {
|
|
531
47
|
console.log(chalk.bold("\nZeroZeeker UI Components\n"));
|
|
532
48
|
console.log(chalk.dim("Modern, polished components that make users actually want to interact.\n"));
|
|
533
|
-
|
|
534
|
-
|
|
49
|
+
const descriptions = {
|
|
50
|
+
"rainbow-button": "Animated rainbow gradient border - for when one color just will not cut it",
|
|
51
|
+
"shimmer-button": "Moving border glow effect - subtle flex, maximum impact",
|
|
52
|
+
"magnetic-button": "Cursor-following magnetic effect - it literally chases your mouse",
|
|
53
|
+
"expand-button": "Expanding pill animation - small to big, just like your startup",
|
|
54
|
+
"flip-button": "3D flip card effect - because flat is boring",
|
|
55
|
+
"circle-reveal-button": "Icon to pill expansion - the element of surprise"
|
|
56
|
+
};
|
|
57
|
+
COMPONENTS.filter((c) => c !== "index").forEach((component) => {
|
|
535
58
|
console.log(chalk.cyan(` ${component}`));
|
|
536
|
-
console.log(chalk.dim(` ${
|
|
59
|
+
console.log(chalk.dim(` ${descriptions[component]}
|
|
537
60
|
`));
|
|
538
|
-
}
|
|
61
|
+
});
|
|
539
62
|
console.log(chalk.dim("Install any component with: ") + chalk.white("npx zerozeeker add <component>"));
|
|
540
63
|
console.log(chalk.dim("More components coming soon. Ship fast. Look good doing it.\n"));
|
|
541
64
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zerozeeker",
|
|
3
|
-
"version": "2.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.7",
|
|
4
|
+
"description": "CLI for installing ZeroZeeker UI components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"zerozeeker": "dist/index.js"
|
|
@@ -16,24 +16,21 @@
|
|
|
16
16
|
"prepublishOnly": "npm run build"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
19
|
-
"
|
|
20
|
-
"ui",
|
|
19
|
+
"shadcn",
|
|
21
20
|
"components",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"typescript"
|
|
21
|
+
"ui",
|
|
22
|
+
"zerozeeker"
|
|
25
23
|
],
|
|
26
24
|
"author": "ZeroZeeker",
|
|
27
25
|
"license": "MIT",
|
|
28
26
|
"dependencies": {
|
|
29
|
-
"chalk": "^5.3.0",
|
|
30
27
|
"commander": "^12.1.0",
|
|
31
|
-
"ora": "^8.0.1"
|
|
28
|
+
"ora": "^8.0.1",
|
|
29
|
+
"chalk": "^5.3.0"
|
|
32
30
|
},
|
|
33
31
|
"devDependencies": {
|
|
34
32
|
"@types/node": "^20.11.5",
|
|
35
33
|
"tsup": "^8.0.1",
|
|
36
|
-
"tsx": "^4.21.0",
|
|
37
34
|
"typescript": "^5.3.3"
|
|
38
35
|
},
|
|
39
36
|
"engines": {
|