@ng-cn/core 1.0.0
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/.cursor/rules/cursor.mdc +53 -0
- package/.editorconfig +17 -0
- package/.postcssrc.json +5 -0
- package/.prettierrc +27 -0
- package/README.md +199 -0
- package/angular.json +122 -0
- package/dist/schematics/component/index.d.ts +8 -0
- package/dist/schematics/component/index.js +109 -0
- package/dist/schematics/ng-add/index.d.ts +7 -0
- package/dist/schematics/ng-add/index.js +51 -0
- package/mcp.json +336 -0
- package/package.json +99 -0
- package/postcss.config.mjs +6 -0
- package/public/.!14865!favicon.ico +0 -0
- package/public/angular-shad-cn.png +0 -0
- package/public/favicon.ico +0 -0
- package/schematics/README.md +97 -0
- package/schematics/collection.json +16 -0
- package/schematics/component/index.d.ts +9 -0
- package/schematics/component/index.js +214 -0
- package/schematics/component/index.ts +238 -0
- package/schematics/component/schema.json +36 -0
- package/schematics/ng-add/index.d.ts +8 -0
- package/schematics/ng-add/index.js +310 -0
- package/schematics/ng-add/index.ts +334 -0
- package/schematics/ng-add/schema.json +25 -0
- package/schematics/tsconfig.json +20 -0
- package/tsconfig.app.json +17 -0
- package/tsconfig.json +45 -0
- package/tsconfig.spec.json +15 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
context: true
|
|
3
|
+
priority: high
|
|
4
|
+
scope: project
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.
|
|
8
|
+
|
|
9
|
+
## TypeScript Best Practices
|
|
10
|
+
|
|
11
|
+
- Use strict type checking
|
|
12
|
+
- Prefer type inference when the type is obvious
|
|
13
|
+
- Avoid the `any` type; use `unknown` when type is uncertain
|
|
14
|
+
|
|
15
|
+
## Angular Best Practices
|
|
16
|
+
|
|
17
|
+
- Always use standalone components over NgModules
|
|
18
|
+
- Must NOT set `standalone: true` inside Angular decorators. It's the default.
|
|
19
|
+
- Use signals for state management
|
|
20
|
+
- Implement lazy loading for feature routes
|
|
21
|
+
- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead
|
|
22
|
+
- Use `NgOptimizedImage` for all static images.
|
|
23
|
+
- `NgOptimizedImage` does not work for inline base64 images.
|
|
24
|
+
|
|
25
|
+
## Components
|
|
26
|
+
|
|
27
|
+
- Keep components small and focused on a single responsibility
|
|
28
|
+
- Use `input()` and `output()` functions instead of decorators
|
|
29
|
+
- Use `computed()` for derived state
|
|
30
|
+
- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator
|
|
31
|
+
- Prefer inline templates for small components
|
|
32
|
+
- Prefer Reactive forms instead of Template-driven ones
|
|
33
|
+
- Do NOT use `ngClass`, use `class` bindings instead
|
|
34
|
+
- Do NOT use `ngStyle`, use `style` bindings instead
|
|
35
|
+
|
|
36
|
+
## State Management
|
|
37
|
+
|
|
38
|
+
- Use signals for local component state
|
|
39
|
+
- Use `computed()` for derived state
|
|
40
|
+
- Keep state transformations pure and predictable
|
|
41
|
+
- Do NOT use `mutate` on signals, use `update` or `set` instead
|
|
42
|
+
|
|
43
|
+
## Templates
|
|
44
|
+
|
|
45
|
+
- Keep templates simple and avoid complex logic
|
|
46
|
+
- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`
|
|
47
|
+
- Use the async pipe to handle observables
|
|
48
|
+
|
|
49
|
+
## Services
|
|
50
|
+
|
|
51
|
+
- Design services around a single responsibility
|
|
52
|
+
- Use the `providedIn: 'root'` option for singleton services
|
|
53
|
+
- Use the `inject()` function instead of constructor injection
|
package/.editorconfig
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Editor configuration, see https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
indent_style = space
|
|
7
|
+
indent_size = 2
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.ts]
|
|
12
|
+
quote_type = single
|
|
13
|
+
ij_typescript_use_double_quotes = false
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
max_line_length = off
|
|
17
|
+
trim_trailing_whitespace = false
|
package/.postcssrc.json
ADDED
package/.prettierrc
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"printWidth": 100,
|
|
3
|
+
"tabWidth": 2,
|
|
4
|
+
"useTabs": false,
|
|
5
|
+
"semi": true,
|
|
6
|
+
"singleQuote": true,
|
|
7
|
+
"trailingComma": "all",
|
|
8
|
+
"bracketSpacing": true,
|
|
9
|
+
"arrowParens": "always",
|
|
10
|
+
"endOfLine": "lf",
|
|
11
|
+
"htmlWhitespaceSensitivity": "ignore",
|
|
12
|
+
"bracketSameLine": false,
|
|
13
|
+
"overrides": [
|
|
14
|
+
{
|
|
15
|
+
"files": "*.html",
|
|
16
|
+
"options": {
|
|
17
|
+
"parser": "angular"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"files": "*.component.html",
|
|
22
|
+
"options": {
|
|
23
|
+
"parser": "angular"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# 🎨 ng-cn
|
|
2
|
+
|
|
3
|
+
> **Beautiful Angular components built with Tailwind CSS v4** — The official Angular port of [shadcn/ui](https://ui.shadcn.com/)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@ng-cn/core)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://angular.io)
|
|
8
|
+
[](https://www.typescriptlang.org)
|
|
9
|
+
[](https://tailwindcss.com)
|
|
10
|
+
|
|
11
|
+
**[🌐 Live Demo](https://shadcn-angular.tigayon.com/)** • **[📚 Documentation](https://shadcn-angular.tigayon.com/docs)** • **[🐛 Report Bug](https://github.com/Tigayon-Innovations/angular-shadcn/issues)**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✨ Why ng-cn?
|
|
16
|
+
|
|
17
|
+
- **🎨 60+ Components** - Production-ready, accessible UI components
|
|
18
|
+
- **⚡ Angular 21+** - Signals, standalone components, modern control flow
|
|
19
|
+
- **📦 Zero Config** - One command sets up everything
|
|
20
|
+
- **🧩 Own Your Code** - Components live in your project, customize freely
|
|
21
|
+
- **🌙 Dark Mode** - Built-in theme support
|
|
22
|
+
- **♿ Accessible** - WCAG 2.1 AA compliant
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 🚀 Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Initialize
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ng add @ng-cn/core
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This automatically:
|
|
35
|
+
- ✅ Installs dependencies (Tailwind, clsx, tailwind-merge, CDK)
|
|
36
|
+
- ✅ Creates `ng-cn.scss` with theme CSS variables
|
|
37
|
+
- ✅ Sets up `lib/utils/cn.ts` utility function
|
|
38
|
+
- ✅ Configures TypeScript path aliases (`@/ui/*`, `@/utils/*`)
|
|
39
|
+
- ✅ Creates the component folder structure
|
|
40
|
+
|
|
41
|
+
### 2. Add Components
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Add components to your project
|
|
45
|
+
ng g @ng-cn/core:c button
|
|
46
|
+
ng g @ng-cn/core:c card
|
|
47
|
+
ng g @ng-cn/core:c dialog
|
|
48
|
+
|
|
49
|
+
# Or use the short alias
|
|
50
|
+
ng g @ng-cn/core:c accordion
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Use
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { Component } from '@angular/core';
|
|
57
|
+
import { Button } from '@/ui/button';
|
|
58
|
+
import { Card, CardHeader, CardTitle, CardContent } from '@/ui/card';
|
|
59
|
+
|
|
60
|
+
@Component({
|
|
61
|
+
selector: 'app-example',
|
|
62
|
+
imports: [Button, Card, CardHeader, CardTitle, CardContent],
|
|
63
|
+
template: \`
|
|
64
|
+
<Card>
|
|
65
|
+
<CardHeader>
|
|
66
|
+
<CardTitle>Welcome</CardTitle>
|
|
67
|
+
</CardHeader>
|
|
68
|
+
<CardContent>
|
|
69
|
+
<Button>Get Started</Button>
|
|
70
|
+
<Button variant="outline">Learn More</Button>
|
|
71
|
+
</CardContent>
|
|
72
|
+
</Card>
|
|
73
|
+
\`,
|
|
74
|
+
})
|
|
75
|
+
export class ExampleComponent {}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 📦 Available Components
|
|
81
|
+
|
|
82
|
+
### Form
|
|
83
|
+
\`button\` \`input\` \`textarea\` \`select\` \`checkbox\` \`radio-group\` \`switch\` \`slider\` \`label\` \`toggle\`
|
|
84
|
+
|
|
85
|
+
### Layout
|
|
86
|
+
\`card\` \`separator\` \`collapsible\` \`accordion\` \`tabs\` \`table\`
|
|
87
|
+
|
|
88
|
+
### Feedback
|
|
89
|
+
\`alert\` \`badge\` \`progress\` \`skeleton\` \`toast\` \`tooltip\`
|
|
90
|
+
|
|
91
|
+
### Overlay
|
|
92
|
+
\`dialog\` \`alert-dialog\` \`sheet\` \`drawer\` \`popover\` \`dropdown-menu\`
|
|
93
|
+
|
|
94
|
+
### Data Display
|
|
95
|
+
\`avatar\` \`calendar\` \`data-table\` \`breadcrumb\`
|
|
96
|
+
|
|
97
|
+
[See all 60+ components →](https://shadcn-angular.tigayon.com/components)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 🎨 Theming
|
|
102
|
+
|
|
103
|
+
The \`ng-cn.scss\` file contains all CSS variables for easy customization:
|
|
104
|
+
|
|
105
|
+
```scss
|
|
106
|
+
:root {
|
|
107
|
+
--primary: oklch(0.205 0 0);
|
|
108
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
109
|
+
--secondary: oklch(0.97 0 0);
|
|
110
|
+
--accent: oklch(0.97 0 0);
|
|
111
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
112
|
+
--radius: 0.625rem;
|
|
113
|
+
/* ... more variables */
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.dark {
|
|
117
|
+
--primary: oklch(0.985 0 0);
|
|
118
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
119
|
+
/* ... dark mode overrides */
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
[📖 Theming Guide →](https://shadcn-angular.tigayon.com/docs/theming)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 📁 Project Structure
|
|
128
|
+
|
|
129
|
+
After running \`ng add @ng-cn/core\`, your project will have:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
src/
|
|
133
|
+
├── ng-cn.scss # Theme CSS variables (auto-imported)
|
|
134
|
+
├── app/
|
|
135
|
+
│ └── lib/
|
|
136
|
+
│ ├── utils/
|
|
137
|
+
│ │ ├── cn.ts # Utility for merging classes
|
|
138
|
+
│ │ └── index.ts
|
|
139
|
+
│ └── components/
|
|
140
|
+
│ └── ui/ # Your components live here
|
|
141
|
+
│ ├── button/
|
|
142
|
+
│ ├── card/
|
|
143
|
+
│ └── ...
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🔧 Manual Installation
|
|
149
|
+
|
|
150
|
+
If you prefer manual setup:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# 1. Install dependencies
|
|
154
|
+
npm i @ng-cn/core clsx tailwind-merge class-variance-authority @angular/cdk lucide-angular
|
|
155
|
+
|
|
156
|
+
# 2. Add Tailwind
|
|
157
|
+
ng add tailwindcss
|
|
158
|
+
|
|
159
|
+
# 3. Copy the CSS variables from docs to your styles.scss
|
|
160
|
+
|
|
161
|
+
# 4. Create the cn utility in src/app/lib/utils/cn.ts
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 🤖 AI Integration (MCP)
|
|
167
|
+
|
|
168
|
+
ng-cn includes an MCP server for AI assistant integration:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npm run build:mcp
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
[🤖 MCP Setup Guide →](docs/MCP-SETUP.md)
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 📖 Documentation
|
|
179
|
+
|
|
180
|
+
- [Installation](https://shadcn-angular.tigayon.com/docs/installation)
|
|
181
|
+
- [Theming](https://shadcn-angular.tigayon.com/docs/theming)
|
|
182
|
+
- [Dark Mode](https://shadcn-angular.tigayon.com/docs/dark-mode)
|
|
183
|
+
- [Components](https://shadcn-angular.tigayon.com/components)
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 📄 License
|
|
188
|
+
|
|
189
|
+
MIT License - see [LICENSE](LICENSE)
|
|
190
|
+
|
|
191
|
+
Inspired by [shadcn/ui](https://github.com/shadcn-ui/ui)
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
<div align="center">
|
|
196
|
+
|
|
197
|
+
Made with ❤️ by [Tigayon Innovations](https://tigayon.com)
|
|
198
|
+
|
|
199
|
+
</div>
|
package/angular.json
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"shadcn-angular": {
|
|
7
|
+
"projectType": "application",
|
|
8
|
+
"schematics": {
|
|
9
|
+
"@schematics/angular:component": {
|
|
10
|
+
"prefix": "",
|
|
11
|
+
"style": "none",
|
|
12
|
+
"changeDetection": "OnPush",
|
|
13
|
+
"standalone": true,
|
|
14
|
+
"skipTests": true
|
|
15
|
+
},
|
|
16
|
+
"@schematics/angular:directive": {
|
|
17
|
+
"prefix": "",
|
|
18
|
+
"type": "directive"
|
|
19
|
+
},
|
|
20
|
+
"@schematics/angular:service": {
|
|
21
|
+
"type": "service"
|
|
22
|
+
},
|
|
23
|
+
"@schematics/angular:guard": {
|
|
24
|
+
"typeSeparator": "."
|
|
25
|
+
},
|
|
26
|
+
"@schematics/angular:interceptor": {
|
|
27
|
+
"typeSeparator": "."
|
|
28
|
+
},
|
|
29
|
+
"@schematics/angular:module": {
|
|
30
|
+
"typeSeparator": "."
|
|
31
|
+
},
|
|
32
|
+
"@schematics/angular:pipe": {
|
|
33
|
+
"typeSeparator": "."
|
|
34
|
+
},
|
|
35
|
+
"@schematics/angular:resolver": {
|
|
36
|
+
"typeSeparator": "."
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"root": "",
|
|
40
|
+
"sourceRoot": "src",
|
|
41
|
+
"prefix": "",
|
|
42
|
+
"architect": {
|
|
43
|
+
"build": {
|
|
44
|
+
"builder": "@angular/build:application",
|
|
45
|
+
"options": {
|
|
46
|
+
"browser": "src/main.ts",
|
|
47
|
+
"tsConfig": "tsconfig.app.json",
|
|
48
|
+
"inlineStyleLanguage": "scss",
|
|
49
|
+
"assets": [
|
|
50
|
+
{
|
|
51
|
+
"glob": "**/*",
|
|
52
|
+
"input": "public"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"styles": [
|
|
56
|
+
"src/styles.scss"
|
|
57
|
+
],
|
|
58
|
+
"server": "src/main.server.ts",
|
|
59
|
+
"outputMode": "server",
|
|
60
|
+
"ssr": {
|
|
61
|
+
"entry": "src/server.ts"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"configurations": {
|
|
65
|
+
"production": {
|
|
66
|
+
"budgets": [
|
|
67
|
+
{
|
|
68
|
+
"type": "initial",
|
|
69
|
+
"maximumWarning": "500kB",
|
|
70
|
+
"maximumError": "1MB"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "anyComponentStyle",
|
|
74
|
+
"maximumWarning": "4kB",
|
|
75
|
+
"maximumError": "8kB"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"outputHashing": "all"
|
|
79
|
+
},
|
|
80
|
+
"development": {
|
|
81
|
+
"optimization": false,
|
|
82
|
+
"extractLicenses": false,
|
|
83
|
+
"sourceMap": true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"defaultConfiguration": "production"
|
|
87
|
+
},
|
|
88
|
+
"serve": {
|
|
89
|
+
"builder": "@angular/build:dev-server",
|
|
90
|
+
"configurations": {
|
|
91
|
+
"production": {
|
|
92
|
+
"buildTarget": "shadcn-angular:build:production"
|
|
93
|
+
},
|
|
94
|
+
"development": {
|
|
95
|
+
"buildTarget": "shadcn-angular:build:development"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"defaultConfiguration": "development"
|
|
99
|
+
},
|
|
100
|
+
"extract-i18n": {
|
|
101
|
+
"builder": "@angular/build:extract-i18n"
|
|
102
|
+
},
|
|
103
|
+
"test": {
|
|
104
|
+
"builder": "@angular/build:karma",
|
|
105
|
+
"options": {
|
|
106
|
+
"tsConfig": "tsconfig.spec.json",
|
|
107
|
+
"inlineStyleLanguage": "scss",
|
|
108
|
+
"assets": [
|
|
109
|
+
{
|
|
110
|
+
"glob": "**/*",
|
|
111
|
+
"input": "public"
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"styles": [
|
|
115
|
+
"src/styles.scss"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.component = component;
|
|
4
|
+
const core_1 = require("@angular-devkit/core");
|
|
5
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
6
|
+
// Component registry - maps component names to their file structure
|
|
7
|
+
const COMPONENT_REGISTRY = {
|
|
8
|
+
button: {
|
|
9
|
+
files: ['button.component.ts', 'index.ts'],
|
|
10
|
+
dependencies: ['class-variance-authority', 'clsx', 'tailwind-merge', '@angular/cdk']
|
|
11
|
+
},
|
|
12
|
+
card: {
|
|
13
|
+
files: ['card.component.ts', 'card-header.component.ts', 'card-title.component.ts', 'card-description.component.ts', 'card-content.component.ts', 'card-footer.component.ts', 'index.ts'],
|
|
14
|
+
dependencies: ['clsx', 'tailwind-merge']
|
|
15
|
+
},
|
|
16
|
+
input: {
|
|
17
|
+
files: ['input.component.ts', 'index.ts'],
|
|
18
|
+
dependencies: ['clsx', 'tailwind-merge', '@angular/forms']
|
|
19
|
+
},
|
|
20
|
+
label: {
|
|
21
|
+
files: ['label.component.ts', 'index.ts'],
|
|
22
|
+
dependencies: ['class-variance-authority', 'clsx', 'tailwind-merge']
|
|
23
|
+
},
|
|
24
|
+
separator: {
|
|
25
|
+
files: ['separator.component.ts', 'index.ts'],
|
|
26
|
+
dependencies: ['clsx', 'tailwind-merge']
|
|
27
|
+
},
|
|
28
|
+
badge: {
|
|
29
|
+
files: ['badge.component.ts', 'index.ts'],
|
|
30
|
+
dependencies: ['class-variance-authority', 'clsx', 'tailwind-merge']
|
|
31
|
+
},
|
|
32
|
+
alert: {
|
|
33
|
+
files: ['alert.component.ts', 'alert-title.component.ts', 'alert-description.component.ts', 'index.ts'],
|
|
34
|
+
dependencies: ['class-variance-authority', 'clsx', 'tailwind-merge']
|
|
35
|
+
},
|
|
36
|
+
dialog: {
|
|
37
|
+
files: ['dialog.component.ts', 'dialog-content.component.ts', 'dialog-header.component.ts', 'dialog-footer.component.ts', 'dialog-title.component.ts', 'dialog-description.component.ts', 'index.ts'],
|
|
38
|
+
dependencies: ['@angular/cdk', 'clsx', 'tailwind-merge']
|
|
39
|
+
},
|
|
40
|
+
'data-table': {
|
|
41
|
+
files: [
|
|
42
|
+
'data-table.component.ts',
|
|
43
|
+
'data-table-content.component.ts',
|
|
44
|
+
'data-table-context.ts',
|
|
45
|
+
'data-table-pagination.component.ts',
|
|
46
|
+
'data-table-search.component.ts',
|
|
47
|
+
'data-table-toolbar.component.ts',
|
|
48
|
+
'data-table-view-options.component.ts',
|
|
49
|
+
'index.ts'
|
|
50
|
+
],
|
|
51
|
+
dependencies: ['clsx', 'tailwind-merge', 'lucide-angular']
|
|
52
|
+
},
|
|
53
|
+
// Add more components as needed
|
|
54
|
+
};
|
|
55
|
+
function component(options) {
|
|
56
|
+
return (tree, context) => {
|
|
57
|
+
const componentName = options.name.toLowerCase();
|
|
58
|
+
if (!COMPONENT_REGISTRY[componentName]) {
|
|
59
|
+
const availableComponents = Object.keys(COMPONENT_REGISTRY).join(', ');
|
|
60
|
+
throw new schematics_1.SchematicsException(`Component "${componentName}" not found. Available components: ${availableComponents}`);
|
|
61
|
+
}
|
|
62
|
+
const componentInfo = COMPONENT_REGISTRY[componentName];
|
|
63
|
+
const basePath = options.path || 'src/app/lib/components/ui';
|
|
64
|
+
const componentPath = (0, core_1.normalize)((0, core_1.join)((0, core_1.normalize)(basePath), (0, core_1.normalize)(componentName)));
|
|
65
|
+
context.logger.info(`📦 Installing ${componentName} component...`);
|
|
66
|
+
// Check if component directory already exists
|
|
67
|
+
if (tree.exists(componentPath)) {
|
|
68
|
+
context.logger.warn(`⚠️ Component directory ${componentPath} already exists. Skipping...`);
|
|
69
|
+
return tree;
|
|
70
|
+
}
|
|
71
|
+
// Create component directory
|
|
72
|
+
tree.create((0, core_1.join)(componentPath, '.gitkeep'), '');
|
|
73
|
+
// Copy component files from the source
|
|
74
|
+
const sourceBasePath = `src/app/lib/components/ui/${componentName}`;
|
|
75
|
+
for (const file of componentInfo.files) {
|
|
76
|
+
const sourcePath = (0, core_1.join)((0, core_1.normalize)(sourceBasePath), (0, core_1.normalize)(file));
|
|
77
|
+
const targetPath = (0, core_1.join)(componentPath, (0, core_1.normalize)(file));
|
|
78
|
+
if (tree.exists(sourcePath)) {
|
|
79
|
+
const content = tree.read(sourcePath);
|
|
80
|
+
if (content) {
|
|
81
|
+
tree.create(targetPath, content);
|
|
82
|
+
context.logger.info(` ✅ Created ${file}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
context.logger.warn(` ⚠️ Source file ${sourcePath} not found`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Check dependencies
|
|
90
|
+
context.logger.info('');
|
|
91
|
+
context.logger.info('📚 Required dependencies:');
|
|
92
|
+
for (const dep of componentInfo.dependencies) {
|
|
93
|
+
context.logger.info(` - ${dep}`);
|
|
94
|
+
}
|
|
95
|
+
context.logger.info('');
|
|
96
|
+
context.logger.info(`✅ ${componentName} component installed successfully!`);
|
|
97
|
+
context.logger.info('');
|
|
98
|
+
context.logger.info('📖 Import the component:');
|
|
99
|
+
context.logger.info(` import { ${toPascalCase(componentName)} } from '@/ui/${componentName}';`);
|
|
100
|
+
context.logger.info('');
|
|
101
|
+
return tree;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function toPascalCase(str) {
|
|
105
|
+
return str
|
|
106
|
+
.split('-')
|
|
107
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
108
|
+
.join('');
|
|
109
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ngAdd = ngAdd;
|
|
4
|
+
const tasks_1 = require("@angular-devkit/schematics/tasks");
|
|
5
|
+
function ngAdd(options) {
|
|
6
|
+
return (tree, context) => {
|
|
7
|
+
context.logger.info('✨ Adding shadcn-angular to your project...');
|
|
8
|
+
// Add dependencies to package.json
|
|
9
|
+
const packageJsonPath = '/package.json';
|
|
10
|
+
if (tree.exists(packageJsonPath)) {
|
|
11
|
+
const packageJson = JSON.parse(tree.read(packageJsonPath).toString('utf-8'));
|
|
12
|
+
const requiredDependencies = {
|
|
13
|
+
'lucide-angular': '^0.562.0',
|
|
14
|
+
'class-variance-authority': '^0.7.1',
|
|
15
|
+
'clsx': '^2.1.1',
|
|
16
|
+
'tailwind-merge': '^3.4.0',
|
|
17
|
+
'@angular/cdk': '^21.0.5',
|
|
18
|
+
'tailwindcss': '^4.1.18',
|
|
19
|
+
'@tailwindcss/postcss': '^4.1.18'
|
|
20
|
+
};
|
|
21
|
+
// Check and add missing dependencies
|
|
22
|
+
let needsInstall = false;
|
|
23
|
+
for (const [pkg, version] of Object.entries(requiredDependencies)) {
|
|
24
|
+
if (!packageJson.dependencies?.[pkg]) {
|
|
25
|
+
packageJson.dependencies = packageJson.dependencies || {};
|
|
26
|
+
packageJson.dependencies[pkg] = version;
|
|
27
|
+
needsInstall = true;
|
|
28
|
+
context.logger.info(` 📦 Adding ${pkg}@${version}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (needsInstall) {
|
|
32
|
+
tree.overwrite(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
33
|
+
if (!options.skipInstall) {
|
|
34
|
+
context.addTask(new tasks_1.NodePackageInstallTask());
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
context.logger.info(' ✅ All dependencies already installed');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
context.logger.info('');
|
|
42
|
+
context.logger.info('✅ shadcn-angular setup complete!');
|
|
43
|
+
context.logger.info('');
|
|
44
|
+
context.logger.info('📚 Next steps:');
|
|
45
|
+
context.logger.info(' 1. Ensure Tailwind CSS is configured in your project');
|
|
46
|
+
context.logger.info(' 2. Add CSS variables to your styles.scss (see docs)');
|
|
47
|
+
context.logger.info(' 3. Install components: ng generate shadcn-angular:component button');
|
|
48
|
+
context.logger.info('');
|
|
49
|
+
return tree;
|
|
50
|
+
};
|
|
51
|
+
}
|