@dinachi/cli 0.4.0 → 0.5.1
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 +27 -5
- package/dist/index.js +1037 -567
- package/package.json +6 -5
- package/templates/autocomplete/autocomplete.tsx +197 -0
- package/templates/autocomplete/index.ts +17 -0
- package/templates/combobox/combobox.tsx +202 -0
- package/templates/combobox/index.ts +17 -0
- package/templates/context-menu/context-menu.tsx +104 -39
- package/templates/drawer/drawer.tsx +109 -0
- package/templates/drawer/index.ts +12 -0
- package/templates/fieldset/fieldset.tsx +32 -0
- package/templates/fieldset/index.ts +1 -0
- package/templates/menu/index.ts +17 -0
- package/templates/menu/menu.tsx +282 -0
- package/templates/menubar/menubar.tsx +7 -7
- package/templates/meter/index.ts +1 -0
- package/templates/meter/meter.tsx +64 -0
- package/templates/number-field/index.ts +9 -0
- package/templates/number-field/number-field.tsx +114 -0
- package/templates/popover/index.ts +12 -0
- package/templates/popover/popover.tsx +137 -0
- package/templates/preview-card/preview-card.tsx +4 -5
- package/templates/progress/index.ts +7 -0
- package/templates/progress/progress.tsx +64 -0
- package/templates/radio/index.ts +1 -0
- package/templates/radio/radio.tsx +39 -0
- package/templates/scroll-area/index.ts +8 -0
- package/templates/scroll-area/scroll-area.tsx +94 -0
- package/templates/separator/index.ts +1 -0
- package/templates/separator/separator.tsx +25 -0
- package/templates/switch/index.ts +1 -0
- package/templates/switch/switch.tsx +42 -0
- package/templates/toggle-group/index.ts +1 -0
- package/templates/toggle-group/toggle-group.tsx +67 -0
- package/templates/tooltip/tooltip.tsx +2 -2
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { Command as Command3 } from "commander";
|
|
|
6
6
|
// src/commands/add.ts
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import fs3 from "fs-extra";
|
|
10
|
+
import path3 from "path";
|
|
11
11
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12
12
|
import ora from "ora";
|
|
13
13
|
import chalk from "chalk";
|
|
@@ -18,315 +18,314 @@ import path from "path";
|
|
|
18
18
|
import { fileURLToPath } from "url";
|
|
19
19
|
var __filename = fileURLToPath(import.meta.url);
|
|
20
20
|
var __dirname = path.dirname(__filename);
|
|
21
|
+
function dirnameLike(input) {
|
|
22
|
+
const normalized = input.replace(/\/+$/, "");
|
|
23
|
+
const idx = normalized.lastIndexOf("/");
|
|
24
|
+
if (idx <= 0) {
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
return normalized.slice(0, idx);
|
|
28
|
+
}
|
|
29
|
+
function normalizeConfig(raw) {
|
|
30
|
+
const style = typeof raw.style === "string" ? raw.style : "default";
|
|
31
|
+
const rsc = typeof raw.rsc === "boolean" ? raw.rsc : false;
|
|
32
|
+
const tsx = typeof raw.tsx === "boolean" ? raw.tsx : true;
|
|
33
|
+
const tailwindConfig = typeof raw.tailwind?.config === "string" ? raw.tailwind.config : "tailwind.config.js";
|
|
34
|
+
const tailwindCss = typeof raw.tailwind?.css === "string" ? raw.tailwind.css : "src/index.css";
|
|
35
|
+
const tailwindBaseColor = typeof raw.tailwind?.baseColor === "string" ? raw.tailwind.baseColor : "slate";
|
|
36
|
+
const tailwindCssVariables = typeof raw.tailwind?.cssVariables === "boolean" ? raw.tailwind.cssVariables : true;
|
|
37
|
+
const rawComponentsAlias = typeof raw.aliases?.components === "string" ? raw.aliases.components : "./src/components";
|
|
38
|
+
const hasLegacyUiPathInComponents = rawComponentsAlias.replace(/\/+$/, "").endsWith("/ui");
|
|
39
|
+
const componentsAlias = hasLegacyUiPathInComponents ? dirnameLike(rawComponentsAlias) : rawComponentsAlias;
|
|
40
|
+
const uiAlias = typeof raw.aliases?.ui === "string" ? raw.aliases.ui : hasLegacyUiPathInComponents ? rawComponentsAlias : `${componentsAlias}/ui`;
|
|
41
|
+
const utilsAlias = typeof raw.aliases?.utils === "string" ? raw.aliases.utils : "./src/lib/utils";
|
|
42
|
+
const libAlias = typeof raw.aliases?.lib === "string" ? raw.aliases.lib : dirnameLike(utilsAlias);
|
|
43
|
+
const hooksAlias = typeof raw.aliases?.hooks === "string" ? raw.aliases.hooks : "./src/hooks";
|
|
44
|
+
return {
|
|
45
|
+
style,
|
|
46
|
+
rsc,
|
|
47
|
+
tsx,
|
|
48
|
+
tailwind: {
|
|
49
|
+
config: tailwindConfig,
|
|
50
|
+
css: tailwindCss,
|
|
51
|
+
baseColor: tailwindBaseColor,
|
|
52
|
+
cssVariables: tailwindCssVariables
|
|
53
|
+
},
|
|
54
|
+
aliases: {
|
|
55
|
+
components: componentsAlias,
|
|
56
|
+
utils: utilsAlias,
|
|
57
|
+
ui: uiAlias,
|
|
58
|
+
lib: libAlias,
|
|
59
|
+
hooks: hooksAlias
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
21
63
|
function getUtilityRegistry() {
|
|
22
64
|
return {
|
|
23
65
|
cn: {
|
|
24
66
|
name: "utils",
|
|
25
|
-
dependencies: [
|
|
26
|
-
"clsx",
|
|
27
|
-
"tailwind-merge"
|
|
28
|
-
]
|
|
67
|
+
dependencies: ["clsx", "tailwind-merge"]
|
|
29
68
|
},
|
|
30
69
|
variants: {
|
|
31
70
|
name: "variants",
|
|
32
|
-
dependencies: [
|
|
33
|
-
"class-variance-authority"
|
|
34
|
-
]
|
|
71
|
+
dependencies: ["class-variance-authority"]
|
|
35
72
|
}
|
|
36
73
|
};
|
|
37
74
|
}
|
|
38
75
|
function getComponentRegistry() {
|
|
39
76
|
return {
|
|
40
|
-
button: {
|
|
41
|
-
name: "button",
|
|
42
|
-
description: "A customizable button component with multiple variants",
|
|
43
|
-
files: [
|
|
44
|
-
{ name: "button.tsx" },
|
|
45
|
-
{ name: "index.ts" }
|
|
46
|
-
],
|
|
47
|
-
dependencies: [
|
|
48
|
-
"@base-ui/react",
|
|
49
|
-
"class-variance-authority"
|
|
50
|
-
],
|
|
51
|
-
componentDependencies: ["core"],
|
|
52
|
-
utilityDependencies: ["cn", "variants"]
|
|
53
|
-
},
|
|
54
|
-
input: {
|
|
55
|
-
name: "input",
|
|
56
|
-
description: "A customizable input field component with variants and sizes",
|
|
57
|
-
files: [
|
|
58
|
-
{ name: "input.tsx" },
|
|
59
|
-
{ name: "index.ts" }
|
|
60
|
-
],
|
|
61
|
-
dependencies: [
|
|
62
|
-
"@base-ui/react"
|
|
63
|
-
],
|
|
64
|
-
utilityDependencies: ["cn"]
|
|
65
|
-
},
|
|
66
|
-
field: {
|
|
67
|
-
name: "field",
|
|
68
|
-
description: "A component for building accessible forms with custom styling and validation.",
|
|
69
|
-
files: [
|
|
70
|
-
{ name: "field.tsx" },
|
|
71
|
-
{ name: "index.ts" }
|
|
72
|
-
],
|
|
73
|
-
dependencies: [
|
|
74
|
-
"@base-ui/react"
|
|
75
|
-
],
|
|
76
|
-
utilityDependencies: ["cn"]
|
|
77
|
-
},
|
|
78
|
-
form: {
|
|
79
|
-
name: "form",
|
|
80
|
-
description: "A native form element with consolidated error handling, built on Base UI foundation.",
|
|
81
|
-
files: [
|
|
82
|
-
{ name: "form.tsx" },
|
|
83
|
-
{ name: "index.ts" }
|
|
84
|
-
],
|
|
85
|
-
dependencies: [
|
|
86
|
-
"@base-ui/react"
|
|
87
|
-
],
|
|
88
|
-
utilityDependencies: ["cn"]
|
|
89
|
-
},
|
|
90
|
-
"alert-dialog": {
|
|
91
|
-
name: "alert-dialog",
|
|
92
|
-
description: "A modal dialog that interrupts the user with important content and expects a response.",
|
|
93
|
-
files: [
|
|
94
|
-
{ name: "alert-dialog.tsx" },
|
|
95
|
-
{ name: "index.ts" }
|
|
96
|
-
],
|
|
97
|
-
dependencies: [
|
|
98
|
-
"@base-ui/react",
|
|
99
|
-
"lucide-react"
|
|
100
|
-
],
|
|
101
|
-
utilityDependencies: ["cn"]
|
|
102
|
-
},
|
|
103
77
|
accordion: {
|
|
104
78
|
name: "accordion",
|
|
105
79
|
description: "A vertically stacked set of interactive headings that each reveal a section of content.",
|
|
106
|
-
files: [
|
|
107
|
-
|
|
108
|
-
{ name: "index.ts" }
|
|
109
|
-
],
|
|
110
|
-
dependencies: [
|
|
111
|
-
"@base-ui/react",
|
|
112
|
-
"lucide-react",
|
|
113
|
-
"tailwindcss-animate"
|
|
114
|
-
],
|
|
80
|
+
files: [{ name: "accordion.tsx" }, { name: "index.ts" }],
|
|
81
|
+
dependencies: ["@base-ui/react", "lucide-react", "tailwindcss-animate"],
|
|
115
82
|
utilityDependencies: ["cn"]
|
|
116
83
|
},
|
|
117
|
-
|
|
118
|
-
name: "
|
|
119
|
-
description: "A
|
|
120
|
-
files: [
|
|
121
|
-
|
|
122
|
-
{ name: "index.ts" }
|
|
123
|
-
],
|
|
124
|
-
dependencies: [
|
|
125
|
-
"@base-ui/react"
|
|
126
|
-
],
|
|
84
|
+
"alert-dialog": {
|
|
85
|
+
name: "alert-dialog",
|
|
86
|
+
description: "A modal dialog that interrupts the user with important content and expects a response.",
|
|
87
|
+
files: [{ name: "alert-dialog.tsx" }, { name: "index.ts" }],
|
|
88
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
127
89
|
utilityDependencies: ["cn"]
|
|
128
90
|
},
|
|
129
|
-
|
|
130
|
-
name: "
|
|
131
|
-
description: "
|
|
132
|
-
files: [
|
|
133
|
-
|
|
134
|
-
{ name: "index.ts" }
|
|
135
|
-
],
|
|
136
|
-
dependencies: [
|
|
137
|
-
"@base-ui/react"
|
|
138
|
-
],
|
|
91
|
+
autocomplete: {
|
|
92
|
+
name: "autocomplete",
|
|
93
|
+
description: "A text input with dynamic suggestions that helps users find and select values quickly.",
|
|
94
|
+
files: [{ name: "autocomplete.tsx" }, { name: "index.ts" }],
|
|
95
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
139
96
|
utilityDependencies: ["cn"]
|
|
140
97
|
},
|
|
141
98
|
avatar: {
|
|
142
99
|
name: "avatar",
|
|
143
100
|
description: "An image element with a fallback for representing a user.",
|
|
144
|
-
files: [
|
|
145
|
-
|
|
146
|
-
{ name: "index.ts" }
|
|
147
|
-
],
|
|
148
|
-
dependencies: [
|
|
149
|
-
"@base-ui/react",
|
|
150
|
-
"class-variance-authority"
|
|
151
|
-
],
|
|
101
|
+
files: [{ name: "avatar.tsx" }, { name: "index.ts" }],
|
|
102
|
+
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
152
103
|
utilityDependencies: ["cn"]
|
|
153
104
|
},
|
|
105
|
+
button: {
|
|
106
|
+
name: "button",
|
|
107
|
+
description: "A customizable button component with multiple variants.",
|
|
108
|
+
files: [{ name: "button.tsx" }, { name: "index.ts" }],
|
|
109
|
+
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
110
|
+
utilityDependencies: ["cn", "variants"]
|
|
111
|
+
},
|
|
154
112
|
checkbox: {
|
|
155
113
|
name: "checkbox",
|
|
156
114
|
description: "A control that allows the user to select one or more options from a set.",
|
|
157
|
-
files: [
|
|
158
|
-
|
|
159
|
-
{ name: "index.ts" }
|
|
160
|
-
],
|
|
161
|
-
dependencies: [
|
|
162
|
-
"@base-ui/react",
|
|
163
|
-
"lucide-react"
|
|
164
|
-
],
|
|
115
|
+
files: [{ name: "checkbox.tsx" }, { name: "index.ts" }],
|
|
116
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
165
117
|
utilityDependencies: ["cn"]
|
|
166
118
|
},
|
|
167
119
|
"checkbox-group": {
|
|
168
120
|
name: "checkbox-group",
|
|
169
121
|
description: "A group of checkboxes that share a common state.",
|
|
170
|
-
files: [
|
|
171
|
-
|
|
172
|
-
{ name: "index.ts" }
|
|
173
|
-
],
|
|
174
|
-
dependencies: [
|
|
175
|
-
"@base-ui/react"
|
|
176
|
-
],
|
|
122
|
+
files: [{ name: "checkbox-group.tsx" }, { name: "index.ts" }],
|
|
123
|
+
dependencies: ["@base-ui/react"],
|
|
177
124
|
componentDependencies: ["checkbox"],
|
|
178
125
|
utilityDependencies: ["cn"]
|
|
179
126
|
},
|
|
180
|
-
|
|
127
|
+
collapsible: {
|
|
181
128
|
name: "collapsible",
|
|
182
129
|
description: "A collapsible panel controlled by a button.",
|
|
183
|
-
files: [
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
],
|
|
130
|
+
files: [{ name: "collapsible.tsx" }, { name: "index.ts" }],
|
|
131
|
+
dependencies: ["@base-ui/react", "tailwindcss-animate"],
|
|
132
|
+
utilityDependencies: ["cn"]
|
|
133
|
+
},
|
|
134
|
+
combobox: {
|
|
135
|
+
name: "combobox",
|
|
136
|
+
description: "A combobox that combines text input with a selectable popup list of options.",
|
|
137
|
+
files: [{ name: "combobox.tsx" }, { name: "index.ts" }],
|
|
138
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
139
|
+
utilityDependencies: ["cn"]
|
|
140
|
+
},
|
|
141
|
+
"context-menu": {
|
|
142
|
+
name: "context-menu",
|
|
143
|
+
description: "A menu that appears at the pointer on right click or long press.",
|
|
144
|
+
files: [{ name: "context-menu.tsx" }, { name: "index.ts" }],
|
|
145
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
191
146
|
utilityDependencies: ["cn"]
|
|
192
147
|
},
|
|
193
148
|
dialog: {
|
|
194
149
|
name: "dialog",
|
|
195
150
|
description: "A popup that opens on top of the entire page, providing a modal interface for user interactions.",
|
|
196
|
-
files: [
|
|
197
|
-
|
|
198
|
-
{ name: "index.ts" }
|
|
199
|
-
],
|
|
200
|
-
dependencies: [
|
|
201
|
-
"@base-ui/react"
|
|
202
|
-
],
|
|
151
|
+
files: [{ name: "dialog.tsx" }, { name: "index.ts" }],
|
|
152
|
+
dependencies: ["@base-ui/react"],
|
|
203
153
|
utilityDependencies: ["cn"]
|
|
204
154
|
},
|
|
205
|
-
|
|
206
|
-
name: "
|
|
207
|
-
description: "
|
|
208
|
-
files: [
|
|
209
|
-
|
|
210
|
-
{ name: "index.ts" }
|
|
211
|
-
],
|
|
212
|
-
dependencies: [
|
|
213
|
-
"@base-ui/react",
|
|
214
|
-
"class-variance-authority"
|
|
215
|
-
],
|
|
155
|
+
drawer: {
|
|
156
|
+
name: "drawer",
|
|
157
|
+
description: "A panel that slides in from the edge of the screen for focused workflows.",
|
|
158
|
+
files: [{ name: "drawer.tsx" }, { name: "index.ts" }],
|
|
159
|
+
dependencies: ["@base-ui/react"],
|
|
216
160
|
utilityDependencies: ["cn"]
|
|
217
161
|
},
|
|
218
|
-
|
|
219
|
-
name: "
|
|
220
|
-
description: "A
|
|
221
|
-
files: [
|
|
222
|
-
|
|
223
|
-
{ name: "index.ts" }
|
|
224
|
-
],
|
|
225
|
-
dependencies: [
|
|
226
|
-
"@base-ui/react",
|
|
227
|
-
"lucide-react"
|
|
228
|
-
],
|
|
162
|
+
field: {
|
|
163
|
+
name: "field",
|
|
164
|
+
description: "A component for building accessible forms with custom styling and validation.",
|
|
165
|
+
files: [{ name: "field.tsx" }, { name: "index.ts" }],
|
|
166
|
+
dependencies: ["@base-ui/react"],
|
|
229
167
|
utilityDependencies: ["cn"]
|
|
230
168
|
},
|
|
231
|
-
|
|
232
|
-
name: "
|
|
233
|
-
description: "A
|
|
234
|
-
files: [
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
],
|
|
169
|
+
fieldset: {
|
|
170
|
+
name: "fieldset",
|
|
171
|
+
description: "A grouping container for related form controls with an accessible legend.",
|
|
172
|
+
files: [{ name: "fieldset.tsx" }, { name: "index.ts" }],
|
|
173
|
+
dependencies: ["@base-ui/react"],
|
|
174
|
+
utilityDependencies: ["cn"]
|
|
175
|
+
},
|
|
176
|
+
form: {
|
|
177
|
+
name: "form",
|
|
178
|
+
description: "A native form element with consolidated error handling, built on Base UI foundation.",
|
|
179
|
+
files: [{ name: "form.tsx" }, { name: "index.ts" }],
|
|
180
|
+
dependencies: ["@base-ui/react"],
|
|
181
|
+
utilityDependencies: ["cn"]
|
|
182
|
+
},
|
|
183
|
+
input: {
|
|
184
|
+
name: "input",
|
|
185
|
+
description: "A customizable input field component with variants and sizes.",
|
|
186
|
+
files: [{ name: "input.tsx" }, { name: "index.ts" }],
|
|
187
|
+
dependencies: ["@base-ui/react"],
|
|
188
|
+
utilityDependencies: ["cn"]
|
|
189
|
+
},
|
|
190
|
+
menu: {
|
|
191
|
+
name: "menu",
|
|
192
|
+
description: "A popup menu for actions and options triggered by a button.",
|
|
193
|
+
files: [{ name: "menu.tsx" }, { name: "index.ts" }],
|
|
194
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
242
195
|
utilityDependencies: ["cn"]
|
|
243
196
|
},
|
|
244
197
|
menubar: {
|
|
245
198
|
name: "menubar",
|
|
246
199
|
description: "A visually persistent menu common in desktop applications that provides access to a consistent set of commands.",
|
|
247
|
-
files: [
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
],
|
|
200
|
+
files: [{ name: "menubar.tsx" }, { name: "index.ts" }],
|
|
201
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
202
|
+
utilityDependencies: ["cn"]
|
|
203
|
+
},
|
|
204
|
+
meter: {
|
|
205
|
+
name: "meter",
|
|
206
|
+
description: "A visual representation of a scalar measurement within a known range.",
|
|
207
|
+
files: [{ name: "meter.tsx" }, { name: "index.ts" }],
|
|
208
|
+
dependencies: ["@base-ui/react"],
|
|
255
209
|
utilityDependencies: ["cn"]
|
|
256
210
|
},
|
|
257
211
|
"navigation-menu": {
|
|
258
212
|
name: "navigation-menu",
|
|
259
213
|
description: "A collection of links and menus for website navigation.",
|
|
260
|
-
files: [
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
],
|
|
214
|
+
files: [{ name: "navigation-menu.tsx" }, { name: "index.ts" }],
|
|
215
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
216
|
+
utilityDependencies: ["cn"]
|
|
217
|
+
},
|
|
218
|
+
"number-field": {
|
|
219
|
+
name: "number-field",
|
|
220
|
+
description: "A numeric input with increment, decrement, and optional scrubbing controls.",
|
|
221
|
+
files: [{ name: "number-field.tsx" }, { name: "index.ts" }],
|
|
222
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
223
|
+
utilityDependencies: ["cn"]
|
|
224
|
+
},
|
|
225
|
+
popover: {
|
|
226
|
+
name: "popover",
|
|
227
|
+
description: "An anchored floating panel for contextual information and lightweight interactions.",
|
|
228
|
+
files: [{ name: "popover.tsx" }, { name: "index.ts" }],
|
|
229
|
+
dependencies: ["@base-ui/react"],
|
|
268
230
|
utilityDependencies: ["cn"]
|
|
269
231
|
},
|
|
270
232
|
"preview-card": {
|
|
271
233
|
name: "preview-card",
|
|
272
234
|
description: "A popup that appears when a link is hovered, showing a preview for sighted users.",
|
|
273
|
-
files: [
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
235
|
+
files: [{ name: "preview-card.tsx" }, { name: "index.ts" }],
|
|
236
|
+
dependencies: ["@base-ui/react"],
|
|
237
|
+
utilityDependencies: ["cn"]
|
|
238
|
+
},
|
|
239
|
+
progress: {
|
|
240
|
+
name: "progress",
|
|
241
|
+
description: "A progress bar that communicates task completion to users and assistive technology.",
|
|
242
|
+
files: [{ name: "progress.tsx" }, { name: "index.ts" }],
|
|
243
|
+
dependencies: ["@base-ui/react"],
|
|
244
|
+
utilityDependencies: ["cn"]
|
|
245
|
+
},
|
|
246
|
+
radio: {
|
|
247
|
+
name: "radio",
|
|
248
|
+
description: "A radio input and group for selecting a single option from a set.",
|
|
249
|
+
files: [{ name: "radio.tsx" }, { name: "index.ts" }],
|
|
250
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
251
|
+
utilityDependencies: ["cn"]
|
|
252
|
+
},
|
|
253
|
+
"scroll-area": {
|
|
254
|
+
name: "scroll-area",
|
|
255
|
+
description: "A custom scroll container with styled scrollbars and optional corner rendering.",
|
|
256
|
+
files: [{ name: "scroll-area.tsx" }, { name: "index.ts" }],
|
|
257
|
+
dependencies: ["@base-ui/react"],
|
|
258
|
+
utilityDependencies: ["cn"]
|
|
259
|
+
},
|
|
260
|
+
select: {
|
|
261
|
+
name: "select",
|
|
262
|
+
description: "A common form component for choosing a predefined value in a dropdown menu.",
|
|
263
|
+
files: [{ name: "select.tsx" }, { name: "index.ts" }],
|
|
264
|
+
dependencies: ["@base-ui/react", "lucide-react"],
|
|
265
|
+
utilityDependencies: ["cn"]
|
|
266
|
+
},
|
|
267
|
+
separator: {
|
|
268
|
+
name: "separator",
|
|
269
|
+
description: "A visual divider used to separate and organize content.",
|
|
270
|
+
files: [{ name: "separator.tsx" }, { name: "index.ts" }],
|
|
271
|
+
dependencies: ["@base-ui/react"],
|
|
272
|
+
utilityDependencies: ["cn"]
|
|
273
|
+
},
|
|
274
|
+
slider: {
|
|
275
|
+
name: "slider",
|
|
276
|
+
description: "An input where the user selects a value from within a given range.",
|
|
277
|
+
files: [{ name: "slider.tsx" }, { name: "index.ts" }],
|
|
278
|
+
dependencies: ["@base-ui/react"],
|
|
279
|
+
utilityDependencies: ["cn"]
|
|
280
|
+
},
|
|
281
|
+
switch: {
|
|
282
|
+
name: "switch",
|
|
283
|
+
description: "A control that allows users to toggle a setting on or off.",
|
|
284
|
+
files: [{ name: "switch.tsx" }, { name: "index.ts" }],
|
|
285
|
+
dependencies: ["@base-ui/react"],
|
|
286
|
+
utilityDependencies: ["cn"]
|
|
287
|
+
},
|
|
288
|
+
tabs: {
|
|
289
|
+
name: "tabs",
|
|
290
|
+
description: "A component for toggling between related panels on the same page.",
|
|
291
|
+
files: [{ name: "tabs.tsx" }, { name: "index.ts" }],
|
|
292
|
+
dependencies: ["@base-ui/react"],
|
|
293
|
+
utilityDependencies: ["cn"]
|
|
294
|
+
},
|
|
295
|
+
toast: {
|
|
296
|
+
name: "toast",
|
|
297
|
+
description: "Generates toast notifications with support for different types, promises, actions, and global management.",
|
|
298
|
+
files: [{ name: "toast.tsx" }, { name: "index.ts" }],
|
|
299
|
+
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
280
300
|
utilityDependencies: ["cn"]
|
|
281
301
|
},
|
|
282
302
|
toggle: {
|
|
283
303
|
name: "toggle",
|
|
284
304
|
description: "A two-state button that can be on or off.",
|
|
285
|
-
files: [
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
],
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
"
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"
|
|
307
|
-
|
|
308
|
-
]
|
|
309
|
-
"utilityDependencies": [
|
|
310
|
-
"cn"
|
|
311
|
-
]
|
|
312
|
-
},
|
|
313
|
-
"tooltip": {
|
|
314
|
-
"name": "tooltip",
|
|
315
|
-
"description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
|
|
316
|
-
"files": [
|
|
317
|
-
{
|
|
318
|
-
"name": "tooltip.tsx"
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
"name": "index.ts"
|
|
322
|
-
}
|
|
323
|
-
],
|
|
324
|
-
"dependencies": [
|
|
325
|
-
"@base-ui/react"
|
|
326
|
-
],
|
|
327
|
-
"utilityDependencies": [
|
|
328
|
-
"cn"
|
|
329
|
-
]
|
|
305
|
+
files: [{ name: "toggle.tsx" }, { name: "index.ts" }],
|
|
306
|
+
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
307
|
+
utilityDependencies: ["cn"]
|
|
308
|
+
},
|
|
309
|
+
"toggle-group": {
|
|
310
|
+
name: "toggle-group",
|
|
311
|
+
description: "A grouped set of toggles supporting single or multiple pressed states.",
|
|
312
|
+
files: [{ name: "toggle-group.tsx" }, { name: "index.ts" }],
|
|
313
|
+
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
314
|
+
utilityDependencies: ["cn"]
|
|
315
|
+
},
|
|
316
|
+
toolbar: {
|
|
317
|
+
name: "toolbar",
|
|
318
|
+
description: "A container for grouping a set of controls, such as buttons, toggle groups, or dropdown menus.",
|
|
319
|
+
files: [{ name: "toolbar.tsx" }, { name: "index.ts" }],
|
|
320
|
+
dependencies: ["@base-ui/react"],
|
|
321
|
+
utilityDependencies: ["cn"]
|
|
322
|
+
},
|
|
323
|
+
tooltip: {
|
|
324
|
+
name: "tooltip",
|
|
325
|
+
description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
|
|
326
|
+
files: [{ name: "tooltip.tsx" }, { name: "index.ts" }],
|
|
327
|
+
dependencies: ["@base-ui/react"],
|
|
328
|
+
utilityDependencies: ["cn"]
|
|
330
329
|
}
|
|
331
330
|
};
|
|
332
331
|
}
|
|
@@ -337,302 +336,676 @@ async function getConfig() {
|
|
|
337
336
|
}
|
|
338
337
|
try {
|
|
339
338
|
const configContent = await fs.readFile(configPath, "utf-8");
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
const parsed = JSON.parse(configContent);
|
|
340
|
+
return normalizeConfig(parsed);
|
|
341
|
+
} catch {
|
|
342
342
|
return null;
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
// src/utils/package-manager.ts
|
|
347
|
+
import fs2 from "fs-extra";
|
|
348
|
+
import path2 from "path";
|
|
349
|
+
var LOCK_FILE_MAP = [
|
|
350
|
+
{ file: "bun.lockb", manager: "bun" },
|
|
351
|
+
{ file: "bun.lock", manager: "bun" },
|
|
352
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
353
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
354
|
+
{ file: "package-lock.json", manager: "npm" }
|
|
355
|
+
];
|
|
356
|
+
function walkUpDirectories(startDir) {
|
|
357
|
+
const dirs = [];
|
|
358
|
+
let current = path2.resolve(startDir);
|
|
359
|
+
while (true) {
|
|
360
|
+
dirs.push(current);
|
|
361
|
+
const parent = path2.dirname(current);
|
|
362
|
+
if (parent === current) {
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
current = parent;
|
|
366
|
+
}
|
|
367
|
+
return dirs;
|
|
368
|
+
}
|
|
369
|
+
function detectManagerFromPackageJson(startDir) {
|
|
370
|
+
for (const dir of walkUpDirectories(startDir)) {
|
|
371
|
+
const packageJsonPath = path2.join(dir, "package.json");
|
|
372
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
377
|
+
const value = packageJson.packageManager ?? "";
|
|
378
|
+
if (value.startsWith("pnpm@")) return "pnpm";
|
|
379
|
+
if (value.startsWith("yarn@")) return "yarn";
|
|
380
|
+
if (value.startsWith("bun@")) return "bun";
|
|
381
|
+
if (value.startsWith("npm@")) return "npm";
|
|
382
|
+
} catch {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
function detectPackageManager(startDir = process.cwd()) {
|
|
389
|
+
const packageJsonManager = detectManagerFromPackageJson(startDir);
|
|
390
|
+
if (packageJsonManager) {
|
|
391
|
+
return packageJsonManager;
|
|
392
|
+
}
|
|
393
|
+
for (const dir of walkUpDirectories(startDir)) {
|
|
394
|
+
for (const entry of LOCK_FILE_MAP) {
|
|
395
|
+
if (fs2.existsSync(path2.join(dir, entry.file))) {
|
|
396
|
+
return entry.manager;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return "npm";
|
|
401
|
+
}
|
|
402
|
+
function getInstallCommand(pm, deps) {
|
|
403
|
+
const depsStr = deps.join(" ");
|
|
404
|
+
switch (pm) {
|
|
405
|
+
case "bun":
|
|
406
|
+
return `bun add ${depsStr}`;
|
|
407
|
+
case "pnpm":
|
|
408
|
+
return `pnpm add ${depsStr}`;
|
|
409
|
+
case "yarn":
|
|
410
|
+
return `yarn add ${depsStr}`;
|
|
411
|
+
default:
|
|
412
|
+
return `npm install ${depsStr}`;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/utils/json.ts
|
|
417
|
+
function parseJsonWithComments(content) {
|
|
418
|
+
let result = "";
|
|
419
|
+
let inString = false;
|
|
420
|
+
let inSingleLineComment = false;
|
|
421
|
+
let inMultiLineComment = false;
|
|
422
|
+
let isEscaped = false;
|
|
423
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
424
|
+
const char = content[i];
|
|
425
|
+
const next = content[i + 1];
|
|
426
|
+
if (inSingleLineComment) {
|
|
427
|
+
if (char === "\n") {
|
|
428
|
+
inSingleLineComment = false;
|
|
429
|
+
result += char;
|
|
430
|
+
}
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (inMultiLineComment) {
|
|
434
|
+
if (char === "*" && next === "/") {
|
|
435
|
+
inMultiLineComment = false;
|
|
436
|
+
i += 1;
|
|
437
|
+
} else if (char === "\n") {
|
|
438
|
+
result += char;
|
|
439
|
+
}
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (inString) {
|
|
443
|
+
result += char;
|
|
444
|
+
if (!isEscaped && char === '"') {
|
|
445
|
+
inString = false;
|
|
446
|
+
}
|
|
447
|
+
isEscaped = !isEscaped && char === "\\";
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (char === '"') {
|
|
451
|
+
inString = true;
|
|
452
|
+
isEscaped = false;
|
|
453
|
+
result += char;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (char === "/" && next === "/") {
|
|
457
|
+
inSingleLineComment = true;
|
|
458
|
+
i += 1;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (char === "/" && next === "*") {
|
|
462
|
+
inMultiLineComment = true;
|
|
463
|
+
i += 1;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
result += char;
|
|
467
|
+
}
|
|
468
|
+
const withoutLineComments = result;
|
|
469
|
+
const withoutTrailingCommas = withoutLineComments.replace(/,\s*([}\]])/g, "$1");
|
|
470
|
+
return JSON.parse(withoutTrailingCommas);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/utils/dependencies.ts
|
|
474
|
+
var DEPENDENCY_VERSION_MAP = {
|
|
475
|
+
"@base-ui/react": "^1.2.0",
|
|
476
|
+
"lucide-react": "^0.552.0",
|
|
477
|
+
"class-variance-authority": "^0.7.1",
|
|
478
|
+
"tailwindcss-animate": "^1.0.7",
|
|
479
|
+
"clsx": "^2.1.1",
|
|
480
|
+
"tailwind-merge": "^3.3.1"
|
|
481
|
+
};
|
|
482
|
+
function toInstallSpec(dep) {
|
|
483
|
+
const version = DEPENDENCY_VERSION_MAP[dep];
|
|
484
|
+
return version ? `${dep}@${version}` : dep;
|
|
485
|
+
}
|
|
486
|
+
|
|
346
487
|
// src/commands/add.ts
|
|
347
488
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
348
|
-
var __dirname2 =
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
489
|
+
var __dirname2 = path3.dirname(__filename2);
|
|
490
|
+
function stripTemplateDirective(content) {
|
|
491
|
+
return content.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
|
|
492
|
+
}
|
|
493
|
+
function stripExtension(filePath) {
|
|
494
|
+
return filePath.replace(/\.[^./\\]+$/, "");
|
|
495
|
+
}
|
|
496
|
+
function toImportPath(fromFilePath, toFilePath) {
|
|
497
|
+
const relativePath = path3.relative(path3.dirname(fromFilePath), stripExtension(toFilePath)).replace(/\\/g, "/");
|
|
498
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
499
|
+
}
|
|
500
|
+
function matchPathPattern(pattern, input) {
|
|
501
|
+
if (!pattern.includes("*")) {
|
|
502
|
+
return pattern === input ? "" : null;
|
|
503
|
+
}
|
|
504
|
+
const [prefix, suffix] = pattern.split("*");
|
|
505
|
+
if (!input.startsWith(prefix) || !input.endsWith(suffix)) {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
return input.slice(prefix.length, input.length - suffix.length);
|
|
509
|
+
}
|
|
510
|
+
function readCompilerPathConfig(projectRoot) {
|
|
511
|
+
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
512
|
+
for (const configFile of configFiles) {
|
|
513
|
+
const configPath = path3.join(projectRoot, configFile);
|
|
514
|
+
if (!fs3.existsSync(configPath)) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
519
|
+
const parsed = parseJsonWithComments(content);
|
|
520
|
+
const compilerOptions = parsed.compilerOptions ?? {};
|
|
521
|
+
const baseUrl = path3.resolve(
|
|
522
|
+
projectRoot,
|
|
523
|
+
typeof compilerOptions.baseUrl === "string" ? compilerOptions.baseUrl : "."
|
|
524
|
+
);
|
|
525
|
+
const rawPaths = compilerOptions.paths ?? {};
|
|
526
|
+
const paths = {};
|
|
527
|
+
for (const [key, value] of Object.entries(rawPaths)) {
|
|
528
|
+
if (!Array.isArray(value)) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const targets = value.filter((entry) => typeof entry === "string");
|
|
532
|
+
if (targets.length > 0) {
|
|
533
|
+
paths[key] = targets;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return { baseUrl, paths };
|
|
537
|
+
} catch {
|
|
538
|
+
continue;
|
|
363
539
|
}
|
|
364
540
|
}
|
|
365
|
-
return
|
|
541
|
+
return null;
|
|
366
542
|
}
|
|
367
|
-
function
|
|
543
|
+
function resolveConfiguredPath(aliasOrPath, projectRoot, compilerConfig) {
|
|
544
|
+
const normalized = aliasOrPath.replace(/\\/g, "/").trim();
|
|
545
|
+
if (path3.isAbsolute(normalized)) {
|
|
546
|
+
return normalized;
|
|
547
|
+
}
|
|
548
|
+
if (normalized.startsWith("./") || normalized.startsWith("../")) {
|
|
549
|
+
return path3.resolve(projectRoot, normalized);
|
|
550
|
+
}
|
|
551
|
+
if (normalized.startsWith("/")) {
|
|
552
|
+
return path3.resolve(projectRoot, `.${normalized}`);
|
|
553
|
+
}
|
|
554
|
+
if (compilerConfig) {
|
|
555
|
+
for (const [pattern, targets] of Object.entries(compilerConfig.paths)) {
|
|
556
|
+
const wildcard = matchPathPattern(pattern, normalized);
|
|
557
|
+
if (wildcard === null) {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const target = targets[0];
|
|
561
|
+
if (!target) {
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
const mappedTarget = target.includes("*") ? target.replace("*", wildcard) : target;
|
|
565
|
+
return path3.resolve(compilerConfig.baseUrl, mappedTarget);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (normalized.startsWith("@/") || normalized.startsWith("~/")) {
|
|
569
|
+
return path3.resolve(projectRoot, normalized.slice(2));
|
|
570
|
+
}
|
|
571
|
+
return path3.resolve(projectRoot, normalized);
|
|
572
|
+
}
|
|
573
|
+
function rewriteTemplateImports(content, targetFilePath, utilsFilePath, libDirPath) {
|
|
574
|
+
const utilsImportPath = toImportPath(targetFilePath, utilsFilePath);
|
|
575
|
+
const variantsImportPath = toImportPath(targetFilePath, path3.join(libDirPath, "variants.ts"));
|
|
576
|
+
return content.replace(/(['"])@\/lib\/utils\1/g, `$1${utilsImportPath}$1`).replace(/(['"])@\/lib\/variants\1/g, `$1${variantsImportPath}$1`);
|
|
577
|
+
}
|
|
578
|
+
function getComponentDependencies(componentName, visited = /* @__PURE__ */ new Set()) {
|
|
579
|
+
if (visited.has(componentName)) {
|
|
580
|
+
return [];
|
|
581
|
+
}
|
|
582
|
+
visited.add(componentName);
|
|
368
583
|
const registry = getComponentRegistry();
|
|
369
584
|
const component = registry[componentName];
|
|
370
585
|
if (!component) return [];
|
|
371
|
-
|
|
586
|
+
const dependencies = [];
|
|
372
587
|
for (const dep of component.componentDependencies || []) {
|
|
373
|
-
|
|
588
|
+
if (!registry[dep]) {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
dependencies.push(dep, ...getComponentDependencies(dep, visited));
|
|
374
592
|
}
|
|
375
593
|
return [...new Set(dependencies)];
|
|
376
594
|
}
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
if (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
595
|
+
function detectTailwindConfigPath(projectRoot, configuredName) {
|
|
596
|
+
const preferred = resolveConfiguredPath(configuredName, projectRoot, null);
|
|
597
|
+
if (fs3.existsSync(preferred)) {
|
|
598
|
+
return preferred;
|
|
599
|
+
}
|
|
600
|
+
const alternatives = [
|
|
601
|
+
"tailwind.config.ts",
|
|
602
|
+
"tailwind.config.js",
|
|
603
|
+
"tailwind.config.mjs",
|
|
604
|
+
"tailwind.config.cjs",
|
|
605
|
+
"tailwind.config.cts",
|
|
606
|
+
"tailwind.config.mts"
|
|
607
|
+
];
|
|
608
|
+
for (const candidate of alternatives) {
|
|
609
|
+
const candidatePath = path3.join(projectRoot, candidate);
|
|
610
|
+
if (fs3.existsSync(candidatePath)) {
|
|
611
|
+
return candidatePath;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return preferred;
|
|
615
|
+
}
|
|
616
|
+
function insertTailwindPlugin(content, pluginExpression) {
|
|
617
|
+
if (/plugins\s*:\s*\[/.test(content)) {
|
|
618
|
+
return content.replace(/plugins\s*:\s*\[([\s\S]*?)\]/m, (_match, pluginsContent) => {
|
|
619
|
+
const trimmedPlugins = pluginsContent.trim();
|
|
620
|
+
if (trimmedPlugins.length === 0) {
|
|
621
|
+
return `plugins: [
|
|
622
|
+
${pluginExpression},
|
|
623
|
+
]`;
|
|
624
|
+
}
|
|
625
|
+
const normalizedPlugins = pluginsContent.trimEnd();
|
|
626
|
+
const withTrailingComma = normalizedPlugins.endsWith(",") ? normalizedPlugins : `${normalizedPlugins},`;
|
|
627
|
+
return `plugins: [
|
|
628
|
+
${withTrailingComma}
|
|
629
|
+
${pluginExpression},
|
|
630
|
+
]`;
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
const trimmed = content.trimEnd();
|
|
634
|
+
const hasSemicolon = trimmed.endsWith(";");
|
|
635
|
+
const withoutSemicolon = hasSemicolon ? trimmed.slice(0, -1) : trimmed;
|
|
636
|
+
const closingBraceIndex = withoutSemicolon.lastIndexOf("}");
|
|
637
|
+
if (closingBraceIndex === -1) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
const beforeClosingBrace = withoutSemicolon.slice(0, closingBraceIndex).trimEnd();
|
|
641
|
+
const needsComma = beforeClosingBrace.length > 0 && !beforeClosingBrace.endsWith(",") && !beforeClosingBrace.endsWith("{");
|
|
642
|
+
const next = `${withoutSemicolon.slice(0, closingBraceIndex)}${needsComma ? "," : ""}
|
|
643
|
+
plugins: [
|
|
644
|
+
${pluginExpression},
|
|
645
|
+
],
|
|
646
|
+
}${hasSemicolon ? ";" : ""}
|
|
647
|
+
`;
|
|
648
|
+
return next;
|
|
649
|
+
}
|
|
650
|
+
async function ensureTailwindConfig(deps, projectRoot, configuredFileName) {
|
|
651
|
+
if (!deps.includes("tailwindcss-animate")) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
const configPath = detectTailwindConfigPath(projectRoot, configuredFileName || "tailwind.config.js");
|
|
655
|
+
if (!fs3.existsSync(configPath)) {
|
|
656
|
+
const ext2 = path3.extname(configPath);
|
|
657
|
+
const isCjs2 = ext2 === ".cjs";
|
|
658
|
+
const configContent = isCjs2 ? `/** @type {import('tailwindcss').Config} */
|
|
659
|
+
module.exports = {
|
|
384
660
|
content: [
|
|
385
661
|
"./src/**/*.{js,ts,jsx,tsx}",
|
|
662
|
+
"./app/**/*.{js,ts,jsx,tsx}",
|
|
386
663
|
"./components/**/*.{js,ts,jsx,tsx}",
|
|
387
664
|
"./pages/**/*.{js,ts,jsx,tsx}",
|
|
388
665
|
],
|
|
389
666
|
theme: {
|
|
390
667
|
extend: {},
|
|
391
668
|
},
|
|
392
|
-
plugins: [
|
|
393
|
-
|
|
669
|
+
plugins: [require("tailwindcss-animate")],
|
|
670
|
+
}
|
|
671
|
+
` : `import tailwindcssAnimate from "tailwindcss-animate"
|
|
672
|
+
|
|
673
|
+
export default {
|
|
674
|
+
content: [
|
|
675
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
676
|
+
"./app/**/*.{js,ts,jsx,tsx}",
|
|
677
|
+
"./components/**/*.{js,ts,jsx,tsx}",
|
|
678
|
+
"./pages/**/*.{js,ts,jsx,tsx}",
|
|
394
679
|
],
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
]`;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
);
|
|
420
|
-
} else {
|
|
421
|
-
updatedContent = configContent.replace(
|
|
422
|
-
/}\s*;?\s*$/,
|
|
423
|
-
' plugins: [\n require("tailwindcss-animate"),\n ],\n};'
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
await fs2.writeFile(configPath, updatedContent);
|
|
427
|
-
return { updated: true };
|
|
428
|
-
}
|
|
680
|
+
theme: {
|
|
681
|
+
extend: {},
|
|
682
|
+
},
|
|
683
|
+
plugins: [tailwindcssAnimate],
|
|
684
|
+
}
|
|
685
|
+
`;
|
|
686
|
+
await fs3.ensureDir(path3.dirname(configPath));
|
|
687
|
+
await fs3.writeFile(configPath, configContent);
|
|
688
|
+
return { created: true, path: configPath };
|
|
689
|
+
}
|
|
690
|
+
const currentContent = await fs3.readFile(configPath, "utf-8");
|
|
691
|
+
if (currentContent.includes("tailwindcss-animate")) {
|
|
692
|
+
return { exists: true, path: configPath };
|
|
693
|
+
}
|
|
694
|
+
const ext = path3.extname(configPath);
|
|
695
|
+
const isCjs = ext === ".cjs" || /module\.exports\s*=/.test(currentContent);
|
|
696
|
+
const pluginExpression = isCjs ? 'require("tailwindcss-animate")' : "tailwindcssAnimate";
|
|
697
|
+
let updatedContent = currentContent;
|
|
698
|
+
if (!isCjs && !/from\s+['"]tailwindcss-animate['"]/.test(updatedContent)) {
|
|
699
|
+
updatedContent = `import tailwindcssAnimate from "tailwindcss-animate"
|
|
700
|
+
${updatedContent}`;
|
|
429
701
|
}
|
|
430
|
-
|
|
702
|
+
const merged = insertTailwindPlugin(updatedContent, pluginExpression);
|
|
703
|
+
if (!merged) {
|
|
704
|
+
return { skipped: true, path: configPath };
|
|
705
|
+
}
|
|
706
|
+
await fs3.writeFile(configPath, merged);
|
|
707
|
+
return { updated: true, path: configPath };
|
|
708
|
+
}
|
|
709
|
+
function escapeRegex(value) {
|
|
710
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
431
711
|
}
|
|
432
|
-
async function handleIndexFile(sourcePath, targetPath,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
712
|
+
async function handleIndexFile(sourcePath, targetPath, allFilesAdded, targetDir) {
|
|
713
|
+
const templateContent = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
714
|
+
if (!fs3.existsSync(targetPath)) {
|
|
715
|
+
await fs3.writeFile(targetPath, templateContent);
|
|
716
|
+
allFilesAdded.push({ name: "index.ts", path: path3.join(targetDir, "index.ts") });
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const existingContent = await fs3.readFile(targetPath, "utf-8");
|
|
720
|
+
const exportLines = templateContent.split("\n").map((line) => line.trim()).filter((line) => /^export\s+/.test(line) && /from\s+['"]\.\/[^'"]+['"]/.test(line));
|
|
721
|
+
const linesToAppend = [];
|
|
722
|
+
for (const line of exportLines) {
|
|
723
|
+
const match = line.match(/from\s+['"]\.\/([^'"]+)['"]/);
|
|
724
|
+
if (!match) {
|
|
725
|
+
continue;
|
|
445
726
|
}
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
await fs2.writeFile(targetPath, updatedContent);
|
|
451
|
-
allFilesAdded.push({ name: "index.ts", path: path2.join(aliasPath, "index.ts") });
|
|
727
|
+
const modulePath = match[1];
|
|
728
|
+
const modulePathPattern = new RegExp(`from\\s+['"]\\./${escapeRegex(modulePath)}['"]`);
|
|
729
|
+
if (modulePathPattern.test(existingContent)) {
|
|
730
|
+
continue;
|
|
452
731
|
}
|
|
732
|
+
linesToAppend.push(line.endsWith(";") ? line : `${line};`);
|
|
453
733
|
}
|
|
734
|
+
if (linesToAppend.length === 0) {
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const updatedContent = `${existingContent.trimEnd()}
|
|
738
|
+
${linesToAppend.join("\n")}
|
|
739
|
+
`;
|
|
740
|
+
await fs3.writeFile(targetPath, updatedContent);
|
|
741
|
+
allFilesAdded.push({ name: "index.ts", path: path3.join(targetDir, "index.ts") });
|
|
454
742
|
}
|
|
455
|
-
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").
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
463
|
-
const registry = getComponentRegistry();
|
|
464
|
-
let componentsToInstall = [];
|
|
465
|
-
if (options.all) {
|
|
466
|
-
const allComponents = Object.keys(registry);
|
|
467
|
-
spinner.text = `Installing all ${allComponents.length} components...`;
|
|
468
|
-
const allComponentsWithDeps = /* @__PURE__ */ new Set();
|
|
469
|
-
for (const name of allComponents) {
|
|
470
|
-
allComponentsWithDeps.add(name);
|
|
471
|
-
const deps = getComponentDependencies(name);
|
|
472
|
-
deps.forEach((dep) => allComponentsWithDeps.add(dep));
|
|
473
|
-
}
|
|
474
|
-
componentsToInstall = Array.from(allComponentsWithDeps);
|
|
475
|
-
} else {
|
|
476
|
-
if (!componentName) {
|
|
477
|
-
spinner.fail("\u274C Component name is required when not using --all flag.");
|
|
478
|
-
console.log("Available components:");
|
|
479
|
-
Object.keys(registry).forEach((name) => {
|
|
480
|
-
console.log(` ${chalk.cyan(name)}`);
|
|
481
|
-
});
|
|
743
|
+
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").option("--skip-install", "Skip package installation").action(
|
|
744
|
+
async (componentName, options) => {
|
|
745
|
+
const spinner = ora("Adding component...").start();
|
|
746
|
+
try {
|
|
747
|
+
const config = await getConfig();
|
|
748
|
+
if (!config) {
|
|
749
|
+
spinner.fail("\u274C No components.json found. Run `dinachi init` first.");
|
|
482
750
|
process.exit(1);
|
|
483
751
|
}
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
|
|
752
|
+
const projectRoot = process.cwd();
|
|
753
|
+
const compilerPathConfig = readCompilerPathConfig(projectRoot);
|
|
754
|
+
const registry = getComponentRegistry();
|
|
755
|
+
let componentsToInstall = [];
|
|
756
|
+
if (options.all) {
|
|
757
|
+
const allComponents = Object.keys(registry);
|
|
758
|
+
spinner.text = `Installing all ${allComponents.length} components...`;
|
|
759
|
+
const allComponentsWithDeps = /* @__PURE__ */ new Set();
|
|
760
|
+
for (const name of allComponents) {
|
|
761
|
+
allComponentsWithDeps.add(name);
|
|
762
|
+
const deps = getComponentDependencies(name);
|
|
763
|
+
deps.forEach((dep) => allComponentsWithDeps.add(dep));
|
|
764
|
+
}
|
|
765
|
+
componentsToInstall = Array.from(allComponentsWithDeps);
|
|
766
|
+
} else {
|
|
767
|
+
if (!componentName) {
|
|
768
|
+
spinner.fail("\u274C Component name is required when not using --all flag.");
|
|
769
|
+
console.log("Available components:");
|
|
770
|
+
Object.keys(registry).forEach((name) => {
|
|
771
|
+
console.log(` ${chalk.cyan(name)}`);
|
|
772
|
+
});
|
|
773
|
+
process.exit(1);
|
|
774
|
+
}
|
|
775
|
+
const component = registry[componentName];
|
|
776
|
+
if (!component) {
|
|
777
|
+
spinner.fail(`\u274C Component "${componentName}" not found.`);
|
|
778
|
+
console.log("Available components:");
|
|
779
|
+
Object.keys(registry).forEach((name) => {
|
|
780
|
+
console.log(` ${chalk.cyan(name)}`);
|
|
781
|
+
});
|
|
782
|
+
process.exit(1);
|
|
783
|
+
}
|
|
784
|
+
componentsToInstall = [componentName, ...getComponentDependencies(componentName)];
|
|
492
785
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (!options.all) {
|
|
496
|
-
spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
|
|
497
|
-
}
|
|
498
|
-
const componentDir = resolveAliasPath(config.aliases.ui, process.cwd());
|
|
499
|
-
await fs2.ensureDir(componentDir);
|
|
500
|
-
let allFilesAdded = [];
|
|
501
|
-
let allDepsInstalled = [];
|
|
502
|
-
let allUtilityDeps = [];
|
|
503
|
-
for (const name of componentsToInstall) {
|
|
504
|
-
const comp = registry[name];
|
|
505
|
-
if (!comp) continue;
|
|
506
|
-
if (comp.utilityDependencies?.length) {
|
|
507
|
-
allUtilityDeps.push(...comp.utilityDependencies);
|
|
786
|
+
if (!options.all) {
|
|
787
|
+
spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
|
|
508
788
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
789
|
+
const componentDir = resolveConfiguredPath(config.aliases.ui, projectRoot, compilerPathConfig);
|
|
790
|
+
const libDir = resolveConfiguredPath(config.aliases.lib, projectRoot, compilerPathConfig);
|
|
791
|
+
const utilsFilePath = resolveConfiguredPath(config.aliases.utils, projectRoot, compilerPathConfig);
|
|
792
|
+
await fs3.ensureDir(componentDir);
|
|
793
|
+
await fs3.ensureDir(libDir);
|
|
794
|
+
const allFilesAdded = [];
|
|
795
|
+
const allDepsInstalled = [];
|
|
796
|
+
const allUtilityDeps = [];
|
|
797
|
+
for (const name of componentsToInstall) {
|
|
798
|
+
const comp = registry[name];
|
|
799
|
+
if (!comp) continue;
|
|
800
|
+
if (comp.utilityDependencies?.length) {
|
|
801
|
+
allUtilityDeps.push(...comp.utilityDependencies);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const utilityRegistry = getUtilityRegistry();
|
|
805
|
+
const uniqueUtilityDeps = [...new Set(allUtilityDeps)];
|
|
806
|
+
if (uniqueUtilityDeps.length > 0) {
|
|
807
|
+
for (const utilityName of uniqueUtilityDeps) {
|
|
808
|
+
const utility = utilityRegistry[utilityName];
|
|
809
|
+
if (!utility) continue;
|
|
810
|
+
const utilityFilename = `${utility.name}.ts`;
|
|
811
|
+
const sourcePath = path3.join(__dirname2, "../templates/utils", utilityFilename);
|
|
812
|
+
const targetPath = path3.join(libDir, utilityFilename);
|
|
813
|
+
if (!fs3.existsSync(targetPath)) {
|
|
814
|
+
const content = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
815
|
+
await fs3.writeFile(targetPath, content);
|
|
816
|
+
allFilesAdded.push({
|
|
817
|
+
name: utilityFilename,
|
|
818
|
+
path: targetPath
|
|
819
|
+
});
|
|
820
|
+
}
|
|
529
821
|
if (utility.dependencies?.length) {
|
|
530
822
|
allDepsInstalled.push(...utility.dependencies);
|
|
531
823
|
}
|
|
532
824
|
}
|
|
533
825
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (
|
|
826
|
+
for (const name of componentsToInstall) {
|
|
827
|
+
const comp = registry[name];
|
|
828
|
+
if (!comp) continue;
|
|
829
|
+
for (const file of comp.files) {
|
|
830
|
+
const sourcePath = path3.join(__dirname2, "../templates", name, file.name);
|
|
831
|
+
const targetPath = path3.join(componentDir, file.name);
|
|
832
|
+
if (file.name === "index.ts") {
|
|
833
|
+
await handleIndexFile(sourcePath, targetPath, allFilesAdded, componentDir);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (fs3.existsSync(targetPath) && !options.overwrite) {
|
|
545
837
|
spinner.warn(`\u26A0\uFE0F ${file.name} already exists. Use --overwrite to replace it.`);
|
|
546
838
|
continue;
|
|
547
839
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
await
|
|
551
|
-
allFilesAdded.push({ name: file.name, path:
|
|
840
|
+
const templateContent = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
841
|
+
const rewrittenContent = rewriteTemplateImports(templateContent, targetPath, utilsFilePath, libDir);
|
|
842
|
+
await fs3.writeFile(targetPath, rewrittenContent);
|
|
843
|
+
allFilesAdded.push({ name: file.name, path: targetPath });
|
|
844
|
+
}
|
|
845
|
+
if (comp.dependencies?.length) {
|
|
846
|
+
allDepsInstalled.push(...comp.dependencies);
|
|
552
847
|
}
|
|
553
848
|
}
|
|
554
|
-
if (comp.dependencies?.length) {
|
|
555
|
-
allDepsInstalled.push(...comp.dependencies);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
let tailwindConfigInfo = null;
|
|
559
|
-
if (allDepsInstalled.includes("tailwindcss-animate")) {
|
|
560
849
|
spinner.text = "Updating Tailwind configuration...";
|
|
561
|
-
tailwindConfigInfo = await ensureTailwindConfig(
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
850
|
+
const tailwindConfigInfo = await ensureTailwindConfig(
|
|
851
|
+
allDepsInstalled,
|
|
852
|
+
projectRoot,
|
|
853
|
+
config.tailwind?.config || "tailwind.config.js"
|
|
854
|
+
);
|
|
855
|
+
const packageJsonPath = path3.join(projectRoot, "package.json");
|
|
856
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
857
|
+
throw new Error("No package.json found in the current directory.");
|
|
858
|
+
}
|
|
859
|
+
const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
|
|
860
|
+
const declaredDeps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
|
|
861
|
+
const uniqueDeps = [...new Set(allDepsInstalled)];
|
|
862
|
+
const missingDeps = uniqueDeps.filter((dep) => !declaredDeps[dep]);
|
|
863
|
+
if (!options.skipInstall && missingDeps.length > 0) {
|
|
864
|
+
spinner.text = "Installing dependencies...";
|
|
570
865
|
try {
|
|
571
|
-
const packageManager =
|
|
572
|
-
const installCmd =
|
|
573
|
-
execSync(installCmd, { stdio: "inherit" });
|
|
574
|
-
} catch
|
|
866
|
+
const packageManager = detectPackageManager(projectRoot);
|
|
867
|
+
const installCmd = getInstallCommand(packageManager, missingDeps.map(toInstallSpec));
|
|
868
|
+
execSync(installCmd, { stdio: "inherit", cwd: projectRoot });
|
|
869
|
+
} catch {
|
|
575
870
|
spinner.warn(`\u26A0\uFE0F Failed to install dependencies. Please install manually: ${missingDeps.join(" ")}`);
|
|
576
871
|
}
|
|
577
|
-
} else {
|
|
872
|
+
} else if (!options.skipInstall && uniqueDeps.length > 0) {
|
|
578
873
|
spinner.text = "All dependencies already installed.";
|
|
579
874
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")} component(s)!`);
|
|
585
|
-
}
|
|
586
|
-
console.log();
|
|
587
|
-
console.log("Files added:");
|
|
588
|
-
allFilesAdded.forEach((file) => {
|
|
589
|
-
console.log(` ${chalk.green("+")} ${file.path}`);
|
|
590
|
-
});
|
|
591
|
-
if (tailwindConfigInfo) {
|
|
592
|
-
console.log();
|
|
593
|
-
if (tailwindConfigInfo.created) {
|
|
594
|
-
console.log(` ${chalk.green("+")} tailwind.config.js (created with tailwindcss-animate plugin)`);
|
|
595
|
-
} else if (tailwindConfigInfo.updated) {
|
|
596
|
-
console.log(` ${chalk.blue("~")} tailwind.config.js (updated with tailwindcss-animate plugin)`);
|
|
875
|
+
if (options.all) {
|
|
876
|
+
spinner.succeed(`\u2705 Added all ${componentsToInstall.length} components!`);
|
|
877
|
+
} else {
|
|
878
|
+
spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")}!`);
|
|
597
879
|
}
|
|
598
|
-
}
|
|
599
|
-
if (missingDeps.length > 0) {
|
|
600
|
-
console.log();
|
|
601
|
-
console.log("Dependencies installed:");
|
|
602
|
-
missingDeps.forEach((dep) => {
|
|
603
|
-
console.log(` ${chalk.green("\u2713")} ${dep}`);
|
|
604
|
-
});
|
|
605
|
-
} else if (allDepsInstalled.length > 0) {
|
|
606
880
|
console.log();
|
|
607
|
-
console.log("
|
|
608
|
-
|
|
609
|
-
console.log(` ${chalk.
|
|
881
|
+
console.log("Files added:");
|
|
882
|
+
allFilesAdded.forEach((file) => {
|
|
883
|
+
console.log(` ${chalk.green("+")} ${file.path}`);
|
|
610
884
|
});
|
|
885
|
+
if (tailwindConfigInfo) {
|
|
886
|
+
console.log();
|
|
887
|
+
if (tailwindConfigInfo.created) {
|
|
888
|
+
console.log(` ${chalk.green("+")} ${tailwindConfigInfo.path} (created with tailwindcss-animate plugin)`);
|
|
889
|
+
} else if (tailwindConfigInfo.updated) {
|
|
890
|
+
console.log(` ${chalk.blue("~")} ${tailwindConfigInfo.path} (updated with tailwindcss-animate plugin)`);
|
|
891
|
+
} else if (tailwindConfigInfo.skipped) {
|
|
892
|
+
console.log(
|
|
893
|
+
` ${chalk.yellow("!")} ${tailwindConfigInfo.path} (could not safely update automatically; add tailwindcss-animate manually)`
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (options.skipInstall && missingDeps.length > 0) {
|
|
898
|
+
console.log();
|
|
899
|
+
console.log("Dependencies to install manually:");
|
|
900
|
+
missingDeps.forEach((dep) => {
|
|
901
|
+
console.log(` ${chalk.yellow("\u2022")} ${toInstallSpec(dep)}`);
|
|
902
|
+
});
|
|
903
|
+
} else if (missingDeps.length > 0) {
|
|
904
|
+
console.log();
|
|
905
|
+
console.log("Dependencies installed:");
|
|
906
|
+
missingDeps.forEach((dep) => {
|
|
907
|
+
console.log(` ${chalk.green("\u2713")} ${toInstallSpec(dep)}`);
|
|
908
|
+
});
|
|
909
|
+
} else if (uniqueDeps.length > 0) {
|
|
910
|
+
console.log();
|
|
911
|
+
console.log("Dependencies (already installed):");
|
|
912
|
+
uniqueDeps.forEach((dep) => {
|
|
913
|
+
console.log(` ${chalk.blue("~")} ${dep}`);
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
} catch (error) {
|
|
917
|
+
spinner.fail(`\u274C Failed to add component: ${error instanceof Error ? error.message : error}`);
|
|
918
|
+
process.exit(1);
|
|
611
919
|
}
|
|
612
|
-
} catch (error) {
|
|
613
|
-
spinner.fail(`\u274C Failed to add component: ${error instanceof Error ? error.message : error}`);
|
|
614
|
-
process.exit(1);
|
|
615
920
|
}
|
|
616
|
-
|
|
617
|
-
function getPackageManager() {
|
|
618
|
-
if (fs2.existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
619
|
-
if (fs2.existsSync("yarn.lock")) return "yarn";
|
|
620
|
-
return "npm";
|
|
621
|
-
}
|
|
921
|
+
);
|
|
622
922
|
|
|
623
923
|
// src/commands/init.ts
|
|
624
924
|
import { Command as Command2 } from "commander";
|
|
625
925
|
import { execSync as execSync2 } from "child_process";
|
|
626
|
-
import
|
|
627
|
-
import
|
|
926
|
+
import fs4 from "fs-extra";
|
|
927
|
+
import path4 from "path";
|
|
628
928
|
import prompts from "prompts";
|
|
629
929
|
import chalk2 from "chalk";
|
|
630
930
|
import ora2 from "ora";
|
|
631
|
-
|
|
931
|
+
function normalizeProjectPath(inputPath, projectRoot) {
|
|
932
|
+
const absolutePath = path4.isAbsolute(inputPath) ? path4.normalize(inputPath) : path4.resolve(projectRoot, inputPath);
|
|
933
|
+
const relativePath = path4.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
934
|
+
const withoutPrefix = relativePath.replace(/^\.\//, "").replace(/\/$/, "");
|
|
935
|
+
return withoutPrefix.length > 0 ? withoutPrefix : ".";
|
|
936
|
+
}
|
|
937
|
+
function toConfigPath(relativePath) {
|
|
938
|
+
return relativePath === "." ? "." : `./${relativePath.replace(/\\/g, "/")}`;
|
|
939
|
+
}
|
|
940
|
+
function createUtilsFileContent() {
|
|
941
|
+
return `import { type ClassValue, clsx } from "clsx"
|
|
942
|
+
import { twMerge } from "tailwind-merge"
|
|
943
|
+
|
|
944
|
+
export function cn(...inputs: ClassValue[]) {
|
|
945
|
+
return twMerge(clsx(inputs))
|
|
946
|
+
}
|
|
947
|
+
`;
|
|
948
|
+
}
|
|
949
|
+
function readJsonConfig(filePath) {
|
|
950
|
+
try {
|
|
951
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
952
|
+
return parseJsonWithComments(content);
|
|
953
|
+
} catch {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async function ensureAtAlias(projectRoot, srcDir, isTypeScript) {
|
|
958
|
+
const tsConfigPath = path4.join(projectRoot, "tsconfig.json");
|
|
959
|
+
const jsConfigPath = path4.join(projectRoot, "jsconfig.json");
|
|
960
|
+
const configPath = fs4.existsSync(tsConfigPath) ? tsConfigPath : fs4.existsSync(jsConfigPath) ? jsConfigPath : path4.join(projectRoot, isTypeScript ? "tsconfig.json" : "jsconfig.json");
|
|
961
|
+
const existedBefore = fs4.existsSync(configPath);
|
|
962
|
+
const parsedConfig = readJsonConfig(configPath);
|
|
963
|
+
if (existedBefore && !parsedConfig) {
|
|
964
|
+
return { path: configPath, skipped: true };
|
|
965
|
+
}
|
|
966
|
+
const parsed = parsedConfig ?? {};
|
|
967
|
+
const compilerOptions = parsed.compilerOptions ?? {};
|
|
968
|
+
const rawPaths = compilerOptions.paths ?? {};
|
|
969
|
+
const paths = {};
|
|
970
|
+
for (const [key, value] of Object.entries(rawPaths)) {
|
|
971
|
+
if (!Array.isArray(value)) {
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const targets = value.filter((entry) => typeof entry === "string");
|
|
975
|
+
if (targets.length > 0) {
|
|
976
|
+
paths[key] = targets;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const aliasTarget = srcDir === "." ? "*" : `${srcDir}/*`;
|
|
980
|
+
const alreadyConfigured = compilerOptions.baseUrl === "." && Array.isArray(paths["@/*"]) && paths["@/*"][0] === aliasTarget;
|
|
981
|
+
if (alreadyConfigured) {
|
|
982
|
+
return { path: configPath };
|
|
983
|
+
}
|
|
984
|
+
const nextConfig = {
|
|
985
|
+
...parsed,
|
|
986
|
+
compilerOptions: {
|
|
987
|
+
...compilerOptions,
|
|
988
|
+
baseUrl: ".",
|
|
989
|
+
paths: {
|
|
990
|
+
...paths,
|
|
991
|
+
"@/*": [aliasTarget]
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
try {
|
|
996
|
+
await fs4.writeFile(configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
997
|
+
`);
|
|
998
|
+
return { path: configPath, [existedBefore ? "updated" : "created"]: true };
|
|
999
|
+
} catch {
|
|
1000
|
+
return { path: configPath, skipped: true };
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
var initCommand = new Command2("init").description("Initialize Dinachi UI in your project").option("--skip-install", "Skip package installation").action(async (options) => {
|
|
632
1004
|
console.log(chalk2.bold.cyan("\u{1F3A8} Welcome to Dinachi UI!"));
|
|
633
1005
|
console.log();
|
|
634
|
-
const
|
|
635
|
-
|
|
1006
|
+
const projectRoot = process.cwd();
|
|
1007
|
+
const packageJsonPath = path4.join(projectRoot, "package.json");
|
|
1008
|
+
if (!fs4.existsSync(packageJsonPath)) {
|
|
636
1009
|
console.log(chalk2.red("\u274C No package.json found. Please run this command in a valid project."));
|
|
637
1010
|
process.exit(1);
|
|
638
1011
|
}
|
|
@@ -651,12 +1024,6 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
|
|
|
651
1024
|
name: "utilsPath",
|
|
652
1025
|
message: "Where would you like to install utilities?",
|
|
653
1026
|
initial: projectConfig.utilsPath
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
type: "confirm",
|
|
657
|
-
name: "installDeps",
|
|
658
|
-
message: "Install required dependencies?",
|
|
659
|
-
initial: true
|
|
660
1027
|
}
|
|
661
1028
|
]);
|
|
662
1029
|
if (!response.componentsPath || !response.utilsPath) {
|
|
@@ -665,65 +1032,91 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
|
|
|
665
1032
|
}
|
|
666
1033
|
const spinner = ora2("Setting up Dinachi UI...").start();
|
|
667
1034
|
try {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
}
|
|
709
|
-
|
|
1035
|
+
const normalizedComponentsPath = normalizeProjectPath(response.componentsPath, projectRoot);
|
|
1036
|
+
const normalizedUtilsPath = normalizeProjectPath(response.utilsPath, projectRoot);
|
|
1037
|
+
const componentsDirPath = path4.resolve(projectRoot, normalizedComponentsPath);
|
|
1038
|
+
const utilsDirPath = path4.resolve(projectRoot, normalizedUtilsPath);
|
|
1039
|
+
const utilsFilePath = path4.join(utilsDirPath, "utils.ts");
|
|
1040
|
+
await fs4.ensureDir(componentsDirPath);
|
|
1041
|
+
await fs4.ensureDir(utilsDirPath);
|
|
1042
|
+
const utilsContent = createUtilsFileContent();
|
|
1043
|
+
await fs4.writeFile(utilsFilePath, utilsContent);
|
|
1044
|
+
spinner.text = "Installing dependencies...";
|
|
1045
|
+
const deps = ["class-variance-authority", "clsx", "tailwind-merge"];
|
|
1046
|
+
if (!options.skipInstall) {
|
|
1047
|
+
const packageManager = detectPackageManager(projectRoot);
|
|
1048
|
+
const installCmd = getInstallCommand(packageManager, deps.map(toInstallSpec));
|
|
1049
|
+
execSync2(installCmd, { stdio: "inherit", cwd: projectRoot });
|
|
1050
|
+
}
|
|
1051
|
+
const hooksPath = projectConfig.srcDir === "." ? "hooks" : path4.join(projectConfig.srcDir, "hooks").replace(/\\/g, "/");
|
|
1052
|
+
const configContent = JSON.stringify(
|
|
1053
|
+
{
|
|
1054
|
+
style: "default",
|
|
1055
|
+
rsc: projectConfig.framework === "next.js",
|
|
1056
|
+
tsx: true,
|
|
1057
|
+
tailwind: {
|
|
1058
|
+
config: projectConfig.tailwindConfig,
|
|
1059
|
+
css: projectConfig.cssPath,
|
|
1060
|
+
baseColor: "slate",
|
|
1061
|
+
cssVariables: true
|
|
1062
|
+
},
|
|
1063
|
+
aliases: {
|
|
1064
|
+
components: toConfigPath(path4.dirname(normalizedComponentsPath)),
|
|
1065
|
+
utils: toConfigPath(path4.join(normalizedUtilsPath, "utils")),
|
|
1066
|
+
ui: toConfigPath(normalizedComponentsPath),
|
|
1067
|
+
lib: toConfigPath(normalizedUtilsPath),
|
|
1068
|
+
hooks: toConfigPath(hooksPath)
|
|
1069
|
+
},
|
|
1070
|
+
iconLibrary: "lucide"
|
|
1071
|
+
},
|
|
1072
|
+
null,
|
|
1073
|
+
2
|
|
1074
|
+
);
|
|
1075
|
+
await fs4.writeFile(path4.join(projectRoot, "components.json"), `${configContent}
|
|
1076
|
+
`);
|
|
1077
|
+
const aliasConfigUpdate = await ensureAtAlias(projectRoot, projectConfig.srcDir, projectConfig.isTypeScript);
|
|
710
1078
|
spinner.succeed("\u2705 Dinachi UI setup complete!");
|
|
711
1079
|
console.log();
|
|
712
1080
|
console.log("Next steps:");
|
|
713
1081
|
console.log(` 1. Add a component: ${chalk2.cyan("npx @dinachi/cli add button")}`);
|
|
714
|
-
console.log(` 2. Components will be installed to: ${chalk2.cyan(
|
|
715
|
-
console.log(` 3. Utils available at: ${chalk2.cyan(
|
|
1082
|
+
console.log(` 2. Components will be installed to: ${chalk2.cyan(componentsDirPath)}`);
|
|
1083
|
+
console.log(` 3. Utils available at: ${chalk2.cyan(utilsFilePath)}`);
|
|
1084
|
+
console.log();
|
|
1085
|
+
if (aliasConfigUpdate.created) {
|
|
1086
|
+
console.log(` ${chalk2.green("+")} Added @/* path alias in ${aliasConfigUpdate.path}`);
|
|
1087
|
+
} else if (aliasConfigUpdate.updated) {
|
|
1088
|
+
console.log(` ${chalk2.blue("~")} Updated @/* path alias in ${aliasConfigUpdate.path}`);
|
|
1089
|
+
} else if (aliasConfigUpdate.skipped) {
|
|
1090
|
+
console.log(
|
|
1091
|
+
` ${chalk2.yellow("!")} Could not update ${aliasConfigUpdate.path}. Configure @/* manually if you use alias imports.`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (!projectConfig.isTypeScript) {
|
|
1095
|
+
console.log();
|
|
1096
|
+
console.log(
|
|
1097
|
+
chalk2.yellow(
|
|
1098
|
+
"\u26A0\uFE0F Dinachi components are TypeScript-first. Your project can still consume TSX files, but type-check tooling is recommended."
|
|
1099
|
+
)
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
716
1102
|
if (projectConfig.framework === "next.js") {
|
|
717
1103
|
console.log();
|
|
718
1104
|
console.log(chalk2.blue("\u{1F4DD} Next.js specific notes:"));
|
|
719
|
-
console.log(
|
|
720
|
-
console.log(
|
|
721
|
-
console.log(` - Tailwind config
|
|
1105
|
+
console.log(" - RSC (React Server Components) enabled in config");
|
|
1106
|
+
console.log(' - Add "use client" for interactive components where needed');
|
|
1107
|
+
console.log(` - Tailwind config: ${chalk2.cyan(projectConfig.tailwindConfig)}`);
|
|
722
1108
|
} else if (projectConfig.framework === "remix") {
|
|
723
1109
|
console.log();
|
|
724
1110
|
console.log(chalk2.blue("\u{1F4DD} Remix specific notes:"));
|
|
725
|
-
console.log(` - Components
|
|
726
|
-
console.log(` -
|
|
1111
|
+
console.log(` - Components directory: ${chalk2.cyan(componentsDirPath)}`);
|
|
1112
|
+
console.log(` - Utilities directory: ${chalk2.cyan(utilsDirPath)}`);
|
|
1113
|
+
}
|
|
1114
|
+
if (options.skipInstall) {
|
|
1115
|
+
console.log();
|
|
1116
|
+
console.log("Dependencies to install manually:");
|
|
1117
|
+
deps.forEach((dep) => {
|
|
1118
|
+
console.log(` ${chalk2.yellow("\u2022")} ${toInstallSpec(dep)}`);
|
|
1119
|
+
});
|
|
727
1120
|
}
|
|
728
1121
|
console.log();
|
|
729
1122
|
console.log("\u{1F4A1} Tip: Install globally for shorter commands:");
|
|
@@ -734,43 +1127,61 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
734
1127
|
process.exit(1);
|
|
735
1128
|
}
|
|
736
1129
|
});
|
|
737
|
-
function getPackageManager2() {
|
|
738
|
-
if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
739
|
-
if (fs3.existsSync("yarn.lock")) return "yarn";
|
|
740
|
-
return "npm";
|
|
741
|
-
}
|
|
742
1130
|
function detectProjectType() {
|
|
743
|
-
const packageJsonPath =
|
|
744
|
-
if (!
|
|
745
|
-
return
|
|
746
|
-
framework: "react",
|
|
747
|
-
componentsPath: "./src/components/ui",
|
|
748
|
-
utilsPath: "./src/lib",
|
|
749
|
-
tailwindConfig: "tailwind.config.js",
|
|
750
|
-
cssPath: "src/index.css",
|
|
751
|
-
srcDir: "src"
|
|
752
|
-
};
|
|
1131
|
+
const packageJsonPath = path4.join(process.cwd(), "package.json");
|
|
1132
|
+
if (!fs4.existsSync(packageJsonPath)) {
|
|
1133
|
+
return getDefaultConfig("react", false);
|
|
753
1134
|
}
|
|
754
|
-
const packageJson = JSON.parse(
|
|
755
|
-
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
1135
|
+
const packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
|
|
1136
|
+
const deps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
|
|
1137
|
+
const hasSrcDir = fs4.existsSync(path4.join(process.cwd(), "src"));
|
|
1138
|
+
const hasAppDir = fs4.existsSync(path4.join(process.cwd(), "app"));
|
|
1139
|
+
const hasSrcAppDir = fs4.existsSync(path4.join(process.cwd(), "src", "app"));
|
|
1140
|
+
const isTypeScript = fs4.existsSync(path4.join(process.cwd(), "tsconfig.json")) || fs4.existsSync(path4.join(process.cwd(), "tsconfig.base.json")) || Boolean(deps.typescript);
|
|
1141
|
+
const tailwindConfig = detectTailwindConfig();
|
|
1142
|
+
const cssPath = detectCssPath(hasSrcDir, hasSrcAppDir);
|
|
756
1143
|
if (deps.next) {
|
|
1144
|
+
if (hasSrcDir && hasSrcAppDir) {
|
|
1145
|
+
return {
|
|
1146
|
+
framework: "next.js",
|
|
1147
|
+
componentsPath: "./src/components/ui",
|
|
1148
|
+
utilsPath: "./src/lib",
|
|
1149
|
+
tailwindConfig,
|
|
1150
|
+
cssPath,
|
|
1151
|
+
srcDir: "src",
|
|
1152
|
+
isTypeScript
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
if (hasAppDir && !hasSrcDir) {
|
|
1156
|
+
return {
|
|
1157
|
+
framework: "next.js",
|
|
1158
|
+
componentsPath: "./components/ui",
|
|
1159
|
+
utilsPath: "./lib",
|
|
1160
|
+
tailwindConfig,
|
|
1161
|
+
cssPath,
|
|
1162
|
+
srcDir: ".",
|
|
1163
|
+
isTypeScript
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
757
1166
|
return {
|
|
758
1167
|
framework: "next.js",
|
|
759
|
-
componentsPath: "./src/components/ui",
|
|
760
|
-
utilsPath: "./src/lib",
|
|
761
|
-
tailwindConfig
|
|
762
|
-
cssPath
|
|
763
|
-
srcDir: "src"
|
|
1168
|
+
componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
|
|
1169
|
+
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
1170
|
+
tailwindConfig,
|
|
1171
|
+
cssPath,
|
|
1172
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1173
|
+
isTypeScript
|
|
764
1174
|
};
|
|
765
1175
|
}
|
|
766
1176
|
if (deps.vite || deps["@vitejs/plugin-react"]) {
|
|
767
1177
|
return {
|
|
768
1178
|
framework: "vite",
|
|
769
|
-
componentsPath: "./src/components/ui",
|
|
770
|
-
utilsPath: "./src/lib",
|
|
771
|
-
tailwindConfig
|
|
772
|
-
cssPath
|
|
773
|
-
srcDir: "src"
|
|
1179
|
+
componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
|
|
1180
|
+
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
1181
|
+
tailwindConfig,
|
|
1182
|
+
cssPath,
|
|
1183
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1184
|
+
isTypeScript
|
|
774
1185
|
};
|
|
775
1186
|
}
|
|
776
1187
|
if (deps["react-scripts"]) {
|
|
@@ -778,9 +1189,10 @@ function detectProjectType() {
|
|
|
778
1189
|
framework: "create-react-app",
|
|
779
1190
|
componentsPath: "./src/components/ui",
|
|
780
1191
|
utilsPath: "./src/lib",
|
|
781
|
-
tailwindConfig
|
|
782
|
-
cssPath
|
|
783
|
-
srcDir: "src"
|
|
1192
|
+
tailwindConfig,
|
|
1193
|
+
cssPath,
|
|
1194
|
+
srcDir: "src",
|
|
1195
|
+
isTypeScript
|
|
784
1196
|
};
|
|
785
1197
|
}
|
|
786
1198
|
if (deps["@remix-run/react"]) {
|
|
@@ -788,23 +1200,81 @@ function detectProjectType() {
|
|
|
788
1200
|
framework: "remix",
|
|
789
1201
|
componentsPath: "./app/components/ui",
|
|
790
1202
|
utilsPath: "./app/lib",
|
|
791
|
-
tailwindConfig
|
|
792
|
-
cssPath:
|
|
793
|
-
srcDir: "app"
|
|
1203
|
+
tailwindConfig,
|
|
1204
|
+
cssPath: detectCssPath(false, false, true),
|
|
1205
|
+
srcDir: "app",
|
|
1206
|
+
isTypeScript
|
|
794
1207
|
};
|
|
795
1208
|
}
|
|
1209
|
+
return getDefaultConfig("react", hasSrcDir);
|
|
1210
|
+
}
|
|
1211
|
+
function getDefaultConfig(framework, hasSrcDir) {
|
|
1212
|
+
const isTypeScript = fs4.existsSync(path4.join(process.cwd(), "tsconfig.json")) || fs4.existsSync(path4.join(process.cwd(), "tsconfig.base.json"));
|
|
796
1213
|
return {
|
|
797
|
-
framework
|
|
798
|
-
componentsPath: "./src/components/ui",
|
|
799
|
-
utilsPath: "./src/lib",
|
|
800
|
-
tailwindConfig:
|
|
801
|
-
cssPath: "src/index.css",
|
|
802
|
-
srcDir: "src"
|
|
1214
|
+
framework,
|
|
1215
|
+
componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
|
|
1216
|
+
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
1217
|
+
tailwindConfig: detectTailwindConfig(),
|
|
1218
|
+
cssPath: hasSrcDir ? "src/index.css" : "index.css",
|
|
1219
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1220
|
+
isTypeScript
|
|
803
1221
|
};
|
|
804
1222
|
}
|
|
1223
|
+
function detectTailwindConfig() {
|
|
1224
|
+
const configCandidates = [
|
|
1225
|
+
"tailwind.config.ts",
|
|
1226
|
+
"tailwind.config.js",
|
|
1227
|
+
"tailwind.config.mjs",
|
|
1228
|
+
"tailwind.config.cjs",
|
|
1229
|
+
"tailwind.config.cts",
|
|
1230
|
+
"tailwind.config.mts"
|
|
1231
|
+
];
|
|
1232
|
+
for (const config of configCandidates) {
|
|
1233
|
+
if (fs4.existsSync(path4.join(process.cwd(), config))) {
|
|
1234
|
+
return config;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
return "tailwind.config.js";
|
|
1238
|
+
}
|
|
1239
|
+
function detectCssPath(hasSrcDir, hasSrcAppDir, isRemix = false) {
|
|
1240
|
+
const cwd = process.cwd();
|
|
1241
|
+
const possiblePaths = [
|
|
1242
|
+
"app/globals.css",
|
|
1243
|
+
"src/app/globals.css",
|
|
1244
|
+
"styles/globals.css",
|
|
1245
|
+
"src/styles/globals.css",
|
|
1246
|
+
"src/index.css",
|
|
1247
|
+
"index.css",
|
|
1248
|
+
"app/tailwind.css",
|
|
1249
|
+
"app/styles/tailwind.css"
|
|
1250
|
+
];
|
|
1251
|
+
for (const cssPath of possiblePaths) {
|
|
1252
|
+
if (fs4.existsSync(path4.join(cwd, cssPath))) {
|
|
1253
|
+
return cssPath;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (isRemix) return "app/tailwind.css";
|
|
1257
|
+
if (hasSrcAppDir) return "src/app/globals.css";
|
|
1258
|
+
if (hasSrcDir) return "src/index.css";
|
|
1259
|
+
return "index.css";
|
|
1260
|
+
}
|
|
805
1261
|
|
|
806
1262
|
// src/index.ts
|
|
1263
|
+
import fs5 from "fs";
|
|
1264
|
+
import path5 from "path";
|
|
1265
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
807
1266
|
var program = new Command3();
|
|
808
|
-
|
|
1267
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
1268
|
+
var __dirname3 = path5.dirname(__filename3);
|
|
1269
|
+
function getCliVersion() {
|
|
1270
|
+
try {
|
|
1271
|
+
const packageJsonPath = path5.resolve(__dirname3, "../package.json");
|
|
1272
|
+
const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
|
|
1273
|
+
return packageJson.version ?? "0.0.0";
|
|
1274
|
+
} catch {
|
|
1275
|
+
return "0.0.0";
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
program.name("dinachi").description("Add Dinachi UI components to your project").version(getCliVersion());
|
|
809
1279
|
program.addCommand(addCommand).addCommand(initCommand);
|
|
810
1280
|
program.parse();
|