tweenlabs 0.1.1 → 0.1.3

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/bin/cli.js +214 -84
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require("fs");
4
- const path = require("path");
5
- const { execSync } = require("child_process");
6
- const https = require("https");
7
- const readline = require("readline");
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { execSync } = require("node:child_process");
6
+ const https = require("node:https");
7
+ const readline = require("node:readline");
8
8
 
9
9
  // Simple Terminal Colors
10
10
  const colors = {
@@ -24,40 +24,44 @@ ${colors.bold}${colors.cyan}TweenLabs CLI${colors.reset} - Install premium GSAP
24
24
  ${colors.bold}Usage:${colors.reset}
25
25
  npx tweenlabs list List all available components
26
26
  npx tweenlabs add <component-slug> Install a specific component
27
- npx tweenlabs add all Install all components
28
-
29
- ${colors.bold}Examples:${colors.reset}
30
- npx tweenlabs list
31
- npx tweenlabs add 11-magnetic-dock
32
- npx tweenlabs add magnetic-dock
33
- npx tweenlabs add all
34
27
 
35
28
  ${colors.bold}Options:${colors.reset}
36
- --help, -h Show this help message
37
- --version, -v Show version
29
+ -y, --yes Skip all prompts (auto-accept defaults & install dependencies)
30
+ -p, --path <path> Specify a custom directory to install the component
31
+ -o, --overwrite Overwrite existing component files without prompting
32
+ -h, --help Show this help message
33
+ -v, --version Show version
38
34
  `;
39
35
 
40
36
  // Helper to make GET requests without external dependencies
41
37
  function fetchJson(url) {
42
38
  return new Promise((resolve, reject) => {
43
- const client = url.startsWith("https") ? https : require("http");
44
- client.get(url, {
45
- headers: { "User-Agent": "tweenlabs-cli" }
46
- }, (res) => {
47
- if (res.statusCode !== 200) {
48
- reject(new Error(`Server returned status code ${res.statusCode}`));
49
- return;
50
- }
51
- let data = "";
52
- res.on("data", (chunk) => { data += chunk; });
53
- res.on("end", () => {
54
- try {
55
- resolve(JSON.parse(data));
56
- } catch (err) {
57
- reject(err);
58
- }
59
- });
60
- }).on("error", reject);
39
+ const client = url.startsWith("https") ? https : require("node:http");
40
+ client
41
+ .get(
42
+ url,
43
+ {
44
+ headers: { "User-Agent": "tweenlabs-cli" },
45
+ },
46
+ (res) => {
47
+ if (res.statusCode !== 200) {
48
+ reject(new Error(`Server returned status code ${res.statusCode}`));
49
+ return;
50
+ }
51
+ let data = "";
52
+ res.on("data", (chunk) => {
53
+ data += chunk;
54
+ });
55
+ res.on("end", () => {
56
+ try {
57
+ resolve(JSON.parse(data));
58
+ } catch (err) {
59
+ reject(err);
60
+ }
61
+ });
62
+ },
63
+ )
64
+ .on("error", reject);
61
65
  });
62
66
  }
63
67
 
@@ -71,7 +75,7 @@ function askQuestion(query) {
71
75
  rl.question(query, (ans) => {
72
76
  rl.close();
73
77
  resolve(ans.trim());
74
- })
78
+ }),
75
79
  );
76
80
  }
77
81
 
@@ -86,50 +90,108 @@ function detectPackageManager() {
86
90
  async function main() {
87
91
  const args = process.argv.slice(2);
88
92
 
89
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
93
+ if (args.includes("--help") || args.includes("-h")) {
90
94
  console.log(helpText);
91
95
  process.exit(0);
92
96
  }
93
97
 
94
98
  if (args.includes("--version") || args.includes("-v")) {
95
- console.log("1.0.0");
99
+ try {
100
+ const pkg = require("../package.json");
101
+ console.log(pkg.version);
102
+ } catch (_err) {
103
+ console.log("0.1.1");
104
+ }
105
+ process.exit(0);
106
+ }
107
+
108
+ // Parse flags
109
+ const isYes = args.includes("-y") || args.includes("--yes");
110
+ const isOverwrite = args.includes("-o") || args.includes("--overwrite");
111
+
112
+ // Parse path option
113
+ let customPath = null;
114
+ const pathIdx = args.findIndex((arg) => arg === "-p" || arg === "--path");
115
+ if (pathIdx !== -1 && pathIdx + 1 < args.length) {
116
+ customPath = args[pathIdx + 1];
117
+ }
118
+
119
+ // Filter out options and their arguments from cleanArgs
120
+ const cleanArgs = [];
121
+ for (let i = 0; i < args.length; i++) {
122
+ if (
123
+ args[i] === "-y" ||
124
+ args[i] === "--yes" ||
125
+ args[i] === "-o" ||
126
+ args[i] === "--overwrite"
127
+ ) {
128
+ continue;
129
+ }
130
+ if (args[i] === "-p" || args[i] === "--path") {
131
+ i++; // skip next arg (the path value)
132
+ continue;
133
+ }
134
+ cleanArgs.push(args[i]);
135
+ }
136
+
137
+ if (cleanArgs.length === 0) {
138
+ console.log(helpText);
96
139
  process.exit(0);
97
140
  }
98
141
 
99
- if (args[0] === "list") {
100
- console.log(`\n${colors.cyan}🔍 Fetching available components list...${colors.reset}`);
101
- const domain = process.env.TWEENLABS_REGISTRY_URL || "https://tweenlabs.xyz";
142
+ if (cleanArgs[0] === "list") {
143
+ console.log(
144
+ `\n${colors.cyan}🔍 Fetching available components list...${colors.reset}`,
145
+ );
146
+ const domain =
147
+ process.env.TWEENLABS_REGISTRY_URL || "https://tweenlabs.xyz";
102
148
  const url = `${domain}/api/registry/list`;
103
149
  try {
104
150
  const data = await fetchJson(url);
105
- console.log(`\n${colors.bold}${colors.green}Available TweenLabs Components:${colors.reset}\n`);
151
+ console.log(
152
+ `\n${colors.bold}${colors.green}Available TweenLabs Components:${colors.reset}\n`,
153
+ );
106
154
  for (const comp of data.components) {
107
- console.log(` ${colors.bold}${colors.cyan}* ${comp.name}${colors.reset}`);
155
+ console.log(
156
+ ` ${colors.bold}${colors.cyan}* ${comp.name}${colors.reset}`,
157
+ );
108
158
  console.log(` Slug: ${comp.slug} (or ${comp.cleanSlug})`);
109
159
  console.log(` Desc: ${comp.description}\n`);
110
160
  }
111
161
  process.exit(0);
112
162
  } catch (err) {
113
- console.error(`\n${colors.red}❌ Failed to fetch components list.${colors.reset}`);
114
- console.error(colors.gray + `Details: ${err.message}` + colors.reset);
163
+ console.error(
164
+ `\n${colors.red}❌ Failed to fetch components list.${colors.reset}`,
165
+ );
166
+ console.error(`${colors.gray}Details: ${err.message}${colors.reset}`);
115
167
  process.exit(1);
116
168
  }
117
169
  }
118
170
 
119
- if (args[0] !== "add") {
120
- console.log(`${colors.red}Error: Unknown command "${args[0]}". Did you mean "add" or "list"?${colors.reset}`);
171
+ if (cleanArgs[0] !== "add") {
172
+ console.log(
173
+ `${colors.red}Error: Unknown command "${cleanArgs[0]}". Did you mean "add" or "list"?${colors.reset}`,
174
+ );
121
175
  console.log(helpText);
122
176
  process.exit(1);
123
177
  }
124
178
 
125
- const componentSlug = args[1];
179
+ const componentSlug = cleanArgs[1];
126
180
  if (!componentSlug) {
127
- console.log(`${colors.red}Error: Please specify a component slug to add.${colors.reset}`);
128
- console.log(colors.gray + "Example: npx tweenlabs add 11-magnetic-dock" + colors.reset);
181
+ console.log(
182
+ `${colors.red}Error: Please specify a component slug to add.${colors.reset}`,
183
+ );
184
+ console.log(
185
+ colors.gray +
186
+ "Example: npx tweenlabs add 11-magnetic-dock" +
187
+ colors.reset,
188
+ );
129
189
  process.exit(1);
130
190
  }
131
191
 
132
- console.log(`\n${colors.cyan}🔍 Fetching ${colors.bold}${componentSlug}${colors.reset}${colors.cyan} registry data...${colors.reset}`);
192
+ console.log(
193
+ `\n${colors.cyan}🔍 Fetching ${colors.bold}${componentSlug}${colors.reset}${colors.cyan} registry data...${colors.reset}`,
194
+ );
133
195
 
134
196
  // Determine registry domain (allow local testing via env variable)
135
197
  const domain = process.env.TWEENLABS_REGISTRY_URL || "https://tweenlabs.xyz";
@@ -139,24 +201,85 @@ async function main() {
139
201
  try {
140
202
  componentData = await fetchJson(url);
141
203
  } catch (err) {
142
- console.error(`\n${colors.red}❌ Failed to fetch component. Make sure the slug is correct and the server is running.${colors.reset}`);
143
- console.error(colors.gray + `Details: ${err.message}` + colors.reset);
204
+ console.error(
205
+ `\n${colors.red}❌ Failed to fetch component. Make sure the slug is correct and the server is running.${colors.reset}`,
206
+ );
207
+ console.error(`${colors.gray}Details: ${err.message}${colors.reset}`);
144
208
  process.exit(1);
145
209
  }
146
210
 
147
- console.log(`${colors.green}✓ Component found: ${colors.bold}${componentData.className}${colors.reset}`);
211
+ console.log(
212
+ `${colors.green}✓ Component found: ${colors.bold}${componentData.className}${colors.reset}`,
213
+ );
148
214
 
149
215
  // Resolve target directory
150
- let targetDir = path.join(process.cwd(), "src", "components");
151
- if (!fs.existsSync(path.join(process.cwd(), "src"))) {
152
- targetDir = path.join(process.cwd(), "components");
216
+ let targetDir = "";
217
+ if (customPath) {
218
+ targetDir = path.resolve(process.cwd(), customPath);
219
+ } else {
220
+ // 1. Try to read components.json (shadcn configuration)
221
+ const componentsJsonPath = path.join(process.cwd(), "components.json");
222
+ if (fs.existsSync(componentsJsonPath)) {
223
+ try {
224
+ const config = JSON.parse(fs.readFileSync(componentsJsonPath, "utf-8"));
225
+ const compAlias = config.aliases?.components;
226
+ if (compAlias) {
227
+ const cleanAlias = compAlias.replace(/^[@~]\//, "");
228
+ if (
229
+ fs.existsSync(path.join(process.cwd(), "src")) &&
230
+ !cleanAlias.startsWith("src/")
231
+ ) {
232
+ targetDir = path.join(
233
+ process.cwd(),
234
+ "src",
235
+ cleanAlias,
236
+ "tweenlabs",
237
+ );
238
+ } else {
239
+ targetDir = path.join(process.cwd(), cleanAlias, "tweenlabs");
240
+ }
241
+ }
242
+ } catch (_err) {
243
+ // Ignore JSON parse errors
244
+ }
245
+ }
246
+
247
+ // 2. Fallback if targetDir is still not resolved
248
+ if (!targetDir) {
249
+ if (fs.existsSync(path.join(process.cwd(), "src"))) {
250
+ targetDir = path.join(process.cwd(), "src", "components", "tweenlabs");
251
+ } else {
252
+ targetDir = path.join(process.cwd(), "components", "tweenlabs");
253
+ }
254
+ }
153
255
  }
154
256
 
155
- const userPathAnswer = await askQuestion(
156
- `📁 Where should the component be installed? ${colors.gray}(default: ${targetDir})${colors.reset}: `
257
+ console.log(
258
+ `📁 Target directory: ${colors.bold}${path.relative(process.cwd(), targetDir)}${colors.reset}`,
157
259
  );
158
- if (userPathAnswer) {
159
- targetDir = path.resolve(process.cwd(), userPathAnswer);
260
+
261
+ // Check if any files already exist
262
+ let hasExistingFiles = false;
263
+ for (const file of componentData.files) {
264
+ const filePath = path.join(targetDir, file.name);
265
+ if (fs.existsSync(filePath)) {
266
+ hasExistingFiles = true;
267
+ break;
268
+ }
269
+ }
270
+
271
+ if (hasExistingFiles && !isOverwrite && !isYes) {
272
+ const overwriteConfirm = await askQuestion(
273
+ `⚠️ Component files already exist in ${colors.bold}${path.relative(process.cwd(), targetDir)}${colors.reset}. Overwrite? (y/n) ${colors.gray}[y]${colors.reset}: `,
274
+ );
275
+ if (
276
+ overwriteConfirm &&
277
+ overwriteConfirm.toLowerCase() !== "y" &&
278
+ overwriteConfirm.toLowerCase() !== "yes"
279
+ ) {
280
+ console.log(`${colors.yellow}Installation cancelled.${colors.reset}`);
281
+ process.exit(0);
282
+ }
160
283
  }
161
284
 
162
285
  // Create target directory if it doesn't exist
@@ -169,7 +292,9 @@ async function main() {
169
292
  for (const file of componentData.files) {
170
293
  const filePath = path.join(targetDir, file.name);
171
294
  fs.writeFileSync(filePath, file.content, "utf-8");
172
- console.log(`${colors.green} → Created: ${colors.bold}${path.relative(process.cwd(), filePath)}${colors.reset}`);
295
+ console.log(
296
+ `${colors.green} → Created: ${colors.bold}${path.relative(process.cwd(), filePath)}${colors.reset}`,
297
+ );
173
298
  }
174
299
 
175
300
  // Check and install dependencies
@@ -178,8 +303,10 @@ async function main() {
178
303
  // Read package.json to see if dependencies are already installed
179
304
  let pkgJson = {};
180
305
  try {
181
- pkgJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), "package.json"), "utf-8"));
182
- } catch (err) {
306
+ pkgJson = JSON.parse(
307
+ fs.readFileSync(path.join(process.cwd(), "package.json"), "utf-8"),
308
+ );
309
+ } catch (_err) {
183
310
  // Ignore
184
311
  }
185
312
 
@@ -188,36 +315,39 @@ async function main() {
188
315
 
189
316
  if (missingDeps.length > 0) {
190
317
  const pm = detectPackageManager();
191
- console.log(`\n${colors.yellow}📦 Missing dependencies: ${colors.bold}${missingDeps.join(", ")}${colors.reset}`);
192
-
193
- const installConfirm = await askQuestion(
194
- `Do you want to install them using ${colors.bold}${pm}${colors.reset}? (y/n) ${colors.gray}[y]${colors.reset}: `
318
+ console.log(
319
+ `\n${colors.cyan}📦 Installing missing dependencies: ${colors.bold}${missingDeps.join(", ")}${colors.reset} using ${pm}...`,
195
320
  );
196
321
 
197
- if (!installConfirm || installConfirm.toLowerCase() === "y" || installConfirm.toLowerCase() === "yes") {
198
- console.log(`${colors.cyan}Installing dependencies using ${pm}...${colors.reset}`);
199
- let installCmd = "";
200
- if (pm === "pnpm") installCmd = `pnpm add ${missingDeps.join(" ")}`;
201
- else if (pm === "yarn") installCmd = `yarn add ${missingDeps.join(" ")}`;
202
- else if (pm === "bun") installCmd = `bun add ${missingDeps.join(" ")}`;
203
- else installCmd = `npm install ${missingDeps.join(" ")}`;
204
-
205
- try {
206
- execSync(installCmd, { stdio: "inherit" });
207
- console.log(`${colors.green}✓ Dependencies installed successfully!${colors.reset}`);
208
- } catch (err) {
209
- console.error(`${colors.red}❌ Failed to install dependencies. Please run "${installCmd}" manually.${colors.reset}`);
210
- }
211
- } else {
212
- console.log(`${colors.yellow}⚠️ Skipping installation. Please make sure to install ${missingDeps.join(", ")} manually.${colors.reset}`);
322
+ let installCmd = "";
323
+ if (pm === "pnpm") installCmd = `pnpm add ${missingDeps.join(" ")}`;
324
+ else if (pm === "yarn") installCmd = `yarn add ${missingDeps.join(" ")}`;
325
+ else if (pm === "bun") installCmd = `bun add ${missingDeps.join(" ")}`;
326
+ else installCmd = `npm install ${missingDeps.join(" ")}`;
327
+
328
+ try {
329
+ execSync(installCmd, { stdio: "inherit" });
330
+ console.log(
331
+ `${colors.green}✓ Dependencies installed successfully!${colors.reset}`,
332
+ );
333
+ } catch (_err) {
334
+ console.error(
335
+ `${colors.red}❌ Failed to install dependencies. Please run "${installCmd}" manually.${colors.reset}`,
336
+ );
213
337
  }
214
338
  } else {
215
- console.log(`\n${colors.green}✓ All dependencies (${dependencies.join(", ")}) already installed.${colors.reset}`);
339
+ console.log(
340
+ `\n${colors.green}✓ All dependencies (${dependencies.join(", ")}) already installed.${colors.reset}`,
341
+ );
216
342
  }
217
343
  }
218
344
 
219
- console.log(`\n${colors.green}${colors.bold}🎉 Installation complete!${colors.reset}`);
220
- console.log(`You can now import and use the ${colors.bold}${componentData.className}${colors.reset} component in your project.\n`);
345
+ console.log(
346
+ `\n${colors.green}${colors.bold}🎉 Installation complete!${colors.reset}`,
347
+ );
348
+ console.log(
349
+ `You can now import and use the ${colors.bold}${componentData.className}${colors.reset} component in your project.\n`,
350
+ );
221
351
  }
222
352
 
223
353
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tweenlabs",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",