@dinachi/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -411,7 +411,30 @@ ${pluginsContent},
411
411
  }
412
412
  return { exists: true };
413
413
  }
414
- var addCommand = new Command("add").description("Add a component to your project").argument("<component>", "Name of the component").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").action(async (componentName, options) => {
414
+ async function handleIndexFile(sourcePath, targetPath, componentName, allFilesAdded, aliasPath) {
415
+ let templateContent = await fs2.readFile(sourcePath, "utf-8");
416
+ templateContent = templateContent.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
417
+ if (!fs2.existsSync(targetPath)) {
418
+ await fs2.writeFile(targetPath, templateContent);
419
+ allFilesAdded.push({ name: "index.ts", path: path2.join(aliasPath, "index.ts") });
420
+ } else {
421
+ const existingContent = await fs2.readFile(targetPath, "utf-8");
422
+ const exportRegex = /export\s+\*\s+from\s+['"]\.\/([^'"]+)['"]/g;
423
+ const templateExports = [];
424
+ let match;
425
+ while ((match = exportRegex.exec(templateContent)) !== null) {
426
+ templateExports.push(match[1]);
427
+ }
428
+ const componentExportExists = existingContent.includes(`export * from './${componentName}'`);
429
+ if (!componentExportExists && templateExports.includes(componentName)) {
430
+ const newExportLine = `export * from './${componentName}'`;
431
+ const updatedContent = existingContent.trim() + "\n" + newExportLine + "\n";
432
+ await fs2.writeFile(targetPath, updatedContent);
433
+ allFilesAdded.push({ name: "index.ts", path: path2.join(aliasPath, "index.ts") });
434
+ }
435
+ }
436
+ }
437
+ var addCommand = new Command("add").description("Add a component to your project").argument("[component]", "Name of the component (optional when using --all)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Install all available components").action(async (componentName, options) => {
415
438
  const spinner = ora("Adding component...").start();
416
439
  try {
417
440
  const config = await getConfig();
@@ -420,17 +443,40 @@ var addCommand = new Command("add").description("Add a component to your project
420
443
  process.exit(1);
421
444
  }
422
445
  const registry = getComponentRegistry();
423
- const component = registry[componentName];
424
- if (!component) {
425
- spinner.fail(`\u274C Component "${componentName}" not found.`);
426
- console.log("Available components:");
427
- Object.keys(registry).forEach((name) => {
428
- console.log(` ${chalk.cyan(name)}`);
429
- });
430
- process.exit(1);
446
+ let componentsToInstall = [];
447
+ if (options.all) {
448
+ const allComponents = Object.keys(registry);
449
+ spinner.text = `Installing all ${allComponents.length} components...`;
450
+ const allComponentsWithDeps = /* @__PURE__ */ new Set();
451
+ for (const name of allComponents) {
452
+ allComponentsWithDeps.add(name);
453
+ const deps = getComponentDependencies(name);
454
+ deps.forEach((dep) => allComponentsWithDeps.add(dep));
455
+ }
456
+ componentsToInstall = Array.from(allComponentsWithDeps);
457
+ } else {
458
+ if (!componentName) {
459
+ spinner.fail("\u274C Component name is required when not using --all flag.");
460
+ console.log("Available components:");
461
+ Object.keys(registry).forEach((name) => {
462
+ console.log(` ${chalk.cyan(name)}`);
463
+ });
464
+ process.exit(1);
465
+ }
466
+ const component = registry[componentName];
467
+ if (!component) {
468
+ spinner.fail(`\u274C Component "${componentName}" not found.`);
469
+ console.log("Available components:");
470
+ Object.keys(registry).forEach((name) => {
471
+ console.log(` ${chalk.cyan(name)}`);
472
+ });
473
+ process.exit(1);
474
+ }
475
+ componentsToInstall = [componentName, ...getComponentDependencies(componentName)];
476
+ }
477
+ if (!options.all) {
478
+ spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
431
479
  }
432
- const componentsToInstall = [componentName, ...getComponentDependencies(componentName)];
433
- spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
434
480
  const componentDir = path2.join(process.cwd(), config.aliases.ui.replace("@/", "src/"));
435
481
  await fs2.ensureDir(componentDir);
436
482
  let allFilesAdded = [];
@@ -474,14 +520,18 @@ var addCommand = new Command("add").description("Add a component to your project
474
520
  for (const file of comp.files) {
475
521
  const sourcePath = path2.join(__dirname2, "../templates", name, file.name);
476
522
  const targetPath = path2.join(componentDir, file.name);
477
- if (fs2.existsSync(targetPath) && !options.overwrite) {
478
- spinner.warn(`\u26A0\uFE0F ${file.name} already exists. Use --overwrite to replace it.`);
479
- continue;
523
+ if (file.name === "index.ts") {
524
+ await handleIndexFile(sourcePath, targetPath, name, allFilesAdded, config.aliases.ui);
525
+ } else {
526
+ if (fs2.existsSync(targetPath) && !options.overwrite) {
527
+ spinner.warn(`\u26A0\uFE0F ${file.name} already exists. Use --overwrite to replace it.`);
528
+ continue;
529
+ }
530
+ let content = await fs2.readFile(sourcePath, "utf-8");
531
+ content = content.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
532
+ await fs2.writeFile(targetPath, content);
533
+ allFilesAdded.push({ name: file.name, path: path2.join(config.aliases.ui, file.name) });
480
534
  }
481
- let content = await fs2.readFile(sourcePath, "utf-8");
482
- content = content.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
483
- await fs2.writeFile(targetPath, content);
484
- allFilesAdded.push({ name: file.name, path: path2.join(config.aliases.ui, file.name) });
485
535
  }
486
536
  if (comp.dependencies?.length) {
487
537
  allDepsInstalled.push(...comp.dependencies);
@@ -492,12 +542,12 @@ var addCommand = new Command("add").description("Add a component to your project
492
542
  spinner.text = "Updating Tailwind configuration...";
493
543
  tailwindConfigInfo = await ensureTailwindConfig(allDepsInstalled);
494
544
  }
545
+ const packageJsonPath = path2.join(process.cwd(), "package.json");
546
+ const packageJson = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
547
+ const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
548
+ const missingDeps = [...new Set(allDepsInstalled)].filter((dep) => !allDeps[dep]);
495
549
  if (allDepsInstalled.length > 0) {
496
550
  spinner.text = "Installing dependencies...";
497
- const packageJsonPath = path2.join(process.cwd(), "package.json");
498
- const packageJson = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
499
- const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
500
- const missingDeps = [...new Set(allDepsInstalled)].filter((dep) => !allDeps[dep]);
501
551
  if (missingDeps.length > 0) {
502
552
  try {
503
553
  const packageManager = getPackageManager();
@@ -506,9 +556,15 @@ var addCommand = new Command("add").description("Add a component to your project
506
556
  } catch (error) {
507
557
  spinner.warn(`\u26A0\uFE0F Failed to install dependencies. Please install manually: ${missingDeps.join(" ")}`);
508
558
  }
559
+ } else {
560
+ spinner.text = "All dependencies already installed.";
509
561
  }
510
562
  }
511
- spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")} component(s)!`);
563
+ if (options.all) {
564
+ spinner.succeed(`\u2705 Added all ${componentsToInstall.length} components!`);
565
+ } else {
566
+ spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")} component(s)!`);
567
+ }
512
568
  console.log();
513
569
  console.log("Files added:");
514
570
  allFilesAdded.forEach((file) => {
@@ -522,12 +578,18 @@ var addCommand = new Command("add").description("Add a component to your project
522
578
  console.log(` ${chalk.blue("~")} tailwind.config.js (updated with tailwindcss-animate plugin)`);
523
579
  }
524
580
  }
525
- if (allDepsInstalled.length > 0) {
581
+ if (missingDeps.length > 0) {
526
582
  console.log();
527
583
  console.log("Dependencies installed:");
528
- [...new Set(allDepsInstalled)].forEach((dep) => {
584
+ missingDeps.forEach((dep) => {
529
585
  console.log(` ${chalk.green("\u2713")} ${dep}`);
530
586
  });
587
+ } else if (allDepsInstalled.length > 0) {
588
+ console.log();
589
+ console.log("Dependencies (already installed):");
590
+ [...new Set(allDepsInstalled)].forEach((dep) => {
591
+ console.log(` ${chalk.blue("~")} ${dep}`);
592
+ });
531
593
  }
532
594
  } catch (error) {
533
595
  spinner.fail(`\u274C Failed to add component: ${error instanceof Error ? error.message : error}`);
@@ -556,18 +618,21 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
556
618
  console.log(chalk2.red("\u274C No package.json found. Please run this command in a valid project."));
557
619
  process.exit(1);
558
620
  }
621
+ const projectConfig = detectProjectType();
622
+ console.log(chalk2.gray(`Detected ${projectConfig.framework} project`));
623
+ console.log();
559
624
  const response = await prompts([
560
625
  {
561
626
  type: "text",
562
627
  name: "componentsPath",
563
628
  message: "Where would you like to install components?",
564
- initial: "./src/components/ui"
629
+ initial: projectConfig.componentsPath
565
630
  },
566
631
  {
567
632
  type: "text",
568
633
  name: "utilsPath",
569
634
  message: "Where would you like to install utilities?",
570
- initial: "./src/lib"
635
+ initial: projectConfig.utilsPath
571
636
  },
572
637
  {
573
638
  type: "confirm",
@@ -603,13 +668,14 @@ export function cn(...inputs: ClassValue[]) {
603
668
  const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"} ${deps.join(" ")}`;
604
669
  execSync2(installCmd, { stdio: "inherit" });
605
670
  }
671
+ const rscEnabled = projectConfig.framework === "next.js";
606
672
  const configContent = `{
607
673
  "style": "default",
608
- "rsc": false,
674
+ "rsc": ${rscEnabled},
609
675
  "tsx": true,
610
676
  "tailwind": {
611
- "config": "tailwind.config.js",
612
- "css": "src/index.css",
677
+ "config": "${projectConfig.tailwindConfig}",
678
+ "css": "${projectConfig.cssPath}",
613
679
  "baseColor": "slate",
614
680
  "cssVariables": true
615
681
  },
@@ -629,6 +695,18 @@ export function cn(...inputs: ClassValue[]) {
629
695
  console.log(` 1. Add a component: ${chalk2.cyan("npx @dinachi/cli add button")}`);
630
696
  console.log(` 2. Components will be installed to: ${chalk2.cyan("@/components/ui")}`);
631
697
  console.log(` 3. Utils available at: ${chalk2.cyan("@/lib/utils")}`);
698
+ if (projectConfig.framework === "next.js") {
699
+ console.log();
700
+ console.log(chalk2.blue("\u{1F4DD} Next.js specific notes:"));
701
+ console.log(` - RSC (React Server Components) enabled in config`);
702
+ console.log(` - Make sure to add "use client" directive if needed`);
703
+ console.log(` - Tailwind config set to: ${chalk2.cyan(projectConfig.tailwindConfig)}`);
704
+ } else if (projectConfig.framework === "remix") {
705
+ console.log();
706
+ console.log(chalk2.blue("\u{1F4DD} Remix specific notes:"));
707
+ console.log(` - Components will be installed to: ${chalk2.cyan(projectConfig.componentsPath)}`);
708
+ console.log(` - Utils will be installed to: ${chalk2.cyan(projectConfig.utilsPath)}`);
709
+ }
632
710
  console.log();
633
711
  console.log("\u{1F4A1} Tip: Install globally for shorter commands:");
634
712
  console.log(` ${chalk2.cyan("npm install -g @dinachi/cli")}`);
@@ -643,6 +721,69 @@ function getPackageManager2() {
643
721
  if (fs3.existsSync("yarn.lock")) return "yarn";
644
722
  return "npm";
645
723
  }
724
+ function detectProjectType() {
725
+ const packageJsonPath = path3.join(process.cwd(), "package.json");
726
+ if (!fs3.existsSync(packageJsonPath)) {
727
+ return {
728
+ framework: "react",
729
+ componentsPath: "./src/components/ui",
730
+ utilsPath: "./src/lib",
731
+ tailwindConfig: "tailwind.config.js",
732
+ cssPath: "src/index.css",
733
+ srcDir: "src"
734
+ };
735
+ }
736
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
737
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
738
+ if (deps.next) {
739
+ return {
740
+ framework: "next.js",
741
+ componentsPath: "./src/components/ui",
742
+ utilsPath: "./src/lib",
743
+ tailwindConfig: "tailwind.config.ts",
744
+ cssPath: "src/app/globals.css",
745
+ srcDir: "src"
746
+ };
747
+ }
748
+ if (deps.vite || deps["@vitejs/plugin-react"]) {
749
+ return {
750
+ framework: "vite",
751
+ componentsPath: "./src/components/ui",
752
+ utilsPath: "./src/lib",
753
+ tailwindConfig: "tailwind.config.js",
754
+ cssPath: "src/index.css",
755
+ srcDir: "src"
756
+ };
757
+ }
758
+ if (deps["react-scripts"]) {
759
+ return {
760
+ framework: "create-react-app",
761
+ componentsPath: "./src/components/ui",
762
+ utilsPath: "./src/lib",
763
+ tailwindConfig: "tailwind.config.js",
764
+ cssPath: "src/index.css",
765
+ srcDir: "src"
766
+ };
767
+ }
768
+ if (deps["@remix-run/react"]) {
769
+ return {
770
+ framework: "remix",
771
+ componentsPath: "./app/components/ui",
772
+ utilsPath: "./app/lib",
773
+ tailwindConfig: "tailwind.config.ts",
774
+ cssPath: "app/tailwind.css",
775
+ srcDir: "app"
776
+ };
777
+ }
778
+ return {
779
+ framework: "react",
780
+ componentsPath: "./src/components/ui",
781
+ utilsPath: "./src/lib",
782
+ tailwindConfig: "tailwind.config.js",
783
+ cssPath: "src/index.css",
784
+ srcDir: "src"
785
+ };
786
+ }
646
787
 
647
788
  // src/index.ts
648
789
  var program = new Command3();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dinachi/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for adding Dinachi UI components to your project",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority"
4
4
  import { cn } from "@/lib/utils"
5
5
 
6
6
  const buttonVariants = cva(
7
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
7
+ "inline-flex items-center cursor-pointer justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
8
8
  {
9
9
  variants: {
10
10
  variant: {
@@ -12,7 +12,7 @@ const DialogTrigger = React.forwardRef<
12
12
  <BaseDialog.Trigger
13
13
  ref={ref}
14
14
  className={cn(
15
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
15
+ "inline-flex items-center cursor-pointer justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
16
16
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
17
17
  "disabled:pointer-events-none disabled:opacity-50",
18
18
  "bg-primary text-primary-foreground hover:bg-primary/90",
@@ -23,7 +23,7 @@ const SelectTrigger = React.forwardRef<
23
23
  <SelectPrimitive.Trigger
24
24
  ref={ref}
25
25
  className={cn(
26
- "flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
26
+ "flex h-10 w-full items-center cursor-pointer justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
27
27
  className
28
28
  )}
29
29
  {...props}