grg-kit-cli 0.6.7 → 0.6.9

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/bin/grg.js CHANGED
@@ -21,7 +21,7 @@ program
21
21
  .option('-t, --theme <name>', 'Theme to install (grg-theme, claude, clean-slate, modern-minimal, amber-minimal, mocks)', 'grg-theme')
22
22
  .action(init);
23
23
 
24
- // Add command with block subcommand
24
+ // Add command with block and component subcommands
25
25
  const addCommand = program.command('add').description('Add resources to your project');
26
26
 
27
27
  addCommand
@@ -31,6 +31,16 @@ addCommand
31
31
  .option('-o, --output <path>', 'Custom output directory')
32
32
  .action(add);
33
33
 
34
+ addCommand
35
+ .command('component [componentName]')
36
+ .description('Add GRG components to your project (e.g., grg add component file-upload)')
37
+ .option('--all', 'Add all components')
38
+ .option('-o, --output <path>', 'Custom output directory')
39
+ .action(async (componentName, options) => {
40
+ const { addComponent } = require('../commands/add');
41
+ await addComponent(componentName, options);
42
+ });
43
+
34
44
  // List command
35
45
  program
36
46
  .command('list [category]')
package/commands/add.js CHANGED
@@ -196,4 +196,100 @@ function showUsage(RESOURCES) {
196
196
  console.log(chalk.gray('\nRun'), chalk.cyan('grg list blocks'), chalk.gray('for more details'));
197
197
  }
198
198
 
199
- module.exports = { add };
199
+ /**
200
+ * Add component command - downloads GRG components
201
+ * Format: grg add component <componentName>
202
+ * Examples:
203
+ * grg add component file-upload # Download file-upload component
204
+ * grg add component --all # All components
205
+ */
206
+ async function addComponent(componentName, options) {
207
+ // Fetch catalog dynamically (with caching)
208
+ const spinner = ora('Fetching catalog...').start();
209
+ const RESOURCES = await fetchCatalog({ silent: true });
210
+ spinner.stop();
211
+
212
+ // Handle --all flag (download all components)
213
+ if (options.all) {
214
+ console.log(chalk.bold.cyan(`\nšŸ“¦ Adding all components\n`));
215
+
216
+ for (const component of RESOURCES.components) {
217
+ await downloadComponent(component, options.output);
218
+ }
219
+
220
+ console.log(chalk.bold.green('✨ Done!'));
221
+ return;
222
+ }
223
+
224
+ // Validate component name
225
+ if (!componentName) {
226
+ showComponentUsage(RESOURCES);
227
+ process.exit(1);
228
+ }
229
+
230
+ const component = RESOURCES.components.find(c => c.name === componentName);
231
+ if (!component) {
232
+ console.error(chalk.red(`\nError: Component "${componentName}" not found`));
233
+ console.log(chalk.yellow('\nAvailable components:'));
234
+ RESOURCES.components.forEach(c => {
235
+ console.log(chalk.cyan(` ${c.name}`), chalk.gray(`- ${c.description}`));
236
+ });
237
+ process.exit(1);
238
+ }
239
+
240
+ await downloadComponent(component, options.output);
241
+ console.log(chalk.bold.green('✨ Done!'));
242
+ }
243
+
244
+ /**
245
+ * Download a component
246
+ */
247
+ async function downloadComponent(component, customOutput) {
248
+ const downloadSpinner = ora();
249
+ const outputPath = customOutput
250
+ ? `${customOutput}/${component.name}`
251
+ : component.defaultOutput;
252
+
253
+ downloadSpinner.start(`Downloading ${component.title}...`);
254
+
255
+ try {
256
+ const emitter = degit(`${REPO}/${component.path}`, {
257
+ cache: false,
258
+ force: true,
259
+ verbose: false,
260
+ });
261
+
262
+ await emitter.clone(outputPath);
263
+
264
+ downloadSpinner.succeed(chalk.green(`āœ“ ${component.title} added`));
265
+ console.log(chalk.gray(` Location: ${outputPath}`));
266
+
267
+ if (component.dependencies && component.dependencies.length > 0) {
268
+ console.log(chalk.gray(` Dependencies: ${component.dependencies.join(', ')}`));
269
+ }
270
+ console.log();
271
+
272
+ } catch (error) {
273
+ downloadSpinner.fail(chalk.red(`Failed to download ${component.title}`));
274
+ console.error(chalk.red(error.message));
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Show component usage help
280
+ */
281
+ function showComponentUsage(RESOURCES) {
282
+ console.log(chalk.yellow('\nUsage: grg add component <componentName>\n'));
283
+ console.log(chalk.bold('Examples:'));
284
+ console.log(chalk.cyan(' grg add component file-upload'), chalk.gray(' # Download file-upload'));
285
+ console.log(chalk.cyan(' grg add component --all'), chalk.gray(' # All components'));
286
+
287
+ console.log(chalk.bold('\nAvailable components:'));
288
+ RESOURCES.components.forEach(c => {
289
+ console.log(chalk.cyan(` ${c.name}`), chalk.gray(`- ${c.description}`));
290
+ });
291
+
292
+ console.log(chalk.gray('\nRun'), chalk.cyan('grg list components'), chalk.gray('for more details'));
293
+ }
294
+
295
+ module.exports = { add, addComponent };
package/commands/init.js CHANGED
@@ -48,10 +48,12 @@ async function init(options) {
48
48
  // Step 1: Install Tailwind CSS v4
49
49
  spinner.start('Installing Tailwind CSS v4...');
50
50
  try {
51
- await execAsync('npm install tailwindcss @tailwindcss/postcss postcss', { stdio: 'pipe' });
51
+ await execAsync('npm install tailwindcss @tailwindcss/postcss postcss');
52
52
  spinner.succeed(chalk.green('āœ“ Tailwind CSS v4 installed'));
53
53
  } catch (error) {
54
- spinner.warn(chalk.yellow('Tailwind CSS installation skipped (may already be installed)'));
54
+ spinner.fail(chalk.red('Failed to install Tailwind CSS v4'));
55
+ console.error(chalk.gray(error.message));
56
+ process.exit(1);
55
57
  }
56
58
 
57
59
  // Step 3: Create .postcssrc.json
@@ -71,10 +73,12 @@ async function init(options) {
71
73
  // Step 4: Install Spartan-NG CLI
72
74
  spinner.start('Installing Spartan-NG CLI...');
73
75
  try {
74
- await execAsync('npm install -D @spartan-ng/cli', { stdio: 'pipe' });
76
+ await execAsync('npm install -D @spartan-ng/cli');
75
77
  spinner.succeed(chalk.green('āœ“ Spartan-NG CLI installed'));
76
78
  } catch (error) {
77
- spinner.warn(chalk.yellow('Spartan-NG CLI installation skipped'));
79
+ spinner.fail(chalk.red('Failed to install Spartan-NG CLI'));
80
+ console.error(chalk.gray(error.message));
81
+ process.exit(1);
78
82
  }
79
83
 
80
84
  // Step 5: Create components.json config file
@@ -97,9 +101,14 @@ async function init(options) {
97
101
  let tsconfigContent = await fs.readFile(tsconfigPath, 'utf-8');
98
102
 
99
103
  // Strip comments from tsconfig (Angular generates tsconfig with comments)
104
+ // Be careful not to strip // inside strings (like URLs)
100
105
  tsconfigContent = tsconfigContent
101
106
  .replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
102
- .replace(/\/\/.*/g, ''); // Remove line comments
107
+ .replace(/^\s*\/\/.*/gm, ''); // Remove line comments (only at start of line after whitespace)
108
+
109
+ // Remove trailing commas (common in tsconfig files)
110
+ tsconfigContent = tsconfigContent
111
+ .replace(/,(\s*[}\]])/g, '$1');
103
112
 
104
113
  const tsconfig = JSON.parse(tsconfigContent);
105
114
 
@@ -123,9 +132,12 @@ async function init(options) {
123
132
  try {
124
133
  const { spawn } = require('child_process');
125
134
  await new Promise((resolve, reject) => {
126
- const child = spawn('npx', ['ng', 'g', '@spartan-ng/cli:ui'], {
135
+ // Use 'ng' directly (works with global @angular/cli) instead of 'npx ng'
136
+ // Exit code 127 occurs when npx can't find the command
137
+ const child = spawn('ng', ['g', '@spartan-ng/cli:ui'], {
127
138
  stdio: ['pipe', 'pipe', 'pipe'],
128
- shell: true
139
+ shell: true,
140
+ env: { ...process.env } // Inherit PATH to find global ng
129
141
  });
130
142
 
131
143
  let output = '';
@@ -156,7 +168,9 @@ async function init(options) {
156
168
  }
157
169
  });
158
170
 
171
+ let stderrOutput = '';
159
172
  child.stderr.on('data', (data) => {
173
+ stderrOutput += data.toString();
160
174
  // Spartan CLI outputs progress to stderr
161
175
  const text = data.toString();
162
176
  if (text.includes('CREATE') || text.includes('UPDATE')) {
@@ -168,14 +182,24 @@ async function init(options) {
168
182
  child.on('close', (code) => {
169
183
  console.log(); // New line after progress dots
170
184
  if (code === 0) resolve();
171
- else reject(new Error(`Process exited with code ${code}`));
185
+ else reject(new Error(`Process exited with code ${code}${stderrOutput ? '\n' + stderrOutput : ''}`));
186
+ });
187
+ child.on('error', (err) => {
188
+ if (err.code === 'ENOENT') {
189
+ reject(new Error('Angular CLI (ng) not found. Please install it: npm install -g @angular/cli'));
190
+ } else {
191
+ reject(err);
192
+ }
172
193
  });
173
- child.on('error', reject);
174
194
  });
175
195
  spinner.succeed(chalk.green('āœ“ All Spartan-NG UI components installed'));
176
196
  } catch (error) {
177
197
  spinner.fail(chalk.red('Failed to run Spartan-NG UI generator'));
178
198
  console.error(chalk.red(error.message));
199
+ console.log(chalk.yellow('\nTroubleshooting:'));
200
+ console.log(chalk.gray(' 1. Ensure Angular CLI is installed:'), chalk.cyan('npm install -g @angular/cli'));
201
+ console.log(chalk.gray(' 2. Ensure @spartan-ng/cli is installed:'), chalk.cyan('npm install -D @spartan-ng/cli'));
202
+ console.log(chalk.gray(' 3. Try running manually:'), chalk.cyan('ng g @spartan-ng/cli:ui'));
179
203
  process.exit(1);
180
204
  }
181
205
 
package/commands/list.js CHANGED
@@ -3,7 +3,7 @@ const ora = require('ora');
3
3
  const { fetchCatalog } = require('../config/catalog-fetcher');
4
4
 
5
5
  /**
6
- * List command - displays available blocks and themes
6
+ * List command - displays available blocks, components, and themes
7
7
  * Usage: grg list [category]
8
8
  */
9
9
  async function list(category) {
@@ -17,16 +17,17 @@ async function list(category) {
17
17
  console.log(chalk.bold.cyan('\nšŸ“¦ GRG Kit Resources\n'));
18
18
 
19
19
  console.log(chalk.bold('Blocks') + chalk.gray(` (${RESOURCES.blocks.length} available)`));
20
- console.log(chalk.gray(' Add with: grg add block --<name>'));
20
+ console.log(chalk.gray(' Add with: grg add block <name>'));
21
21
  console.log(chalk.gray(' Run: grg list blocks\n'));
22
22
 
23
+ console.log(chalk.bold('Components') + chalk.gray(` (${RESOURCES.components.length} available)`));
24
+ console.log(chalk.gray(' Add with: grg add component <name>'));
25
+ console.log(chalk.gray(' Run: grg list components\n'));
26
+
23
27
  console.log(chalk.bold('Themes') + chalk.gray(` (${RESOURCES.themes.length} available)`));
24
28
  console.log(chalk.gray(' Set with: grg init --theme <name>'));
25
29
  console.log(chalk.gray(' Run: grg list themes\n'));
26
30
 
27
- console.log(chalk.gray('Components and spartan-ng examples are installed automatically with'), chalk.cyan('grg init'));
28
- console.log();
29
-
30
31
  return;
31
32
  }
32
33
 
@@ -36,7 +37,10 @@ async function list(category) {
36
37
  RESOURCES.blocks.forEach(block => {
37
38
  console.log(chalk.bold(` ${block.name}`));
38
39
  console.log(chalk.gray(` ${block.description}`));
39
- console.log(chalk.yellow(` grg add block --${block.name}`));
40
+ console.log(chalk.yellow(` grg add block ${block.name}`));
41
+ if (block.files && block.files.length > 0) {
42
+ console.log(chalk.gray(` Files: ${block.files.map(f => f.id).join(', ')}`));
43
+ }
40
44
  if (block.tags && block.tags.length > 0) {
41
45
  console.log(chalk.gray(` Tags: ${block.tags.join(', ')}`));
42
46
  }
@@ -44,6 +48,23 @@ async function list(category) {
44
48
  });
45
49
  break;
46
50
 
51
+ case 'components':
52
+ console.log(chalk.bold.cyan('\n🧩 Available Components\n'));
53
+ console.log(chalk.gray(' Use with: grg add component <name>\n'));
54
+ RESOURCES.components.forEach(component => {
55
+ console.log(chalk.bold(` ${component.name}`));
56
+ console.log(chalk.gray(` ${component.description}`));
57
+ console.log(chalk.yellow(` grg add component ${component.name}`));
58
+ if (component.dependencies && component.dependencies.length > 0) {
59
+ console.log(chalk.gray(` Dependencies: ${component.dependencies.join(', ')}`));
60
+ }
61
+ if (component.tags && component.tags.length > 0) {
62
+ console.log(chalk.gray(` Tags: ${component.tags.join(', ')}`));
63
+ }
64
+ console.log();
65
+ });
66
+ break;
67
+
47
68
  case 'themes':
48
69
  console.log(chalk.bold.cyan('\nšŸŽØ Available Themes\n'));
49
70
  console.log(chalk.gray(' Use with: grg init --theme <name>\n'));
@@ -60,7 +81,7 @@ async function list(category) {
60
81
 
61
82
  default:
62
83
  console.error(chalk.red(`Error: Unknown category "${category}"`));
63
- console.log(chalk.yellow('Valid categories: blocks, themes'));
84
+ console.log(chalk.yellow('Valid categories: blocks, components, themes'));
64
85
  process.exit(1);
65
86
  }
66
87
  }
@@ -183,7 +183,7 @@ This project uses **GRG Kit**, a comprehensive Angular UI toolkit built on top o
183
183
  **GRG Kit Components** (in \`libs/grg-ui/\`):
184
184
  - Use \`grg-\` prefix for selectors
185
185
  - Import via \`GrgComponentImports\`
186
- - Example: \`GrgStepperImports\`
186
+ - Example: \`GrgFileUploadImports\`
187
187
  - Path alias: \`@grg-kit/ui/component-name\`
188
188
 
189
189
  ### 3. Import Patterns
@@ -213,14 +213,14 @@ import { HlmDialogImports } from '@spartan-ng/helm/dialog';
213
213
 
214
214
  #### GRG Kit Components
215
215
  \`\`\`typescript
216
- import { GrgStepperImports } from '@grg-kit/ui/stepper';
216
+ import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
217
217
 
218
218
  @Component({
219
- imports: [GrgStepperImports],
219
+ imports: [GrgFileUploadImports],
220
220
  template: \`
221
- <grg-stepper>
222
- <grg-step>...</grg-step>
223
- </grg-stepper>
221
+ <grg-file-upload>
222
+ <grg-file-upload-trigger>Drop files here</grg-file-upload-trigger>
223
+ </grg-file-upload>
224
224
  \`
225
225
  })
226
226
  \`\`\`
@@ -343,6 +343,178 @@ class="flex flex-col justify-between gap-4 py-4 sm:flex-row sm:items-center"
343
343
  [attr.data-state]="row.getIsSelected() && 'selected'"
344
344
  \`\`\`
345
345
 
346
+ ## TailwindCSS Best Practices (CRITICAL)
347
+
348
+ ### NEVER Use Raw Color Classes
349
+
350
+ **FORBIDDEN - Do NOT use these patterns:**
351
+ \`\`\`typescript
352
+ // āŒ WRONG - Raw Tailwind colors
353
+ class="text-green-600 bg-green-100" // No raw green
354
+ class="text-red-500 bg-red-50" // No raw red
355
+ class="text-yellow-600 bg-yellow-100" // No raw yellow
356
+ class="text-blue-500 bg-blue-100" // No raw blue
357
+ class="border-gray-200" // No raw gray
358
+ class="text-slate-700" // No raw slate
359
+ \`\`\`
360
+
361
+ **REQUIRED - Use semantic color tokens:**
362
+ \`\`\`typescript
363
+ // āœ… CORRECT - Semantic colors from design system
364
+ class="text-foreground" // Primary text
365
+ class="text-muted-foreground" // Secondary/muted text
366
+ class="bg-background" // Page background
367
+ class="bg-card" // Card background
368
+ class="bg-muted" // Muted/subtle background
369
+ class="bg-primary text-primary-foreground" // Primary actions
370
+ class="bg-secondary text-secondary-foreground" // Secondary elements
371
+ class="bg-destructive text-destructive-foreground" // Errors/danger
372
+ class="bg-accent text-accent-foreground" // Accents/highlights
373
+ class="border-border" // Standard borders
374
+ class="border-input" // Input borders
375
+ \`\`\`
376
+
377
+ ### Available Semantic Colors
378
+
379
+ These are the ONLY colors you should use (defined in \`styles.css\` and theme files):
380
+
381
+ | Token | Usage |
382
+ |-------|-------|
383
+ | \`background\` / \`foreground\` | Page background and primary text |
384
+ | \`card\` / \`card-foreground\` | Card containers |
385
+ | \`popover\` / \`popover-foreground\` | Popovers, dropdowns |
386
+ | \`primary\` / \`primary-foreground\` | Primary buttons, links |
387
+ | \`secondary\` / \`secondary-foreground\` | Secondary actions |
388
+ | \`muted\` / \`muted-foreground\` | Subtle backgrounds, secondary text |
389
+ | \`accent\` / \`accent-foreground\` | Highlights, hover states |
390
+ | \`destructive\` / \`destructive-foreground\` | Errors, delete actions |
391
+ | \`border\` | Standard borders |
392
+ | \`input\` | Form input borders |
393
+ | \`ring\` | Focus rings |
394
+ | \`chart-1\` through \`chart-5\` | Chart/data visualization colors |
395
+ | \`sidebar-*\` | Sidebar-specific colors |
396
+
397
+ ### Adding New Semantic Colors
398
+
399
+ If you need a color that doesn't exist (e.g., success, warning, info):
400
+
401
+ **Step 1: Add CSS variables to \`src/styles.css\`:**
402
+ \`\`\`css
403
+ :root {
404
+ /* Existing variables... */
405
+
406
+ /* Add new semantic color with BOTH light and dark values */
407
+ --success: oklch(0.72 0.19 142); /* Green for light mode */
408
+ --success-foreground: oklch(1 0 0); /* White text */
409
+
410
+ --warning: oklch(0.75 0.18 85); /* Amber for light mode */
411
+ --warning-foreground: oklch(0.2 0 0); /* Dark text */
412
+
413
+ --info: oklch(0.65 0.15 250); /* Blue for light mode */
414
+ --info-foreground: oklch(1 0 0); /* White text */
415
+ }
416
+
417
+ .dark {
418
+ /* Dark mode equivalents */
419
+ --success: oklch(0.65 0.17 142);
420
+ --success-foreground: oklch(1 0 0);
421
+
422
+ --warning: oklch(0.70 0.16 85);
423
+ --warning-foreground: oklch(0.15 0 0);
424
+
425
+ --info: oklch(0.60 0.14 250);
426
+ --info-foreground: oklch(1 0 0);
427
+ }
428
+ \`\`\`
429
+
430
+ **Step 2: Register in \`@theme inline\` block (in theme file):**
431
+ \`\`\`css
432
+ @theme inline {
433
+ --color-success: var(--success);
434
+ --color-success-foreground: var(--success-foreground);
435
+ --color-warning: var(--warning);
436
+ --color-warning-foreground: var(--warning-foreground);
437
+ --color-info: var(--info);
438
+ --color-info-foreground: var(--info-foreground);
439
+ }
440
+ \`\`\`
441
+
442
+ **Step 3: Now use in templates:**
443
+ \`\`\`typescript
444
+ class="bg-success text-success-foreground" // Success states
445
+ class="bg-warning text-warning-foreground" // Warning states
446
+ class="bg-info text-info-foreground" // Info states
447
+ \`\`\`
448
+
449
+ ### Typography Best Practices
450
+
451
+ **NEVER use arbitrary font sizes:**
452
+ \`\`\`typescript
453
+ // āŒ WRONG - Arbitrary sizes
454
+ class="text-[13px]" // No arbitrary values
455
+ class="text-[1.1rem]" // No arbitrary values
456
+ \`\`\`
457
+
458
+ **USE the Tailwind typography scale:**
459
+ \`\`\`typescript
460
+ // āœ… CORRECT - Standard typography scale
461
+ class="text-xs" // 0.75rem (12px)
462
+ class="text-sm" // 0.875rem (14px)
463
+ class="text-base" // 1rem (16px) - default body
464
+ class="text-lg" // 1.125rem (18px)
465
+ class="text-xl" // 1.25rem (20px)
466
+ class="text-2xl" // 1.5rem (24px)
467
+ class="text-3xl" // 1.875rem (30px)
468
+ class="text-4xl" // 2.25rem (36px)
469
+ \`\`\`
470
+
471
+ **Font weights:**
472
+ \`\`\`typescript
473
+ class="font-normal" // 400
474
+ class="font-medium" // 500
475
+ class="font-semibold" // 600
476
+ class="font-bold" // 700
477
+ \`\`\`
478
+
479
+ **Font families (from theme):**
480
+ \`\`\`typescript
481
+ class="font-sans" // System UI font stack
482
+ class="font-mono" // Monospace for code
483
+ class="font-serif" // Serif for special cases
484
+ \`\`\`
485
+
486
+ ### Spacing Best Practices
487
+
488
+ **USE the standard spacing scale:**
489
+ \`\`\`typescript
490
+ // āœ… CORRECT - Standard spacing
491
+ class="p-4" // 1rem
492
+ class="gap-2" // 0.5rem
493
+ class="mt-6" // 1.5rem
494
+ class="space-y-4" // 1rem between children
495
+ \`\`\`
496
+
497
+ **AVOID arbitrary spacing unless absolutely necessary:**
498
+ \`\`\`typescript
499
+ // āŒ AVOID - Arbitrary spacing
500
+ class="p-[13px]" // Use p-3 or p-4 instead
501
+ \`\`\`
502
+
503
+ ### Dark Mode Support
504
+
505
+ All semantic colors automatically support dark mode. The theme system handles this via:
506
+ - \`:root\` for light mode values
507
+ - \`.dark\` or \`[data-theme="theme-name"].dark\` for dark mode values
508
+
509
+ **You do NOT need to add \`dark:\` prefixes** when using semantic colors:
510
+ \`\`\`typescript
511
+ // āœ… CORRECT - Semantic colors auto-adapt
512
+ class="bg-background text-foreground" // Works in both light and dark
513
+
514
+ // āŒ WRONG - Manual dark mode with raw colors
515
+ class="bg-white dark:bg-gray-900" // Don't do this
516
+ \`\`\`
517
+
346
518
  ### Component Variants
347
519
  Components support multiple variants through the \`variant\` attribute:
348
520
 
@@ -504,7 +676,7 @@ export class FormComponent {
504
676
  - **Slider**: Range input controls
505
677
 
506
678
  ### GRG Kit Custom Components
507
- - **Stepper**: Multi-step form wizard component
679
+ - **File Upload**: Drag and drop file upload component
508
680
 
509
681
  ## Package Manager
510
682
 
@@ -568,7 +740,7 @@ After adding, restart your IDE for the MCP server to be available.
568
740
  Use the MCP server for:
569
741
  1. **Themes** - Install different color themes
570
742
  2. **Blocks** - Pre-built page layouts (auth, shell, settings)
571
- 3. **GRG Kit Components** - Custom components like stepper, file-upload
743
+ 3. **GRG Kit Components** - Custom components like file-upload
572
744
 
573
745
  **Do NOT use MCP for:**
574
746
  - Spartan-NG components (button, card, dialog, etc.) - already installed
@@ -592,7 +764,7 @@ mcp2_search_ui_resources({
592
764
  **When to use:**
593
765
  - User needs a page layout or block
594
766
  - Looking for a theme
595
- - Need a GRG Kit component (stepper, file-upload)
767
+ - Need a GRG Kit component (file-upload)
596
768
 
597
769
  ### 2. mcp2_suggest_resources
598
770
 
@@ -698,14 +870,14 @@ AI Workflow:
698
870
  ### Example 4: User Wants a Form Component
699
871
 
700
872
  \`\`\`
701
- User: "I need a multi-step form"
873
+ User: "I need a file upload"
702
874
 
703
875
  AI Workflow:
704
- 1. mcp2_search_ui_resources({ query: "stepper form" })
705
- → Finds: component:stepper
876
+ 1. mcp2_search_ui_resources({ query: "file upload" })
877
+ → Finds: component:file-upload
706
878
 
707
879
  2. Components are included automatically with grg init
708
- → Just import and use: import { GrgStepperImports } from '@grg-kit/ui/stepper';
880
+ → Just import and use: import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
709
881
 
710
882
  3. Use with Spartan-NG form components (from design-system.md)
711
883
  \`\`\`
@@ -735,7 +907,7 @@ User request:
735
907
  ā”œā”€ Need a theme?
736
908
  │ └─ Use MCP: mcp2_list_available_resources({ category: "themes" })
737
909
  │
738
- └─ Need stepper, file-upload, or other GRG Kit component?
910
+ └─ Need file-upload or other GRG Kit component?
739
911
  └─ Use MCP: mcp2_search_ui_resources({ query: "..." })
740
912
  \`\`\`
741
913
 
@@ -789,7 +961,7 @@ import { HlmDialogImports } from '@spartan-ng/helm/dialog';
789
961
 
790
962
  **GRG Kit (grg- prefix):**
791
963
  \`\`\`typescript
792
- import { GrgStepperImports } from '@grg-kit/ui/stepper';
964
+ import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
793
965
  \`\`\`
794
966
 
795
967
  ### Common Patterns
@@ -849,15 +1021,56 @@ import { lucideCheck, lucideX } from '@ng-icons/lucide';
849
1021
  Use MCP only for:
850
1022
  - **Blocks** (auth, shell, settings) - \`mcp2_search_ui_resources({ query: "auth" })\`
851
1023
  - **Themes** - \`mcp2_list_available_resources({ category: "themes" })\`
852
- - **GRG Kit components** (stepper, file-upload) - \`mcp2_search_ui_resources({ query: "stepper" })\`
1024
+ - **GRG Kit components** (file-upload) - \`mcp2_search_ui_resources({ query: "file-upload" })\`
853
1025
 
854
1026
  **Do NOT use MCP for Spartan-NG components** - they are already installed!
855
1027
 
1028
+ ## TailwindCSS Rules (CRITICAL)
1029
+
1030
+ ### NEVER use raw Tailwind colors:
1031
+ \`\`\`html
1032
+ <!-- āŒ FORBIDDEN -->
1033
+ <div class="text-green-600 bg-green-100">Success</div>
1034
+ <div class="text-red-500">Error</div>
1035
+ <div class="bg-yellow-50 border-yellow-200">Warning</div>
1036
+ \`\`\`
1037
+
1038
+ ### ALWAYS use semantic color tokens:
1039
+ \`\`\`html
1040
+ <!-- āœ… CORRECT -->
1041
+ <div class="bg-primary text-primary-foreground">Primary</div>
1042
+ <div class="bg-destructive text-destructive-foreground">Error</div>
1043
+ <div class="text-muted-foreground">Secondary text</div>
1044
+ <div class="bg-muted">Subtle background</div>
1045
+ <div class="border-border">Standard border</div>
1046
+ \`\`\`
1047
+
1048
+ ### Available semantic colors:
1049
+ \`background\`, \`foreground\`, \`card\`, \`card-foreground\`, \`popover\`, \`popover-foreground\`,
1050
+ \`primary\`, \`primary-foreground\`, \`secondary\`, \`secondary-foreground\`, \`muted\`, \`muted-foreground\`,
1051
+ \`accent\`, \`accent-foreground\`, \`destructive\`, \`destructive-foreground\`, \`border\`, \`input\`, \`ring\`
1052
+
1053
+ ### Need a new color (e.g., success, warning)?
1054
+ 1. Add CSS variable to \`src/styles.css\` with light AND dark mode values
1055
+ 2. Register in \`@theme inline\` block
1056
+ 3. Then use: \`bg-success text-success-foreground\`
1057
+
1058
+ ### Typography - use standard scale:
1059
+ \`\`\`html
1060
+ <!-- āœ… CORRECT -->
1061
+ <p class="text-sm">Small</p>
1062
+ <p class="text-base">Body</p>
1063
+ <h2 class="text-xl font-semibold">Heading</h2>
1064
+
1065
+ <!-- āŒ WRONG - arbitrary sizes -->
1066
+ <p class="text-[13px]">Don't do this</p>
1067
+ \`\`\`
1068
+
856
1069
  ## Remember
857
1070
  - Spartan-NG components are pre-installed - just import and use
858
1071
  - Follow existing patterns in the codebase
859
- - Use TailwindCSS v4 for styling
860
- - Prefer signals for state management
1072
+ - Use TailwindCSS v4 for styling with SEMANTIC colors only
1073
+ - NEVER use raw colors like text-green-600, bg-yellow-100, etc.
861
1074
  `;
862
1075
  }
863
1076
 
@@ -900,7 +1113,7 @@ import { HlmDialogImports } from '@spartan-ng/helm/dialog';
900
1113
 
901
1114
  **GRG Kit:**
902
1115
  \`\`\`typescript
903
- import { GrgStepperImports } from '@grg-kit/ui/stepper';
1116
+ import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
904
1117
  \`\`\`
905
1118
 
906
1119
  ## Common Components
@@ -982,7 +1195,7 @@ ${blocksList}
982
1195
  - Need button, card, dialog, form field, table? → Use Spartan-NG (already installed)
983
1196
  - Need page layout (dashboard, auth, settings)? → Use MCP: \`mcp2_search_ui_resources\`
984
1197
  - Need theme? → Use MCP: \`mcp2_list_available_resources({ category: "themes" })\`
985
- - Need stepper, file-upload? → Use MCP: \`mcp2_search_ui_resources\`
1198
+ - Need file-upload? → Use MCP: \`mcp2_search_ui_resources\`
986
1199
 
987
1200
  ## Package Manager
988
1201
 
@@ -991,6 +1204,91 @@ Use npm for package management.
991
1204
  ## Styling
992
1205
 
993
1206
  Use TailwindCSS v4 for all styling. Prefer signals for state management.
1207
+
1208
+ ## TailwindCSS Best Practices (CRITICAL)
1209
+
1210
+ ### NEVER use raw Tailwind colors:
1211
+ \`\`\`html
1212
+ <!-- āŒ FORBIDDEN - These break theming and dark mode -->
1213
+ <div class="text-green-600 bg-green-100">Success</div>
1214
+ <div class="text-red-500">Error</div>
1215
+ <div class="bg-yellow-50">Warning</div>
1216
+ <div class="border-gray-200">Border</div>
1217
+ \`\`\`
1218
+
1219
+ ### ALWAYS use semantic color tokens:
1220
+ \`\`\`html
1221
+ <!-- āœ… CORRECT - These respect theming and dark mode -->
1222
+ <div class="bg-primary text-primary-foreground">Primary action</div>
1223
+ <div class="bg-destructive text-destructive-foreground">Error/Delete</div>
1224
+ <div class="text-muted-foreground">Secondary text</div>
1225
+ <div class="bg-muted">Subtle background</div>
1226
+ <div class="bg-accent text-accent-foreground">Highlighted</div>
1227
+ <div class="border-border">Standard border</div>
1228
+ \`\`\`
1229
+
1230
+ ### Available semantic colors:
1231
+ | Token | Usage |
1232
+ |-------|-------|
1233
+ | \`background\` / \`foreground\` | Page background, primary text |
1234
+ | \`card\` / \`card-foreground\` | Card containers |
1235
+ | \`primary\` / \`primary-foreground\` | Primary buttons, CTAs |
1236
+ | \`secondary\` / \`secondary-foreground\` | Secondary actions |
1237
+ | \`muted\` / \`muted-foreground\` | Subtle backgrounds, secondary text |
1238
+ | \`accent\` / \`accent-foreground\` | Highlights, hover states |
1239
+ | \`destructive\` / \`destructive-foreground\` | Errors, delete actions |
1240
+ | \`border\` | Standard borders |
1241
+ | \`input\` | Form input borders |
1242
+
1243
+ ### Adding new semantic colors (e.g., success, warning, info):
1244
+
1245
+ **Step 1:** Add to \`src/styles.css\` with BOTH light and dark values:
1246
+ \`\`\`css
1247
+ :root {
1248
+ --success: oklch(0.72 0.19 142);
1249
+ --success-foreground: oklch(1 0 0);
1250
+ }
1251
+ .dark {
1252
+ --success: oklch(0.65 0.17 142);
1253
+ --success-foreground: oklch(1 0 0);
1254
+ }
1255
+ \`\`\`
1256
+
1257
+ **Step 2:** Register in \`@theme inline\` block in theme file:
1258
+ \`\`\`css
1259
+ @theme inline {
1260
+ --color-success: var(--success);
1261
+ --color-success-foreground: var(--success-foreground);
1262
+ }
1263
+ \`\`\`
1264
+
1265
+ **Step 3:** Use in templates:
1266
+ \`\`\`html
1267
+ <div class="bg-success text-success-foreground">Success!</div>
1268
+ \`\`\`
1269
+
1270
+ ### Typography - use standard scale only:
1271
+ \`\`\`html
1272
+ <!-- āœ… CORRECT -->
1273
+ <p class="text-sm">Small (14px)</p>
1274
+ <p class="text-base">Body (16px)</p>
1275
+ <h2 class="text-xl font-semibold">Heading</h2>
1276
+
1277
+ <!-- āŒ WRONG - arbitrary sizes -->
1278
+ <p class="text-[13px]">Avoid arbitrary values</p>
1279
+ \`\`\`
1280
+
1281
+ Standard scale: \`text-xs\` (12px), \`text-sm\` (14px), \`text-base\` (16px), \`text-lg\` (18px), \`text-xl\` (20px), \`text-2xl\` (24px), \`text-3xl\` (30px), \`text-4xl\` (36px)
1282
+
1283
+ ### Dark mode is automatic:
1284
+ Semantic colors automatically adapt to dark mode. Do NOT use \`dark:\` prefix with raw colors.
1285
+ \`\`\`html
1286
+ <!-- āœ… Auto-adapts to dark mode -->
1287
+ <div class="bg-background text-foreground">Content</div>
1288
+
1289
+ <!-- āŒ Don't do this -->
1290
+ <div class="bg-white dark:bg-gray-900">Content</div>
1291
+ \`\`\`
994
1292
  `;
995
1293
  }
996
1294
 
@@ -145,23 +145,6 @@ const RESOURCES = {
145
145
  "dependencies": [
146
146
  "@spartan-ng/helm/button"
147
147
  ]
148
- },
149
- {
150
- "name": "stepper",
151
- "title": "Stepper Component",
152
- "description": "Multi-step form component with progress indicator",
153
- "path": "templates/ui/components/stepper",
154
- "defaultOutput": "src/app/components/stepper",
155
- "tags": [
156
- "form",
157
- "wizard",
158
- "multi-step",
159
- "progress"
160
- ],
161
- "dependencies": [
162
- "@spartan-ng/helm/button",
163
- "@spartan-ng/helm/card"
164
- ]
165
148
  }
166
149
  ],
167
150
  "blocks": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grg-kit-cli",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "CLI tool for pulling GRG Kit resources into your Angular project",
5
5
  "main": "index.js",
6
6
  "bin": {
package/scripts/README.md CHANGED
@@ -187,7 +187,6 @@ grg-kit/
187
187
  │ │ ā”œā”€ā”€ meta.json ← All themes metadata
188
188
  │ │ └── *.css
189
189
  │ ā”œā”€ā”€ libs/grg-ui/
190
- │ │ ā”œā”€ā”€ stepper/meta.json
191
190
  │ │ └── file-upload/meta.json
192
191
  │ └── scripts/
193
192
  │ └── generate-sources.js ← Stage 1
@@ -216,8 +215,7 @@ grg-kit/
216
215
  │ ā”œā”€ā”€ meta.json ← Copied from app
217
216
  │ └── *.css
218
217
  └── components/
219
- ā”œā”€ā”€ stepper/meta.json ← Copied from app
220
- └── file-upload/meta.json
218
+ └── file-upload/meta.json ← Copied from app
221
219
  ```
222
220
 
223
221
  ---
@@ -1 +0,0 @@
1
- {"timestamp":1765202627293,"data":{"themes":[{"name":"amber-minimal","title":"Amber Minimal","description":"Warm amber accents","file":"amber-minimal.css","tags":["minimal","warm","amber","orange"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/amber-minimal.css","defaultOutput":"src/themes/amber-minimal.css"},{"name":"claude","title":"Claude","description":"Claude-inspired warm tones","file":"claude.css","tags":["warm","orange","brown","claude"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/claude.css","defaultOutput":"src/themes/claude.css"},{"name":"clean-slate","title":"Clean Slate","description":"Minimal grayscale palette","file":"clean-slate.css","tags":["minimal","grayscale","neutral","clean"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/clean-slate.css","defaultOutput":"src/themes/clean-slate.css"},{"name":"grg-theme","title":"Grg Theme","description":"Default theme with purple/orange accents","file":"grg-theme.css","tags":["default","purple","orange","colorful"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/grg-theme.css","defaultOutput":"src/themes/grg-theme.css"},{"name":"mocks","title":"Mocks","description":"Theme for mockups and prototypes","file":"mocks.css","tags":["mockup","prototype","design"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/mocks.css","defaultOutput":"src/themes/mocks.css"},{"name":"modern-minimal","title":"Modern Minimal","description":"Contemporary minimal design","file":"modern-minimal.css","tags":["minimal","modern","contemporary","clean"],"features":["dark-mode","tailwind-v4","spartan-ng","oklch"],"path":"templates/ui/themes/modern-minimal.css","defaultOutput":"src/themes/modern-minimal.css"}],"components":[{"name":"file-upload","title":"File Upload","description":"Drag and drop file upload component","tags":["file","upload","form","drag-drop"],"dependencies":["@spartan-ng/helm/button"],"path":"templates/ui/components/file-upload","defaultOutput":"src/app/components/file-upload"},{"name":"stepper","title":"Stepper","description":"Multi-step form component with progress indicator","tags":["form","wizard","multi-step","progress"],"dependencies":["@spartan-ng/helm/button","@spartan-ng/helm/card"],"path":"templates/ui/components/stepper","defaultOutput":"src/app/components/stepper"}],"blocks":[{"name":"auth","title":"Auth","description":"Authentication pages (login, signup, forgot password)","tags":["auth","login","signup","authentication","form"],"dependencies":["@spartan-ng/helm/button","@spartan-ng/helm/card","@spartan-ng/helm/form-field"],"files":[{"id":"forgot-password","file":"forgot-password.component.ts","title":"Forgot Password","description":"Forgot Password"},{"id":"login","file":"login.component.ts","title":"Login","description":"Login"},{"id":"register","file":"register.component.ts","title":"Register","description":"Register"}],"path":"templates/ui/blocks/auth","defaultOutput":"src/app/blocks/auth"},{"name":"settings","title":"Settings","description":"Settings pages: profile, notifications, security, danger zone","tags":["settings","preferences","account","profile","security"],"dependencies":["@spartan-ng/helm/button","@spartan-ng/helm/card","@spartan-ng/helm/form-field","@spartan-ng/helm/switch"],"files":[{"id":"danger-zone","file":"danger-zone.component.ts","title":"Danger Zone","description":"Danger Zone"},{"id":"notification","file":"notification-settings.component.ts","title":"Notification Settings","description":"Notification Settings"},{"id":"profile","file":"profile-settings.component.ts","title":"Profile Settings","description":"Profile Settings"},{"id":"security","file":"security-settings.component.ts","title":"Security Settings","description":"Security Settings"}],"path":"templates/ui/blocks/settings","defaultOutput":"src/app/blocks/settings"},{"name":"shell","title":"Shell","description":"Application shell layouts: sidebar, topnav, collapsible - each with optional footer variant","tags":["shell","layout","sidebar","header","footer","navigation","topnav","collapsible"],"dependencies":["@spartan-ng/helm/button","@spartan-ng/helm/icon","@spartan-ng/helm/dropdown-menu"],"files":[{"id":"collapsible-footer","file":"collapsible-shell-footer.component.ts","title":"Collapsible Shell Footer","description":"Collapsible Shell Footer"},{"id":"collapsible","file":"collapsible-shell.component.ts","title":"Collapsible Shell","description":"Collapsible Shell"},{"id":"sidebar-footer","file":"sidebar-shell-footer.component.ts","title":"Sidebar Shell Footer","description":"Sidebar Shell Footer"},{"id":"sidebar","file":"sidebar-shell.component.ts","title":"Sidebar Shell","description":"Sidebar Shell"},{"id":"topnav-footer","file":"topnav-shell-footer.component.ts","title":"Topnav Shell Footer","description":"Topnav Shell Footer"},{"id":"topnav","file":"topnav-shell.component.ts","title":"Topnav Shell","description":"Topnav Shell"}],"path":"templates/ui/blocks/shell","defaultOutput":"src/app/blocks/shell"}]}}