shadcn-nextjs-page-generator 1.0.4 → 1.0.6
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 +38 -6
- package/dist/index.cjs +217 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +217 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
✨ **Interactive CLI** - User-friendly prompts guide you through the generation process
|
|
13
13
|
🏗️ **Flexible Architecture** - Choose between DDD (Domain-Driven Design) or Simplified structure
|
|
14
14
|
🎨 **shadcn/ui Components** - Beautiful, accessible components built with Radix UI
|
|
15
|
+
� **Auto-Install** - Automatically detects and installs missing shadcn components
|
|
15
16
|
💨 **Tailwind CSS v4** - Latest Tailwind with modern CSS-first syntax
|
|
16
17
|
🎭 **Framer Motion** - Smooth animations with configurable intensity
|
|
17
18
|
📊 **Complete CRUD** - Tables with search, filter, sort, pagination out of the box
|
|
18
19
|
🔄 **Multiple Data Fetching** - Support for Mock data, TanStack Query, or standard fetch
|
|
19
20
|
⚡ **TypeScript First** - Full type safety and IntelliSense support
|
|
21
|
+
♻️ **Smart Overwrite** - Regenerate files safely with automatic overwrite detection
|
|
20
22
|
|
|
21
23
|
## Quick Start
|
|
22
24
|
|
|
@@ -98,6 +100,20 @@ npx shadcn-nextjs-page-generator
|
|
|
98
100
|
|
|
99
101
|
### 3. Install Dependencies (if needed)
|
|
100
102
|
|
|
103
|
+
The CLI automatically checks and installs missing shadcn/ui components! You'll see:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
🔍 Checking shadcn components...
|
|
107
|
+
✓ button already installed
|
|
108
|
+
✓ table already installed
|
|
109
|
+
- card missing, installing...
|
|
110
|
+
- pagination missing, installing...
|
|
111
|
+
|
|
112
|
+
✓ Installed 2 component(s): card, pagination
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
If you prefer to install manually or need additional dependencies:
|
|
116
|
+
|
|
101
117
|
```bash
|
|
102
118
|
# If you selected TanStack Query
|
|
103
119
|
npm install @tanstack/react-query
|
|
@@ -106,6 +122,8 @@ npm install @tanstack/react-query
|
|
|
106
122
|
npm install framer-motion
|
|
107
123
|
```
|
|
108
124
|
|
|
125
|
+
> **Note:** Auto-install requires shadcn/ui to be initialized in your project (`npx shadcn@latest init`)
|
|
126
|
+
|
|
109
127
|
### 4. Navigate to Your Page
|
|
110
128
|
|
|
111
129
|
```bash
|
|
@@ -301,8 +319,9 @@ const containerVariants = {
|
|
|
301
319
|
|
|
302
320
|
## shadcn/ui Components Used
|
|
303
321
|
|
|
304
|
-
The
|
|
322
|
+
The generator automatically detects and installs the required shadcn/ui components based on your configuration:
|
|
305
323
|
|
|
324
|
+
**Always installed:**
|
|
306
325
|
- `button`
|
|
307
326
|
- `table`
|
|
308
327
|
- `card`
|
|
@@ -311,14 +330,27 @@ The generated code uses these shadcn/ui components:
|
|
|
311
330
|
- `badge`
|
|
312
331
|
- `pagination`
|
|
313
332
|
- `dropdown-menu`
|
|
314
|
-
- `popover`
|
|
315
|
-
- `calendar` (if date filters)
|
|
316
|
-
- `checkbox` (if row selection)
|
|
317
333
|
|
|
318
|
-
|
|
334
|
+
**Conditionally installed:**
|
|
335
|
+
- `popover` + `calendar` (if date filters enabled)
|
|
336
|
+
- `checkbox` (if row selection enabled)
|
|
337
|
+
|
|
338
|
+
### Auto-Install Feature
|
|
339
|
+
|
|
340
|
+
The CLI automatically checks for missing components and installs them using:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
npx shadcn@latest add <component> --yes --overwrite
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
This happens before generating your files, ensuring all required components are available.
|
|
347
|
+
|
|
348
|
+
### Manual Installation
|
|
349
|
+
|
|
350
|
+
If you prefer to install components manually:
|
|
319
351
|
|
|
320
352
|
```bash
|
|
321
|
-
npx shadcn
|
|
353
|
+
npx shadcn@latest add button table card input select badge pagination dropdown-menu popover calendar checkbox
|
|
322
354
|
```
|
|
323
355
|
|
|
324
356
|
## FAQ
|
package/dist/index.cjs
CHANGED
|
@@ -377,7 +377,7 @@ ${message}
|
|
|
377
377
|
};
|
|
378
378
|
|
|
379
379
|
// src/generators/ddd-generator.ts
|
|
380
|
-
var
|
|
380
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
381
381
|
|
|
382
382
|
// src/utils/file-system.ts
|
|
383
383
|
var import_fs_extra = __toESM(require("fs-extra"), 1);
|
|
@@ -385,22 +385,134 @@ var import_path = __toESM(require("path"), 1);
|
|
|
385
385
|
async function ensureDir(dirPath) {
|
|
386
386
|
await import_fs_extra.default.ensureDir(dirPath);
|
|
387
387
|
}
|
|
388
|
-
async function writeFile(filePath, content) {
|
|
388
|
+
async function writeFile(filePath, content, shouldOverwrite = true) {
|
|
389
389
|
const dir = import_path.default.dirname(filePath);
|
|
390
390
|
await ensureDir(dir);
|
|
391
|
-
|
|
391
|
+
const writeOptions = shouldOverwrite ? { encoding: "utf-8", flag: "w" } : { encoding: "utf-8", flag: "wx" };
|
|
392
|
+
await import_fs_extra.default.writeFile(filePath, content, writeOptions);
|
|
393
|
+
}
|
|
394
|
+
async function exists(pathToCheck) {
|
|
395
|
+
try {
|
|
396
|
+
await import_fs_extra.default.access(pathToCheck);
|
|
397
|
+
return true;
|
|
398
|
+
} catch {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
392
401
|
}
|
|
393
402
|
async function createDirectories(dirs) {
|
|
394
403
|
for (const dir of dirs) {
|
|
395
404
|
await ensureDir(dir);
|
|
396
405
|
}
|
|
397
406
|
}
|
|
398
|
-
async function writeFiles(files) {
|
|
407
|
+
async function writeFiles(files, shouldOverwrite = true) {
|
|
399
408
|
for (const file of files) {
|
|
400
|
-
await
|
|
401
|
-
|
|
409
|
+
const fileExists = await exists(file.path);
|
|
410
|
+
await writeFile(file.path, file.content, shouldOverwrite);
|
|
411
|
+
if (fileExists) {
|
|
412
|
+
logger.dim(` Updated: ${file.path}`);
|
|
413
|
+
} else {
|
|
414
|
+
logger.dim(` Created: ${file.path}`);
|
|
415
|
+
}
|
|
402
416
|
}
|
|
403
417
|
}
|
|
418
|
+
async function checkExistingFiles(filePaths) {
|
|
419
|
+
const existingFiles = [];
|
|
420
|
+
for (const filePath of filePaths) {
|
|
421
|
+
if (await exists(filePath)) {
|
|
422
|
+
existingFiles.push(filePath);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return existingFiles;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/utils/shadcn-installer.ts
|
|
429
|
+
var import_child_process = require("child_process");
|
|
430
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
431
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
432
|
+
var COMPONENT_MAP = {
|
|
433
|
+
button: "button",
|
|
434
|
+
table: "table",
|
|
435
|
+
select: "select",
|
|
436
|
+
input: "input",
|
|
437
|
+
badge: "badge",
|
|
438
|
+
card: "card",
|
|
439
|
+
checkbox: "checkbox",
|
|
440
|
+
calendar: "calendar",
|
|
441
|
+
popover: "popover",
|
|
442
|
+
pagination: "pagination",
|
|
443
|
+
dropdown: "dropdown-menu"
|
|
444
|
+
};
|
|
445
|
+
function isComponentInstalled(componentName, cwd) {
|
|
446
|
+
const componentPath = import_path2.default.join(cwd, "components", "ui", `${componentName}.tsx`);
|
|
447
|
+
return import_fs.default.existsSync(componentPath);
|
|
448
|
+
}
|
|
449
|
+
function installComponent(componentName, cwd) {
|
|
450
|
+
try {
|
|
451
|
+
logger.info(`Installing ${componentName} component...`);
|
|
452
|
+
(0, import_child_process.execSync)(`npx shadcn@latest add ${componentName} --yes --overwrite`, {
|
|
453
|
+
cwd,
|
|
454
|
+
stdio: "inherit"
|
|
455
|
+
});
|
|
456
|
+
return true;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
logger.error(`Failed to install ${componentName}: ${error}`);
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function detectRequiredComponents(config) {
|
|
463
|
+
const required = /* @__PURE__ */ new Set();
|
|
464
|
+
required.add(COMPONENT_MAP.button);
|
|
465
|
+
required.add(COMPONENT_MAP.table);
|
|
466
|
+
required.add(COMPONENT_MAP.select);
|
|
467
|
+
required.add(COMPONENT_MAP.input);
|
|
468
|
+
required.add(COMPONENT_MAP.badge);
|
|
469
|
+
required.add(COMPONENT_MAP.card);
|
|
470
|
+
required.add(COMPONENT_MAP.pagination);
|
|
471
|
+
required.add(COMPONENT_MAP.dropdown);
|
|
472
|
+
if (config.includeRowSelection) {
|
|
473
|
+
required.add(COMPONENT_MAP.checkbox);
|
|
474
|
+
}
|
|
475
|
+
if (config.filters.some((f) => f.type === "date")) {
|
|
476
|
+
required.add(COMPONENT_MAP.calendar);
|
|
477
|
+
required.add(COMPONENT_MAP.popover);
|
|
478
|
+
}
|
|
479
|
+
return Array.from(required);
|
|
480
|
+
}
|
|
481
|
+
async function autoInstallComponents(config, cwd = process.cwd()) {
|
|
482
|
+
const result = {
|
|
483
|
+
installed: [],
|
|
484
|
+
skipped: [],
|
|
485
|
+
failed: []
|
|
486
|
+
};
|
|
487
|
+
const required = detectRequiredComponents(config);
|
|
488
|
+
logger.info(`Checking ${required.length} shadcn components...`);
|
|
489
|
+
for (const component of required) {
|
|
490
|
+
if (isComponentInstalled(component, cwd)) {
|
|
491
|
+
result.skipped.push(component);
|
|
492
|
+
logger.dim(` \u2713 ${component} already installed`);
|
|
493
|
+
} else {
|
|
494
|
+
logger.dim(` - ${component} missing, installing...`);
|
|
495
|
+
const success = installComponent(component, cwd);
|
|
496
|
+
if (success) {
|
|
497
|
+
result.installed.push(component);
|
|
498
|
+
} else {
|
|
499
|
+
result.failed.push(component);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return result;
|
|
504
|
+
}
|
|
505
|
+
function checkShadcnCli() {
|
|
506
|
+
try {
|
|
507
|
+
(0, import_child_process.execSync)("npx shadcn@latest --version", { stdio: "ignore" });
|
|
508
|
+
return true;
|
|
509
|
+
} catch {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function isShadcnInitialized(cwd = process.cwd()) {
|
|
514
|
+
return import_fs.default.existsSync(import_path2.default.join(cwd, "components.json"));
|
|
515
|
+
}
|
|
404
516
|
|
|
405
517
|
// src/templates/ddd/entity.ts
|
|
406
518
|
function generateEntity(config) {
|
|
@@ -633,7 +745,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
|
|
|
633
745
|
import { Calendar as CalendarIcon } from 'lucide-react';
|
|
634
746
|
import { format } from 'date-fns';` : ""}
|
|
635
747
|
import { Badge } from '@/components/ui/badge';
|
|
636
|
-
|
|
748
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
637
749
|
import {
|
|
638
750
|
Search,
|
|
639
751
|
Plus,
|
|
@@ -1144,10 +1256,10 @@ import { motion } from 'framer-motion';
|
|
|
1144
1256
|
export default function Template({ children }: { children: React.ReactNode }) {
|
|
1145
1257
|
return (
|
|
1146
1258
|
<motion.div
|
|
1147
|
-
initial
|
|
1148
|
-
animate
|
|
1259
|
+
initial={${animConfig.initial}}
|
|
1260
|
+
animate={${animConfig.animate}}
|
|
1149
1261
|
exit={{ opacity: 0, y: -20 }}
|
|
1150
|
-
transition
|
|
1262
|
+
transition={${animConfig.transition}}
|
|
1151
1263
|
>
|
|
1152
1264
|
{children}
|
|
1153
1265
|
</motion.div>
|
|
@@ -1165,48 +1277,61 @@ var DDDGenerator = class {
|
|
|
1165
1277
|
const files = [];
|
|
1166
1278
|
const cwd = process.cwd();
|
|
1167
1279
|
const { moduleName, routePath } = this.config;
|
|
1168
|
-
|
|
1169
|
-
const
|
|
1280
|
+
await this.checkAndInstallComponents(cwd);
|
|
1281
|
+
const moduleDir = import_path3.default.join(cwd, "modules", moduleName);
|
|
1282
|
+
const appDir = import_path3.default.join(cwd, "app", "(dashboard)", routePath);
|
|
1170
1283
|
const dirs = [
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1284
|
+
import_path3.default.join(moduleDir, "domain", "entities"),
|
|
1285
|
+
import_path3.default.join(moduleDir, "domain", "repositories"),
|
|
1286
|
+
import_path3.default.join(moduleDir, "application", "use-cases"),
|
|
1287
|
+
import_path3.default.join(moduleDir, "infrastructure", "repositories"),
|
|
1288
|
+
import_path3.default.join(moduleDir, "presentation", "components"),
|
|
1176
1289
|
appDir
|
|
1177
1290
|
];
|
|
1178
1291
|
await createDirectories(dirs);
|
|
1179
1292
|
files.push({
|
|
1180
|
-
path:
|
|
1293
|
+
path: import_path3.default.join(moduleDir, "domain", "entities", `${moduleName}.entity.ts`),
|
|
1181
1294
|
content: generateEntity(this.config)
|
|
1182
1295
|
});
|
|
1183
1296
|
files.push({
|
|
1184
|
-
path:
|
|
1297
|
+
path: import_path3.default.join(moduleDir, "domain", "repositories", `${moduleName}.repository.interface.ts`),
|
|
1185
1298
|
content: generateRepositoryInterface(this.config)
|
|
1186
1299
|
});
|
|
1187
1300
|
files.push({
|
|
1188
|
-
path:
|
|
1301
|
+
path: import_path3.default.join(moduleDir, "infrastructure", "repositories", `${moduleName}.repository.ts`),
|
|
1189
1302
|
content: generateRepositoryImpl(this.config)
|
|
1190
1303
|
});
|
|
1191
1304
|
files.push({
|
|
1192
|
-
path:
|
|
1305
|
+
path: import_path3.default.join(moduleDir, "application", "use-cases", `get-${moduleName}s.use-case.ts`),
|
|
1193
1306
|
content: generateUseCase(this.config)
|
|
1194
1307
|
});
|
|
1195
1308
|
files.push({
|
|
1196
|
-
path:
|
|
1309
|
+
path: import_path3.default.join(moduleDir, "presentation", "components", `${moduleName}-list.tsx`),
|
|
1197
1310
|
content: generateComponent(this.config)
|
|
1198
1311
|
});
|
|
1199
1312
|
files.push({
|
|
1200
|
-
path:
|
|
1313
|
+
path: import_path3.default.join(appDir, "page.tsx"),
|
|
1201
1314
|
content: generatePage(this.config)
|
|
1202
1315
|
});
|
|
1203
1316
|
if (this.config.animations.pageTransitions) {
|
|
1204
1317
|
files.push({
|
|
1205
|
-
path:
|
|
1318
|
+
path: import_path3.default.join(appDir, "template.tsx"),
|
|
1206
1319
|
content: generateTemplate(this.config)
|
|
1207
1320
|
});
|
|
1208
1321
|
}
|
|
1209
|
-
|
|
1322
|
+
const filePaths = files.map((f) => f.path);
|
|
1323
|
+
const existingFiles = await checkExistingFiles(filePaths);
|
|
1324
|
+
if (existingFiles.length > 0) {
|
|
1325
|
+
console.log("");
|
|
1326
|
+
logger.warning(`Found ${existingFiles.length} existing file(s):`);
|
|
1327
|
+
existingFiles.forEach((file) => {
|
|
1328
|
+
const relativePath = import_path3.default.relative(cwd, file);
|
|
1329
|
+
logger.dim(` - ${relativePath}`);
|
|
1330
|
+
});
|
|
1331
|
+
console.log("");
|
|
1332
|
+
logger.info("Overwriting existing files...");
|
|
1333
|
+
}
|
|
1334
|
+
await writeFiles(files, true);
|
|
1210
1335
|
const instructions = this.generateInstructions();
|
|
1211
1336
|
return { files, instructions };
|
|
1212
1337
|
}
|
|
@@ -1230,10 +1355,33 @@ var DDDGenerator = class {
|
|
|
1230
1355
|
}
|
|
1231
1356
|
return instructions;
|
|
1232
1357
|
}
|
|
1358
|
+
async checkAndInstallComponents(cwd) {
|
|
1359
|
+
if (!isShadcnInitialized(cwd)) {
|
|
1360
|
+
logger.warning("shadcn/ui is not initialized in this project.");
|
|
1361
|
+
logger.info("Please run: npx shadcn@latest init");
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
if (!checkShadcnCli()) {
|
|
1365
|
+
logger.warning("shadcn CLI not available. Skipping component auto-install.");
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
console.log("");
|
|
1369
|
+
logger.info("\u{1F50D} Checking shadcn components...");
|
|
1370
|
+
const result = await autoInstallComponents(this.config, cwd);
|
|
1371
|
+
if (result.installed.length > 0) {
|
|
1372
|
+
console.log("");
|
|
1373
|
+
logger.success(`\u2713 Installed ${result.installed.length} component(s): ${result.installed.join(", ")}`);
|
|
1374
|
+
}
|
|
1375
|
+
if (result.failed.length > 0) {
|
|
1376
|
+
console.log("");
|
|
1377
|
+
logger.error(`\u2717 Failed to install ${result.failed.length} component(s): ${result.failed.join(", ")}`);
|
|
1378
|
+
}
|
|
1379
|
+
console.log("");
|
|
1380
|
+
}
|
|
1233
1381
|
};
|
|
1234
1382
|
|
|
1235
1383
|
// src/generators/simplified-generator.ts
|
|
1236
|
-
var
|
|
1384
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
1237
1385
|
|
|
1238
1386
|
// src/templates/simplified/component.ts
|
|
1239
1387
|
function generateSimplifiedComponent(config) {
|
|
@@ -1360,7 +1508,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
|
|
|
1360
1508
|
import { Calendar as CalendarIcon } from 'lucide-react';
|
|
1361
1509
|
import { format } from 'date-fns';` : ""}
|
|
1362
1510
|
import { Badge } from '@/components/ui/badge';
|
|
1363
|
-
|
|
1511
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
1364
1512
|
import {
|
|
1365
1513
|
Search,
|
|
1366
1514
|
Plus,
|
|
@@ -1794,24 +1942,37 @@ var SimplifiedGenerator = class {
|
|
|
1794
1942
|
const files = [];
|
|
1795
1943
|
const cwd = process.cwd();
|
|
1796
1944
|
const { moduleName, routePath } = this.config;
|
|
1797
|
-
|
|
1798
|
-
const
|
|
1945
|
+
await this.checkAndInstallComponents(cwd);
|
|
1946
|
+
const componentDir = import_path4.default.join(cwd, "components", moduleName);
|
|
1947
|
+
const appDir = import_path4.default.join(cwd, "app", "(dashboard)", routePath);
|
|
1799
1948
|
await createDirectories([componentDir, appDir]);
|
|
1800
1949
|
files.push({
|
|
1801
|
-
path:
|
|
1950
|
+
path: import_path4.default.join(componentDir, `${moduleName}-list.tsx`),
|
|
1802
1951
|
content: generateSimplifiedComponent(this.config)
|
|
1803
1952
|
});
|
|
1804
1953
|
files.push({
|
|
1805
|
-
path:
|
|
1954
|
+
path: import_path4.default.join(appDir, "page.tsx"),
|
|
1806
1955
|
content: generateSimplifiedPage(this.config)
|
|
1807
1956
|
});
|
|
1808
1957
|
if (this.config.animations.pageTransitions) {
|
|
1809
1958
|
files.push({
|
|
1810
|
-
path:
|
|
1959
|
+
path: import_path4.default.join(appDir, "template.tsx"),
|
|
1811
1960
|
content: generateTemplate(this.config)
|
|
1812
1961
|
});
|
|
1813
1962
|
}
|
|
1814
|
-
|
|
1963
|
+
const filePaths = files.map((f) => f.path);
|
|
1964
|
+
const existingFiles = await checkExistingFiles(filePaths);
|
|
1965
|
+
if (existingFiles.length > 0) {
|
|
1966
|
+
console.log("");
|
|
1967
|
+
logger.warning(`Found ${existingFiles.length} existing file(s):`);
|
|
1968
|
+
existingFiles.forEach((file) => {
|
|
1969
|
+
const relativePath = import_path4.default.relative(cwd, file);
|
|
1970
|
+
logger.dim(` - ${relativePath}`);
|
|
1971
|
+
});
|
|
1972
|
+
console.log("");
|
|
1973
|
+
logger.info("Overwriting existing files...");
|
|
1974
|
+
}
|
|
1975
|
+
await writeFiles(files, true);
|
|
1815
1976
|
const instructions = this.generateInstructions();
|
|
1816
1977
|
return { files, instructions };
|
|
1817
1978
|
}
|
|
@@ -1835,6 +1996,29 @@ var SimplifiedGenerator = class {
|
|
|
1835
1996
|
}
|
|
1836
1997
|
return instructions;
|
|
1837
1998
|
}
|
|
1999
|
+
async checkAndInstallComponents(cwd) {
|
|
2000
|
+
if (!isShadcnInitialized(cwd)) {
|
|
2001
|
+
logger.warning("shadcn/ui is not initialized in this project.");
|
|
2002
|
+
logger.info("Please run: npx shadcn@latest init");
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
if (!checkShadcnCli()) {
|
|
2006
|
+
logger.warning("shadcn CLI not available. Skipping component auto-install.");
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
console.log("");
|
|
2010
|
+
logger.info("\u{1F50D} Checking shadcn components...");
|
|
2011
|
+
const result = await autoInstallComponents(this.config, cwd);
|
|
2012
|
+
if (result.installed.length > 0) {
|
|
2013
|
+
console.log("");
|
|
2014
|
+
logger.success(`\u2713 Installed ${result.installed.length} component(s): ${result.installed.join(", ")}`);
|
|
2015
|
+
}
|
|
2016
|
+
if (result.failed.length > 0) {
|
|
2017
|
+
console.log("");
|
|
2018
|
+
logger.error(`\u2717 Failed to install ${result.failed.length} component(s): ${result.failed.join(", ")}`);
|
|
2019
|
+
}
|
|
2020
|
+
console.log("");
|
|
2021
|
+
}
|
|
1838
2022
|
};
|
|
1839
2023
|
|
|
1840
2024
|
// src/generators/index.ts
|