ui-thing 0.1.56 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/pre-commit +1 -0
- package/CHANGELOG.md +64 -0
- package/README.md +4 -3
- package/dist/index.js +1273 -15771
- package/dist/index.js.map +1 -1
- package/package.json +33 -21
- package/src/commands/add.ts +218 -274
- package/src/commands/init.ts +107 -58
- package/src/commands/prettier.ts +6 -8
- package/src/commands/shortcuts.ts +13 -13
- package/src/commands/theme.ts +9 -6
- package/src/index.ts +2 -2
- package/src/templates/css.ts +958 -773
- package/src/templates/prettier.ts +14 -16
- package/src/templates/shortcuts.ts +225 -126
- package/src/templates/tw-helper.ts +8 -0
- package/src/templates/vs-code.ts +24 -0
- package/src/types.ts +74 -3
- package/src/utils/addPrettierConfig.ts +49 -6
- package/src/utils/addShortcutFiles.ts +5 -4
- package/src/utils/addTailwindVitePlugin.ts +35 -0
- package/src/utils/addVSCodeFiles.ts +13 -0
- package/src/utils/compareUIConfig.ts +1 -2
- package/src/utils/config.ts +59 -86
- package/src/utils/constants.ts +67 -13
- package/src/utils/detectNuxtVersion.ts +20 -0
- package/src/utils/fetchComponents.ts +14 -1
- package/src/utils/installPackages.ts +3 -27
- package/src/utils/mergeJsonFile.ts +28 -0
- package/src/utils/printFancyBoxMessage.ts +62 -16
- package/src/utils/promptForComponents.ts +8 -6
- package/src/utils/uiConfigPrompt.ts +12 -37
- package/tsconfig.json +2 -1
- package/dist/chunk-FW4363Y4.js +0 -2
- package/dist/chunk-FW4363Y4.js.map +0 -1
- package/dist/prompt-4NXDAQWE.js +0 -46
- package/dist/prompt-4NXDAQWE.js.map +0 -1
- package/src/comps.ts +0 -3237
- package/src/templates/tailwind.ts +0 -142
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-thing",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI used to add Nuxt
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "CLI used to add Nuxt components to a project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
7
|
"ui",
|
|
8
8
|
"thing",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"nuxt",
|
|
10
|
+
"reka-ui",
|
|
11
11
|
"tailwindcss",
|
|
12
12
|
"nuxtui",
|
|
13
13
|
"shadcn-ui"
|
|
@@ -33,39 +33,51 @@
|
|
|
33
33
|
"coverage": "vitest run --coverage",
|
|
34
34
|
"dev": "tsup --watch",
|
|
35
35
|
"format": "npx prettier --write .",
|
|
36
|
+
"knip": "knip",
|
|
37
|
+
"knip:fix": "knip --fix",
|
|
38
|
+
"lint-staged": "lint-staged",
|
|
39
|
+
"prepare": "husky",
|
|
36
40
|
"release": "npm run build && npx changelogen@latest --release && npm publish && git push --follow-tags",
|
|
37
41
|
"start": "node dist/index.js",
|
|
38
42
|
"test": "vitest"
|
|
39
43
|
},
|
|
44
|
+
"lint-staged": {
|
|
45
|
+
"*": [
|
|
46
|
+
"npm run format"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
40
49
|
"dependencies": {
|
|
41
|
-
"axios": "^1.
|
|
50
|
+
"axios": "^1.11.0",
|
|
42
51
|
"boxen": "^8.0.1",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
52
|
+
"c12": "^3.2.0",
|
|
53
|
+
"commander": "^14.0.0",
|
|
54
|
+
"consola": "^3.4.2",
|
|
55
|
+
"dotenv": "^17.2.1",
|
|
56
|
+
"es-toolkit": "^1.39.9",
|
|
57
|
+
"execa": "^9.6.0",
|
|
58
|
+
"figlet": "^1.8.2",
|
|
59
|
+
"fs-extra": "^11.3.1",
|
|
50
60
|
"kleur": "^4.1.5",
|
|
51
61
|
"lodash": "^4.17.21",
|
|
52
|
-
"nypm": "^0.5.4",
|
|
53
62
|
"ora": "^8.2.0",
|
|
54
63
|
"prompts": "^2.4.2"
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
|
-
"@
|
|
58
|
-
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
|
66
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.6.2",
|
|
59
67
|
"@types/figlet": "^1.7.0",
|
|
60
68
|
"@types/fs-extra": "^11.0.4",
|
|
61
|
-
"@types/lodash": "^4.17.
|
|
62
|
-
"@types/node": "^
|
|
69
|
+
"@types/lodash": "^4.17.20",
|
|
70
|
+
"@types/node": "^24.2.1",
|
|
63
71
|
"@types/prompts": "^2.4.9",
|
|
64
|
-
"@vitest/coverage-v8": "^3.
|
|
72
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
73
|
+
"husky": "^9.1.7",
|
|
74
|
+
"knip": "^5.62.0",
|
|
75
|
+
"lint-staged": "^16.1.5",
|
|
65
76
|
"magicast": "^0.3.5",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
77
|
+
"prettier": "^3.6.2",
|
|
78
|
+
"tsup": "^8.5.0",
|
|
79
|
+
"typescript": "^5.9.2",
|
|
80
|
+
"vitest": "^3.2.4"
|
|
69
81
|
},
|
|
70
82
|
"publishConfig": {
|
|
71
83
|
"access": "public"
|
package/src/commands/add.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { updateConfig } from "c12/update";
|
|
2
3
|
import { Command } from "commander";
|
|
3
4
|
import { consola } from "consola";
|
|
4
5
|
import kleur from "kleur";
|
|
5
6
|
import _ from "lodash";
|
|
6
7
|
import prompts from "prompts";
|
|
7
8
|
|
|
8
|
-
import
|
|
9
|
-
import { Component } from "../types";
|
|
9
|
+
import { AddCommand, Component } from "../types";
|
|
10
10
|
import { compareUIConfig } from "../utils/compareUIConfig";
|
|
11
|
-
import { addModuleToConfig,
|
|
11
|
+
import { addModuleToConfig, getUIConfig } from "../utils/config";
|
|
12
|
+
import { fetchComponents } from "../utils/fetchComponents";
|
|
12
13
|
import { fileExists } from "../utils/fileExists";
|
|
13
14
|
import { installPackages } from "../utils/installPackages";
|
|
14
15
|
import { installValidator } from "../utils/installValidator";
|
|
@@ -16,302 +17,245 @@ import { printFancyBoxMessage } from "../utils/printFancyBoxMessage";
|
|
|
16
17
|
import { promptUserForComponents } from "../utils/promptForComponents";
|
|
17
18
|
import { writeFile } from "../utils/writeFile";
|
|
18
19
|
|
|
20
|
+
let allComponents: Component[] = [];
|
|
19
21
|
const currentDirectory = process.cwd();
|
|
20
22
|
|
|
21
|
-
const findComponent = (name: string) => {
|
|
22
|
-
return allComponents.find((c) => c.value.toLowerCase() === name.toLowerCase());
|
|
23
|
-
};
|
|
24
|
-
|
|
25
23
|
/**
|
|
26
|
-
*
|
|
24
|
+
* Finds a component definition by its name (case-insensitive).
|
|
27
25
|
*/
|
|
28
|
-
|
|
29
|
-
.name(
|
|
30
|
-
.command("add")
|
|
31
|
-
.description("Add a list of components to your project.")
|
|
32
|
-
.option("-a --all", "Add all components to your project.", false)
|
|
33
|
-
.argument("[componentNames...]", "Components that you want to add.")
|
|
34
|
-
.action(async (components: Array<string>, options: { all?: boolean }) => {
|
|
35
|
-
// Get nuxt config
|
|
36
|
-
const cfg = await getNuxtConfig();
|
|
37
|
-
// Get ui config
|
|
38
|
-
let uiConfig = await getUIConfig();
|
|
39
|
-
let uiConfigIsCorrect = await compareUIConfig();
|
|
40
|
-
if (!uiConfigIsCorrect) {
|
|
41
|
-
uiConfig = await getUIConfig({ force: true });
|
|
42
|
-
}
|
|
43
|
-
if (_.isEmpty(uiConfig)) {
|
|
44
|
-
consola.info("Config file not set. Exiting...");
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
26
|
+
const findComponent = (name: string) =>
|
|
27
|
+
allComponents.find((c) => c.value.toLowerCase() === name.toLowerCase());
|
|
47
28
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Handles writing a file with overwrite checks.
|
|
31
|
+
*/
|
|
32
|
+
async function safeWriteFile(
|
|
33
|
+
targetPath: string,
|
|
34
|
+
content: string,
|
|
35
|
+
forceOverwrite: boolean,
|
|
36
|
+
promptMessage: string
|
|
37
|
+
) {
|
|
38
|
+
const exists = await fileExists(targetPath);
|
|
58
39
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
40
|
+
if (exists && !forceOverwrite) {
|
|
41
|
+
const { value: overwrite } = await prompts({
|
|
42
|
+
type: "confirm",
|
|
43
|
+
name: "value",
|
|
44
|
+
message: promptMessage,
|
|
45
|
+
initial: false,
|
|
65
46
|
});
|
|
66
|
-
if (
|
|
67
|
-
consola.
|
|
47
|
+
if (!overwrite) {
|
|
48
|
+
consola.info(`Skipped: ${kleur.cyan(path.basename(targetPath))}`);
|
|
49
|
+
return false;
|
|
68
50
|
}
|
|
51
|
+
}
|
|
69
52
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
53
|
+
await writeFile(targetPath, content);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Writes all files in a given category (utils, composables, plugins).
|
|
59
|
+
*/
|
|
60
|
+
async function writeCategoryFiles(
|
|
61
|
+
category: string,
|
|
62
|
+
items: Array<{ fileName: string; fileContent: string; dirPath?: string }>,
|
|
63
|
+
baseDir: string,
|
|
64
|
+
forceOverwrite: boolean
|
|
65
|
+
) {
|
|
66
|
+
for (const item of items) {
|
|
67
|
+
const targetPath = path.join(currentDirectory, baseDir, item.fileName);
|
|
68
|
+
await safeWriteFile(
|
|
69
|
+
targetPath,
|
|
70
|
+
item.fileContent,
|
|
71
|
+
forceOverwrite,
|
|
72
|
+
`The ${category} file ${kleur.bold(item.fileName)} already exists. Overwrite?`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Main command logic for adding components.
|
|
79
|
+
*/
|
|
80
|
+
const runAddCommand = async (components: string[], options: AddCommand) => {
|
|
81
|
+
// Step 1 — Load and verify UI config
|
|
82
|
+
let uiConfig = await getUIConfig();
|
|
83
|
+
if (!(await compareUIConfig())) {
|
|
84
|
+
uiConfig = await getUIConfig({ force: true });
|
|
85
|
+
}
|
|
86
|
+
if (_.isEmpty(uiConfig)) {
|
|
87
|
+
consola.info("Config file not set. Exiting...");
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Step 2 — Fetch all available components
|
|
92
|
+
allComponents = await fetchComponents();
|
|
93
|
+
|
|
94
|
+
// Step 3 — If no components were passed, prompt user to select them
|
|
95
|
+
let componentNames = components;
|
|
96
|
+
if (componentNames.length === 0) {
|
|
97
|
+
const response = await promptUserForComponents(options.all, allComponents);
|
|
98
|
+
if (!response || response.length === 0) {
|
|
99
|
+
consola.info("No components selected. Exiting...");
|
|
100
|
+
process.exit(0);
|
|
88
101
|
}
|
|
102
|
+
componentNames = response;
|
|
103
|
+
}
|
|
89
104
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
let fileName = file.fileName;
|
|
96
|
-
let dirPath = uiConfig.componentsLocation;
|
|
97
|
-
let filePath = path.join(currentDirectory, dirPath, fileName);
|
|
98
|
-
if (!uiConfig.useDefaultFilename) {
|
|
99
|
-
const res = await prompts({
|
|
100
|
-
type: "text",
|
|
101
|
-
name: "value",
|
|
102
|
-
message: `Where should we add the file`,
|
|
103
|
-
initial: dirPath,
|
|
104
|
-
onRender(kleur) {
|
|
105
|
-
//@ts-ignore
|
|
106
|
-
this.msg =
|
|
107
|
-
kleur.bgCyan(" Location ") +
|
|
108
|
-
` Where should we add the file ${kleur.cyan(`${fileName}`)} `;
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
if (res.value) {
|
|
112
|
-
dirPath = res.value;
|
|
113
|
-
filePath = path.join(currentDirectory, res.value, fileName);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Check if the file exists
|
|
117
|
-
const exists = await fileExists(filePath);
|
|
118
|
-
// if it exists & the force option was not passed, ask the user to confirm overwriting the file
|
|
119
|
-
if (exists && !uiConfig.force) {
|
|
120
|
-
const res = await prompts({
|
|
121
|
-
type: "confirm",
|
|
122
|
-
name: "value",
|
|
123
|
-
message: `The file that we are trying to add ${kleur.bold(
|
|
124
|
-
fileName
|
|
125
|
-
)} to is already taken. Overwrite?`,
|
|
126
|
-
initial: false,
|
|
127
|
-
});
|
|
128
|
-
if (!res.value) {
|
|
129
|
-
consola.info(`We will not overwrite the file for ${kleur.cyan(fileName)}`);
|
|
130
|
-
continue loop2;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
await writeFile(filePath, file.fileContent);
|
|
105
|
+
// Step 4 — Validate component names
|
|
106
|
+
const notFound = componentNames.filter((name) => !findComponent(name));
|
|
107
|
+
if (notFound.length > 0) {
|
|
108
|
+
consola.error(`Not found: ${kleur.bgRed(notFound.join(", "))}`);
|
|
109
|
+
}
|
|
134
110
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
cfg.defaultExport.build ||= {};
|
|
140
|
-
cfg.defaultExport.imports.imports ||= [];
|
|
141
|
-
cfg.defaultExport.build.transpile ||= [];
|
|
142
|
-
const sonnerExists = cfg.defaultExport.imports.imports.find(
|
|
143
|
-
(i: any) => i.from === "vue-sonner" && i.name === "toast"
|
|
144
|
-
);
|
|
145
|
-
if (!sonnerExists) {
|
|
146
|
-
// prettier-ignore
|
|
147
|
-
cfg.defaultExport.imports.imports.push({ from: "vue-sonner", name: "toast", as: "useSonner" });
|
|
148
|
-
}
|
|
149
|
-
const transpileExists = cfg.defaultExport.build.transpile.find((i: any) => "vue-sonner");
|
|
150
|
-
if (!transpileExists) {
|
|
151
|
-
cfg.defaultExport.build.transpile.push("vue-sonner");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// @not-scalable
|
|
155
|
-
if (component.value === "datatable") {
|
|
156
|
-
cfg.defaultExport.app ||= {};
|
|
157
|
-
cfg.defaultExport.app.head ||= {};
|
|
158
|
-
cfg.defaultExport.app.head.script ||= [];
|
|
159
|
-
const scriptOneExists = cfg.defaultExport.app.head.script.find(
|
|
160
|
-
(i: any) =>
|
|
161
|
-
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/pdfmake.min.js"
|
|
162
|
-
);
|
|
163
|
-
if (!scriptOneExists) {
|
|
164
|
-
cfg.defaultExport.app.head.script.push({
|
|
165
|
-
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/pdfmake.min.js",
|
|
166
|
-
defer: true,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
const scriptTwoExists = cfg.defaultExport.app.head.script.find(
|
|
170
|
-
(i: any) =>
|
|
171
|
-
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/vfs_fonts.min.js"
|
|
172
|
-
);
|
|
173
|
-
if (!scriptTwoExists) {
|
|
174
|
-
cfg.defaultExport.app.head.script.push({
|
|
175
|
-
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/vfs_fonts.min.js",
|
|
176
|
-
defer: true,
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
111
|
+
// Step 5 — Collect found components and their dependencies
|
|
112
|
+
let found: Component[] = componentNames
|
|
113
|
+
.map((name) => findComponent(name))
|
|
114
|
+
.filter(Boolean) as Component[];
|
|
180
115
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const exists = await fileExists(filePath);
|
|
187
|
-
if (exists && !uiConfig.force) {
|
|
188
|
-
const res = await prompts({
|
|
189
|
-
type: "confirm",
|
|
190
|
-
name: "value",
|
|
191
|
-
message: `The utils file that we are trying to add ${kleur.bold(
|
|
192
|
-
util.fileName
|
|
193
|
-
)} already exists. Overwrite?`,
|
|
194
|
-
initial: true,
|
|
195
|
-
});
|
|
196
|
-
if (!res.value) {
|
|
197
|
-
consola.info(`We will not overwrite the file for ${kleur.cyan(util.fileName)}`);
|
|
198
|
-
continue loop3;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
await writeFile(filePath, util.fileContent);
|
|
202
|
-
}
|
|
203
|
-
// add composables attached to the component
|
|
204
|
-
loop4: for (let j = 0; j < component.composables.length; j++) {
|
|
205
|
-
const composable = component.composables[j];
|
|
206
|
-
const filePath = path.join(
|
|
207
|
-
currentDirectory,
|
|
208
|
-
uiConfig.composablesLocation,
|
|
209
|
-
composable.fileName
|
|
210
|
-
);
|
|
211
|
-
// Check if the file exists
|
|
212
|
-
const exists = await fileExists(filePath);
|
|
213
|
-
if (exists && !uiConfig.force) {
|
|
214
|
-
const res = await prompts({
|
|
215
|
-
type: "confirm",
|
|
216
|
-
name: "value",
|
|
217
|
-
message: `The composables file that we are trying to add ${kleur.bold(
|
|
218
|
-
composable.fileName
|
|
219
|
-
)} already exists. Overwrite?`,
|
|
220
|
-
initial: true,
|
|
221
|
-
});
|
|
222
|
-
if (!res.value) {
|
|
223
|
-
consola.info(`We will not overwrite the file for ${kleur.cyan(composable.fileName)}`);
|
|
224
|
-
continue loop4;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
await writeFile(filePath, composable.fileContent);
|
|
228
|
-
}
|
|
229
|
-
// add plugins attached to the component
|
|
230
|
-
loop5: for (let j = 0; j < component.plugins.length; j++) {
|
|
231
|
-
const plugin = component.plugins[j];
|
|
232
|
-
const filePath = path.join(
|
|
233
|
-
currentDirectory,
|
|
234
|
-
uiConfig.pluginsLocation ?? plugin.dirPath,
|
|
235
|
-
plugin.fileName
|
|
236
|
-
);
|
|
237
|
-
// Check if the file exists
|
|
238
|
-
const exists = await fileExists(filePath);
|
|
239
|
-
if (exists && !uiConfig.force) {
|
|
240
|
-
const res = await prompts({
|
|
241
|
-
type: "confirm",
|
|
242
|
-
name: "value",
|
|
243
|
-
message: `The plugins file that we are trying to add ${kleur.bold(
|
|
244
|
-
plugin.fileName
|
|
245
|
-
)} already exists. Overwrite?`,
|
|
246
|
-
initial: true,
|
|
247
|
-
});
|
|
248
|
-
if (!res.value) {
|
|
249
|
-
consola.info(`We will not overwrite the file for ${kleur.cyan(plugin.fileName)}`);
|
|
250
|
-
continue loop5;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
await writeFile(filePath, plugin.fileContent);
|
|
116
|
+
for (const comp of [...found]) {
|
|
117
|
+
if (comp.components) {
|
|
118
|
+
comp.components.forEach((dep) => {
|
|
119
|
+
if (!found.find((c) => c.value === dep)) {
|
|
120
|
+
found.push(findComponent(dep)!);
|
|
254
121
|
}
|
|
255
|
-
}
|
|
122
|
+
});
|
|
256
123
|
}
|
|
257
|
-
|
|
258
|
-
addModuleToConfig(cfg.nuxtConfig, _.uniq(found.map((c) => c.nuxtModules || []).flat()));
|
|
259
|
-
// Write the changes to the nuxt config
|
|
260
|
-
await updateConfig(cfg.nuxtConfig, "nuxt.config.ts");
|
|
261
|
-
const foundDeps = _.uniq(found.map((c) => c.deps || []).flat());
|
|
262
|
-
const foundDevDeps = _.uniq(found.map((c) => c.devDeps || []).flat());
|
|
124
|
+
}
|
|
263
125
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
initial: true,
|
|
126
|
+
// Step 6 — Write files for each component
|
|
127
|
+
for (const component of found) {
|
|
128
|
+
for (const file of component.files) {
|
|
129
|
+
let dirPath = uiConfig.componentsLocation;
|
|
130
|
+
let filePath = path.join(currentDirectory, dirPath, file.fileName);
|
|
131
|
+
|
|
132
|
+
// Ask for custom location if not using default
|
|
133
|
+
if (!uiConfig.useDefaultFilename) {
|
|
134
|
+
const { value: newDir } = await prompts({
|
|
135
|
+
type: "text",
|
|
136
|
+
name: "value",
|
|
137
|
+
message: `Where should we add the file ${kleur.cyan(file.fileName)}?`,
|
|
138
|
+
initial: dirPath,
|
|
278
139
|
});
|
|
279
|
-
if (
|
|
280
|
-
|
|
140
|
+
if (newDir) {
|
|
141
|
+
dirPath = newDir;
|
|
142
|
+
filePath = path.join(currentDirectory, dirPath, file.fileName);
|
|
281
143
|
}
|
|
282
144
|
}
|
|
145
|
+
|
|
146
|
+
const fileWritten = await safeWriteFile(
|
|
147
|
+
filePath,
|
|
148
|
+
file.fileContent,
|
|
149
|
+
uiConfig.force,
|
|
150
|
+
`The file ${kleur.bold(file.fileName)} already exists. Overwrite?`
|
|
151
|
+
);
|
|
152
|
+
if (!fileWritten) continue;
|
|
153
|
+
|
|
154
|
+
// Component-specific logic hooks
|
|
155
|
+
if (component.value === "vue-sonner" || component.value === "sonner") await addSonner();
|
|
156
|
+
if (component.value === "datatable") await addDataTable();
|
|
157
|
+
|
|
158
|
+
// Write related files
|
|
159
|
+
await writeCategoryFiles("utils", component.utils, uiConfig.utilsLocation, uiConfig.force);
|
|
160
|
+
await writeCategoryFiles(
|
|
161
|
+
"composables",
|
|
162
|
+
component.composables,
|
|
163
|
+
uiConfig.composablesLocation,
|
|
164
|
+
uiConfig.force
|
|
165
|
+
);
|
|
166
|
+
await writeCategoryFiles(
|
|
167
|
+
"plugins",
|
|
168
|
+
component.plugins,
|
|
169
|
+
uiConfig.pluginsLocation ?? "",
|
|
170
|
+
uiConfig.force
|
|
171
|
+
);
|
|
283
172
|
}
|
|
173
|
+
}
|
|
284
174
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
175
|
+
// Step 7 — Add Nuxt modules
|
|
176
|
+
await addModuleToConfig(_.uniq(found.flatMap((c) => c.nuxtModules || [])));
|
|
177
|
+
|
|
178
|
+
// Step 8 — Install dependencies if necessary
|
|
179
|
+
const deps = _.uniq(found.flatMap((c) => c.deps || []));
|
|
180
|
+
const devDeps = _.uniq(found.flatMap((c) => c.devDeps || []));
|
|
181
|
+
if (deps.length > 0 || devDeps.length > 0) {
|
|
182
|
+
if (options.all) {
|
|
183
|
+
await installPackages(uiConfig.packageManager, deps, devDeps);
|
|
184
|
+
} else {
|
|
185
|
+
const { confirmInstall } = await prompts({
|
|
186
|
+
type: "confirm",
|
|
187
|
+
name: "confirmInstall",
|
|
188
|
+
message: `Install packages: ${kleur.cyan([...deps, ...devDeps].join(", "))}?`,
|
|
189
|
+
initial: true,
|
|
190
|
+
});
|
|
191
|
+
if (confirmInstall) {
|
|
192
|
+
await installPackages(uiConfig.packageManager, deps, devDeps);
|
|
292
193
|
}
|
|
293
194
|
}
|
|
195
|
+
}
|
|
294
196
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
197
|
+
// Step 9 — Install validator if required
|
|
198
|
+
if (found.some((c) => c.askValidator)) {
|
|
199
|
+
await installValidator(uiConfig.packageManager);
|
|
200
|
+
}
|
|
299
201
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
202
|
+
// Step 10 — Success message & instructions
|
|
203
|
+
printFancyBoxMessage(
|
|
204
|
+
"All Done!",
|
|
205
|
+
`Run the ${kleur.cyan("ui-thing@latest --help")} command to learn more.\n`,
|
|
206
|
+
{ box: { title: "Components Added" } }
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const instructions = _.compact(found.flatMap((c) => c.instructions));
|
|
210
|
+
if (instructions.length > 0) {
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log(kleur.bgCyan(" Instructions "));
|
|
213
|
+
instructions.forEach((i) => console.log(`${kleur.cyan("-")} ${i}`));
|
|
214
|
+
}
|
|
215
|
+
};
|
|
308
216
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
217
|
+
/**
|
|
218
|
+
* CLI Command Registration
|
|
219
|
+
*/
|
|
220
|
+
export const add = new Command()
|
|
221
|
+
.name("add")
|
|
222
|
+
.command("add")
|
|
223
|
+
.description("Add a list of components to your project.")
|
|
224
|
+
.option("-a --all", "Add all components to your project.", false)
|
|
225
|
+
.argument("[componentNames...]", "Components that you want to add.")
|
|
226
|
+
.action(runAddCommand);
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Component-specific setup helpers
|
|
230
|
+
*/
|
|
231
|
+
async function addSonner() {
|
|
232
|
+
await updateConfig({
|
|
233
|
+
configFile: "nuxt.config",
|
|
234
|
+
cwd: currentDirectory,
|
|
235
|
+
onUpdate(config: any) {
|
|
236
|
+
config.imports ||= { imports: [] };
|
|
237
|
+
if (!config.imports.imports.find((i: any) => i.from === "vue-sonner" && i.name === "toast")) {
|
|
238
|
+
config.imports.imports.push({ from: "vue-sonner", name: "toast", as: "useSonner" });
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function addDataTable() {
|
|
245
|
+
await updateConfig({
|
|
246
|
+
configFile: "nuxt.config",
|
|
247
|
+
cwd: currentDirectory,
|
|
248
|
+
onUpdate(cfg: any) {
|
|
249
|
+
cfg.app ||= { head: { script: [] } };
|
|
250
|
+
const scripts = [
|
|
251
|
+
"https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/pdfmake.min.js",
|
|
252
|
+
"https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/vfs_fonts.min.js",
|
|
253
|
+
];
|
|
254
|
+
scripts.forEach((src) => {
|
|
255
|
+
if (!cfg.app.head.script.find((i: any) => i.src === src)) {
|
|
256
|
+
cfg.app.head.script.push({ src, defer: true });
|
|
257
|
+
}
|
|
315
258
|
});
|
|
316
|
-
}
|
|
259
|
+
},
|
|
317
260
|
});
|
|
261
|
+
}
|