@gilav21/shadcn-angular 0.0.11 → 0.0.12

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.
@@ -6,6 +6,7 @@ import chalk from 'chalk';
6
6
  import ora from 'ora';
7
7
  import { getConfig } from '../utils/config.js';
8
8
  import { registry } from '../registry/index.js';
9
+ import { installPackages } from '../utils/package-manager.js';
9
10
  const __filename = fileURLToPath(import.meta.url);
10
11
  const __dirname = path.dirname(__filename);
11
12
  // Base URL for the component registry (GitHub raw content)
@@ -231,6 +232,26 @@ export async function add(components, options) {
231
232
  else {
232
233
  spinner.info('No new components installed.');
233
234
  }
235
+ if (finalComponents.length > 0) {
236
+ const npmDependencies = new Set();
237
+ for (const name of finalComponents) {
238
+ const component = registry[name];
239
+ if (component.npmDependencies) {
240
+ component.npmDependencies.forEach(dep => npmDependencies.add(dep));
241
+ }
242
+ }
243
+ if (npmDependencies.size > 0) {
244
+ const depSpinner = ora('Installing dependencies...').start();
245
+ try {
246
+ await installPackages(Array.from(npmDependencies), { cwd });
247
+ depSpinner.succeed('Dependencies installed.');
248
+ }
249
+ catch (e) {
250
+ depSpinner.fail('Failed to install dependencies.');
251
+ console.error(e);
252
+ }
253
+ }
254
+ }
234
255
  if (componentsToSkip.length > 0) {
235
256
  console.log('\n' + chalk.dim('Components skipped (up to date):'));
236
257
  componentsToSkip.forEach(name => {
@@ -2,6 +2,7 @@ export interface ComponentDefinition {
2
2
  name: string;
3
3
  files: string[];
4
4
  dependencies?: string[];
5
+ npmDependencies?: string[];
5
6
  }
6
7
  export type ComponentName = keyof typeof registry;
7
8
  export declare const registry: Record<string, ComponentDefinition>;
@@ -89,6 +89,29 @@ export const registry = {
89
89
  files: ['date-picker.component.ts'],
90
90
  dependencies: ['calendar'],
91
91
  },
92
+ chat: {
93
+ name: 'chat',
94
+ files: ['chat.component.ts'],
95
+ dependencies: ['avatar', 'button', 'textarea', 'scroll-area'],
96
+ },
97
+ 'streaming-text': {
98
+ name: 'streaming-text',
99
+ files: ['streaming-text.component.ts'],
100
+ },
101
+ sparkles: {
102
+ name: 'sparkles',
103
+ files: ['sparkles.component.ts'],
104
+ dependencies: ['button'],
105
+ },
106
+ 'code-block': {
107
+ name: 'code-block',
108
+ files: ['code-block.component.ts'],
109
+ dependencies: ['button', 'scroll-area'],
110
+ },
111
+ 'text-reveal': {
112
+ name: 'text-reveal',
113
+ files: ['text-reveal.component.ts'],
114
+ },
92
115
  'data-table': {
93
116
  name: 'data-table',
94
117
  files: [
@@ -217,6 +240,7 @@ export const registry = {
217
240
  sidebar: {
218
241
  name: 'sidebar',
219
242
  files: ['sidebar.component.ts'],
243
+ dependencies: ['scroll-area', 'tooltip'],
220
244
  },
221
245
  skeleton: {
222
246
  name: 'skeleton',
@@ -0,0 +1,6 @@
1
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
2
+ export declare function getPackageManager(cwd: string): Promise<PackageManager>;
3
+ export declare function installPackages(packages: string[], options: {
4
+ cwd: string;
5
+ dev?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,49 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ export async function getPackageManager(cwd) {
5
+ const userAgent = process.env['npm_config_user_agent'];
6
+ if (userAgent) {
7
+ if (userAgent.startsWith('yarn'))
8
+ return 'yarn';
9
+ if (userAgent.startsWith('pnpm'))
10
+ return 'pnpm';
11
+ if (userAgent.startsWith('bun'))
12
+ return 'bun';
13
+ return 'npm';
14
+ }
15
+ // Check for lock files
16
+ if (await fs.pathExists(path.join(cwd, 'yarn.lock')))
17
+ return 'yarn';
18
+ if (await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml')))
19
+ return 'pnpm';
20
+ if (await fs.pathExists(path.join(cwd, 'bun.lockb')))
21
+ return 'bun';
22
+ return 'npm';
23
+ }
24
+ export async function installPackages(packages, options) {
25
+ const packageManager = await getPackageManager(options.cwd);
26
+ const args = [];
27
+ if (packageManager === 'npm') {
28
+ args.push('install');
29
+ if (options.dev)
30
+ args.push('-D');
31
+ }
32
+ else if (packageManager === 'yarn') {
33
+ args.push('add');
34
+ if (options.dev)
35
+ args.push('-D');
36
+ }
37
+ else if (packageManager === 'pnpm') {
38
+ args.push('add');
39
+ if (options.dev)
40
+ args.push('-D');
41
+ }
42
+ else if (packageManager === 'bun') {
43
+ args.push('add');
44
+ if (options.dev)
45
+ args.push('-d');
46
+ }
47
+ args.push(...packages);
48
+ await execa(packageManager, args, { cwd: options.cwd });
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gilav21/shadcn-angular",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "CLI for adding shadcn-angular components to your project",
5
5
  "bin": {
6
6
  "shadcn-angular": "./dist/index.js"
@@ -32,4 +32,4 @@
32
32
  "@types/prompts": "^2.4.9",
33
33
  "typescript": "^5.5.0"
34
34
  }
35
- }
35
+ }
@@ -6,6 +6,7 @@ import chalk from 'chalk';
6
6
  import ora from 'ora';
7
7
  import { getConfig } from '../utils/config.js';
8
8
  import { registry, type ComponentName } from '../registry/index.js';
9
+ import { installPackages } from '../utils/package-manager.js';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = path.dirname(__filename);
@@ -264,6 +265,27 @@ export async function add(components: string[], options: AddOptions) {
264
265
  spinner.info('No new components installed.');
265
266
  }
266
267
 
268
+ if (finalComponents.length > 0) {
269
+ const npmDependencies = new Set<string>();
270
+ for (const name of finalComponents) {
271
+ const component = registry[name];
272
+ if (component.npmDependencies) {
273
+ component.npmDependencies.forEach(dep => npmDependencies.add(dep));
274
+ }
275
+ }
276
+
277
+ if (npmDependencies.size > 0) {
278
+ const depSpinner = ora('Installing dependencies...').start();
279
+ try {
280
+ await installPackages(Array.from(npmDependencies), { cwd });
281
+ depSpinner.succeed('Dependencies installed.');
282
+ } catch (e) {
283
+ depSpinner.fail('Failed to install dependencies.');
284
+ console.error(e);
285
+ }
286
+ }
287
+ }
288
+
267
289
  if (componentsToSkip.length > 0) {
268
290
  console.log('\n' + chalk.dim('Components skipped (up to date):'));
269
291
  componentsToSkip.forEach(name => {
@@ -5,6 +5,7 @@ export interface ComponentDefinition {
5
5
  name: string;
6
6
  files: string[]; // Relative paths to component files
7
7
  dependencies?: string[]; // Other components this depends on
8
+ npmDependencies?: string[]; // NPM packages this depends on
8
9
  }
9
10
 
10
11
  export type ComponentName = keyof typeof registry;
@@ -98,6 +99,29 @@ export const registry: Record<string, ComponentDefinition> = {
98
99
  files: ['date-picker.component.ts'],
99
100
  dependencies: ['calendar'],
100
101
  },
102
+ chat: {
103
+ name: 'chat',
104
+ files: ['chat.component.ts'],
105
+ dependencies: ['avatar', 'button', 'textarea', 'scroll-area'],
106
+ },
107
+ 'streaming-text': {
108
+ name: 'streaming-text',
109
+ files: ['streaming-text.component.ts'],
110
+ },
111
+ sparkles: {
112
+ name: 'sparkles',
113
+ files: ['sparkles.component.ts'],
114
+ dependencies: ['button'],
115
+ },
116
+ 'code-block': {
117
+ name: 'code-block',
118
+ files: ['code-block.component.ts'],
119
+ dependencies: ['button', 'scroll-area'],
120
+ },
121
+ 'text-reveal': {
122
+ name: 'text-reveal',
123
+ files: ['text-reveal.component.ts'],
124
+ },
101
125
  'data-table': {
102
126
  name: 'data-table',
103
127
  files: [
@@ -137,6 +161,7 @@ export const registry: Record<string, ComponentDefinition> = {
137
161
  name: 'field',
138
162
  files: ['field.component.ts'],
139
163
  },
164
+
140
165
  'file-upload': {
141
166
  name: 'file-upload',
142
167
  files: ['file-upload.component.ts'],
@@ -226,6 +251,7 @@ export const registry: Record<string, ComponentDefinition> = {
226
251
  sidebar: {
227
252
  name: 'sidebar',
228
253
  files: ['sidebar.component.ts'],
254
+ dependencies: ['scroll-area', 'tooltip'],
229
255
  },
230
256
  skeleton: {
231
257
  name: 'skeleton',
@@ -0,0 +1,50 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
6
+
7
+ export async function getPackageManager(cwd: string): Promise<PackageManager> {
8
+ const userAgent = process.env['npm_config_user_agent'];
9
+
10
+ if (userAgent) {
11
+ if (userAgent.startsWith('yarn')) return 'yarn';
12
+ if (userAgent.startsWith('pnpm')) return 'pnpm';
13
+ if (userAgent.startsWith('bun')) return 'bun';
14
+ return 'npm';
15
+ }
16
+
17
+ // Check for lock files
18
+ if (await fs.pathExists(path.join(cwd, 'yarn.lock'))) return 'yarn';
19
+ if (await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
20
+ if (await fs.pathExists(path.join(cwd, 'bun.lockb'))) return 'bun';
21
+
22
+ return 'npm';
23
+ }
24
+
25
+ export async function installPackages(
26
+ packages: string[],
27
+ options: { cwd: string; dev?: boolean }
28
+ ) {
29
+ const packageManager = await getPackageManager(options.cwd);
30
+
31
+ const args: string[] = [];
32
+
33
+ if (packageManager === 'npm') {
34
+ args.push('install');
35
+ if (options.dev) args.push('-D');
36
+ } else if (packageManager === 'yarn') {
37
+ args.push('add');
38
+ if (options.dev) args.push('-D');
39
+ } else if (packageManager === 'pnpm') {
40
+ args.push('add');
41
+ if (options.dev) args.push('-D');
42
+ } else if (packageManager === 'bun') {
43
+ args.push('add');
44
+ if (options.dev) args.push('-d');
45
+ }
46
+
47
+ args.push(...packages);
48
+
49
+ await execa(packageManager, args, { cwd: options.cwd });
50
+ }