grg-kit-cli 0.2.0 → 0.3.1

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/commands/init.js CHANGED
@@ -1,15 +1,19 @@
1
1
  const fs = require('fs').promises;
2
2
  const path = require('path');
3
+ const { exec } = require('child_process');
4
+ const { promisify } = require('util');
3
5
  const degit = require('degit');
4
6
  const chalk = require('chalk');
5
7
  const ora = require('ora');
6
8
  const { RESOURCES, REPO } = require('../config/resources');
7
9
 
10
+ const execAsync = promisify(exec);
11
+
8
12
  /**
9
13
  * Init command - initializes GRG Kit in the project
10
- * Creates themes directory and downloads a theme
14
+ * Creates Angular project, installs Tailwind CSS v4, runs spartan-ng ui, downloads theme
11
15
  */
12
- async function init(options) {
16
+ async function init(projectName, options) {
13
17
  const themeName = options.theme || 'grg-theme';
14
18
  const theme = RESOURCES.themes.find(t => t.name === themeName);
15
19
 
@@ -21,37 +25,161 @@ async function init(options) {
21
25
  }
22
26
 
23
27
  console.log(chalk.bold.cyan('\nšŸš€ Initializing GRG Kit\n'));
28
+ console.log(chalk.gray(` Project: ${projectName}`));
29
+ console.log(chalk.gray(` Theme: ${theme.title}\n`));
30
+
31
+ const spinner = ora();
24
32
 
25
- // Step 1: Create themes directory
26
- const spinner = ora('Creating themes directory...').start();
33
+ // Step 1: Create Angular project
34
+ spinner.start(`Creating Angular project "${projectName}"...`);
27
35
  try {
28
- await fs.mkdir('src/themes', { recursive: true });
29
- spinner.succeed(chalk.green('āœ“ Created src/themes directory'));
36
+ await execAsync(`ng new ${projectName} --style=css`, { stdio: 'pipe' });
37
+ spinner.succeed(chalk.green(`āœ“ Created Angular project "${projectName}"`));
30
38
  } catch (error) {
31
- spinner.fail(chalk.red('Failed to create themes directory'));
39
+ spinner.fail(chalk.red('Failed to create Angular project'));
32
40
  console.error(chalk.red(error.message));
33
41
  process.exit(1);
34
42
  }
35
43
 
36
- // Step 2: Download theme
37
- spinner.start(`Downloading ${theme.title}...`);
44
+ // Change to project directory for remaining steps
45
+ process.chdir(projectName);
46
+
47
+ // Step 2: Install Tailwind CSS v4
48
+ spinner.start('Installing Tailwind CSS v4...');
38
49
  try {
39
- const emitter = degit(`${REPO}/${theme.path}`, {
50
+ await execAsync('pnpm install tailwindcss @tailwindcss/postcss postcss', { stdio: 'pipe' });
51
+ spinner.succeed(chalk.green('āœ“ Tailwind CSS v4 installed'));
52
+ } catch (error) {
53
+ spinner.warn(chalk.yellow('Tailwind CSS installation skipped (may already be installed)'));
54
+ }
55
+
56
+ // Step 3: Create .postcssrc.json
57
+ spinner.start('Creating PostCSS configuration...');
58
+ try {
59
+ const postcssConfig = {
60
+ plugins: {
61
+ '@tailwindcss/postcss': {}
62
+ }
63
+ };
64
+ await fs.writeFile('.postcssrc.json', JSON.stringify(postcssConfig, null, 2) + '\n');
65
+ spinner.succeed(chalk.green('āœ“ Created .postcssrc.json'));
66
+ } catch (error) {
67
+ spinner.warn(chalk.yellow('Could not create .postcssrc.json (may already exist)'));
68
+ }
69
+
70
+ // Step 4: Install Spartan-NG CLI
71
+ spinner.start('Installing Spartan-NG CLI...');
72
+ try {
73
+ await execAsync('pnpm install -D @spartan-ng/cli', { stdio: 'pipe' });
74
+ spinner.succeed(chalk.green('āœ“ Spartan-NG CLI installed'));
75
+ } catch (error) {
76
+ spinner.warn(chalk.yellow('Spartan-NG CLI installation skipped'));
77
+ }
78
+
79
+ // Step 5: Create components.json config file
80
+ spinner.start('Creating Spartan-NG configuration...');
81
+ try {
82
+ const componentsConfig = {
83
+ componentsPath: 'libs/ui',
84
+ importAlias: '@spartan-ng/helm'
85
+ };
86
+ await fs.writeFile('components.json', JSON.stringify(componentsConfig, null, 2) + '\n');
87
+ spinner.succeed(chalk.green('āœ“ Created components.json'));
88
+ } catch (error) {
89
+ spinner.warn(chalk.yellow('Could not create components.json'));
90
+ }
91
+
92
+ // Step 6: Update tsconfig.json with paths for Spartan-NG
93
+ spinner.start('Configuring TypeScript paths...');
94
+ try {
95
+ const tsconfigPath = 'tsconfig.json';
96
+ let tsconfigContent = await fs.readFile(tsconfigPath, 'utf-8');
97
+
98
+ // Strip comments from tsconfig (Angular generates tsconfig with comments)
99
+ tsconfigContent = tsconfigContent
100
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
101
+ .replace(/\/\/.*/g, ''); // Remove line comments
102
+
103
+ const tsconfig = JSON.parse(tsconfigContent);
104
+
105
+ // Add baseUrl and paths for @spartan-ng/helm
106
+ tsconfig.compilerOptions = tsconfig.compilerOptions || {};
107
+ tsconfig.compilerOptions.baseUrl = '.';
108
+ tsconfig.compilerOptions.paths = {
109
+ '@spartan-ng/helm/*': ['./libs/ui/*/src/index.ts']
110
+ };
111
+
112
+ await fs.writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\n');
113
+ spinner.succeed(chalk.green('āœ“ Configured TypeScript paths'));
114
+ } catch (error) {
115
+ spinner.warn(chalk.yellow('Could not update tsconfig.json'));
116
+ console.error(chalk.gray(error.message));
117
+ }
118
+
119
+ // Step 7: Run Spartan-NG UI generator (install all components)
120
+ spinner.start('Installing all Spartan-NG UI components...');
121
+ try {
122
+ const { spawn } = require('child_process');
123
+ await new Promise((resolve, reject) => {
124
+ const child = spawn('pnpm', ['ng', 'g', '@spartan-ng/cli:ui', 'all', '--defaults'], {
125
+ stdio: 'inherit',
126
+ shell: true
127
+ });
128
+ child.on('close', (code) => {
129
+ if (code === 0) resolve();
130
+ else reject(new Error(`Process exited with code ${code}`));
131
+ });
132
+ child.on('error', reject);
133
+ });
134
+ spinner.succeed(chalk.green('āœ“ All Spartan-NG UI components installed'));
135
+ } catch (error) {
136
+ spinner.fail(chalk.red('Failed to run Spartan-NG UI generator'));
137
+ console.error(chalk.red(error.message));
138
+ process.exit(1);
139
+ }
140
+
141
+ // Step 8: Download Spartan-NG examples
142
+ spinner.start('Downloading Spartan-NG examples...');
143
+ try {
144
+ const examplesEmitter = degit(`${REPO}/templates/spartan-examples`, {
40
145
  cache: false,
41
146
  force: true,
42
147
  verbose: false,
43
148
  });
149
+ await examplesEmitter.clone('libs/examples');
150
+ spinner.succeed(chalk.green('āœ“ Downloaded Spartan-NG examples to libs/examples'));
151
+ } catch (error) {
152
+ spinner.warn(chalk.yellow('Could not download Spartan-NG examples'));
153
+ console.error(chalk.gray(error.message));
154
+ }
44
155
 
156
+ // Step 9: Create themes directory
157
+ spinner.start('Creating themes directory...');
158
+ try {
159
+ await fs.mkdir('src/themes', { recursive: true });
160
+ spinner.succeed(chalk.green('āœ“ Created themes directory'));
161
+ } catch (error) {
162
+ spinner.warn(chalk.yellow('Themes directory may already exist'));
163
+ }
164
+
165
+ // Step 10: Download theme
166
+ spinner.start(`Downloading ${theme.title} theme...`);
167
+ try {
168
+ const emitter = degit(`${REPO}/${theme.path}`, {
169
+ cache: false,
170
+ force: true,
171
+ verbose: false,
172
+ });
45
173
  await emitter.clone(theme.defaultOutput);
46
- spinner.succeed(chalk.green(`āœ“ Downloaded ${theme.title}`));
174
+ spinner.succeed(chalk.green(`āœ“ Downloaded ${theme.title} theme`));
47
175
  } catch (error) {
48
176
  spinner.fail(chalk.red('Failed to download theme'));
49
177
  console.error(chalk.red(error.message));
50
178
  process.exit(1);
51
179
  }
52
180
 
53
- // Step 3: Check and update styles.css
54
- spinner.start('Checking src/styles.css...');
181
+ // Step 11: Update styles.css
182
+ spinner.start('Updating src/styles.css...');
55
183
  try {
56
184
  const stylesPath = 'src/styles.css';
57
185
  let stylesContent = '';
@@ -66,7 +194,6 @@ async function init(options) {
66
194
  const themeImport = `@import './themes/${theme.file}';`;
67
195
 
68
196
  if (!stylesContent.includes(themeImport)) {
69
- // Add required imports if not present
70
197
  const requiredImports = [
71
198
  '@import "@angular/cdk/overlay-prebuilt.css";',
72
199
  '@import "tailwindcss";',
@@ -89,13 +216,17 @@ async function init(options) {
89
216
 
90
217
  // Success message
91
218
  console.log(chalk.bold.green('\n✨ GRG Kit initialized successfully!\n'));
92
- console.log(chalk.gray('Theme installed:'), chalk.cyan(theme.title));
93
- console.log(chalk.gray('Description:'), theme.description);
219
+
220
+ console.log(chalk.bold('Installed:'));
221
+ console.log(chalk.gray(' Tailwind CSS:'), chalk.cyan('v4 with PostCSS'));
222
+ console.log(chalk.gray(' Spartan-NG:'), chalk.cyan('All UI components in libs/ui'));
223
+ console.log(chalk.gray(' Examples:'), chalk.cyan('56+ component examples in libs/examples'));
224
+ console.log(chalk.gray(' Theme:'), chalk.cyan(theme.title));
94
225
 
95
226
  console.log(chalk.yellow('\nNext steps:'));
96
- console.log(chalk.gray(' 1. Run'), chalk.cyan('grg list'), chalk.gray('to see available resources'));
97
- console.log(chalk.gray(' 2. Add components with'), chalk.cyan('grg add component:<name>'));
98
- console.log(chalk.gray(' 3. Add examples with'), chalk.cyan('grg add examples:all'));
227
+ console.log(chalk.gray(' 1.'), chalk.cyan(`cd ${projectName}`));
228
+ console.log(chalk.gray(' 2. Run'), chalk.cyan('grg list blocks'), chalk.gray('to see available blocks'));
229
+ console.log(chalk.gray(' 3. Add blocks with'), chalk.cyan('grg add block --auth'));
99
230
  console.log();
100
231
  }
101
232
 
package/commands/list.js CHANGED
@@ -2,91 +2,59 @@ const chalk = require('chalk');
2
2
  const { RESOURCES } = require('../config/resources');
3
3
 
4
4
  /**
5
- * List command - displays available resources
5
+ * List command - displays available blocks and themes
6
6
  * Usage: grg list [category]
7
7
  */
8
8
  async function list(category) {
9
9
  if (!category) {
10
- // Show all categories
10
+ // Show overview
11
11
  console.log(chalk.bold.cyan('\nšŸ“¦ GRG Kit Resources\n'));
12
12
 
13
+ console.log(chalk.bold('Blocks') + chalk.gray(` (${RESOURCES.blocks.length} available)`));
14
+ console.log(chalk.gray(' Add with: grg add block --<name>'));
15
+ console.log(chalk.gray(' Run: grg list blocks\n'));
16
+
13
17
  console.log(chalk.bold('Themes') + chalk.gray(` (${RESOURCES.themes.length} available)`));
18
+ console.log(chalk.gray(' Set with: grg init --theme <name>'));
14
19
  console.log(chalk.gray(' Run: grg list themes\n'));
15
20
 
16
- console.log(chalk.bold('Components') + chalk.gray(` (${RESOURCES.components.length} available)`));
17
- console.log(chalk.gray(' Run: grg list components\n'));
18
-
19
- console.log(chalk.bold('Layouts') + chalk.gray(` (${RESOURCES.layouts.length} available)`));
20
- console.log(chalk.gray(' Run: grg list layouts\n'));
21
-
22
- console.log(chalk.bold('Spartan-NG Examples') + chalk.gray(` (${RESOURCES.examples.components.length}+ available)`));
23
- console.log(chalk.gray(' Run: grg list examples\n'));
21
+ console.log(chalk.gray('Components and spartan-ng examples are installed automatically with'), chalk.cyan('grg init'));
22
+ console.log();
24
23
 
25
24
  return;
26
25
  }
27
26
 
28
27
  switch (category) {
28
+ case 'blocks':
29
+ console.log(chalk.bold.cyan('\n🧱 Available Blocks\n'));
30
+ RESOURCES.blocks.forEach(block => {
31
+ console.log(chalk.bold(` ${block.name}`));
32
+ console.log(chalk.gray(` ${block.description}`));
33
+ console.log(chalk.yellow(` grg add block --${block.name}`));
34
+ if (block.tags && block.tags.length > 0) {
35
+ console.log(chalk.gray(` Tags: ${block.tags.join(', ')}`));
36
+ }
37
+ console.log();
38
+ });
39
+ break;
40
+
29
41
  case 'themes':
30
42
  console.log(chalk.bold.cyan('\nšŸŽØ Available Themes\n'));
43
+ console.log(chalk.gray(' Use with: grg init --theme <name>\n'));
31
44
  RESOURCES.themes.forEach(theme => {
32
45
  console.log(chalk.bold(` ${theme.name}`));
33
46
  console.log(chalk.gray(` ${theme.description}`));
34
- console.log(chalk.yellow(` grg add theme:${theme.name}`));
35
- if (theme.tags.length > 0) {
47
+ console.log(chalk.yellow(` grg init --theme ${theme.name}`));
48
+ if (theme.tags && theme.tags.length > 0) {
36
49
  console.log(chalk.gray(` Tags: ${theme.tags.join(', ')}`));
37
50
  }
38
51
  console.log();
39
52
  });
40
53
  break;
41
54
 
42
- case 'components':
43
- console.log(chalk.bold.cyan('\n🧩 Available Components\n'));
44
- RESOURCES.components.forEach(component => {
45
- console.log(chalk.bold(` ${component.name}`));
46
- console.log(chalk.gray(` ${component.description}`));
47
- console.log(chalk.yellow(` grg add component:${component.name}`));
48
- if (component.tags.length > 0) {
49
- console.log(chalk.gray(` Tags: ${component.tags.join(', ')}`));
50
- }
51
- console.log();
52
- });
53
- break;
54
-
55
- case 'layouts':
56
- console.log(chalk.bold.cyan('\nšŸ“ Available Layouts\n'));
57
- RESOURCES.layouts.forEach(layout => {
58
- console.log(chalk.bold(` ${layout.name}`));
59
- console.log(chalk.gray(` ${layout.description}`));
60
- console.log(chalk.yellow(` grg add layout:${layout.name}`));
61
- if (layout.tags.length > 0) {
62
- console.log(chalk.gray(` Tags: ${layout.tags.join(', ')}`));
63
- }
64
- console.log();
65
- });
66
- break;
67
-
68
- case 'examples':
69
- console.log(chalk.bold.cyan('\nšŸ“š Available Spartan-NG Examples\n'));
70
-
71
- // Show "all" option first
72
- console.log(chalk.bold(` all`) + chalk.gray(' (recommended)'));
73
- console.log(chalk.gray(` ${RESOURCES.examples.all.description}`));
74
- console.log(chalk.yellow(` grg add examples:all`));
75
- console.log();
76
-
77
- console.log(chalk.gray(' Or add individual component examples:\n'));
78
-
79
- RESOURCES.examples.components.forEach(example => {
80
- console.log(chalk.bold(` ${example.name}`));
81
- console.log(chalk.gray(` ${example.description}`));
82
- console.log(chalk.yellow(` grg add examples:${example.name}`));
83
- console.log();
84
- });
85
- break;
86
-
87
55
  default:
88
56
  console.error(chalk.red(`Error: Unknown category "${category}"`));
89
- console.log(chalk.yellow('Valid categories: themes, components, layouts, examples'));
57
+ console.log(chalk.yellow('Valid categories: blocks, themes'));
90
58
  process.exit(1);
91
59
  }
92
60
  }