zerozeeker 2.2.3 → 2.2.5
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 +274 -94
- 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,96 +148,233 @@ 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) {
|
|
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
|
+
}
|
|
130
208
|
const tailwindConfigs = [
|
|
131
209
|
"tailwind.config.ts",
|
|
132
210
|
"tailwind.config.js",
|
|
133
211
|
"tailwind.config.mjs",
|
|
134
212
|
"tailwind.config.cjs"
|
|
135
213
|
];
|
|
136
|
-
const
|
|
137
|
-
|
|
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" };
|
|
138
233
|
}
|
|
139
234
|
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 };
|
|
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" };
|
|
148
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 };
|
|
149
245
|
return { name: "React/Next.js", passed: false, message: "Not found in dependencies" };
|
|
150
246
|
}
|
|
151
247
|
function displaySetupHelp(checks) {
|
|
152
|
-
const tsCheck = checks.find((c) => c.name
|
|
153
|
-
const tailwindCheck = checks.find((c) => c.name
|
|
248
|
+
const tsCheck = checks.find((c) => c.name.startsWith("TypeScript"));
|
|
249
|
+
const tailwindCheck = checks.find((c) => c.name.startsWith("Tailwind"));
|
|
250
|
+
const pm = detectPackageManager();
|
|
154
251
|
if (tsCheck && !tsCheck.passed) {
|
|
155
252
|
console.log(chalk.dim("Install TypeScript:"));
|
|
156
|
-
console.log(chalk.white("
|
|
253
|
+
console.log(chalk.white(` ${pm} ${pm === "npm" ? "install" : "add"} -D typescript @types/node @types/react`));
|
|
157
254
|
console.log(chalk.dim("\nCreate tsconfig.json with path aliases:"));
|
|
158
255
|
console.log(chalk.white(" npx tsc --init"));
|
|
159
256
|
}
|
|
160
257
|
if (tailwindCheck && !tailwindCheck.passed) {
|
|
161
|
-
console.log(chalk.dim("\nInstall Tailwind CSS:"));
|
|
162
|
-
console.log(chalk.white("
|
|
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`));
|
|
163
262
|
console.log(chalk.white(" npx tailwindcss init -p"));
|
|
164
263
|
}
|
|
165
264
|
console.log(chalk.dim("\nOr create a new Next.js project:"));
|
|
166
265
|
console.log(chalk.white(" npx create-next-app@latest --typescript --tailwind\n"));
|
|
167
266
|
}
|
|
168
267
|
async function autoFixSetup(projectRoot, needsTypeScript, needsTailwind, spinner) {
|
|
268
|
+
const pm = detectPackageManager();
|
|
269
|
+
const installCmd = pm === "npm" ? "install" : "add";
|
|
169
270
|
if (needsTypeScript) {
|
|
170
271
|
spinner.text = "Installing TypeScript and types...";
|
|
171
|
-
execSync(
|
|
272
|
+
execSync(`${pm} ${installCmd} -D typescript @types/node @types/react`, { stdio: "inherit" });
|
|
172
273
|
}
|
|
173
274
|
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 {
|
|
275
|
+
const tsconfig = parseJsonFile(tsconfigPath) ?? { compilerOptions: {} };
|
|
276
|
+
if (!existsSync(tsconfigPath)) {
|
|
182
277
|
spinner.text = "Creating tsconfig.json...";
|
|
183
|
-
tsconfig = { compilerOptions: {} };
|
|
184
278
|
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
185
279
|
}
|
|
186
|
-
tsconfig.compilerOptions
|
|
187
|
-
tsconfig.compilerOptions.baseUrl
|
|
188
|
-
tsconfig.compilerOptions.paths
|
|
280
|
+
tsconfig.compilerOptions ??= {};
|
|
281
|
+
tsconfig.compilerOptions.baseUrl ??= ".";
|
|
282
|
+
tsconfig.compilerOptions.paths ??= {};
|
|
189
283
|
tsconfig.compilerOptions.paths["@/components/*"] = ["components/*"];
|
|
190
284
|
tsconfig.compilerOptions.paths["@/lib/*"] = ["lib/*"];
|
|
191
285
|
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
|
|
192
286
|
if (needsTailwind) {
|
|
193
|
-
spinner.text = "Installing Tailwind CSS...";
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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 globalsCssDir;
|
|
305
|
+
let globalsCssPath;
|
|
306
|
+
if (existsSync(srcAppDir)) {
|
|
307
|
+
globalsCssDir = srcAppDir;
|
|
308
|
+
globalsCssPath = join(srcAppDir, "globals.css");
|
|
309
|
+
} else if (existsSync(appDir)) {
|
|
310
|
+
globalsCssDir = appDir;
|
|
311
|
+
globalsCssPath = join(appDir, "globals.css");
|
|
312
|
+
} else {
|
|
313
|
+
globalsCssDir = appDir;
|
|
314
|
+
globalsCssPath = join(appDir, "globals.css");
|
|
315
|
+
mkdirSync(appDir, { recursive: true });
|
|
316
|
+
}
|
|
317
|
+
const globals = `@import "tailwindcss";
|
|
318
|
+
|
|
319
|
+
/*
|
|
320
|
+
* Tailwind CSS v4 uses CSS-first configuration.
|
|
321
|
+
* Customize your theme using the @theme directive:
|
|
322
|
+
*
|
|
323
|
+
* @theme {
|
|
324
|
+
* --color-primary: oklch(0.7 0.15 200);
|
|
325
|
+
* --font-display: "Satoshi", sans-serif;
|
|
326
|
+
* }
|
|
327
|
+
*
|
|
328
|
+
* Learn more: https://tailwindcss.com/docs/v4-beta
|
|
329
|
+
*/
|
|
330
|
+
`;
|
|
331
|
+
writeFileSync(join(projectRoot, "postcss.config.mjs"), postcssConfig, "utf-8");
|
|
332
|
+
if (!existsSync(globalsCssPath)) {
|
|
333
|
+
writeFileSync(globalsCssPath, globals, "utf-8");
|
|
334
|
+
console.log(chalk.green(`Created postcss.config.mjs and ${globalsCssPath.replace(projectRoot, "")}`));
|
|
335
|
+
} else {
|
|
336
|
+
const existingContent = readFileSync(globalsCssPath, "utf-8");
|
|
337
|
+
if (!existingContent.includes('@import "tailwindcss"') && !existingContent.includes("@import 'tailwindcss'") && !existingContent.includes("@tailwind")) {
|
|
338
|
+
writeFileSync(globalsCssPath, `@import "tailwindcss";
|
|
339
|
+
|
|
340
|
+
${existingContent}`, "utf-8");
|
|
341
|
+
console.log(chalk.green(`Created postcss.config.mjs and added Tailwind import to ${globalsCssPath.replace(projectRoot, "")}`));
|
|
342
|
+
} else {
|
|
343
|
+
console.log(chalk.green("Created postcss.config.mjs"));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} catch (writeErr) {
|
|
347
|
+
const errorMessage = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
348
|
+
console.warn(chalk.yellow(`Failed to write Tailwind config files: ${errorMessage}`));
|
|
349
|
+
console.log(chalk.dim("Attempting fallback to Tailwind v3 configuration..."));
|
|
350
|
+
try {
|
|
351
|
+
execSync("npx tailwindcss init -p", { stdio: "inherit" });
|
|
352
|
+
} catch {
|
|
353
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
354
|
+
export default {
|
|
355
|
+
content: [
|
|
356
|
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
357
|
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
358
|
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}'
|
|
359
|
+
],
|
|
360
|
+
theme: {
|
|
361
|
+
extend: {},
|
|
362
|
+
},
|
|
363
|
+
plugins: [],
|
|
364
|
+
};
|
|
365
|
+
`;
|
|
366
|
+
const postcssConfig = `export default {
|
|
367
|
+
plugins: {
|
|
368
|
+
tailwindcss: {},
|
|
369
|
+
autoprefixer: {},
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
`;
|
|
373
|
+
writeFileSync(join(projectRoot, "tailwind.config.js"), tailwindConfig, "utf-8");
|
|
374
|
+
writeFileSync(join(projectRoot, "postcss.config.js"), postcssConfig, "utf-8");
|
|
375
|
+
console.log(chalk.green("Created tailwind.config.js and postcss.config.js (v3 fallback)"));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
197
378
|
}
|
|
198
379
|
}
|
|
199
380
|
var COMPONENT_DESCRIPTIONS = {
|
|
@@ -205,7 +386,7 @@ var COMPONENT_DESCRIPTIONS = {
|
|
|
205
386
|
"circle-reveal-button": "Icon to pill expansion - the element of surprise"
|
|
206
387
|
};
|
|
207
388
|
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.
|
|
389
|
+
program.name("zerozeeker").description("CLI for installing ZeroZeeker UI components - because life is too short for boring interfaces").version("2.3.0");
|
|
209
390
|
program.command("init").description("Initialize ZeroZeeker in your project").action(async () => {
|
|
210
391
|
const spinner = ora("Checking project setup...").start();
|
|
211
392
|
try {
|
|
@@ -236,10 +417,8 @@ program.command("init").description("Initialize ZeroZeeker in your project").act
|
|
|
236
417
|
}
|
|
237
418
|
console.log(chalk.yellow("\n[!] Some setup issues detected\n"));
|
|
238
419
|
displaySetupHelp(checks);
|
|
239
|
-
const needsTypeScript = !checks.find(
|
|
240
|
-
|
|
241
|
-
)?.passed;
|
|
242
|
-
const needsTailwind = !checks.find((c) => c.name === "Tailwind CSS")?.passed;
|
|
420
|
+
const needsTypeScript = !checks.find((c) => c.name.startsWith("TypeScript"))?.passed;
|
|
421
|
+
const needsTailwind = !checks.find((c) => c.name.startsWith("Tailwind"))?.passed;
|
|
243
422
|
const doAuto = await askYesNo("Would you like ZeroZeeker to try to automatically fix these issues now?", true);
|
|
244
423
|
if (!doAuto) {
|
|
245
424
|
process.exit(1);
|
|
@@ -267,7 +446,7 @@ program.command("init").description("Initialize ZeroZeeker in your project").act
|
|
|
267
446
|
process.exit(1);
|
|
268
447
|
}
|
|
269
448
|
});
|
|
270
|
-
program.command("add <component>").description("Add a component from ZeroZeeker registry").action(async (component) => {
|
|
449
|
+
program.command("add <component>").description("Add a component from ZeroZeeker registry").option("-f, --force", "Overwrite existing files").action(async (component, options) => {
|
|
271
450
|
if (!COMPONENTS.includes(component)) {
|
|
272
451
|
console.error(chalk.red(`[x] Component "${component}" does not exist in this dimension.`));
|
|
273
452
|
console.log(chalk.dim("\nHere are the components that actually exist:"));
|
|
@@ -284,9 +463,9 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
284
463
|
spinner.text = `Fetching ${chalk.cyan(component)} from registry...`;
|
|
285
464
|
const registry = await fetchRegistry(url);
|
|
286
465
|
const filesInstalled = [];
|
|
287
|
-
const allDependencies = [...registry.dependencies
|
|
288
|
-
if (registry.registryDependencies
|
|
289
|
-
spinner.text =
|
|
466
|
+
const allDependencies = [...registry.dependencies ?? []];
|
|
467
|
+
if (registry.registryDependencies?.length) {
|
|
468
|
+
spinner.text = "Installing registry dependencies...";
|
|
290
469
|
const registryResult = await installRegistryDependencies(
|
|
291
470
|
registry.registryDependencies,
|
|
292
471
|
projectRoot
|
|
@@ -294,18 +473,18 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
294
473
|
filesInstalled.push(...registryResult.files);
|
|
295
474
|
allDependencies.push(...registryResult.npmDeps);
|
|
296
475
|
}
|
|
297
|
-
if (registry.files
|
|
476
|
+
if (registry.files?.length) {
|
|
298
477
|
spinner.text = `Installing ${chalk.cyan(component)} files...`;
|
|
299
478
|
for (const file of registry.files) {
|
|
300
479
|
const targetPath = file.target || file.path;
|
|
301
480
|
const fullPath = join(projectRoot, targetPath);
|
|
302
|
-
if (existsSync(fullPath)) {
|
|
481
|
+
if (existsSync(fullPath) && !options.force) {
|
|
303
482
|
spinner.stop();
|
|
304
483
|
console.warn(chalk.yellow(`
|
|
305
484
|
[!] File already exists: ${targetPath}`));
|
|
306
485
|
console.log(chalk.dim(" Skipping to avoid overwriting your changes."));
|
|
307
|
-
console.log(chalk.dim(
|
|
308
|
-
|
|
486
|
+
console.log(chalk.dim(" Use --force flag to overwrite existing files.\n"));
|
|
487
|
+
spinner.start();
|
|
309
488
|
continue;
|
|
310
489
|
}
|
|
311
490
|
ensureDir(fullPath);
|
|
@@ -323,15 +502,15 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
323
502
|
[+] Successfully installed ${component}`));
|
|
324
503
|
if (filesInstalled.length > 0) {
|
|
325
504
|
console.log(chalk.dim("\n Files added:"));
|
|
326
|
-
|
|
505
|
+
for (const f of filesInstalled) {
|
|
327
506
|
console.log(chalk.cyan(` ${f}`));
|
|
328
|
-
}
|
|
507
|
+
}
|
|
329
508
|
}
|
|
330
509
|
if (uniqueDeps.length > 0) {
|
|
331
510
|
console.log(chalk.dim("\n Dependencies installed:"));
|
|
332
|
-
|
|
511
|
+
for (const d of uniqueDeps) {
|
|
333
512
|
console.log(chalk.cyan(` ${d}`));
|
|
334
|
-
}
|
|
513
|
+
}
|
|
335
514
|
}
|
|
336
515
|
console.log(chalk.dim("\n Now go make something beautiful.\n"));
|
|
337
516
|
} catch (error) {
|
|
@@ -341,7 +520,7 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
341
520
|
if (error instanceof Error) {
|
|
342
521
|
if (error.message.includes("package.json")) {
|
|
343
522
|
console.log(chalk.dim("\n Make sure you're in a React/Next.js project directory."));
|
|
344
|
-
} else if (error.message.includes("fetch")) {
|
|
523
|
+
} else if (error.message.includes("fetch") || error.name === "AbortError") {
|
|
345
524
|
console.log(chalk.dim("\n Check your internet connection and try again."));
|
|
346
525
|
} else {
|
|
347
526
|
console.log(chalk.dim(`
|
|
@@ -355,11 +534,12 @@ program.command("add <component>").description("Add a component from ZeroZeeker
|
|
|
355
534
|
program.command("list").description("List all available components").action(() => {
|
|
356
535
|
console.log(chalk.bold("\nZeroZeeker UI Components\n"));
|
|
357
536
|
console.log(chalk.dim("Modern, polished components that make users actually want to interact.\n"));
|
|
358
|
-
|
|
537
|
+
for (const component of COMPONENTS) {
|
|
538
|
+
if (component === "index") continue;
|
|
359
539
|
console.log(chalk.cyan(` ${component}`));
|
|
360
540
|
console.log(chalk.dim(` ${COMPONENT_DESCRIPTIONS[component]}
|
|
361
541
|
`));
|
|
362
|
-
}
|
|
542
|
+
}
|
|
363
543
|
console.log(chalk.dim("Install any component with: ") + chalk.white("npx zerozeeker add <component>"));
|
|
364
544
|
console.log(chalk.dim("More components coming soon. Ship fast. Look good doing it.\n"));
|
|
365
545
|
});
|