@tioelvis/next-template 1.0.8 → 2.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tioelvis/next-template",
3
- "version": "1.0.8",
3
+ "version": "2.0.2",
4
4
  "description": "CLI to scaffold a Next.js + Tailwind project using shadcn/ui components",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,6 +31,8 @@
31
31
  "devDependencies": {
32
32
  "@eslint/eslintrc": "^3.3.1",
33
33
  "@radix-ui/react-accordion": "^1.2.11",
34
+ "@radix-ui/react-alert-dialog": "^1.1.14",
35
+ "@radix-ui/react-aspect-ratio": "^1.1.7",
34
36
  "@tailwindcss/postcss": "^4.1.11",
35
37
  "@tanstack/react-query": "^5.83.0",
36
38
  "@types/node": "^24.1.0",
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": ["@radix-ui/react-accordion"],
3
+ "dev_dependence": [],
4
+ "hooks": [],
5
+ "supports": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": ["@radix-ui/react-alert-dialog"],
3
+ "dev_dependence": [],
4
+ "hooks": [],
5
+ "supports": ["button"]
6
+ }
@@ -0,0 +1,157 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
5
+
6
+ import { cn } from "@/lib/utils";
7
+ import { buttonVariants } from "@/components/ui/button";
8
+
9
+ function AlertDialog({
10
+ ...props
11
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
12
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
13
+ }
14
+
15
+ function AlertDialogTrigger({
16
+ ...props
17
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
18
+ return (
19
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
20
+ );
21
+ }
22
+
23
+ function AlertDialogPortal({
24
+ ...props
25
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
26
+ return (
27
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
28
+ );
29
+ }
30
+
31
+ function AlertDialogOverlay({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
35
+ return (
36
+ <AlertDialogPrimitive.Overlay
37
+ data-slot="alert-dialog-overlay"
38
+ className={cn(
39
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function AlertDialogContent({
48
+ className,
49
+ ...props
50
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
51
+ return (
52
+ <AlertDialogPortal>
53
+ <AlertDialogOverlay />
54
+ <AlertDialogPrimitive.Content
55
+ data-slot="alert-dialog-content"
56
+ className={cn(
57
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
58
+ className
59
+ )}
60
+ {...props}
61
+ />
62
+ </AlertDialogPortal>
63
+ );
64
+ }
65
+
66
+ function AlertDialogHeader({
67
+ className,
68
+ ...props
69
+ }: React.ComponentProps<"div">) {
70
+ return (
71
+ <div
72
+ data-slot="alert-dialog-header"
73
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
74
+ {...props}
75
+ />
76
+ );
77
+ }
78
+
79
+ function AlertDialogFooter({
80
+ className,
81
+ ...props
82
+ }: React.ComponentProps<"div">) {
83
+ return (
84
+ <div
85
+ data-slot="alert-dialog-footer"
86
+ className={cn(
87
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
88
+ className
89
+ )}
90
+ {...props}
91
+ />
92
+ );
93
+ }
94
+
95
+ function AlertDialogTitle({
96
+ className,
97
+ ...props
98
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
99
+ return (
100
+ <AlertDialogPrimitive.Title
101
+ data-slot="alert-dialog-title"
102
+ className={cn("text-lg font-semibold", className)}
103
+ {...props}
104
+ />
105
+ );
106
+ }
107
+
108
+ function AlertDialogDescription({
109
+ className,
110
+ ...props
111
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
112
+ return (
113
+ <AlertDialogPrimitive.Description
114
+ data-slot="alert-dialog-description"
115
+ className={cn("text-muted-foreground text-sm", className)}
116
+ {...props}
117
+ />
118
+ );
119
+ }
120
+
121
+ function AlertDialogAction({
122
+ className,
123
+ ...props
124
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
125
+ return (
126
+ <AlertDialogPrimitive.Action
127
+ className={cn(buttonVariants(), className)}
128
+ {...props}
129
+ />
130
+ );
131
+ }
132
+
133
+ function AlertDialogCancel({
134
+ className,
135
+ ...props
136
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
137
+ return (
138
+ <AlertDialogPrimitive.Cancel
139
+ className={cn(buttonVariants({ variant: "outline" }), className)}
140
+ {...props}
141
+ />
142
+ );
143
+ }
144
+
145
+ export {
146
+ AlertDialog,
147
+ AlertDialogPortal,
148
+ AlertDialogOverlay,
149
+ AlertDialogTrigger,
150
+ AlertDialogContent,
151
+ AlertDialogHeader,
152
+ AlertDialogFooter,
153
+ AlertDialogTitle,
154
+ AlertDialogDescription,
155
+ AlertDialogAction,
156
+ AlertDialogCancel,
157
+ };
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": [],
3
+ "dev_dependence": [],
4
+ "hooks": [],
5
+ "supports": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": ["@radix-ui/react-aspect-ratio"],
3
+ "dev_dependence": [],
4
+ "hooks": [],
5
+ "supports": []
6
+ }
@@ -0,0 +1,11 @@
1
+ "use client";
2
+
3
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
4
+
5
+ function AspectRatio({
6
+ ...props
7
+ }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
8
+ return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />;
9
+ }
10
+
11
+ export { AspectRatio };
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": ["@radix-ui/react-slot"],
3
+ "dev_dependence": [],
4
+ "hooks": [],
5
+ "supports": []
6
+ }
@@ -0,0 +1,59 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const buttonVariants = cva(
8
+ "cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14
+ destructive:
15
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
+ outline:
17
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
+ ghost:
21
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22
+ link: "text-primary underline-offset-4 hover:underline",
23
+ },
24
+ size: {
25
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
26
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
+ icon: "size-9",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default",
34
+ },
35
+ }
36
+ );
37
+
38
+ function Button({
39
+ className,
40
+ variant,
41
+ size,
42
+ asChild = false,
43
+ ...props
44
+ }: React.ComponentProps<"button"> &
45
+ VariantProps<typeof buttonVariants> & {
46
+ asChild?: boolean;
47
+ }) {
48
+ const Comp = asChild ? Slot : "button";
49
+
50
+ return (
51
+ <Comp
52
+ data-slot="button"
53
+ className={cn(buttonVariants({ variant, size, className }))}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+
59
+ export { Button, buttonVariants };
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
6
+
7
+ const TEMPLATE_PATH = path.join(__dirname, "template");
8
+ const COMPONENTS_PATH = path.join(__dirname, "app", "components", "ui");
9
+ const HOOKS_PATH = path.join(__dirname, "app", "hooks");
10
+
11
+ const DEPENDENCIES = [
12
+ "@tanstack/react-query",
13
+ "axios",
14
+ "class-variance-authority",
15
+ "clsx",
16
+ "cookies-next",
17
+ "date-fns",
18
+ "lucide-react",
19
+ "next",
20
+ "next-auth",
21
+ "next-themes",
22
+ "react",
23
+ "react-dom",
24
+ "tailwind-merge",
25
+ ];
26
+
27
+ const DEV_DEPENDENCIES = [
28
+ "@eslint/eslintrc",
29
+ "@tailwindcss/postcss",
30
+ "@types/node",
31
+ "@types/react",
32
+ "@types/react-dom",
33
+ "eslint",
34
+ "eslint-config-next",
35
+ "tailwindcss",
36
+ "tw-animate-css",
37
+ "typescript",
38
+ ];
39
+
40
+ const COMPONENTS = ["accordion", "alert", "alert-dialog", "aspect-ratio"];
41
+
42
+ export {
43
+ __dirname,
44
+ __filename,
45
+ TEMPLATE_PATH,
46
+ COMPONENTS_PATH,
47
+ HOOKS_PATH,
48
+ DEPENDENCIES,
49
+ DEV_DEPENDENCIES,
50
+ COMPONENTS,
51
+ };
package/src/main.js CHANGED
@@ -1,113 +1,218 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
+
2
3
  import {
3
- copy_components_files,
4
- copy_hooks_files,
5
- copy_template_files,
6
- get_prompts,
7
- run,
8
- } from "./lib/utils.js";
4
+ copy_components,
5
+ copy_template,
6
+ on_cancel,
7
+ run_command,
8
+ } from "./utils.js";
9
9
  import fs from "node:fs";
10
10
  import chalk from "chalk";
11
11
  import path from "node:path";
12
- import { fileURLToPath } from "node:url";
13
- import { DEPENDENCIES, DEV_DEPENDENCIES } from "./lib/constants.js";
14
-
15
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ import prompts from "prompts";
13
+ import { COMPONENTS, DEPENDENCIES, DEV_DEPENDENCIES } from "./constants.js";
16
14
 
17
15
  // Manage Ctrl+C command
18
- process.on("SIGINT", () => {
19
- console.log(chalk.yellow("\n👋 Exiting..."));
20
- process.exit(0);
21
- });
16
+ process.on("SIGINT", () => on_cancel());
17
+
18
+ (async function () {
19
+ let DEST;
20
+ const CWD = path.resolve(process.cwd());
21
+
22
+ const { is_new_project } = await prompts(
23
+ {
24
+ type: "confirm",
25
+ initial: true,
26
+ name: "is_new_project",
27
+ message: "Is a new project?",
28
+ },
29
+ { onCancel: on_cancel }
30
+ );
31
+
32
+ if (is_new_project === true) {
33
+ try {
34
+ if (fs.existsSync(path.join(CWD, "next.config.ts")) === true) {
35
+ throw new Error("Config file already exists");
36
+ }
37
+
38
+ const responses = await prompts(
39
+ [
40
+ {
41
+ type: "text",
42
+ name: "project_name",
43
+ message: "What is your project named?",
44
+ validate: (e) => {
45
+ if (e === undefined || e.trim() === "") {
46
+ return chalk.red("⚠️ The name is required");
47
+ }
48
+
49
+ if (!/^[a-zA-Z0-9-_]+$/.test(e.trim())) {
50
+ return chalk.red(
51
+ "⚠️ Use only letters, numbers, dashes, and underscores"
52
+ );
53
+ }
54
+
55
+ return true;
56
+ },
57
+ },
58
+ {
59
+ type: "select",
60
+ name: "package_manager",
61
+ message: "Which package manager would you want to use?",
62
+ choices: [
63
+ { title: "npm", value: "npm" },
64
+ { title: "pnpm", value: "pnpm" },
65
+ ],
66
+ },
67
+ {
68
+ type: "multiselect",
69
+ name: "components",
70
+ message: "Which components do you want to install?",
71
+ instructions: false,
72
+ choices: COMPONENTS.map((e) => {
73
+ return { title: e, value: e };
74
+ }),
75
+ },
76
+ ],
77
+ { onCancel: on_cancel }
78
+ );
79
+
80
+ const { project_name, package_manager, components } = responses;
81
+
82
+ // Creating folder and copying files
83
+ DEST = path.resolve(CWD, project_name);
84
+
85
+ if (fs.existsSync(DEST) === true) {
86
+ throw new Error("A folder with that name already exists");
87
+ }
88
+
89
+ console.log(chalk.blue("📁 Creating project..."));
90
+
91
+ fs.mkdirSync(DEST, { recursive: true });
92
+
93
+ copy_template(DEST);
94
+ await copy_components(DEST, components);
22
95
 
23
- async function main() {
24
- let project_path = "";
96
+ // Initialize package.json
97
+ console.log(chalk.blue("📦 Initializing and configure package.json..."));
25
98
 
26
- try {
27
- const { project_name, package_manager, components } = await get_prompts();
99
+ const package_json = {
100
+ name: project_name,
101
+ version: "1.0.0",
102
+ private: true,
103
+ scripts: {
104
+ dev: "next dev --turbopack",
105
+ build: "next build",
106
+ start: "next start",
107
+ lint: "next lint",
108
+ },
109
+ };
28
110
 
29
- // Creating folder and copying files
30
- project_path = path.resolve(project_name);
111
+ const package_json_path = path.join(DEST, "package.json");
112
+
113
+ fs.writeFileSync(
114
+ package_json_path,
115
+ JSON.stringify(package_json, null, 2)
116
+ );
117
+
118
+ // Install dependencies
119
+ console.log(chalk.cyan("⬇️ Installing dependencies..."));
120
+
121
+ if (package_manager === "npm") {
122
+ run_command(`npm install ${DEPENDENCIES.join(" ")}`, DEST);
123
+ run_command(`npm install ${DEV_DEPENDENCIES.join(" ")} -D`, DEST);
124
+ }
125
+
126
+ if (package_manager === "pnpm") {
127
+ run_command(`pnpm add ${DEPENDENCIES.join(" ")}`, DEST);
128
+ run_command(`pnpm add ${DEV_DEPENDENCIES.join(" ")} -D`, DEST);
129
+ }
130
+
131
+ // Finish project
132
+ console.log(
133
+ chalk.yellow(
134
+ "📄 IMPORTANT: make sure to add your variable NEXT_PUBLIC_API in the .env file, e.g.: NEXT_PUBLIC_API=http://localhost:9000"
135
+ )
136
+ );
137
+
138
+ console.log(
139
+ chalk.green(`\n✅ Project ${project_name} created successfully! 🚀`)
140
+ );
141
+ } catch (error) {
142
+ console.error(chalk.red("❌ Internal error:"), error.message);
143
+
144
+ if (fs.existsSync(DEST) === true) {
145
+ fs.rmSync(DEST, { recursive: true, force: true });
146
+ }
31
147
 
32
- if (fs.existsSync(project_path)) {
33
- console.error(chalk.red("❌ A folder with that name already exists"));
34
148
  process.exit(1);
35
149
  }
150
+ }
151
+
152
+ if (is_new_project === false) {
153
+ let package_manager;
154
+
155
+ try {
156
+ if (fs.existsSync(path.join(CWD, "next.config.ts")) === false) {
157
+ throw new Error("Config file not exists");
158
+ }
36
159
 
37
- console.log(
38
- chalk.blue("📁 Creating project in:"),
39
- chalk.bold(project_name)
40
- );
41
-
42
- fs.mkdirSync(project_path, { recursive: true });
43
- const template_path = path.join(__dirname, "template");
44
- const components_path = path.join(__dirname, "ui", "components");
45
- const hooks_path = path.join(__dirname, "ui", "hooks");
46
-
47
- copy_template_files(template_path, project_path);
48
- copy_components_files(components_path, project_path, components);
49
- copy_hooks_files(hooks_path, components_path, project_path, components);
50
-
51
- // Initialize package.json
52
- console.log(chalk.cyan("📦 Initializing and configure package.json..."));
53
-
54
- const package_json = {
55
- name: project_name,
56
- version: "1.0.0",
57
- private: true,
58
- scripts: {
59
- dev: "next dev --turbopack",
60
- build: "next build",
61
- start: "next start",
62
- lint: "next lint",
63
- },
64
- };
65
-
66
- const package_json_path = path.join(project_path, "package.json");
67
- fs.writeFileSync(package_json_path, JSON.stringify(package_json, null, 2));
68
-
69
- // Install dependencies
70
- console.log(chalk.cyan("⬇️ Installing dependencies..."));
71
-
72
- components.forEach((e) => {
73
- const component_path = path.resolve(components_path, `${e}.json`);
74
-
75
- if (fs.existsSync(component_path) === false) {
76
- throw new Error(`Component ${e} not found`);
160
+ const responses = await prompts(
161
+ [
162
+ {
163
+ type: "multiselect",
164
+ name: "components",
165
+ message: "Which components do you want to install?",
166
+ instructions: false,
167
+ choices: COMPONENTS.map((e) => {
168
+ return { title: e, value: e };
169
+ }),
170
+ },
171
+ ],
172
+ { onCancel: on_cancel }
173
+ );
174
+
175
+ const { components } = responses;
176
+
177
+ // Set package manager
178
+ if (fs.existsSync(path.join(CWD, "package-lock.json")) === true) {
179
+ package_manager = "npm";
77
180
  }
78
181
 
79
- const json = JSON.parse(fs.readFileSync(component_path, "utf-8"));
182
+ if (fs.existsSync(path.join(CWD, "pnpm-lock.yaml")) === true) {
183
+ package_manager = "pnpm";
184
+ }
80
185
 
81
- json.forEach((e) => {
82
- DEPENDENCIES.push(e);
83
- });
84
- });
186
+ if (package_manager === undefined) {
187
+ throw new Error("Not package_manager found");
188
+ }
85
189
 
86
- if (package_manager === "npm") {
87
- run(`npm install ${DEPENDENCIES.join(" ")}`, project_path);
88
- run(`npm install ${DEV_DEPENDENCIES.join(" ")} -D`, project_path);
89
- }
190
+ // Copying files
191
+ DEST = path.resolve(CWD);
90
192
 
91
- if (package_manager === "pnpm") {
92
- run(`pnpm add ${DEPENDENCIES.join(" ")}`, project_path);
93
- run(`pnpm add ${DEV_DEPENDENCIES.join(" ")} -D`, project_path);
94
- }
193
+ await copy_components(DEST, components);
95
194
 
96
- console.log(chalk.green("\n✅ Project created successfully! 🚀"));
97
-
98
- console.log(
99
- chalk.yellow(
100
- "📄 Make sure to add your API in the .env file, e.g.: API=http://localhost:9000"
101
- )
102
- );
103
- process.exit(0);
104
- } catch (error) {
105
- console.error(chalk.red(" Internal error"), error.message);
106
- if (fs.existsSync(project_path) === true) {
107
- fs.rmSync(project_path, { recursive: true, force: true });
195
+ // Install dependencies
196
+ console.log(chalk.cyan("⬇️ Installing dependencies..."));
197
+
198
+ if (package_manager === "npm") {
199
+ run_command(`npm install ${DEPENDENCIES.join(" ")}`, DEST);
200
+ run_command(`npm install ${DEV_DEPENDENCIES.join(" ")} -D`, DEST);
201
+ }
202
+
203
+ if (package_manager === "pnpm") {
204
+ run_command(`pnpm add ${DEPENDENCIES.join(" ")}`, DEST);
205
+ run_command(`pnpm add ${DEV_DEPENDENCIES.join(" ")} -D`, DEST);
206
+ }
207
+
208
+ // Finish project
209
+ console.log(chalk.green("\n✅ Components add successfully!"));
210
+ } catch (error) {
211
+ console.error(chalk.red("❌ Internal error:"), error.message);
212
+
213
+ process.exit(1);
108
214
  }
109
- process.exit(1);
110
215
  }
111
- }
112
216
 
113
- main();
217
+ process.exit(0);
218
+ })();
package/src/utils.js ADDED
@@ -0,0 +1,113 @@
1
+ import {
2
+ COMPONENTS_PATH,
3
+ DEPENDENCIES,
4
+ DEV_DEPENDENCIES,
5
+ HOOKS_PATH,
6
+ TEMPLATE_PATH,
7
+ } from "./constants.js";
8
+ import fs from "node:fs";
9
+ import chalk from "chalk";
10
+ import path from "node:path";
11
+ import prompts from "prompts";
12
+ import { execSync } from "node:child_process";
13
+
14
+ function on_cancel() {
15
+ console.log(chalk.yellow("\n👋 Exiting..."));
16
+ process.exit(0);
17
+ }
18
+
19
+ function run_command(cmd, cwd) {
20
+ try {
21
+ execSync(cmd, { cwd, stdio: "inherit" });
22
+ } catch (error) {
23
+ throw error;
24
+ }
25
+ }
26
+
27
+ function copy_template(dest) {
28
+ try {
29
+ fs.cpSync(TEMPLATE_PATH, dest, { recursive: true });
30
+ } catch (error) {
31
+ throw error;
32
+ }
33
+ }
34
+
35
+ async function copy_components(DEST, components) {
36
+ try {
37
+ for (const component of components) {
38
+ let replace = false;
39
+
40
+ const component_path = path.resolve(COMPONENTS_PATH, `${component}.tsx`);
41
+ const dest_folder = path.resolve(DEST, "src", "components", "ui");
42
+ const final_dest = path.join(dest_folder, `${component}.tsx`);
43
+
44
+ if (fs.existsSync(component_path) === false) {
45
+ throw new Error(`Component ${component} not found`);
46
+ }
47
+
48
+ if (fs.existsSync(dest_folder) === false) {
49
+ fs.mkdirSync(dest_folder, { recursive: true });
50
+ }
51
+
52
+ if (fs.existsSync(final_dest) === true) {
53
+ const response = await prompts(
54
+ [
55
+ {
56
+ type: "confirm",
57
+ name: "replace",
58
+ message: `Do you want to replace ${component}.tsx?`,
59
+ },
60
+ ],
61
+ { onCancel: on_cancel }
62
+ );
63
+
64
+ replace = response.replace;
65
+ }
66
+
67
+ const json_path = path.resolve(COMPONENTS_PATH, `${component}.json`);
68
+
69
+ if (fs.existsSync(json_path) === false) {
70
+ throw new Error(`Json file of ${component} not found`);
71
+ }
72
+
73
+ const json = JSON.parse(fs.readFileSync(json_path, "utf8"));
74
+
75
+ if (fs.existsSync(final_dest) === false || replace === true) {
76
+ console.log(chalk.gray(`📄 Add ${component}.tsx file`));
77
+ fs.copyFileSync(component_path, final_dest);
78
+
79
+ for (const hook of json.hooks) {
80
+ const hook_path = path.resolve(HOOKS_PATH, `${hook}.ts`);
81
+ const dest_folder = path.resolve(DEST, "src", "hooks");
82
+ const final_dest = path.join(dest_folder, `${hook}.ts`);
83
+
84
+ if (fs.existsSync(hook_path) === false) {
85
+ throw new Error(`Hook ${hook} not found for component ${e}`);
86
+ }
87
+
88
+ if (fs.existsSync(dest_folder) === false) {
89
+ fs.mkdirSync(dest_folder, { recursive: true });
90
+ }
91
+
92
+ fs.copyFileSync(hook_path, final_dest);
93
+ }
94
+ }
95
+
96
+ for (const support of json.supports) {
97
+ await copy_components(DEST, [support]);
98
+ }
99
+
100
+ for (const dependence of json.dependencies) {
101
+ DEPENDENCIES.push(dependence);
102
+ }
103
+
104
+ for (const dev_dependence of json.dev_dependence) {
105
+ DEV_DEPENDENCIES.push(dev_dependence);
106
+ }
107
+ }
108
+ } catch (error) {
109
+ throw error;
110
+ }
111
+ }
112
+
113
+ export { on_cancel, run_command, copy_template, copy_components };
@@ -1,28 +0,0 @@
1
- export const DEPENDENCIES = [
2
- "@tanstack/react-query",
3
- "axios",
4
- "class-variance-authority",
5
- "clsx",
6
- "cookies-next",
7
- "date-fns",
8
- "lucide-react",
9
- "next",
10
- "next-auth",
11
- "next-themes",
12
- "react",
13
- "react-dom",
14
- "tailwind-merge",
15
- ];
16
-
17
- export const DEV_DEPENDENCIES = [
18
- "@eslint/eslintrc",
19
- "@tailwindcss/postcss",
20
- "@types/node",
21
- "@types/react",
22
- "@types/react-dom",
23
- "eslint",
24
- "eslint-config-next",
25
- "tailwindcss",
26
- "tw-animate-css",
27
- "typescript",
28
- ];
package/src/lib/utils.js DELETED
@@ -1,144 +0,0 @@
1
- import fs from "node:fs";
2
- import chalk from "chalk";
3
- import path from "node:path";
4
- import prompts from "prompts";
5
- import { execSync } from "node:child_process";
6
-
7
- export async function get_prompts() {
8
- const responses = await prompts([
9
- {
10
- type: "text",
11
- name: "project_name",
12
- message: "What is your project named?",
13
- validate: (e) => {
14
- if (e === undefined || e.trim() === "") {
15
- return chalk.red("⚠️ The name is required");
16
- }
17
-
18
- if (!/^[a-zA-Z0-9-_]+$/.test(e.trim())) {
19
- return chalk.red(
20
- "⚠️ Use only letters, numbers, dashes, and underscores."
21
- );
22
- }
23
-
24
- return true;
25
- },
26
- },
27
- {
28
- type: "select",
29
- name: "package_manager",
30
- message: "Which package manager would you want to use?",
31
- choices: [
32
- { title: "npm", value: "npm" },
33
- { title: "pnpm", value: "pnpm" },
34
- ],
35
- },
36
- {
37
- type: "multiselect",
38
- name: "components",
39
- message: "Which components do you want to install?",
40
- instructions: false,
41
- choices: [
42
- { title: "Accordion", value: "accordion" },
43
- { title: "Alert", value: "alert" },
44
- ],
45
- },
46
- {
47
- onCancel: () => {
48
- console.log(chalk.yellow("\n👋 Exiting..."));
49
- process.exit(0);
50
- },
51
- },
52
- ]);
53
-
54
- return responses;
55
- }
56
-
57
- export function copy_template_files(src, project_path) {
58
- try {
59
- const entries = fs.readdirSync(src, { withFileTypes: true });
60
-
61
- for (const entry of entries) {
62
- const src_path = path.join(src, entry.name);
63
- const dest_path = path.join(project_path, entry.name);
64
-
65
- if (entry.isDirectory()) {
66
- fs.mkdirSync(dest_path, { recursive: true });
67
- copy_template_files(src_path, dest_path);
68
- } else {
69
- fs.copyFileSync(src_path, dest_path);
70
- }
71
- }
72
- } catch (error) {
73
- throw error;
74
- }
75
- }
76
-
77
- export function copy_components_files(src, project_path, components) {
78
- try {
79
- components.forEach((e) => {
80
- const component_path = path.resolve(src, `${e}.tsx`);
81
- const dest_path = path.resolve(project_path, "src", "components", "ui");
82
-
83
- if (fs.existsSync(component_path) === false) {
84
- throw new Error(`Component ${e} not found`);
85
- }
86
-
87
- if (fs.existsSync(dest_path) === false) {
88
- fs.mkdirSync(dest_path, { recursive: true });
89
- }
90
-
91
- fs.copyFileSync(component_path, path.join(dest_path, `${e}.tsx`));
92
- });
93
- } catch (error) {
94
- throw error;
95
- }
96
- }
97
-
98
- export function copy_hooks_files(
99
- src,
100
- components_path,
101
- project_path,
102
- components
103
- ) {
104
- const map = {};
105
-
106
- try {
107
- components.forEach((e) => {
108
- const hook = map[e];
109
- const component_path = path.resolve(components_path, `${e}.tsx`);
110
-
111
- if (fs.existsSync(component_path) === false) {
112
- throw new Error(`Component ${e} not found`);
113
- }
114
-
115
- if (hook === undefined) {
116
- console.warn(`No hook mapping found for component ${e}, skipping.`);
117
- return;
118
- }
119
-
120
- const hook_path = path.resolve(src, `${hook}.ts`);
121
- const dest_path = path.resolve(project_path, "src", "hooks");
122
-
123
- if (fs.existsSync(hook_path) === false) {
124
- throw new Error(`Hook ${hook} not found for component ${e}`);
125
- }
126
-
127
- if (fs.existsSync(dest_path) === false) {
128
- fs.mkdirSync(dest_path, { recursive: true });
129
- }
130
-
131
- fs.copyFileSync(hook_path, path.join(dest_path, `${hook}.ts`));
132
- });
133
- } catch (error) {
134
- throw error;
135
- }
136
- }
137
-
138
- export function run(cmd, cwd) {
139
- try {
140
- execSync(cmd, { cwd, stdio: "inherit" });
141
- } catch (error) {
142
- throw error;
143
- }
144
- }
@@ -1 +0,0 @@
1
- ["@radix-ui/react-accordion"]
@@ -1 +0,0 @@
1
- []
File without changes
File without changes