create-ng-tailwind 3.1.0 → 4.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +81 -350
  2. package/README.md +93 -157
  3. package/lib/cli/index.js +29 -3
  4. package/lib/cli/interactive.js +26 -1
  5. package/lib/managers/ProjectManager.js +0 -4
  6. package/lib/templates/base/components.js +243 -0
  7. package/lib/templates/base/index.js +207 -0
  8. package/lib/templates/base/infrastructure.js +314 -0
  9. package/lib/templates/base/linting.js +359 -0
  10. package/lib/templates/base/pwa.js +103 -0
  11. package/lib/templates/base/services.js +362 -0
  12. package/lib/templates/blog/app.js +250 -0
  13. package/lib/templates/blog/components.js +360 -0
  14. package/lib/templates/blog/i18n.js +77 -0
  15. package/lib/templates/blog/index.js +126 -0
  16. package/lib/templates/blog/pages.js +554 -0
  17. package/lib/templates/blog/services.js +390 -0
  18. package/lib/templates/dashboard/app.js +320 -0
  19. package/lib/templates/dashboard/charts.js +305 -0
  20. package/lib/templates/dashboard/components.js +410 -0
  21. package/lib/templates/dashboard/i18n.js +340 -0
  22. package/lib/templates/dashboard/index.js +141 -0
  23. package/lib/templates/dashboard/layout.js +310 -0
  24. package/lib/templates/dashboard/pages.js +681 -0
  25. package/lib/templates/ecommerce/app.js +315 -0
  26. package/lib/templates/ecommerce/components.js +496 -0
  27. package/lib/templates/ecommerce/i18n.js +389 -0
  28. package/lib/templates/ecommerce/index.js +152 -0
  29. package/lib/templates/ecommerce/layout.js +270 -0
  30. package/lib/templates/ecommerce/pages.js +969 -0
  31. package/lib/templates/ecommerce/services.js +300 -0
  32. package/lib/templates/index.js +12 -0
  33. package/lib/templates/landing/index.js +1117 -0
  34. package/lib/templates/portfolio/index.js +1160 -0
  35. package/lib/templates/saas/index.js +1371 -0
  36. package/lib/templates/starter/app.js +364 -0
  37. package/lib/templates/starter/i18n.js +856 -0
  38. package/lib/templates/starter/index.js +52 -4060
  39. package/lib/templates/starter/layout.js +852 -0
  40. package/lib/templates/starter/pages.js +1241 -0
  41. package/package.json +1 -1
  42. package/lib/templates/starter/features.js +0 -867
  43. package/lib/utils/ai-config.js +0 -641
  44. /package/lib/templates/{starter → base}/advanced-features.js +0 -0
  45. /package/lib/templates/{starter → base}/seo-assets.js +0 -0
  46. /package/lib/templates/{starter → base}/seo-features.js +0 -0
  47. /package/lib/templates/{starter → base}/ui-features.js +0 -0
package/README.md CHANGED
@@ -4,218 +4,154 @@
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/create-ng-tailwind.svg)](https://badge.fury.io/js/create-ng-tailwind)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
- [![Node.js Version](https://img.shields.io/node/v/create-ng-tailwind.svg)](https://nodejs.org/)
8
7
  [![Downloads](https://img.shields.io/npm/dm/create-ng-tailwind.svg)](https://www.npmjs.com/package/create-ng-tailwind)
9
8
 
10
- **🚀 A CLI tool to give starter template for angular project with tailwind css**
9
+ **Production-ready Angular + Tailwind CSS starter templates**
11
10
 
12
11
  </div>
13
12
 
14
13
  ---
15
14
 
16
- ## ✨ Features
17
-
18
- - 🎯 **Angular 20+** - Latest version with standalone components and signals
19
- - 🎨 **Tailwind CSS v4** - Utility-first CSS framework preconfigured
20
- - 🚀 **SEO Optimized** - Meta tags, Open Graph, Twitter Cards, structured data, robots.txt
21
- - 🌍 **i18n Translation** - English & Arabic with RTL support
22
- - 🎮 **Interactive UI** - Toast notifications, Modal dialogs, and components
23
- - 🏗️ **Zero Configuration** - Everything set up and ready to go
24
-
25
15
  ## Quick Start
26
16
 
27
- ### Using npx (Recommended)
28
-
29
- Run the following command and follow the prompts:
30
-
31
- ```bash
32
- npx create-ng-tailwind my-awesome-app
33
- ```
34
-
35
- ### Using npm
36
-
37
- Install globally and use:
38
-
39
17
  ```bash
40
- npm install -g create-ng-tailwind
41
- create-ng-tailwind my-awesome-app
18
+ npx create-ng-tailwind my-app
42
19
  ```
43
20
 
44
- ### What happens next?
45
-
46
- The CLI will guide you through:
47
- 1. Choosing a template (Minimal or Starter)
48
- 2. Configuring Server-Side Rendering (optional)
49
- 3. Setting up zoneless application (optional)
50
- 4. Selecting AI tools integration (optional)
51
-
52
- After setup completes:
21
+ Then follow the prompts to choose your template.
53
22
 
54
23
  ```bash
55
- cd my-awesome-app
24
+ cd my-app
56
25
  npm install
57
26
  ng serve
58
27
  ```
59
28
 
60
- Your app will be running at `http://localhost:4200` 🎉
61
-
62
- ## 🏗️ Project Structure
63
-
64
- ```
65
- my-app/
66
- ├── src/
67
- │ ├── app/
68
- │ │ ├── core/ # Core services and interceptors
69
- │ │ │ ├── services/ # Auth, API, SEO, Toast, Modal, etc.
70
- │ │ │ ├── interceptors/ # HTTP interceptors
71
- │ │ │ ├── guards/ # Route guards
72
- │ │ │ ├── i18n/ # Translation service
73
- │ │ │ └── utils/ # Structured data utilities
74
- │ │ ├── shared/ # Shared components and utilities
75
- │ │ │ ├── components/ # Button, Card, Toast, Modal
76
- │ │ │ ├── pipes/ # Truncate, TimeAgo
77
- │ │ │ ├── directives/ # ClickOutside, Tooltip
78
- │ │ │ └── models/ # TypeScript interfaces
79
- │ │ ├── features/ # Feature modules
80
- │ │ │ ├── home/ # Home page
81
- │ │ │ ├── about/ # About page
82
- │ │ │ ├── contact/ # Contact page
83
- │ │ │ └── auth/ # Authentication pages
84
- │ │ ├── layout/ # Layout components
85
- │ │ │ ├── header/ # Navigation header
86
- │ │ │ └── footer/ # Footer component
87
- │ │ ├── app.config.ts # App configuration
88
- │ │ ├── app.routes.ts # Routing configuration
89
- │ │ └── app.ts # Main app component
90
- │ ├── styles.css # Tailwind CSS imports
91
- │ └── main.ts # Bootstrap
92
- ├── public/
93
- │ ├── assets/
94
- │ │ ├── i18n/ # Translation files (en.json, ar.json)
95
- │ │ └── images/ # OG images, logos
96
- │ ├── robots.txt # SEO robots file
97
- │ ├── favicon.svg # Favicon
98
- │ └── android-chrome-*.svg # PWA icons
99
- ├── .postcssrc.json # PostCSS configuration
100
- ├── package.json
101
- └── ...
102
- ```
103
-
104
- ## 🎯 Starter Template Features
105
-
106
- The **Starter Template** includes 25+ production-ready features:
107
-
108
- ### Core Services
29
+ Your app runs at `http://localhost:4200`
109
30
 
110
- - **AuthService** - Authentication & user management
111
- - **ApiService** - Centralized HTTP request handling
112
- - **SeoService** - Comprehensive SEO management (meta tags, Open Graph, Twitter Cards, structured data)
113
- - **ToastService** - Notification system (success, error, warning, info)
114
- - **ModalService** - Dialog system with confirm & alert
115
- - **LoadingService** - Global loading state with signals
116
- - **CacheService** - Response caching with TTL
117
- - **StorageService** - LocalStorage wrapper with type safety
118
- - **i18nService** - Internationalization management
119
-
120
- ### SEO Optimization (Simple & Ready to Use)
31
+ ---
121
32
 
122
- - **SEO Service** - Just 2 methods: `updateMeta()` and `addStructuredData()`
123
- - **Meta Tags** - Title, description, keywords (auto-configured on all pages)
124
- - **Social Sharing** - Open Graph & Twitter Cards (pre-configured)
125
- - **Structured Data** - Organization & WebSite schemas (included)
126
- - **Canonical URLs** - Auto-updated on route changes
127
- - **Assets** - robots.txt, favicon set, OG image placeholder
128
- - **Extensible** - Easy to add more schemas as needed
33
+ ## Templates
129
34
 
130
- ### UI Components
35
+ ### Starter (Recommended)
131
36
 
132
- - **ButtonComponent** - Variants: primary, secondary, danger
133
- - **CardComponent** - Flexible container with title & shadow
134
- - **LoadingSpinnerComponent** - Animated loading indicator
135
- - **ToastComponent** - Auto-dismiss notifications
136
- - **ModalComponent** - Accessible dialog with sizes
37
+ Professional foundation with everything you need:
137
38
 
138
- ### Utilities
39
+ - Header, Footer, Auth pages (Login, Register, Forgot Password)
40
+ - i18n (English & Arabic with RTL)
41
+ - Toast & Modal systems
42
+ - SEO optimization
43
+ - HTTP interceptors (Auth, Error, Loading, Cache)
44
+ - PWA support
139
45
 
140
- - **Pipes** - Truncate, TimeAgo
141
- - **Directives** - ClickOutside, Tooltip
142
- - **HTTP Interceptors** - Auth, Error handling, Loading, Caching
143
- - **TypeScript Path Aliases** - Clean imports with `@core/*`, `@shared/*`, `@features/*`
46
+ ### Dashboard
144
47
 
145
- ### Internationalization
48
+ Admin dashboard with:
146
49
 
147
- - **Complete i18n Support** - English & Arabic with RTL support
148
- - **Language Switcher** - Built-in header component
149
- - **Translation Files** - JSON-based translation system
50
+ - Collapsible sidebar navigation
51
+ - Stats cards with icons and trends
52
+ - Chart components (Bar, Line, Donut)
53
+ - Data table with sorting & pagination
54
+ - 5 pages: Overview, Analytics, Users, Orders, Settings
55
+ - i18n support (EN/AR) with RTL
56
+ - Dark mode ready
150
57
 
151
- ### Additional Features
58
+ ### Minimal
152
59
 
153
- - **Routing** - Pre-configured with lazy loading
154
- - **Authentication Pages** - Login, Register, Forgot Password
155
- - **Example Pages** - Home, About, Contact with reactive forms
156
- - **PWA Support** - Service worker configuration
157
- - **Linting & Formatting** - ESLint + Prettier + simple-git-hooks (pre-commit linting)
158
- - **Modern Stack** - Tailwind v4, TypeScript, Signals
60
+ Clean slate - just Angular + Tailwind CSS configured.
159
61
 
160
- ## 🎨 Tailwind CSS v4
62
+ ---
161
63
 
162
- This tool uses **Tailwind CSS v4** with the official PostCSS approach:
64
+ ## Features Comparison
65
+
66
+ | Feature | Minimal | Starter | Dashboard |
67
+ | ------------------ | ------- | ------- | --------- |
68
+ | Tailwind CSS v4 | ✅ | ✅ | ✅ |
69
+ | Routing | ✅ | ✅ | ✅ |
70
+ | i18n (EN/AR + RTL) | - | ✅ | ✅ |
71
+ | Auth UI | - | ✅ | - |
72
+ | HTTP Interceptors | - | ✅ | ✅ |
73
+ | Toast/Modal | - | ✅ | ✅ |
74
+ | SEO Service | - | ✅ | ✅ |
75
+ | PWA | - | ✅ | ✅ |
76
+ | ESLint + Prettier | ✅ | ✅ | ✅ |
77
+ | Sidebar Layout | - | - | ✅ |
78
+ | Charts | - | - | ✅ |
79
+ | Data Tables | - | - | ✅ |
163
80
 
164
- - ✅ **Modern PostCSS Plugin** - `@tailwindcss/postcss`
165
- - ⚡ **LightningCSS** - Fast CSS processing
166
- - 🎨 **Modern CSS Features** - Nesting, variables, and more built-in
167
- - 🚀 **Simplified Build** - No preprocessors needed
81
+ ---
168
82
 
169
- **Note:** Tailwind v4 does not support SCSS, Sass, or Less. Modern CSS provides all the features you need!
83
+ ## Project Structure
170
84
 
171
- ### 🎨 Comprehensive Theming System
85
+ ```
86
+ src/app/
87
+ ├── core/ # Services, guards, interceptors, i18n
88
+ ├── shared/ # Components, pipes, directives
89
+ ├── features/ # Page components (home, about, auth...)
90
+ ├── layout/ # Header, footer, sidebar
91
+ ├── app.config.ts # App configuration
92
+ ├── app.routes.ts # Routing
93
+ └── app.ts # Root component
94
+ ```
172
95
 
173
- The starter template includes a **powerful Tailwind v4 theming system** using the `@theme` directive:
96
+ ---
174
97
 
175
- **Theme Colors:**
176
- - `primary` - Main brand color (with full 50-950 scale)
177
- - `secondary` - Secondary brand color (with full 50-950 scale)
178
- - `accent` - Accent/highlight color (with full 50-950 scale)
179
- - `success` - Success states (green)
180
- - `danger` - Error/danger states (red)
181
- - `warning` - Warning states (yellow/orange)
182
- - `info` - Informational states (blue)
98
+ ## Theming
183
99
 
184
- **Customization:**
185
- Simply edit `src/styles.css` and change the color values in the `@theme` block. All components automatically update!
100
+ Edit `src/styles.css` to customize colors:
186
101
 
187
102
  ```css
188
103
  @theme {
189
- --color-primary-500: #3b82f6; /* Change this to your brand color */
104
+ --color-primary-500: #3b82f6;
190
105
  --color-secondary-500: #06b6d4;
191
106
  --color-accent-500: #a855f7;
192
- /* ... complete color scales included */
193
107
  }
194
108
  ```
195
109
 
196
- **Usage in templates:**
110
+ Use in templates:
111
+
197
112
  ```html
198
- <div class="bg-primary-600 text-white">Primary button</div>
199
- <div class="bg-secondary-500">Secondary element</div>
200
- <p class="text-danger-600">Error message</p>
113
+ <button class="bg-primary-500 text-white">Click me</button>
201
114
  ```
202
115
 
203
- All UI components, pages, and layouts use these theme colors, making it easy to rebrand your entire application by changing a few color values!
116
+ ---
204
117
 
205
- ## 📄 License
118
+ ## CLI Options
206
119
 
207
- MIT License - see the LICENSE file included in the package.
120
+ ```bash
121
+ # Interactive (default)
122
+ npx create-ng-tailwind my-app
208
123
 
209
- ## 🙏 Support & Community
124
+ # With options
125
+ npx create-ng-tailwind my-app --template=starter --ssr --zoneless
210
126
 
211
- If you find this tool helpful, please consider:
127
+ # Available templates
128
+ --template=<minimal|starter|dashboard>
212
129
 
213
- - **Star the package** on [npm](https://www.npmjs.com/package/create-ng-tailwind)
214
- - 🔄 **Share** with your developer friends
215
- - 📧 **Contact**: [tehseen_ullah786@hotmail.com](mailto:tehseen_ullah786@hotmail.com)
130
+ # Other flags
131
+ --ssr # Enable Server-Side Rendering
132
+ --zoneless # Create zoneless application
133
+ --ai-config # Configure AI tools (Claude, Cursor, etc.)
134
+ ```
216
135
 
217
136
  ---
218
137
 
138
+ ## Requirements
139
+
140
+ - Node.js 18+
141
+ - npm 9+
142
+
143
+ ---
144
+
145
+ ## License
146
+
147
+ MIT
148
+
149
+ ---
150
+
151
+ ## Support
152
+
153
+ - Contact: [tehseen_ullah786@hotmail.com](mailto:tehseen_ullah786@hotmail.com)
154
+
219
155
  <div align="center">
220
156
 
221
157
  [![NPM](https://nodei.co/npm/create-ng-tailwind.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/create-ng-tailwind)
package/lib/cli/index.js CHANGED
@@ -15,7 +15,7 @@ class CLIHandler {
15
15
  .description("Create Angular projects with Tailwind CSS")
16
16
  .version(require("../../package.json").version)
17
17
  .argument("[project-name]", "Project name")
18
- .option("-t, --template <template>", "Template to use (minimal, starter)")
18
+ .option("-t, --template <template>", "Template to use (minimal, starter, dashboard)")
19
19
  .option("--routing", "Enable Angular routing")
20
20
  .option("--no-routing", "Disable Angular routing")
21
21
  .option(
@@ -64,15 +64,41 @@ class CLIHandler {
64
64
  type: "list",
65
65
  name: "template",
66
66
  message: "Which template would you like to use?",
67
+ pageSize: 10,
67
68
  choices: [
68
69
  {
69
- name: "Minimal - Clean Angular + Tailwind CSS (zero features, build your own way)",
70
+ name: "Minimal - Clean Angular + Tailwind CSS (zero features)",
70
71
  value: "minimal",
71
72
  },
72
73
  {
73
- name: "Starter - Professional foundation (routing, i18n, auth UI, components, services, interceptors)",
74
+ name: "Starter - Professional foundation (routing, i18n, auth, services)",
74
75
  value: "starter",
75
76
  },
77
+ {
78
+ name: "Dashboard - Admin panel with sidebar, charts, and analytics",
79
+ value: "dashboard",
80
+ },
81
+ // TODO: Enable these templates in future releases
82
+ // {
83
+ // name: "Ecommerce - Online store with products, cart, and checkout",
84
+ // value: "ecommerce",
85
+ // },
86
+ // {
87
+ // name: "Blog - CMS with posts, categories, tags, and comments",
88
+ // value: "blog",
89
+ // },
90
+ // {
91
+ // name: "SaaS - Pricing, subscriptions, and user dashboard",
92
+ // value: "saas",
93
+ // },
94
+ // {
95
+ // name: "Portfolio - Projects showcase, skills, and resume",
96
+ // value: "portfolio",
97
+ // },
98
+ // {
99
+ // name: "Landing - Marketing page with hero, features, and pricing",
100
+ // value: "landing",
101
+ // },
76
102
  ],
77
103
  default: "starter",
78
104
  },
@@ -6,15 +6,40 @@ async function getInteractiveOptions() {
6
6
  type: "list",
7
7
  name: "template",
8
8
  message: "Which template would you like to use?",
9
+ pageSize: 10,
9
10
  choices: [
10
11
  {
11
12
  name: "Minimal - Clean Angular + Tailwind CSS (zero features, build your own way)",
12
13
  value: "minimal",
13
14
  },
14
15
  {
15
- name: "Starter - Professional foundation (routing, i18n, auth UI, components, services, interceptors)",
16
+ name: "Starter - Professional foundation (routing, i18n, auth UI, components, services)",
16
17
  value: "starter",
17
18
  },
19
+ {
20
+ name: "Dashboard - Admin dashboard with sidebar, charts, tables, and analytics",
21
+ value: "dashboard",
22
+ },
23
+ {
24
+ name: "Ecommerce - Online store with products, cart, checkout, and wishlist",
25
+ value: "ecommerce",
26
+ },
27
+ {
28
+ name: "Blog - Content management with posts, categories, tags, and comments",
29
+ value: "blog",
30
+ },
31
+ {
32
+ name: "SaaS - Pricing page, subscription management, and user dashboard",
33
+ value: "saas",
34
+ },
35
+ {
36
+ name: "Portfolio - Projects showcase, skills, experience timeline, and resume",
37
+ value: "portfolio",
38
+ },
39
+ {
40
+ name: "Landing - Marketing page with hero, features, testimonials, pricing, FAQ",
41
+ value: "landing",
42
+ },
18
43
  ],
19
44
  default: "starter",
20
45
  },
@@ -2,7 +2,6 @@ const fs = require('fs-extra');
2
2
  const execa = require('execa');
3
3
  const TailwindManager = require('./TailwindManager');
4
4
  const TemplateManager = require('./TemplateManager');
5
- const { createAIConfigs } = require('../utils/ai-config');
6
5
 
7
6
  class ProjectManager {
8
7
  constructor(config, logger) {
@@ -40,9 +39,6 @@ class ProjectManager {
40
39
 
41
40
  // Apply template
42
41
  await this.templateManager.apply();
43
-
44
- // Create AI configuration files (CLAUDE.md + tool-specific)
45
- await createAIConfigs(this.config.fullPath, this.config.projectName, this.config.aiConfig);
46
42
  }
47
43
 
48
44
  async createAngularProject() {
@@ -0,0 +1,243 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Create Button Component
6
+ */
7
+ async function createButtonComponent(config) {
8
+ const buttonComponent = `import { Component, Input, Output, EventEmitter } from '@angular/core';
9
+
10
+ export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
11
+ export type ButtonSize = 'sm' | 'md' | 'lg';
12
+
13
+ @Component({
14
+ selector: 'app-button',
15
+ standalone: true,
16
+ imports: [],
17
+ template: \`
18
+ <button
19
+ [class]="buttonClasses"
20
+ [disabled]="disabled || loading"
21
+ (click)="handleClick($event)"
22
+ [type]="type">
23
+
24
+ @if (loading) {
25
+ <svg class="animate-spin -ml-1 mr-3 h-4 w-4" fill="none" viewBox="0 0 24 24">
26
+ <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" class="opacity-25"></circle>
27
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
28
+ </svg>
29
+ }
30
+
31
+ <ng-content></ng-content>
32
+ </button>
33
+ \`
34
+ })
35
+ export class ButtonComponent {
36
+ @Input() variant: ButtonVariant = 'primary';
37
+ @Input() size: ButtonSize = 'md';
38
+ @Input() disabled = false;
39
+ @Input() loading = false;
40
+ @Input() type: 'button' | 'submit' | 'reset' = 'button';
41
+ @Input() fullWidth = false;
42
+
43
+ @Output() clicked = new EventEmitter<Event>();
44
+
45
+ get buttonClasses(): string {
46
+ const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50';
47
+
48
+ const sizeClasses = {
49
+ sm: 'text-sm px-3 py-2 h-9',
50
+ md: 'text-sm px-4 py-2 h-10',
51
+ lg: 'text-base px-8 py-3 h-11'
52
+ };
53
+
54
+ const variantClasses = {
55
+ primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500',
56
+ secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-400',
57
+ outline: 'border-2 border-primary-600 text-primary-600 hover:bg-primary-600 hover:text-white focus:ring-primary-500',
58
+ ghost: 'hover:bg-gray-100 hover:text-gray-900 focus:ring-gray-400',
59
+ danger: 'bg-danger-600 text-white hover:bg-danger-700 focus:ring-danger-500'
60
+ };
61
+
62
+ const widthClass = this.fullWidth ? 'w-full' : '';
63
+
64
+ return \`\${baseClasses} \${sizeClasses[this.size]} \${variantClasses[this.variant]} \${widthClass}\`.trim();
65
+ }
66
+
67
+ handleClick(event: Event): void {
68
+ if (!this.disabled && !this.loading) {
69
+ this.clicked.emit(event);
70
+ }
71
+ }
72
+ }`;
73
+
74
+ await fs.writeFile(
75
+ path.join(config.fullPath, 'src/app/shared/components/button/button.component.ts'),
76
+ buttonComponent
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Create Card Component
82
+ */
83
+ async function createCardComponent(config) {
84
+ const cardComponent = `import { Component, Input } from '@angular/core';
85
+
86
+ @Component({
87
+ selector: 'app-card',
88
+ standalone: true,
89
+ imports: [],
90
+ template: \`
91
+ <div [class]="cardClasses">
92
+ @if (title || subtitle) {
93
+ <div class="px-6 py-4 border-b border-gray-200">
94
+ @if (title) {
95
+ <h3 class="text-lg font-semibold text-gray-900">
96
+ {{ title }}
97
+ </h3>
98
+ }
99
+ @if (subtitle) {
100
+ <p class="text-sm text-gray-600 mt-1">
101
+ {{ subtitle }}
102
+ </p>
103
+ }
104
+ </div>
105
+ }
106
+
107
+ <div [class]="contentClasses">
108
+ <ng-content></ng-content>
109
+ </div>
110
+
111
+ @if (hasFooter) {
112
+ <div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
113
+ <ng-content select="[slot=footer]"></ng-content>
114
+ </div>
115
+ }
116
+ </div>
117
+ \`
118
+ })
119
+ export class CardComponent {
120
+ @Input() title?: string;
121
+ @Input() subtitle?: string;
122
+ @Input() padding = true;
123
+ @Input() shadow = true;
124
+ @Input() hover = false;
125
+ @Input() hasFooter = false;
126
+
127
+ get cardClasses(): string {
128
+ const baseClasses = 'bg-white border border-gray-200 rounded-lg overflow-hidden';
129
+ const shadowClasses = this.shadow ? 'shadow-sm' : '';
130
+ const hoverClasses = this.hover ? 'hover:shadow-md transition-shadow duration-200' : '';
131
+
132
+ return \`\${baseClasses} \${shadowClasses} \${hoverClasses}\`.trim();
133
+ }
134
+
135
+ get contentClasses(): string {
136
+ return this.padding ? 'p-6' : '';
137
+ }
138
+ }`;
139
+
140
+ await fs.writeFile(
141
+ path.join(config.fullPath, 'src/app/shared/components/card/card.component.ts'),
142
+ cardComponent
143
+ );
144
+ }
145
+
146
+ /**
147
+ * Create Loading Spinner Component
148
+ */
149
+ async function createLoadingSpinnerComponent(config) {
150
+ const spinnerComponent = `import { Component, Input } from '@angular/core';
151
+
152
+ export type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl';
153
+
154
+ @Component({
155
+ selector: 'app-loading-spinner',
156
+ standalone: true,
157
+ imports: [],
158
+ template: \`
159
+ <div [class]="containerClasses">
160
+ <svg [class]="spinnerClasses" fill="none" viewBox="0 0 24 24">
161
+ <circle
162
+ cx="12" cy="12" r="10"
163
+ stroke="currentColor"
164
+ stroke-width="4"
165
+ class="opacity-25">
166
+ </circle>
167
+ <path
168
+ class="opacity-75"
169
+ fill="currentColor"
170
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
171
+ </path>
172
+ </svg>
173
+ @if (text) {
174
+ <span [class]="textClasses">{{ text }}</span>
175
+ }
176
+ </div>
177
+ \`
178
+ })
179
+ export class LoadingSpinnerComponent {
180
+ @Input() size: SpinnerSize = 'md';
181
+ @Input() text?: string;
182
+ @Input() centered = false;
183
+ @Input() color = 'primary';
184
+
185
+ private readonly sizeClasses = {
186
+ sm: 'h-4 w-4',
187
+ md: 'h-8 w-8',
188
+ lg: 'h-12 w-12',
189
+ xl: 'h-16 w-16'
190
+ } as const;
191
+
192
+ private readonly colorClasses = {
193
+ primary: 'text-primary-600',
194
+ secondary: 'text-secondary-600',
195
+ accent: 'text-accent-600',
196
+ success: 'text-success-600',
197
+ danger: 'text-danger-600',
198
+ warning: 'text-warning-600',
199
+ info: 'text-info-600',
200
+ gray: 'text-gray-600',
201
+ white: 'text-white'
202
+ } as const;
203
+
204
+ protected readonly textClasses = 'text-sm text-gray-600';
205
+
206
+ get containerClasses(): string {
207
+ const baseClasses = 'flex items-center';
208
+ const centerClasses = this.centered ? 'justify-center' : '';
209
+ const directionClasses = this.text ? 'flex-col space-y-2' : '';
210
+
211
+ return \`\${baseClasses} \${centerClasses} \${directionClasses}\`.trim();
212
+ }
213
+
214
+ get spinnerClasses(): string {
215
+ const baseClasses = 'animate-spin';
216
+ return \`\${baseClasses} \${this.sizeClasses[this.size]} \${this.colorClasses[this.color as keyof typeof this.colorClasses] || this.colorClasses.primary}\`.trim();
217
+ }
218
+ }`;
219
+
220
+ await fs.writeFile(
221
+ path.join(
222
+ config.fullPath,
223
+ 'src/app/shared/components/loading-spinner/loading-spinner.component.ts'
224
+ ),
225
+ spinnerComponent
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Create all shared components
231
+ */
232
+ async function createSharedComponents(config) {
233
+ await createButtonComponent(config);
234
+ await createCardComponent(config);
235
+ await createLoadingSpinnerComponent(config);
236
+ }
237
+
238
+ module.exports = {
239
+ createButtonComponent,
240
+ createCardComponent,
241
+ createLoadingSpinnerComponent,
242
+ createSharedComponents,
243
+ };