grg-kit-cli 0.6.11 → 0.6.13
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 +18 -52
- package/bin/grg.js +1 -0
- package/commands/add.js +1 -5
- package/commands/list.js +26 -8
- package/commands/llm-setup.js +24 -454
- package/config/resources.js +158 -13
- package/package.json +1 -1
- package/scripts/generate-resources.js +4 -10
- package/config/.catalog-cache.json +0 -1
- package/config/catalog-fetcher.js +0 -199
package/README.md
CHANGED
|
@@ -78,12 +78,15 @@ Examples:
|
|
|
78
78
|
- Updates `src/styles.css` with theme import
|
|
79
79
|
|
|
80
80
|
**Available themes:**
|
|
81
|
-
- `grg-theme` - Default theme with
|
|
81
|
+
- `grg-theme` - Default theme with blue accents
|
|
82
82
|
- `claude` - Claude-inspired warm tones
|
|
83
83
|
- `clean-slate` - Minimal grayscale palette
|
|
84
84
|
- `modern-minimal` - Contemporary minimal design
|
|
85
85
|
- `amber-minimal` - Warm amber accents
|
|
86
|
-
- `
|
|
86
|
+
- `chroma-clinic` - Professional blue theme for healthcare
|
|
87
|
+
- `bio-lab` - Fresh green theme for life sciences
|
|
88
|
+
- `pharma-teal` - Calming teal for pharmaceutical apps
|
|
89
|
+
- `helix-purple` - DNA-inspired purple for genomics
|
|
87
90
|
|
|
88
91
|
### `grg add theme`
|
|
89
92
|
|
|
@@ -153,17 +156,23 @@ Examples:
|
|
|
153
156
|
List available blocks and themes.
|
|
154
157
|
|
|
155
158
|
```bash
|
|
156
|
-
grg list [category]
|
|
159
|
+
grg list [category] [options]
|
|
160
|
+
|
|
161
|
+
Options:
|
|
162
|
+
--json Output as JSON (for MCP server integration)
|
|
157
163
|
|
|
158
164
|
Examples:
|
|
159
165
|
grg list # Show overview
|
|
160
166
|
grg list blocks # List all blocks
|
|
161
167
|
grg list themes # List all themes
|
|
168
|
+
grg list --json # Output all resources as JSON
|
|
162
169
|
```
|
|
163
170
|
|
|
171
|
+
The `--json` flag outputs structured data used by the MCP server to get resource information.
|
|
172
|
+
|
|
164
173
|
### `grg llm-setup`
|
|
165
174
|
|
|
166
|
-
Generate
|
|
175
|
+
Generate design system rules for AI assistants (Windsurf, Cursor, Claude Code).
|
|
167
176
|
|
|
168
177
|
```bash
|
|
169
178
|
grg llm-setup [options]
|
|
@@ -172,60 +181,17 @@ Options:
|
|
|
172
181
|
-o, --output <path> Output directory for rules (default: ".windsurf/rules")
|
|
173
182
|
|
|
174
183
|
Examples:
|
|
175
|
-
grg llm-setup # Windsurf (
|
|
184
|
+
grg llm-setup # Windsurf/Cursor (design-system.md)
|
|
176
185
|
grg llm-setup --output .claude # Claude Code (single CLAUDE.md)
|
|
177
186
|
```
|
|
178
187
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
For AI assistants to automatically discover and use GRG Kit resources:
|
|
182
|
-
|
|
183
|
-
### 1. Install the MCP Server
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
npm install -g grg-kit-mcp-server
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### 2. Configure Your AI Assistant
|
|
190
|
-
|
|
191
|
-
**Windsurf** (`~/.codeium/windsurf/mcp_config.json`):
|
|
192
|
-
|
|
193
|
-
```json
|
|
194
|
-
{
|
|
195
|
-
"mcpServers": {
|
|
196
|
-
"grg-kit": {
|
|
197
|
-
"command": "grg-mcp-server"
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**Claude Code** (`~/.claude/settings.json`):
|
|
204
|
-
|
|
205
|
-
```json
|
|
206
|
-
{
|
|
207
|
-
"mcpServers": {
|
|
208
|
-
"grg-kit": {
|
|
209
|
-
"command": "grg-mcp-server"
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### 3. Generate AI Rules
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
cd your-angular-project
|
|
219
|
-
grg llm-setup
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 4. Restart Your IDE
|
|
188
|
+
**What this creates:**
|
|
189
|
+
- `design-system.md` - Component usage patterns, styling rules, import patterns
|
|
223
190
|
|
|
224
191
|
**What this enables:**
|
|
225
|
-
- ✅ AI automatically searches GRG Kit before writing custom code
|
|
226
|
-
- ✅ AI knows about themes, components, blocks, and examples
|
|
227
192
|
- ✅ AI follows GRG Kit design system patterns
|
|
228
|
-
- ✅ AI
|
|
193
|
+
- ✅ AI uses Spartan-NG components correctly
|
|
194
|
+
- ✅ AI uses semantic colors instead of raw Tailwind colors
|
|
229
195
|
|
|
230
196
|
## Quick Reference
|
|
231
197
|
|
package/bin/grg.js
CHANGED
package/commands/add.js
CHANGED
|
@@ -4,7 +4,7 @@ const ora = require('ora');
|
|
|
4
4
|
const fs = require('fs').promises;
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const https = require('https');
|
|
7
|
-
const {
|
|
7
|
+
const { RESOURCES, REPO } = require('../config/resources');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Add command - downloads blocks or specific block files
|
|
@@ -16,10 +16,6 @@ const { fetchCatalog, REPO } = require('../config/catalog-fetcher');
|
|
|
16
16
|
* grg add block --all # All blocks with all files
|
|
17
17
|
*/
|
|
18
18
|
async function add(blockName, fileIds, options) {
|
|
19
|
-
// Fetch catalog dynamically (with caching)
|
|
20
|
-
const spinner = ora('Fetching catalog...').start();
|
|
21
|
-
const RESOURCES = await fetchCatalog({ silent: true });
|
|
22
|
-
spinner.stop();
|
|
23
19
|
|
|
24
20
|
// Handle --all flag (download everything)
|
|
25
21
|
if (options.all) {
|
package/commands/list.js
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const
|
|
3
|
-
const {
|
|
2
|
+
const { RESOURCES } = require('../config/resources');
|
|
3
|
+
const { version } = require('../package.json');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* List command - displays available blocks, components, and themes
|
|
7
|
-
* Usage: grg list [category]
|
|
7
|
+
* Usage: grg list [category] [--json]
|
|
8
8
|
*/
|
|
9
|
-
async function list(category) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
async function list(category, options = {}) {
|
|
10
|
+
|
|
11
|
+
// JSON output for MCP server integration
|
|
12
|
+
if (options.json) {
|
|
13
|
+
const output = {
|
|
14
|
+
cli: {
|
|
15
|
+
name: 'grg',
|
|
16
|
+
version,
|
|
17
|
+
commands: {
|
|
18
|
+
init: { usage: 'grg init [--theme <name>]', themeFlag: '--theme' },
|
|
19
|
+
addBlock: { usage: 'grg add block <blockName> [fileIds...]', validBlocks: RESOURCES.blocks.map(b => b.name) },
|
|
20
|
+
addComponent: { usage: 'grg add component <componentName>', validComponents: RESOURCES.components.map(c => c.name) },
|
|
21
|
+
addTheme: { usage: 'grg add theme <themeName>' },
|
|
22
|
+
list: { usage: 'grg list [category] [--json]' }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
themes: RESOURCES.themes,
|
|
26
|
+
components: RESOURCES.components,
|
|
27
|
+
blocks: RESOURCES.blocks
|
|
28
|
+
};
|
|
29
|
+
console.log(JSON.stringify(output, null, 2));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
14
32
|
|
|
15
33
|
if (!category) {
|
|
16
34
|
// Show overview
|
package/commands/llm-setup.js
CHANGED
|
@@ -2,11 +2,10 @@ const fs = require('fs').promises;
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const ora = require('ora');
|
|
5
|
-
const { RESOURCES } = require('../config/resources');
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* LLM Setup command - generates LLM-specific prompts and rules
|
|
9
|
-
* Helps AI assistants understand GRG Kit design system
|
|
8
|
+
* Helps AI assistants understand GRG Kit design system
|
|
10
9
|
*/
|
|
11
10
|
async function llmPrompts(options) {
|
|
12
11
|
const outputDir = options.output || '.windsurf/rules';
|
|
@@ -78,8 +77,7 @@ async function llmPrompts(options) {
|
|
|
78
77
|
|
|
79
78
|
console.log(chalk.yellow('\nNext steps:'));
|
|
80
79
|
console.log(chalk.gray(' 1. The CLAUDE.md file will be automatically picked up by Claude Code'));
|
|
81
|
-
console.log(chalk.gray(' 2.
|
|
82
|
-
console.log(chalk.gray(' 3. Claude will now check GRG Kit resources before writing custom code'));
|
|
80
|
+
console.log(chalk.gray(' 2. Claude will now follow GRG Kit design system patterns'));
|
|
83
81
|
console.log();
|
|
84
82
|
return;
|
|
85
83
|
}
|
|
@@ -109,44 +107,15 @@ async function llmPrompts(options) {
|
|
|
109
107
|
process.exit(1);
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
// Step 3: Generate grg-kit-mcp.md
|
|
113
|
-
spinner.start('Generating grg-kit-mcp.md...');
|
|
114
|
-
try {
|
|
115
|
-
const mcpContent = generateMCPRules();
|
|
116
|
-
const mcpPath = path.join(outputDir, 'grg-kit-mcp.md');
|
|
117
|
-
await fs.writeFile(mcpPath, mcpContent);
|
|
118
|
-
spinner.succeed(chalk.green('✓ Generated grg-kit-mcp.md'));
|
|
119
|
-
} catch (error) {
|
|
120
|
-
spinner.fail(chalk.red('Failed to generate grg-kit-mcp.md'));
|
|
121
|
-
console.error(chalk.red(error.message));
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Step 4: Generate angular-components.md (glob-triggered)
|
|
126
|
-
spinner.start('Generating angular-components.md...');
|
|
127
|
-
try {
|
|
128
|
-
const angularContent = generateAngularComponentRules();
|
|
129
|
-
const angularPath = path.join(outputDir, 'angular-components.md');
|
|
130
|
-
await fs.writeFile(angularPath, angularContent);
|
|
131
|
-
spinner.succeed(chalk.green('✓ Generated angular-components.md'));
|
|
132
|
-
} catch (error) {
|
|
133
|
-
spinner.fail(chalk.red('Failed to generate angular-components.md'));
|
|
134
|
-
console.error(chalk.red(error.message));
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
110
|
// Success message
|
|
139
111
|
console.log(chalk.bold.green('\n✨ LLM rules generated successfully!\n'));
|
|
140
|
-
console.log(chalk.gray('
|
|
112
|
+
console.log(chalk.gray('File created:'));
|
|
141
113
|
console.log(chalk.cyan(` ${outputDir}/design-system.md`));
|
|
142
|
-
console.log(chalk.cyan(` ${outputDir}/grg-kit-mcp.md`));
|
|
143
|
-
console.log(chalk.cyan(` ${outputDir}/angular-components.md`));
|
|
144
114
|
|
|
145
115
|
console.log(chalk.yellow('\nNext steps:'));
|
|
146
116
|
console.log(chalk.gray(' 1. These rules will be automatically picked up by your AI assistant'));
|
|
147
|
-
console.log(chalk.gray(' 2.
|
|
148
|
-
console.log(chalk.gray('
|
|
149
|
-
console.log(chalk.gray('\nSupported IDEs: Windsurf, Claude Code, Claude Desktop'));
|
|
117
|
+
console.log(chalk.gray(' 2. AI will now follow GRG Kit design system patterns'));
|
|
118
|
+
console.log(chalk.gray('\nSupported IDEs: Windsurf, Cursor, Claude Code'));
|
|
150
119
|
console.log();
|
|
151
120
|
}
|
|
152
121
|
|
|
@@ -169,8 +138,8 @@ This project uses **GRG Kit**, a comprehensive Angular UI toolkit built on top o
|
|
|
169
138
|
|
|
170
139
|
### 1. Always Check GRG Kit First
|
|
171
140
|
**BEFORE writing any UI component, layout, or page:**
|
|
172
|
-
1.
|
|
173
|
-
2. Check if a
|
|
141
|
+
1. Check if a Spartan-NG component exists (button, card, dialog, form-field, table, etc.)
|
|
142
|
+
2. Check if a block exists for page layouts (auth, shell, settings)
|
|
174
143
|
3. Only write custom code if no suitable resource exists
|
|
175
144
|
|
|
176
145
|
### 2. Component Organization
|
|
@@ -689,411 +658,17 @@ This design system provides a comprehensive foundation for building consistent,
|
|
|
689
658
|
`;
|
|
690
659
|
}
|
|
691
660
|
|
|
692
|
-
function generateMCPRules() {
|
|
693
|
-
// Dynamically build resource lists from resources.js
|
|
694
|
-
// Note: Spartan-NG components are pre-installed, so we only list GRG Kit resources
|
|
695
|
-
const themes = RESOURCES.themes || [];
|
|
696
|
-
const components = RESOURCES.components || [];
|
|
697
|
-
const blocks = RESOURCES.blocks || [];
|
|
698
|
-
|
|
699
|
-
const themesList = themes.map(t => `- \`theme:${t.name}\` - ${t.description}`).join('\n');
|
|
700
|
-
const componentsList = components.map(c => `- \`component:${c.name}\` - ${c.description}`).join('\n');
|
|
701
|
-
const blocksList = blocks.map(b => `- \`block:${b.name}\` - ${b.description}`).join('\n');
|
|
702
|
-
|
|
703
|
-
const totalResources = themes.length + components.length + blocks.length;
|
|
704
|
-
|
|
705
|
-
return `---
|
|
706
|
-
trigger: always_on
|
|
707
|
-
---
|
|
708
|
-
|
|
709
|
-
# GRG Kit MCP Server Integration
|
|
710
|
-
|
|
711
|
-
## Setup
|
|
712
|
-
|
|
713
|
-
Add the grg-kit MCP server to your AI assistant configuration:
|
|
714
|
-
|
|
715
|
-
**Windsurf:** \`~/.codeium/windsurf/mcp_config.json\`
|
|
716
|
-
**Claude Code:** \`~/.claude/settings.json\`
|
|
717
|
-
**Claude Desktop (macOS):** \`~/Library/Application Support/Claude/claude_desktop_config.json\`
|
|
718
|
-
|
|
719
|
-
\`\`\`json
|
|
720
|
-
{
|
|
721
|
-
"mcpServers": {
|
|
722
|
-
"grg-kit": {
|
|
723
|
-
"command": "grg-mcp-server"
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
\`\`\`
|
|
728
|
-
|
|
729
|
-
After adding, restart your IDE for the MCP server to be available.
|
|
730
|
-
|
|
731
|
-
## Important: Spartan-NG is Pre-installed
|
|
732
|
-
|
|
733
|
-
**Spartan-NG components are already installed** in this project. You do NOT need to use MCP to install them.
|
|
734
|
-
|
|
735
|
-
- For Spartan-NG usage patterns → Refer to \`design-system.md\`
|
|
736
|
-
- For themes, blocks, and GRG Kit components → Use MCP tools below
|
|
737
|
-
|
|
738
|
-
## When to Use MCP
|
|
739
|
-
|
|
740
|
-
Use the MCP server for:
|
|
741
|
-
1. **Themes** - Install different color themes
|
|
742
|
-
2. **Blocks** - Pre-built page layouts (auth, shell, settings)
|
|
743
|
-
3. **GRG Kit Components** - Custom components like file-upload
|
|
744
|
-
|
|
745
|
-
**Do NOT use MCP for:**
|
|
746
|
-
- Spartan-NG components (button, card, dialog, etc.) - already installed
|
|
747
|
-
- Basic UI patterns - see \`design-system.md\`
|
|
748
|
-
|
|
749
|
-
## MCP Server Tools
|
|
750
|
-
|
|
751
|
-
The \`grg-kit\` MCP server provides these tools:
|
|
752
|
-
|
|
753
|
-
### 1. mcp2_search_ui_resources
|
|
754
|
-
|
|
755
|
-
Search for GRG Kit resources (themes, blocks, components).
|
|
756
|
-
|
|
757
|
-
\`\`\`typescript
|
|
758
|
-
mcp2_search_ui_resources({
|
|
759
|
-
query: "auth",
|
|
760
|
-
category: "all" // or "themes", "components", "blocks"
|
|
761
|
-
})
|
|
762
|
-
\`\`\`
|
|
763
|
-
|
|
764
|
-
**When to use:**
|
|
765
|
-
- User needs a page layout or block
|
|
766
|
-
- Looking for a theme
|
|
767
|
-
- Need a GRG Kit component (file-upload)
|
|
768
|
-
|
|
769
|
-
### 2. mcp2_suggest_resources
|
|
770
|
-
|
|
771
|
-
Get suggestions based on user requirements.
|
|
772
|
-
|
|
773
|
-
\`\`\`typescript
|
|
774
|
-
mcp2_suggest_resources({
|
|
775
|
-
requirement: "I need a login page"
|
|
776
|
-
})
|
|
777
|
-
|
|
778
|
-
// Returns: block:auth, theme suggestions
|
|
779
|
-
\`\`\`
|
|
780
|
-
|
|
781
|
-
### 3. mcp2_get_resource_details
|
|
782
|
-
|
|
783
|
-
Get detailed information about a resource.
|
|
784
|
-
|
|
785
|
-
\`\`\`typescript
|
|
786
|
-
mcp2_get_resource_details({
|
|
787
|
-
resource: "block:auth"
|
|
788
|
-
})
|
|
789
|
-
|
|
790
|
-
// Returns: dependencies, tags, install command
|
|
791
|
-
\`\`\`
|
|
792
|
-
|
|
793
|
-
### 4. mcp2_install_resource
|
|
794
|
-
|
|
795
|
-
Get the install command for a block. Returns a command to run via run_command tool.
|
|
796
|
-
|
|
797
|
-
\`\`\`typescript
|
|
798
|
-
mcp2_install_resource({
|
|
799
|
-
resource: "auth", // Just the block name, NOT "block:auth"
|
|
800
|
-
files: ["login"], // Optional: specific files to install
|
|
801
|
-
output: "src/app/pages/auth" // Optional: custom output directory
|
|
802
|
-
})
|
|
803
|
-
// Returns: { command: "grg add block auth login", instruction: "Run this command..." }
|
|
804
|
-
\`\`\`
|
|
805
|
-
|
|
806
|
-
**Important:** The resource parameter should be just the block name (e.g., "auth", "shell", "settings"), NOT prefixed with "block:".
|
|
807
|
-
|
|
808
|
-
### 5. mcp2_list_available_resources
|
|
809
|
-
|
|
810
|
-
List all available resources.
|
|
811
|
-
|
|
812
|
-
\`\`\`typescript
|
|
813
|
-
mcp2_list_available_resources({
|
|
814
|
-
category: "all" // or "themes", "components", "blocks"
|
|
815
|
-
})
|
|
816
|
-
\`\`\`
|
|
817
|
-
|
|
818
|
-
## Workflow Examples
|
|
819
|
-
|
|
820
|
-
### Example 1: User Wants a Dashboard
|
|
821
|
-
|
|
822
|
-
\`\`\`
|
|
823
|
-
User: "Create a dashboard with a sidebar"
|
|
824
|
-
|
|
825
|
-
AI Workflow:
|
|
826
|
-
1. mcp2_search_ui_resources({ query: "shell sidebar" })
|
|
827
|
-
→ Finds: block:shell
|
|
828
|
-
|
|
829
|
-
2. mcp2_install_resource({ resource: "shell", files: ["sidebar"] })
|
|
830
|
-
→ Returns command: "grg add block shell sidebar"
|
|
831
|
-
|
|
832
|
-
3. Run the command via run_command tool in the Angular project root
|
|
833
|
-
|
|
834
|
-
4. Customize using Spartan-NG components (from design-system.md)
|
|
835
|
-
→ Add cards, tables, etc.
|
|
836
|
-
\`\`\`
|
|
837
|
-
|
|
838
|
-
### Example 2: User Wants a Login Page
|
|
839
|
-
|
|
840
|
-
\`\`\`
|
|
841
|
-
User: "I need a login page"
|
|
842
|
-
|
|
843
|
-
AI Workflow:
|
|
844
|
-
1. mcp2_search_ui_resources({ query: "auth login" })
|
|
845
|
-
→ Finds: block:auth
|
|
846
|
-
|
|
847
|
-
2. mcp2_install_resource({ resource: "auth", files: ["login"] })
|
|
848
|
-
→ Returns command: "grg add block auth login"
|
|
849
|
-
|
|
850
|
-
3. Run the command via run_command tool in the Angular project root
|
|
851
|
-
|
|
852
|
-
4. Customize as needed
|
|
853
|
-
\`\`\`
|
|
854
|
-
|
|
855
|
-
### Example 3: User Wants a Theme
|
|
856
|
-
|
|
857
|
-
\`\`\`
|
|
858
|
-
User: "Change the theme to something warmer"
|
|
859
|
-
|
|
860
|
-
AI Workflow:
|
|
861
|
-
1. mcp2_list_available_resources({ category: "themes" })
|
|
862
|
-
→ Show: claude, amber-minimal, etc.
|
|
863
|
-
|
|
864
|
-
2. mcp2_install_resource({ resource: "claude" })
|
|
865
|
-
→ Returns command: "grg add theme claude"
|
|
866
|
-
|
|
867
|
-
3. Run the command via run_command tool
|
|
868
|
-
→ Theme is downloaded and styles.css is updated automatically
|
|
869
|
-
\`\`\`
|
|
870
|
-
|
|
871
|
-
### Example 4: User Wants a Form Component
|
|
872
|
-
|
|
873
|
-
\`\`\`
|
|
874
|
-
User: "I need a file upload"
|
|
875
|
-
|
|
876
|
-
AI Workflow:
|
|
877
|
-
1. mcp2_search_ui_resources({ query: "file upload" })
|
|
878
|
-
→ Finds: component:file-upload
|
|
879
|
-
|
|
880
|
-
2. Components are included automatically with grg init
|
|
881
|
-
→ Just import and use: import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
|
|
882
|
-
|
|
883
|
-
3. Use with Spartan-NG form components (from design-system.md)
|
|
884
|
-
\`\`\`
|
|
885
|
-
|
|
886
|
-
## Available Resources (${totalResources} total)
|
|
887
|
-
|
|
888
|
-
### Themes (${themes.length} available)
|
|
889
|
-
${themesList}
|
|
890
|
-
|
|
891
|
-
### GRG Kit Components (${components.length} available)
|
|
892
|
-
${componentsList}
|
|
893
|
-
|
|
894
|
-
### Blocks/Layouts (${blocks.length} available)
|
|
895
|
-
${blocksList}
|
|
896
|
-
|
|
897
|
-
## Decision Tree
|
|
898
|
-
|
|
899
|
-
\`\`\`
|
|
900
|
-
User request:
|
|
901
|
-
│
|
|
902
|
-
├─ Need a button, card, dialog, form field, table, etc.?
|
|
903
|
-
│ └─ Use Spartan-NG (see design-system.md) - ALREADY INSTALLED
|
|
904
|
-
│
|
|
905
|
-
├─ Need a page layout (dashboard, auth, settings)?
|
|
906
|
-
│ └─ Use MCP: mcp2_search_ui_resources({ query: "..." })
|
|
907
|
-
│
|
|
908
|
-
├─ Need a theme?
|
|
909
|
-
│ └─ Use MCP: mcp2_list_available_resources({ category: "themes" })
|
|
910
|
-
│
|
|
911
|
-
└─ Need file-upload or other GRG Kit component?
|
|
912
|
-
└─ Use MCP: mcp2_search_ui_resources({ query: "..." })
|
|
913
|
-
\`\`\`
|
|
914
|
-
|
|
915
|
-
## Remember
|
|
916
|
-
|
|
917
|
-
- **Spartan-NG is pre-installed** - Don't search for button, card, dialog, etc.
|
|
918
|
-
- **Use design-system.md** for Spartan-NG patterns
|
|
919
|
-
- **Use MCP** only for themes, blocks, and GRG Kit components
|
|
920
|
-
- **Check blocks first** when building pages - don't start from scratch
|
|
921
|
-
`;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
function generateAngularComponentRules() {
|
|
925
|
-
// Spartan-NG components are pre-installed - list the common ones
|
|
926
|
-
const spartanComponents = [
|
|
927
|
-
'accordion', 'alert', 'alert-dialog', 'avatar', 'badge', 'breadcrumb',
|
|
928
|
-
'button', 'calendar', 'card', 'checkbox', 'collapsible', 'combobox',
|
|
929
|
-
'command', 'context-menu', 'data-table', 'date-picker', 'dialog',
|
|
930
|
-
'dropdown-menu', 'form-field', 'hover-card', 'input', 'label', 'menubar',
|
|
931
|
-
'navigation-menu', 'pagination', 'popover', 'progress', 'radio-group',
|
|
932
|
-
'scroll-area', 'select', 'separator', 'sheet', 'sidebar', 'skeleton',
|
|
933
|
-
'slider', 'sonner', 'spinner', 'switch', 'table', 'tabs', 'textarea',
|
|
934
|
-
'toggle', 'tooltip'
|
|
935
|
-
];
|
|
936
|
-
const componentNames = spartanComponents.join(', ');
|
|
937
|
-
|
|
938
|
-
return `---
|
|
939
|
-
trigger: glob
|
|
940
|
-
globs: ["**/*.component.ts", "**/*.component.html"]
|
|
941
|
-
---
|
|
942
|
-
|
|
943
|
-
# Angular Component Development with GRG Kit
|
|
944
|
-
|
|
945
|
-
You are editing an Angular component. Before writing UI code:
|
|
946
|
-
|
|
947
|
-
## Quick Reference
|
|
948
|
-
|
|
949
|
-
### Spartan-NG Components (Pre-installed)
|
|
950
|
-
These components are already available - just import and use them:
|
|
951
|
-
${componentNames}
|
|
952
|
-
|
|
953
|
-
### Import Patterns
|
|
954
|
-
|
|
955
|
-
**Spartan-NG (hlm prefix):**
|
|
956
|
-
\`\`\`typescript
|
|
957
|
-
import { HlmButtonImports } from '@spartan-ng/helm/button';
|
|
958
|
-
import { HlmCardImports } from '@spartan-ng/helm/card';
|
|
959
|
-
import { BrnDialogImports } from '@spartan-ng/brain/dialog';
|
|
960
|
-
import { HlmDialogImports } from '@spartan-ng/helm/dialog';
|
|
961
|
-
\`\`\`
|
|
962
|
-
|
|
963
|
-
**GRG Kit (grg- prefix):**
|
|
964
|
-
\`\`\`typescript
|
|
965
|
-
import { GrgFileUploadImports } from '@grg-kit/ui/file-upload';
|
|
966
|
-
\`\`\`
|
|
967
|
-
|
|
968
|
-
### Common Patterns
|
|
969
|
-
|
|
970
|
-
**Button:**
|
|
971
|
-
\`\`\`html
|
|
972
|
-
<button hlmBtn>Default</button>
|
|
973
|
-
<button hlmBtn variant="outline">Outline</button>
|
|
974
|
-
<button hlmBtn variant="destructive">Destructive</button>
|
|
975
|
-
\`\`\`
|
|
976
|
-
|
|
977
|
-
**Card:**
|
|
978
|
-
\`\`\`html
|
|
979
|
-
<section hlmCard>
|
|
980
|
-
<div hlmCardHeader>
|
|
981
|
-
<h3 hlmCardTitle>Title</h3>
|
|
982
|
-
<p hlmCardDescription>Description</p>
|
|
983
|
-
</div>
|
|
984
|
-
<div hlmCardContent>Content</div>
|
|
985
|
-
</section>
|
|
986
|
-
\`\`\`
|
|
987
|
-
|
|
988
|
-
**Form Field:**
|
|
989
|
-
\`\`\`html
|
|
990
|
-
<hlm-form-field>
|
|
991
|
-
<input hlmInput [formControl]="control" placeholder="Email" />
|
|
992
|
-
<hlm-error>Required</hlm-error>
|
|
993
|
-
</hlm-form-field>
|
|
994
|
-
\`\`\`
|
|
995
|
-
|
|
996
|
-
**Dialog:**
|
|
997
|
-
\`\`\`html
|
|
998
|
-
<hlm-dialog>
|
|
999
|
-
<button brnDialogTrigger hlmBtn>Open</button>
|
|
1000
|
-
<hlm-dialog-content *brnDialogContent="let ctx">
|
|
1001
|
-
<hlm-dialog-header>
|
|
1002
|
-
<h3 hlmDialogTitle>Title</h3>
|
|
1003
|
-
</hlm-dialog-header>
|
|
1004
|
-
<!-- content -->
|
|
1005
|
-
</hlm-dialog-content>
|
|
1006
|
-
</hlm-dialog>
|
|
1007
|
-
\`\`\`
|
|
1008
|
-
|
|
1009
|
-
### Icons
|
|
1010
|
-
\`\`\`typescript
|
|
1011
|
-
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
1012
|
-
import { lucideCheck, lucideX } from '@ng-icons/lucide';
|
|
1013
|
-
|
|
1014
|
-
@Component({
|
|
1015
|
-
providers: [provideIcons({ lucideCheck, lucideX })],
|
|
1016
|
-
template: \`<ng-icon hlm name="lucideCheck" />\`
|
|
1017
|
-
})
|
|
1018
|
-
\`\`\`
|
|
1019
|
-
|
|
1020
|
-
## When to Use MCP
|
|
1021
|
-
|
|
1022
|
-
Use MCP only for:
|
|
1023
|
-
- **Blocks** (auth, shell, settings) - \`mcp2_search_ui_resources({ query: "auth" })\`
|
|
1024
|
-
- **Themes** - \`mcp2_list_available_resources({ category: "themes" })\`
|
|
1025
|
-
- **GRG Kit components** (file-upload) - \`mcp2_search_ui_resources({ query: "file-upload" })\`
|
|
1026
|
-
|
|
1027
|
-
**Do NOT use MCP for Spartan-NG components** - they are already installed!
|
|
1028
|
-
|
|
1029
|
-
## TailwindCSS Rules (CRITICAL)
|
|
1030
|
-
|
|
1031
|
-
### NEVER use raw Tailwind colors:
|
|
1032
|
-
\`\`\`html
|
|
1033
|
-
<!-- ❌ FORBIDDEN -->
|
|
1034
|
-
<div class="text-green-600 bg-green-100">Success</div>
|
|
1035
|
-
<div class="text-red-500">Error</div>
|
|
1036
|
-
<div class="bg-yellow-50 border-yellow-200">Warning</div>
|
|
1037
|
-
\`\`\`
|
|
1038
|
-
|
|
1039
|
-
### ALWAYS use semantic color tokens:
|
|
1040
|
-
\`\`\`html
|
|
1041
|
-
<!-- ✅ CORRECT -->
|
|
1042
|
-
<div class="bg-primary text-primary-foreground">Primary</div>
|
|
1043
|
-
<div class="bg-destructive text-destructive-foreground">Error</div>
|
|
1044
|
-
<div class="text-muted-foreground">Secondary text</div>
|
|
1045
|
-
<div class="bg-muted">Subtle background</div>
|
|
1046
|
-
<div class="border-border">Standard border</div>
|
|
1047
|
-
\`\`\`
|
|
1048
|
-
|
|
1049
|
-
### Available semantic colors:
|
|
1050
|
-
\`background\`, \`foreground\`, \`card\`, \`card-foreground\`, \`popover\`, \`popover-foreground\`,
|
|
1051
|
-
\`primary\`, \`primary-foreground\`, \`secondary\`, \`secondary-foreground\`, \`muted\`, \`muted-foreground\`,
|
|
1052
|
-
\`accent\`, \`accent-foreground\`, \`destructive\`, \`destructive-foreground\`, \`border\`, \`input\`, \`ring\`
|
|
1053
|
-
|
|
1054
|
-
### Need a new color (e.g., success, warning)?
|
|
1055
|
-
1. Add CSS variable to \`src/styles.css\` with light AND dark mode values
|
|
1056
|
-
2. Register in \`@theme inline\` block
|
|
1057
|
-
3. Then use: \`bg-success text-success-foreground\`
|
|
1058
|
-
|
|
1059
|
-
### Typography - use standard scale:
|
|
1060
|
-
\`\`\`html
|
|
1061
|
-
<!-- ✅ CORRECT -->
|
|
1062
|
-
<p class="text-sm">Small</p>
|
|
1063
|
-
<p class="text-base">Body</p>
|
|
1064
|
-
<h2 class="text-xl font-semibold">Heading</h2>
|
|
1065
|
-
|
|
1066
|
-
<!-- ❌ WRONG - arbitrary sizes -->
|
|
1067
|
-
<p class="text-[13px]">Don't do this</p>
|
|
1068
|
-
\`\`\`
|
|
1069
|
-
|
|
1070
|
-
## Remember
|
|
1071
|
-
- Spartan-NG components are pre-installed - just import and use
|
|
1072
|
-
- Follow existing patterns in the codebase
|
|
1073
|
-
- Use TailwindCSS v4 for styling with SEMANTIC colors only
|
|
1074
|
-
- NEVER use raw colors like text-green-600, bg-yellow-100, etc.
|
|
1075
|
-
`;
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
661
|
function generateClaudeMdRules() {
|
|
1079
662
|
// Generate a combined CLAUDE.md file for Claude Code
|
|
1080
|
-
const themes = RESOURCES.themes || [];
|
|
1081
|
-
const components = RESOURCES.components || [];
|
|
1082
|
-
const blocks = RESOURCES.blocks || [];
|
|
1083
|
-
|
|
1084
|
-
const themesList = themes.map(t => `- \`theme:${t.name}\` - ${t.description}`).join('\n');
|
|
1085
|
-
const componentsList = components.map(c => `- \`component:${c.name}\` - ${c.description}`).join('\n');
|
|
1086
|
-
const blocksList = blocks.map(b => `- \`block:${b.name}\` - ${b.description}`).join('\n');
|
|
1087
|
-
|
|
1088
663
|
return `# GRG Kit Project Rules
|
|
1089
664
|
|
|
1090
665
|
This project uses **GRG Kit**, an Angular UI toolkit built on **Spartan-NG UI**.
|
|
1091
666
|
|
|
1092
|
-
## Critical: Check
|
|
667
|
+
## Critical: Check Design System First
|
|
1093
668
|
|
|
1094
669
|
**BEFORE writing any UI component:**
|
|
1095
|
-
1.
|
|
1096
|
-
2. Check if a
|
|
670
|
+
1. Check if a Spartan-NG component exists (button, card, dialog, form-field, table, etc.)
|
|
671
|
+
2. Check if a block exists for page layouts (auth, shell, settings)
|
|
1097
672
|
3. Only write custom code if no suitable resource exists
|
|
1098
673
|
|
|
1099
674
|
## Architecture
|
|
@@ -1169,34 +744,29 @@ import { lucideCheck } from '@ng-icons/lucide';
|
|
|
1169
744
|
})
|
|
1170
745
|
\`\`\`
|
|
1171
746
|
|
|
1172
|
-
##
|
|
747
|
+
## Available Blocks
|
|
1173
748
|
|
|
1174
|
-
|
|
749
|
+
Pre-built page layouts available via \`grg add block <name>\`:
|
|
750
|
+
- **auth** - Login, register, forgot-password pages
|
|
751
|
+
- **shell** - Sidebar, topnav, collapsible layouts
|
|
752
|
+
- **settings** - Profile, security, notifications pages
|
|
1175
753
|
|
|
1176
|
-
|
|
1177
|
-
- \`mcp2_suggest_resources({ requirement: "login page" })\` - Get suggestions
|
|
1178
|
-
- \`mcp2_install_resource({ resource: "auth", files: ["login"] })\` - Get install command (returns command to run)
|
|
1179
|
-
- \`mcp2_list_available_resources({ category: "blocks" })\` - List all
|
|
1180
|
-
|
|
1181
|
-
**Note:** \`mcp2_install_resource\` returns a command string. Use \`run_command\` to execute it in the Angular project root.
|
|
1182
|
-
|
|
1183
|
-
## Available Resources
|
|
754
|
+
## Available Themes
|
|
1184
755
|
|
|
1185
|
-
|
|
1186
|
-
|
|
756
|
+
Switch themes via \`grg add theme <name>\`:
|
|
757
|
+
- grg-theme, claude, amber-minimal, clean-slate, modern-minimal
|
|
758
|
+
- Medical themes: chroma-clinic, bio-lab, pharma-teal, helix-purple
|
|
1187
759
|
|
|
1188
|
-
|
|
1189
|
-
${componentsList}
|
|
760
|
+
## GRG Kit Components
|
|
1190
761
|
|
|
1191
|
-
|
|
1192
|
-
${blocksList}
|
|
762
|
+
- **file-upload** - Drag and drop file upload (\`@grg-kit/ui/file-upload\`)
|
|
1193
763
|
|
|
1194
764
|
## Decision Tree
|
|
1195
765
|
|
|
1196
766
|
- Need button, card, dialog, form field, table? → Use Spartan-NG (already installed)
|
|
1197
|
-
- Need page layout (dashboard, auth, settings)? →
|
|
1198
|
-
- Need theme? →
|
|
1199
|
-
- Need file-upload? →
|
|
767
|
+
- Need page layout (dashboard, auth, settings)? → Run: \`grg add block <name>\`
|
|
768
|
+
- Need theme? → Run: \`grg add theme <name>\`
|
|
769
|
+
- Need file-upload? → Import from \`@grg-kit/ui/file-upload\`
|
|
1200
770
|
|
|
1201
771
|
## Package Manager
|
|
1202
772
|
|
package/config/resources.js
CHANGED
|
@@ -29,6 +29,46 @@ const RESOURCES = {
|
|
|
29
29
|
"oklch"
|
|
30
30
|
]
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"name": "bio-lab",
|
|
34
|
+
"title": "Bio Lab",
|
|
35
|
+
"description": "Fresh green theme for life sciences",
|
|
36
|
+
"file": "bio-lab.css",
|
|
37
|
+
"path": "templates/ui/themes/bio-lab.css",
|
|
38
|
+
"defaultOutput": "src/themes/bio-lab.css",
|
|
39
|
+
"tags": [
|
|
40
|
+
"medical",
|
|
41
|
+
"green",
|
|
42
|
+
"life-sciences",
|
|
43
|
+
"biotech"
|
|
44
|
+
],
|
|
45
|
+
"features": [
|
|
46
|
+
"dark-mode",
|
|
47
|
+
"tailwind-v4",
|
|
48
|
+
"spartan-ng",
|
|
49
|
+
"oklch"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "chroma-clinic",
|
|
54
|
+
"title": "Chroma Clinic",
|
|
55
|
+
"description": "Professional blue theme with Open Sans",
|
|
56
|
+
"file": "chroma-clinic.css",
|
|
57
|
+
"path": "templates/ui/themes/chroma-clinic.css",
|
|
58
|
+
"defaultOutput": "src/themes/chroma-clinic.css",
|
|
59
|
+
"tags": [
|
|
60
|
+
"medical",
|
|
61
|
+
"professional",
|
|
62
|
+
"blue",
|
|
63
|
+
"healthcare"
|
|
64
|
+
],
|
|
65
|
+
"features": [
|
|
66
|
+
"dark-mode",
|
|
67
|
+
"tailwind-v4",
|
|
68
|
+
"spartan-ng",
|
|
69
|
+
"oklch"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
32
72
|
{
|
|
33
73
|
"name": "claude",
|
|
34
74
|
"title": "Claude",
|
|
@@ -72,15 +112,15 @@ const RESOURCES = {
|
|
|
72
112
|
{
|
|
73
113
|
"name": "grg-theme",
|
|
74
114
|
"title": "Grg Theme",
|
|
75
|
-
"description": "Default theme with
|
|
115
|
+
"description": "Default theme with blue accents",
|
|
76
116
|
"file": "grg-theme.css",
|
|
77
117
|
"path": "templates/ui/themes/grg-theme.css",
|
|
78
118
|
"defaultOutput": "src/themes/grg-theme.css",
|
|
79
119
|
"tags": [
|
|
80
120
|
"default",
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
121
|
+
"blue",
|
|
122
|
+
"minimal",
|
|
123
|
+
"professional"
|
|
84
124
|
],
|
|
85
125
|
"features": [
|
|
86
126
|
"dark-mode",
|
|
@@ -90,16 +130,17 @@ const RESOURCES = {
|
|
|
90
130
|
]
|
|
91
131
|
},
|
|
92
132
|
{
|
|
93
|
-
"name": "
|
|
94
|
-
"title": "
|
|
95
|
-
"description": "
|
|
96
|
-
"file": "
|
|
97
|
-
"path": "templates/ui/themes/
|
|
98
|
-
"defaultOutput": "src/themes/
|
|
133
|
+
"name": "helix-purple",
|
|
134
|
+
"title": "Helix Purple",
|
|
135
|
+
"description": "DNA-inspired purple for genomics",
|
|
136
|
+
"file": "helix-purple.css",
|
|
137
|
+
"path": "templates/ui/themes/helix-purple.css",
|
|
138
|
+
"defaultOutput": "src/themes/helix-purple.css",
|
|
99
139
|
"tags": [
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
140
|
+
"medical",
|
|
141
|
+
"purple",
|
|
142
|
+
"genomics",
|
|
143
|
+
"biotech"
|
|
103
144
|
],
|
|
104
145
|
"features": [
|
|
105
146
|
"dark-mode",
|
|
@@ -127,6 +168,26 @@ const RESOURCES = {
|
|
|
127
168
|
"spartan-ng",
|
|
128
169
|
"oklch"
|
|
129
170
|
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "pharma-teal",
|
|
174
|
+
"title": "Pharma Teal",
|
|
175
|
+
"description": "Calming teal for pharmaceutical applications",
|
|
176
|
+
"file": "pharma-teal.css",
|
|
177
|
+
"path": "templates/ui/themes/pharma-teal.css",
|
|
178
|
+
"defaultOutput": "src/themes/pharma-teal.css",
|
|
179
|
+
"tags": [
|
|
180
|
+
"medical",
|
|
181
|
+
"teal",
|
|
182
|
+
"pharmaceutical",
|
|
183
|
+
"healthcare"
|
|
184
|
+
],
|
|
185
|
+
"features": [
|
|
186
|
+
"dark-mode",
|
|
187
|
+
"tailwind-v4",
|
|
188
|
+
"spartan-ng",
|
|
189
|
+
"oklch"
|
|
190
|
+
]
|
|
130
191
|
}
|
|
131
192
|
],
|
|
132
193
|
"components": [
|
|
@@ -165,6 +226,26 @@ const RESOURCES = {
|
|
|
165
226
|
"@spartan-ng/helm/button",
|
|
166
227
|
"@spartan-ng/helm/card",
|
|
167
228
|
"@spartan-ng/helm/form-field"
|
|
229
|
+
],
|
|
230
|
+
"files": [
|
|
231
|
+
{
|
|
232
|
+
"id": "forgot-password",
|
|
233
|
+
"file": "forgot-password.component.ts",
|
|
234
|
+
"title": "Forgot Password",
|
|
235
|
+
"description": "Forgot Password"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"id": "login",
|
|
239
|
+
"file": "login.component.ts",
|
|
240
|
+
"title": "Login",
|
|
241
|
+
"description": "Login"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "register",
|
|
245
|
+
"file": "register.component.ts",
|
|
246
|
+
"title": "Register",
|
|
247
|
+
"description": "Register"
|
|
248
|
+
}
|
|
168
249
|
]
|
|
169
250
|
},
|
|
170
251
|
{
|
|
@@ -185,6 +266,32 @@ const RESOURCES = {
|
|
|
185
266
|
"@spartan-ng/helm/card",
|
|
186
267
|
"@spartan-ng/helm/form-field",
|
|
187
268
|
"@spartan-ng/helm/switch"
|
|
269
|
+
],
|
|
270
|
+
"files": [
|
|
271
|
+
{
|
|
272
|
+
"id": "danger-zone",
|
|
273
|
+
"file": "danger-zone.component.ts",
|
|
274
|
+
"title": "Danger Zone",
|
|
275
|
+
"description": "Danger Zone"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"id": "notification",
|
|
279
|
+
"file": "notification-settings.component.ts",
|
|
280
|
+
"title": "Notification Settings",
|
|
281
|
+
"description": "Notification Settings"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"id": "profile",
|
|
285
|
+
"file": "profile-settings.component.ts",
|
|
286
|
+
"title": "Profile Settings",
|
|
287
|
+
"description": "Profile Settings"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"id": "security",
|
|
291
|
+
"file": "security-settings.component.ts",
|
|
292
|
+
"title": "Security Settings",
|
|
293
|
+
"description": "Security Settings"
|
|
294
|
+
}
|
|
188
295
|
]
|
|
189
296
|
},
|
|
190
297
|
{
|
|
@@ -207,6 +314,44 @@ const RESOURCES = {
|
|
|
207
314
|
"@spartan-ng/helm/button",
|
|
208
315
|
"@spartan-ng/helm/icon",
|
|
209
316
|
"@spartan-ng/helm/dropdown-menu"
|
|
317
|
+
],
|
|
318
|
+
"files": [
|
|
319
|
+
{
|
|
320
|
+
"id": "collapsible-footer",
|
|
321
|
+
"file": "collapsible-shell-footer.component.ts",
|
|
322
|
+
"title": "Collapsible Shell Footer",
|
|
323
|
+
"description": "Collapsible Shell Footer"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"id": "collapsible",
|
|
327
|
+
"file": "collapsible-shell.component.ts",
|
|
328
|
+
"title": "Collapsible Shell",
|
|
329
|
+
"description": "Collapsible Shell"
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"id": "sidebar-footer",
|
|
333
|
+
"file": "sidebar-shell-footer.component.ts",
|
|
334
|
+
"title": "Sidebar Shell Footer",
|
|
335
|
+
"description": "Sidebar Shell Footer"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"id": "sidebar",
|
|
339
|
+
"file": "sidebar-shell.component.ts",
|
|
340
|
+
"title": "Sidebar Shell",
|
|
341
|
+
"description": "Sidebar Shell"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"id": "topnav-footer",
|
|
345
|
+
"file": "topnav-shell-footer.component.ts",
|
|
346
|
+
"title": "Topnav Shell Footer",
|
|
347
|
+
"description": "Topnav Shell Footer"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"id": "topnav",
|
|
351
|
+
"file": "topnav-shell.component.ts",
|
|
352
|
+
"title": "Topnav Shell",
|
|
353
|
+
"description": "Topnav Shell"
|
|
354
|
+
}
|
|
210
355
|
]
|
|
211
356
|
}
|
|
212
357
|
]
|
package/package.json
CHANGED
|
@@ -156,7 +156,7 @@ function scanBlockFiles(blockDir, blockName) {
|
|
|
156
156
|
.sort((a, b) => a.file.localeCompare(b.file));
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
function generateBlocks(
|
|
159
|
+
function generateBlocks() {
|
|
160
160
|
const blocksDir = path.join(TEMPLATES_DIR, 'ui/blocks');
|
|
161
161
|
const dirs = scanDirectory(blocksDir);
|
|
162
162
|
|
|
@@ -166,22 +166,16 @@ function generateBlocks(includeFiles = false) {
|
|
|
166
166
|
const blockDir = path.join(blocksDir, dir.name);
|
|
167
167
|
const metadata = readMeta(blockDir) || defaultBlockMeta(dir.name);
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
return {
|
|
170
170
|
name: dir.name,
|
|
171
171
|
title: dir.name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
|
|
172
172
|
description: metadata.description,
|
|
173
173
|
path: `templates/ui/blocks/${dir.name}`,
|
|
174
174
|
defaultOutput: `src/app/blocks/${dir.name}`,
|
|
175
175
|
tags: metadata.tags || [],
|
|
176
|
-
dependencies: metadata.dependencies || []
|
|
176
|
+
dependencies: metadata.dependencies || [],
|
|
177
|
+
files: scanBlockFiles(blockDir, dir.name) // Always include files
|
|
177
178
|
};
|
|
178
|
-
|
|
179
|
-
// Include file-level details for catalog
|
|
180
|
-
if (includeFiles) {
|
|
181
|
-
block.files = scanBlockFiles(blockDir, dir.name);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return block;
|
|
185
179
|
});
|
|
186
180
|
}
|
|
187
181
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"timestamp":1765262345803,"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"}],"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"}]}}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic catalog fetcher with caching
|
|
3
|
-
* Fetches catalog.json from GitHub with fallback to static resources
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const https = require('https');
|
|
9
|
-
|
|
10
|
-
const REPO = 'Genesis-Research/grg-kit';
|
|
11
|
-
const CATALOG_URL = `https://raw.githubusercontent.com/${REPO}/main/templates/catalog.json`;
|
|
12
|
-
const CACHE_FILE = path.join(__dirname, '.catalog-cache.json');
|
|
13
|
-
const CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes
|
|
14
|
-
|
|
15
|
-
// In-memory cache for current session
|
|
16
|
-
let memoryCache = null;
|
|
17
|
-
let memoryCacheTime = 0;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Fetch JSON from URL
|
|
21
|
-
*/
|
|
22
|
-
function fetchJson(url) {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
https.get(url, (res) => {
|
|
25
|
-
if (res.statusCode !== 200) {
|
|
26
|
-
reject(new Error(`HTTP ${res.statusCode}`));
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let data = '';
|
|
31
|
-
res.on('data', chunk => data += chunk);
|
|
32
|
-
res.on('end', () => {
|
|
33
|
-
try {
|
|
34
|
-
resolve(JSON.parse(data));
|
|
35
|
-
} catch (e) {
|
|
36
|
-
reject(new Error('Invalid JSON'));
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}).on('error', reject);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Read file cache
|
|
45
|
-
*/
|
|
46
|
-
function readFileCache() {
|
|
47
|
-
try {
|
|
48
|
-
if (fs.existsSync(CACHE_FILE)) {
|
|
49
|
-
const cached = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));
|
|
50
|
-
if (Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
51
|
-
return cached.data;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch (e) {
|
|
55
|
-
// Cache read failed, ignore
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Write file cache
|
|
62
|
-
*/
|
|
63
|
-
function writeFileCache(data) {
|
|
64
|
-
try {
|
|
65
|
-
fs.writeFileSync(CACHE_FILE, JSON.stringify({
|
|
66
|
-
timestamp: Date.now(),
|
|
67
|
-
data
|
|
68
|
-
}), 'utf-8');
|
|
69
|
-
} catch (e) {
|
|
70
|
-
// Cache write failed, ignore
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Get static fallback resources
|
|
76
|
-
*/
|
|
77
|
-
function getStaticFallback() {
|
|
78
|
-
try {
|
|
79
|
-
const { RESOURCES } = require('./resources');
|
|
80
|
-
return RESOURCES;
|
|
81
|
-
} catch (e) {
|
|
82
|
-
return { themes: [], components: [], blocks: [] };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Fetch catalog with caching
|
|
88
|
-
* Priority: memory cache -> file cache -> network -> static fallback
|
|
89
|
-
*/
|
|
90
|
-
async function fetchCatalog(options = {}) {
|
|
91
|
-
const { forceRefresh = false, silent = false } = options;
|
|
92
|
-
|
|
93
|
-
// Check memory cache first (fastest)
|
|
94
|
-
if (!forceRefresh && memoryCache && (Date.now() - memoryCacheTime < CACHE_TTL_MS)) {
|
|
95
|
-
return memoryCache;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Check file cache
|
|
99
|
-
if (!forceRefresh) {
|
|
100
|
-
const fileCached = readFileCache();
|
|
101
|
-
if (fileCached) {
|
|
102
|
-
memoryCache = fileCached;
|
|
103
|
-
memoryCacheTime = Date.now();
|
|
104
|
-
return fileCached;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Fetch from network
|
|
109
|
-
try {
|
|
110
|
-
const catalog = await fetchJson(CATALOG_URL);
|
|
111
|
-
|
|
112
|
-
// Transform to match expected format
|
|
113
|
-
const resources = {
|
|
114
|
-
themes: catalog.themes.map(t => ({
|
|
115
|
-
...t,
|
|
116
|
-
path: `templates/ui/themes/${t.file}`,
|
|
117
|
-
defaultOutput: `src/themes/${t.file}`
|
|
118
|
-
})),
|
|
119
|
-
components: catalog.components.map(c => ({
|
|
120
|
-
...c,
|
|
121
|
-
path: `templates/ui/components/${c.name}`,
|
|
122
|
-
defaultOutput: `src/app/components/${c.name}`
|
|
123
|
-
})),
|
|
124
|
-
blocks: catalog.blocks.map(b => ({
|
|
125
|
-
...b,
|
|
126
|
-
path: `templates/ui/blocks/${b.name}`,
|
|
127
|
-
defaultOutput: `src/app/blocks/${b.name}`,
|
|
128
|
-
files: b.files || []
|
|
129
|
-
}))
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// Update caches
|
|
133
|
-
memoryCache = resources;
|
|
134
|
-
memoryCacheTime = Date.now();
|
|
135
|
-
writeFileCache(resources);
|
|
136
|
-
|
|
137
|
-
return resources;
|
|
138
|
-
} catch (error) {
|
|
139
|
-
if (!silent) {
|
|
140
|
-
console.warn(`Warning: Could not fetch catalog (${error.message}), using cached/static resources`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Try file cache even if expired
|
|
144
|
-
try {
|
|
145
|
-
if (fs.existsSync(CACHE_FILE)) {
|
|
146
|
-
const cached = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));
|
|
147
|
-
return cached.data;
|
|
148
|
-
}
|
|
149
|
-
} catch (e) {
|
|
150
|
-
// Ignore
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Final fallback to static resources
|
|
154
|
-
return getStaticFallback();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Get resources synchronously (uses cache or static fallback)
|
|
160
|
-
*/
|
|
161
|
-
function getResourcesSync() {
|
|
162
|
-
// Check memory cache
|
|
163
|
-
if (memoryCache && (Date.now() - memoryCacheTime < CACHE_TTL_MS)) {
|
|
164
|
-
return memoryCache;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Check file cache
|
|
168
|
-
const fileCached = readFileCache();
|
|
169
|
-
if (fileCached) {
|
|
170
|
-
memoryCache = fileCached;
|
|
171
|
-
memoryCacheTime = Date.now();
|
|
172
|
-
return fileCached;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Static fallback
|
|
176
|
-
return getStaticFallback();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Clear all caches
|
|
181
|
-
*/
|
|
182
|
-
function clearCache() {
|
|
183
|
-
memoryCache = null;
|
|
184
|
-
memoryCacheTime = 0;
|
|
185
|
-
try {
|
|
186
|
-
if (fs.existsSync(CACHE_FILE)) {
|
|
187
|
-
fs.unlinkSync(CACHE_FILE);
|
|
188
|
-
}
|
|
189
|
-
} catch (e) {
|
|
190
|
-
// Ignore
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
module.exports = {
|
|
195
|
-
fetchCatalog,
|
|
196
|
-
getResourcesSync,
|
|
197
|
-
clearCache,
|
|
198
|
-
REPO
|
|
199
|
-
};
|