@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.
@@ -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
@@ -0,0 +1,5 @@
1
+ {
2
+ "plugins": {
3
+ "@tailwindcss/postcss": {}
4
+ }
5
+ }
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
+ [![npm version](https://img.shields.io/npm/v/@ng-cn/core.svg)](https://www.npmjs.com/package/@ng-cn/core)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Angular](https://img.shields.io/badge/Angular-21%2B-red.svg)](https://angular.io)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org)
9
+ [![Tailwind CSS](https://img.shields.io/badge/Tailwind-4.x-06B6D4.svg)](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,8 @@
1
+ import { Rule } from '@angular-devkit/schematics';
2
+ interface ComponentOptions {
3
+ name: string;
4
+ project?: string;
5
+ path?: string;
6
+ }
7
+ export declare function component(options: ComponentOptions): Rule;
8
+ export {};
@@ -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,7 @@
1
+ import { Rule } from '@angular-devkit/schematics';
2
+ interface NgAddOptions {
3
+ project?: string;
4
+ skipInstall?: boolean;
5
+ }
6
+ export declare function ngAdd(options: NgAddOptions): Rule;
7
+ export {};
@@ -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
+ }