@gilav21/shadcn-angular 0.0.19 → 0.0.21

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.
@@ -0,0 +1,131 @@
1
+ import chalk from 'chalk';
2
+ import { registry } from '../registry/index.js';
3
+
4
+ type Category = 'UI' | 'Charts' | 'Layout / Page Building' | 'Animation' | 'Kanban';
5
+
6
+ const CATEGORY_ORDER: readonly Category[] = ['UI', 'Charts', 'Layout / Page Building', 'Animation', 'Kanban'];
7
+
8
+ const ANIMATION_COMPONENTS = new Set([
9
+ 'gradient-text', 'flip-text', 'meteors', 'shine-border', 'scroll-progress',
10
+ 'blur-fade', 'ripple', 'marquee', 'word-rotate', 'morphing-text',
11
+ 'typing-animation', 'wobble-card', 'magnetic', 'orbit', 'stagger-children',
12
+ 'particles', 'confetti', 'number-ticker', 'text-reveal', 'streaming-text', 'sparkles',
13
+ ]);
14
+
15
+ const KANBAN_COMPONENTS = new Set(['kanban']);
16
+
17
+ const LAYOUT_COMPONENTS = new Set(['bento-grid', 'page-builder']);
18
+
19
+ function categorize(name: string): Category {
20
+ const def = registry[name];
21
+ if (!def) return 'UI';
22
+
23
+ const hasChartFile = def.files.some(f => f.startsWith('charts/'));
24
+ if (hasChartFile) return 'Charts';
25
+
26
+ if (LAYOUT_COMPONENTS.has(name)) return 'Layout / Page Building';
27
+ if (ANIMATION_COMPONENTS.has(name)) return 'Animation';
28
+ if (KANBAN_COMPONENTS.has(name)) return 'Kanban';
29
+
30
+ return 'UI';
31
+ }
32
+
33
+ function buildComponentsByCategory(): Map<Category, readonly string[]> {
34
+ const groups = new Map<Category, string[]>();
35
+
36
+ for (const cat of CATEGORY_ORDER) {
37
+ groups.set(cat, []);
38
+ }
39
+
40
+ for (const name of Object.keys(registry)) {
41
+ const cat = categorize(name);
42
+ const list = groups.get(cat);
43
+ if (list) list.push(name);
44
+ }
45
+
46
+ for (const list of groups.values()) {
47
+ list.sort();
48
+ }
49
+
50
+ return groups;
51
+ }
52
+
53
+ function formatComponentList(names: readonly string[], columns = 4): string {
54
+ const colWidth = 26;
55
+ const lines: string[] = [];
56
+
57
+ for (let i = 0; i < names.length; i += columns) {
58
+ const row = names.slice(i, i + columns);
59
+ lines.push(' ' + row.map(n => n.padEnd(colWidth)).join(''));
60
+ }
61
+
62
+ return lines.join('\n');
63
+ }
64
+
65
+ function buildCommandsSection(): string[] {
66
+ const branchDefault = chalk.gray('(default: master)');
67
+
68
+ return [
69
+ chalk.bold('Commands'),
70
+ '',
71
+ ' ' + chalk.cyan('init') + ' Initialize shadcn-angular in your project',
72
+ ' ' + chalk.gray('-y, --yes') + ' Skip confirmation prompt',
73
+ ' ' + chalk.gray('-d, --defaults') + ' Use default configuration',
74
+ ' ' + chalk.gray('-b, --branch') + ' <branch> GitHub branch to fetch from ' + branchDefault,
75
+ '',
76
+ ' ' + chalk.cyan('add') + ' Add component(s) to your project',
77
+ ' ' + chalk.gray('[components...]') + ' One or more component names',
78
+ ' ' + chalk.gray('-y, --yes') + ' Skip confirmation prompt',
79
+ ' ' + chalk.gray('-o, --overwrite') + ' Overwrite existing files',
80
+ ' ' + chalk.gray('-a, --all') + ' Add all available components',
81
+ ' ' + chalk.gray('-p, --path') + ' <path> Custom install path',
82
+ ' ' + chalk.gray('--remote') + ' Force remote fetch from GitHub registry',
83
+ ' ' + chalk.gray('-b, --branch') + ' <branch> GitHub branch to fetch from ' + branchDefault,
84
+ '',
85
+ ' ' + chalk.cyan('help') + ' Show this reference',
86
+ '',
87
+ ];
88
+ }
89
+
90
+ function buildOptionalDepsSection(): string[] {
91
+ return [
92
+ chalk.bold('Optional Dependencies'),
93
+ '',
94
+ ' Some components offer companion packages during installation.',
95
+ ' With ' + chalk.cyan('--yes') + ' they are skipped; with ' + chalk.cyan('--all') + ' they are included automatically.',
96
+ '',
97
+ ];
98
+ }
99
+
100
+ function buildComponentsSection(): string[] {
101
+ const groups = buildComponentsByCategory();
102
+ const lines: string[] = [
103
+ chalk.bold('Available Components'),
104
+ '',
105
+ ];
106
+
107
+ for (const [category, names] of groups) {
108
+ if (names.length === 0) continue;
109
+ const countLabel = chalk.gray('(' + String(names.length) + ')');
110
+ lines.push(
111
+ ' ' + chalk.yellow(category) + ' ' + countLabel,
112
+ formatComponentList(names),
113
+ '',
114
+ );
115
+ }
116
+
117
+ return lines;
118
+ }
119
+
120
+ export function help(): void {
121
+ const output = [
122
+ '',
123
+ chalk.bold.underline('shadcn-angular CLI'),
124
+ '',
125
+ ...buildCommandsSection(),
126
+ ...buildOptionalDepsSection(),
127
+ ...buildComponentsSection(),
128
+ ];
129
+
130
+ console.log(output.join('\n'));
131
+ }
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs-extra';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
4
  import prompts from 'prompts';
5
5
  import chalk from 'chalk';
6
6
  import ora from 'ora';
@@ -10,7 +10,9 @@ import { getUtilsTemplate } from '../templates/utils.js';
10
10
  import { installPackages } from '../utils/package-manager.js';
11
11
  import { writeShortcutRegistryIndex } from '../utils/shortcut-registry.js';
12
12
 
13
- const LIB_REGISTRY_BASE_URL = 'https://raw.githubusercontent.com/gilav21/shadcn-angular/master/packages/components/lib';
13
+ function getLibRegistryBaseUrl(branch: string) {
14
+ return `https://raw.githubusercontent.com/gilav21/shadcn-angular/${branch}/packages/components/lib`;
15
+ }
14
16
  const __filename = fileURLToPath(import.meta.url);
15
17
  const __dirname = path.dirname(__filename);
16
18
 
@@ -22,7 +24,7 @@ function getLocalLibDir(): string | null {
22
24
  return null;
23
25
  }
24
26
 
25
- async function fetchLibFileContent(file: string): Promise<string> {
27
+ async function fetchLibFileContent(file: string, branch: string): Promise<string> {
26
28
  const localLibDir = getLocalLibDir();
27
29
  if (localLibDir) {
28
30
  const localPath = path.join(localLibDir, file);
@@ -31,7 +33,7 @@ async function fetchLibFileContent(file: string): Promise<string> {
31
33
  }
32
34
  }
33
35
 
34
- const url = `${LIB_REGISTRY_BASE_URL}/${file}`;
36
+ const url = `${getLibRegistryBaseUrl(branch)}/${file}`;
35
37
  const response = await fetch(url);
36
38
  if (!response.ok) {
37
39
  throw new Error(`Failed to fetch library file from ${url}: ${response.statusText}`);
@@ -42,6 +44,7 @@ async function fetchLibFileContent(file: string): Promise<string> {
42
44
  interface InitOptions {
43
45
  yes?: boolean;
44
46
  defaults?: boolean;
47
+ branch: string;
45
48
  }
46
49
 
47
50
  function resolveProjectPath(cwd: string, inputPath: string): string {
@@ -95,7 +98,6 @@ export async function init(options: InitOptions) {
95
98
 
96
99
  if (options.defaults || options.yes) {
97
100
  config = getDefaultConfig();
98
- createShortcutRegistry = true;
99
101
  } else {
100
102
  const THEME_COLORS: Record<string, string> = {
101
103
  zinc: '#71717a',
@@ -227,7 +229,7 @@ export async function init(options: InitOptions) {
227
229
  spinner.text = 'Created utils.ts';
228
230
 
229
231
  const shortcutServicePath = path.join(libDir, 'shortcut-binding.service.ts');
230
- const shortcutServiceContent = await fetchLibFileContent('shortcut-binding.service.ts');
232
+ const shortcutServiceContent = await fetchLibFileContent('shortcut-binding.service.ts', options.branch);
231
233
  await fs.writeFile(shortcutServicePath, shortcutServiceContent);
232
234
  spinner.text = 'Created shortcut-binding.service.ts';
233
235
 
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Command } from 'commander';
3
3
  import { init } from './commands/init.js';
4
4
  import { add } from './commands/add.js';
5
+ import { help } from './commands/help.js';
5
6
 
6
7
  const program = new Command();
7
8
 
@@ -15,6 +16,7 @@ program
15
16
  .description('Initialize shadcn-angular in your project')
16
17
  .option('-y, --yes', 'Skip confirmation prompt')
17
18
  .option('-d, --defaults', 'Use default configuration')
19
+ .option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
18
20
  .action(init);
19
21
 
20
22
  program
@@ -26,6 +28,12 @@ program
26
28
  .option('-a, --all', 'Add all available components')
27
29
  .option('-p, --path <path>', 'The path to add the component to')
28
30
  .option('--remote', 'Force remote fetch from GitHub registry')
31
+ .option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
29
32
  .action(add);
30
33
 
34
+ program
35
+ .command('help')
36
+ .description('Show detailed usage information')
37
+ .action(help);
38
+
31
39
  program.parse();
@@ -1,10 +1,17 @@
1
1
  // Component Registry - Defines available components and their file mappings
2
2
  // Actual component files are stored in packages/components/ui/
3
3
 
4
+ export interface OptionalDependency {
5
+ readonly name: string;
6
+ readonly description: string;
7
+ }
8
+
4
9
  export interface ComponentDefinition {
5
10
  name: string;
6
11
  files: string[]; // Relative paths to component files
12
+ peerFiles?: string[]; // Files to update only if they already exist in the user's project
7
13
  dependencies?: string[]; // Other components this depends on
14
+ optionalDependencies?: readonly OptionalDependency[]; // Companion components offered during install
8
15
  npmDependencies?: string[]; // NPM packages this depends on
9
16
  libFiles?: string[]; // Lib utility files this component requires (e.g. 'xlsx.ts')
10
17
  shortcutDefinitions?: {
@@ -143,8 +150,12 @@ export const registry: Record<string, ComponentDefinition> = {
143
150
  'data-table/data-table-column-header.component.ts',
144
151
  'data-table/data-table-pagination.component.ts',
145
152
  'data-table/data-table.types.ts',
153
+ 'data-table/data-table.utils.ts',
146
154
  'data-table/index.ts',
147
155
  ],
156
+ peerFiles: [
157
+ 'context-menu-integrations.ts',
158
+ ],
148
159
  dependencies: [
149
160
  'table',
150
161
  'input',
@@ -157,6 +168,9 @@ export const registry: Record<string, ComponentDefinition> = {
157
168
  'icon',
158
169
  ],
159
170
  libFiles: ['xlsx.ts'],
171
+ optionalDependencies: [
172
+ { name: 'context-menu', description: 'Enables right-click context menus on rows and headers' },
173
+ ],
160
174
  },
161
175
  dialog: {
162
176
  name: 'dialog',
@@ -354,6 +368,9 @@ export const registry: Record<string, ComponentDefinition> = {
354
368
  name: 'tree',
355
369
  files: ['tree.component.ts'],
356
370
  dependencies: ['icon'],
371
+ optionalDependencies: [
372
+ { name: 'context-menu', description: 'Enables right-click context menus on tree nodes' },
373
+ ],
357
374
  },
358
375
  'speed-dial': {
359
376
  name: 'speed-dial',
@@ -1,5 +1,5 @@
1
1
  import fs from 'fs-extra';
2
- import path from 'path';
2
+ import path from 'node:path';
3
3
 
4
4
  export interface Config {
5
5
  $schema: string;
@@ -1,6 +1,6 @@
1
1
  import { execa } from 'execa';
2
2
  import fs from 'fs-extra';
3
- import path from 'path';
3
+ import path from 'node:path';
4
4
 
5
5
  export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
6
6
 
@@ -33,10 +33,7 @@ export async function installPackages(
33
33
  if (packageManager === 'npm') {
34
34
  args.push('install');
35
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') {
36
+ } else if (packageManager === 'yarn' || packageManager === 'pnpm') {
40
37
  args.push('add');
41
38
  if (options.dev) args.push('-D');
42
39
  } else if (packageManager === 'bun') {
@@ -1,5 +1,5 @@
1
1
  import fs from 'fs-extra';
2
- import path from 'path';
2
+ import path from 'node:path';
3
3
  import type { Config } from './config.js';
4
4
 
5
5
  export interface ShortcutRegistryEntry {