create-ng-tailwind 3.0.1 → 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 -344
  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 +53 -4055
  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
@@ -0,0 +1,390 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * Create Blog Services
6
+ */
7
+ async function createServices(config) {
8
+ const blogService = `import { Injectable, signal, computed } from '@angular/core';
9
+
10
+ export interface Author {
11
+ id: number;
12
+ name: string;
13
+ avatar: string;
14
+ bio: string;
15
+ social?: {
16
+ twitter?: string;
17
+ github?: string;
18
+ linkedin?: string;
19
+ };
20
+ }
21
+
22
+ export interface Post {
23
+ id: number;
24
+ slug: string;
25
+ title: string;
26
+ excerpt: string;
27
+ content: string;
28
+ coverImage: string;
29
+ author: Author;
30
+ category: string;
31
+ tags: string[];
32
+ publishedAt: Date;
33
+ updatedAt?: Date;
34
+ readingTime: number;
35
+ featured?: boolean;
36
+ }
37
+
38
+ export interface Comment {
39
+ id: number;
40
+ postId: number;
41
+ author: string;
42
+ email: string;
43
+ content: string;
44
+ createdAt: Date;
45
+ replies?: Comment[];
46
+ }
47
+
48
+ @Injectable({ providedIn: 'root' })
49
+ export class BlogService {
50
+ private postsSignal = signal<Post[]>(this.getMockPosts());
51
+ private commentsSignal = signal<Comment[]>(this.getMockComments());
52
+
53
+ posts = this.postsSignal.asReadonly();
54
+ comments = this.commentsSignal.asReadonly();
55
+
56
+ categories = computed(() => {
57
+ const cats = new Set(this.postsSignal().map(p => p.category));
58
+ return Array.from(cats);
59
+ });
60
+
61
+ tags = computed(() => {
62
+ const allTags = this.postsSignal().flatMap(p => p.tags);
63
+ return Array.from(new Set(allTags));
64
+ });
65
+
66
+ featuredPosts = computed(() =>
67
+ this.postsSignal().filter(p => p.featured).slice(0, 3)
68
+ );
69
+
70
+ recentPosts = computed(() =>
71
+ [...this.postsSignal()]
72
+ .sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime())
73
+ .slice(0, 5)
74
+ );
75
+
76
+ getPostBySlug(slug: string): Post | undefined {
77
+ return this.postsSignal().find(p => p.slug === slug);
78
+ }
79
+
80
+ getPostsByCategory(category: string): Post[] {
81
+ return this.postsSignal().filter(p => p.category === category);
82
+ }
83
+
84
+ getPostsByTag(tag: string): Post[] {
85
+ return this.postsSignal().filter(p => p.tags.includes(tag));
86
+ }
87
+
88
+ getPostsByAuthor(authorId: number): Post[] {
89
+ return this.postsSignal().filter(p => p.author.id === authorId);
90
+ }
91
+
92
+ getRelatedPosts(post: Post, limit = 3): Post[] {
93
+ return this.postsSignal()
94
+ .filter(p => p.id !== post.id && (p.category === post.category || p.tags.some(t => post.tags.includes(t))))
95
+ .slice(0, limit);
96
+ }
97
+
98
+ searchPosts(query: string): Post[] {
99
+ const q = query.toLowerCase();
100
+ return this.postsSignal().filter(p =>
101
+ p.title.toLowerCase().includes(q) ||
102
+ p.excerpt.toLowerCase().includes(q) ||
103
+ p.tags.some(t => t.toLowerCase().includes(q))
104
+ );
105
+ }
106
+
107
+ getCommentsByPostId(postId: number): Comment[] {
108
+ return this.commentsSignal().filter(c => c.postId === postId);
109
+ }
110
+
111
+ addComment(comment: Omit<Comment, 'id' | 'createdAt'>): void {
112
+ const newComment: Comment = {
113
+ ...comment,
114
+ id: Date.now(),
115
+ createdAt: new Date(),
116
+ };
117
+ this.commentsSignal.update(comments => [...comments, newComment]);
118
+ }
119
+
120
+ private getMockPosts(): Post[] {
121
+ const authors: Author[] = [
122
+ {
123
+ id: 1,
124
+ name: 'Sarah Johnson',
125
+ avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150',
126
+ bio: 'Senior Frontend Developer passionate about Angular and modern web technologies.',
127
+ social: { twitter: 'sarahj', github: 'sarahj' }
128
+ },
129
+ {
130
+ id: 2,
131
+ name: 'Michael Chen',
132
+ avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150',
133
+ bio: 'Full-stack developer and tech blogger. Love sharing knowledge.',
134
+ social: { twitter: 'mchen', linkedin: 'michaelchen' }
135
+ },
136
+ {
137
+ id: 3,
138
+ name: 'Emily Davis',
139
+ avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150',
140
+ bio: 'UX/UI Designer turned developer. Bridging design and code.',
141
+ social: { github: 'emilyd' }
142
+ },
143
+ ];
144
+
145
+ return [
146
+ {
147
+ id: 1,
148
+ slug: 'getting-started-with-angular-signals',
149
+ title: 'Getting Started with Angular Signals',
150
+ excerpt: 'Learn how to use Angular Signals for reactive state management in your applications.',
151
+ content: \`# Getting Started with Angular Signals
152
+
153
+ Angular Signals represent a new way to handle reactive state in Angular applications. They provide a simpler, more predictable way to manage state compared to traditional approaches.
154
+
155
+ ## What are Signals?
156
+
157
+ Signals are reactive primitives that hold a value and notify consumers when that value changes. They're similar to observables but with a simpler API.
158
+
159
+ \\\`\\\`\\\`typescript
160
+ import { signal, computed } from '@angular/core';
161
+
162
+ // Create a signal
163
+ const count = signal(0);
164
+
165
+ // Read the value
166
+ console.log(count()); // 0
167
+
168
+ // Update the value
169
+ count.set(1);
170
+ count.update(v => v + 1);
171
+
172
+ // Create computed signals
173
+ const doubled = computed(() => count() * 2);
174
+ \\\`\\\`\\\`
175
+
176
+ ## Benefits of Signals
177
+
178
+ 1. **Simplicity**: No need to manage subscriptions
179
+ 2. **Performance**: Fine-grained reactivity
180
+ 3. **Debugging**: Easier to trace state changes
181
+ 4. **Integration**: Works seamlessly with Angular's change detection
182
+
183
+ ## Conclusion
184
+
185
+ Signals are a powerful addition to Angular's reactive toolkit. Start using them today!\`,
186
+ coverImage: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=800',
187
+ author: authors[0],
188
+ category: 'Angular',
189
+ tags: ['Angular', 'Signals', 'State Management', 'Tutorial'],
190
+ publishedAt: new Date('2025-01-15'),
191
+ readingTime: 5,
192
+ featured: true,
193
+ },
194
+ {
195
+ id: 2,
196
+ slug: 'tailwind-css-v4-whats-new',
197
+ title: "Tailwind CSS v4: What's New",
198
+ excerpt: 'Explore the exciting new features in Tailwind CSS v4 including the new @theme directive.',
199
+ content: \`# Tailwind CSS v4: What's New
200
+
201
+ Tailwind CSS v4 brings significant improvements to how we style our applications. Let's explore the key changes.
202
+
203
+ ## The @theme Directive
204
+
205
+ The new @theme directive allows you to define your design tokens directly in CSS:
206
+
207
+ \\\`\\\`\\\`css
208
+ @theme {
209
+ --color-primary-500: #3b82f6;
210
+ --color-secondary-500: #06b6d4;
211
+ }
212
+ \\\`\\\`\\\`
213
+
214
+ ## Lightning CSS Integration
215
+
216
+ Tailwind v4 now uses Lightning CSS for faster builds and better CSS processing.
217
+
218
+ ## No More Config File
219
+
220
+ You can now configure Tailwind entirely through CSS, no JavaScript config needed!
221
+
222
+ ## Conclusion
223
+
224
+ Tailwind v4 is a major step forward for utility-first CSS.\`,
225
+ coverImage: 'https://images.unsplash.com/photo-1507721999472-8ed4421c4af2?w=800',
226
+ author: authors[1],
227
+ category: 'CSS',
228
+ tags: ['Tailwind', 'CSS', 'Frontend', 'Styling'],
229
+ publishedAt: new Date('2025-01-10'),
230
+ readingTime: 4,
231
+ featured: true,
232
+ },
233
+ {
234
+ id: 3,
235
+ slug: 'building-accessible-components',
236
+ title: 'Building Accessible Components',
237
+ excerpt: 'A comprehensive guide to creating accessible Angular components that work for everyone.',
238
+ content: \`# Building Accessible Components
239
+
240
+ Accessibility (a11y) is crucial for creating inclusive web applications. Here's how to build accessible Angular components.
241
+
242
+ ## Key Principles
243
+
244
+ 1. **Semantic HTML**: Use the right elements
245
+ 2. **Keyboard Navigation**: Everything should be keyboard accessible
246
+ 3. **ARIA Labels**: Provide context for screen readers
247
+ 4. **Color Contrast**: Ensure readable text
248
+
249
+ ## Testing Accessibility
250
+
251
+ Use tools like axe-core and Lighthouse to audit your components.\`,
252
+ coverImage: 'https://images.unsplash.com/photo-1573164713714-d95e436ab8d6?w=800',
253
+ author: authors[2],
254
+ category: 'Accessibility',
255
+ tags: ['Accessibility', 'A11y', 'Angular', 'Components'],
256
+ publishedAt: new Date('2025-01-05'),
257
+ readingTime: 6,
258
+ },
259
+ {
260
+ id: 4,
261
+ slug: 'typescript-best-practices-2025',
262
+ title: 'TypeScript Best Practices for 2025',
263
+ excerpt: 'Modern TypeScript patterns and best practices to write cleaner, safer code.',
264
+ content: \`# TypeScript Best Practices for 2025
265
+
266
+ TypeScript continues to evolve. Here are the best practices for writing modern TypeScript.
267
+
268
+ ## Use Strict Mode
269
+
270
+ Always enable strict mode in your tsconfig.
271
+
272
+ ## Prefer Unknown Over Any
273
+
274
+ Use unknown instead of any for better type safety.
275
+
276
+ ## Conclusion
277
+
278
+ Following these practices will make your TypeScript code more maintainable and type-safe.\`,
279
+ coverImage: 'https://images.unsplash.com/photo-1516116216624-53e697fedbea?w=800',
280
+ author: authors[0],
281
+ category: 'TypeScript',
282
+ tags: ['TypeScript', 'JavaScript', 'Best Practices'],
283
+ publishedAt: new Date('2025-01-01'),
284
+ readingTime: 7,
285
+ featured: true,
286
+ },
287
+ {
288
+ id: 5,
289
+ slug: 'state-management-patterns',
290
+ title: 'State Management Patterns in Angular',
291
+ excerpt: 'Compare different state management approaches: Services, Signals, NgRx, and more.',
292
+ content: \`# State Management Patterns in Angular
293
+
294
+ Choosing the right state management approach is crucial. Let's compare the options.
295
+
296
+ ## Simple Service with Signals
297
+
298
+ Best for small to medium apps.
299
+
300
+ ## NgRx for Complex Apps
301
+
302
+ When you need predictable state with time-travel debugging.
303
+
304
+ ## Conclusion
305
+
306
+ Start simple with signals, scale to NgRx when needed.\`,
307
+ coverImage: 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800',
308
+ author: authors[1],
309
+ category: 'Angular',
310
+ tags: ['Angular', 'State Management', 'NgRx', 'Signals'],
311
+ publishedAt: new Date('2024-12-28'),
312
+ readingTime: 8,
313
+ },
314
+ {
315
+ id: 6,
316
+ slug: 'responsive-design-techniques',
317
+ title: 'Modern Responsive Design Techniques',
318
+ excerpt: 'Master responsive design with CSS Grid, Flexbox, and container queries.',
319
+ content: \`# Modern Responsive Design Techniques
320
+
321
+ Responsive design has evolved. Here are modern techniques to create adaptive layouts.
322
+
323
+ ## CSS Grid
324
+
325
+ Perfect for two-dimensional layouts.
326
+
327
+ ## Container Queries
328
+
329
+ Style based on container size, not viewport.
330
+
331
+ ## Conclusion
332
+
333
+ Combine these techniques for truly responsive designs.\`,
334
+ coverImage: 'https://images.unsplash.com/photo-1517292987719-0369a794ec0f?w=800',
335
+ author: authors[2],
336
+ category: 'CSS',
337
+ tags: ['CSS', 'Responsive', 'Grid', 'Flexbox'],
338
+ publishedAt: new Date('2024-12-20'),
339
+ readingTime: 5,
340
+ },
341
+ ];
342
+ }
343
+
344
+ private getMockComments(): Comment[] {
345
+ return [
346
+ {
347
+ id: 1,
348
+ postId: 1,
349
+ author: 'John Doe',
350
+ email: 'john@example.com',
351
+ content: 'Great article! Signals have really simplified my state management.',
352
+ createdAt: new Date('2025-01-16'),
353
+ replies: [
354
+ {
355
+ id: 2,
356
+ postId: 1,
357
+ author: 'Sarah Johnson',
358
+ email: 'sarah@example.com',
359
+ content: 'Thanks John! Glad you found it helpful.',
360
+ createdAt: new Date('2025-01-16'),
361
+ }
362
+ ]
363
+ },
364
+ {
365
+ id: 3,
366
+ postId: 1,
367
+ author: 'Jane Smith',
368
+ email: 'jane@example.com',
369
+ content: 'Could you write a follow-up about computed signals?',
370
+ createdAt: new Date('2025-01-17'),
371
+ },
372
+ {
373
+ id: 4,
374
+ postId: 2,
375
+ author: 'Alex Turner',
376
+ email: 'alex@example.com',
377
+ content: 'The @theme directive is a game changer!',
378
+ createdAt: new Date('2025-01-11'),
379
+ },
380
+ ];
381
+ }
382
+ }`;
383
+
384
+ await fs.writeFile(
385
+ path.join(config.fullPath, "src/app/core/services/blog.service.ts"),
386
+ blogService
387
+ );
388
+ }
389
+
390
+ module.exports = { createServices };
@@ -0,0 +1,320 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * Create routing configuration
6
+ */
7
+ async function createRouting(config) {
8
+ const routesFile = `import { Routes } from '@angular/router';
9
+ import { DashboardLayoutComponent } from './layout/dashboard/dashboard-layout.component';
10
+
11
+ export const routes: Routes = [
12
+ {
13
+ path: '',
14
+ redirectTo: 'dashboard',
15
+ pathMatch: 'full',
16
+ },
17
+ {
18
+ path: 'dashboard',
19
+ component: DashboardLayoutComponent,
20
+ children: [
21
+ {
22
+ path: '',
23
+ loadComponent: () =>
24
+ import('./features/dashboard/overview/overview.component').then(
25
+ (c) => c.OverviewComponent
26
+ ),
27
+ },
28
+ {
29
+ path: 'analytics',
30
+ loadComponent: () =>
31
+ import('./features/dashboard/analytics/analytics.component').then(
32
+ (c) => c.AnalyticsComponent
33
+ ),
34
+ },
35
+ {
36
+ path: 'users',
37
+ loadComponent: () =>
38
+ import('./features/dashboard/users/users.component').then(
39
+ (c) => c.UsersComponent
40
+ ),
41
+ },
42
+ {
43
+ path: 'orders',
44
+ loadComponent: () =>
45
+ import('./features/dashboard/orders/orders.component').then(
46
+ (c) => c.OrdersComponent
47
+ ),
48
+ },
49
+ {
50
+ path: 'settings',
51
+ loadComponent: () =>
52
+ import('./features/dashboard/settings/settings.component').then(
53
+ (c) => c.SettingsComponent
54
+ ),
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ path: '**',
60
+ redirectTo: 'dashboard',
61
+ },
62
+ ];`;
63
+
64
+ await fs.writeFile(
65
+ path.join(config.fullPath, "src/app/app.routes.ts"),
66
+ routesFile
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Create app configuration
72
+ */
73
+ async function createAppConfig(config) {
74
+ const appConfigFile = `import { ApplicationConfig, provideZoneChangeDetection, importProvidersFrom } from '@angular/core';
75
+ import { provideRouter } from '@angular/router';
76
+ import { provideHttpClient, withInterceptors, HttpClient } from '@angular/common/http';
77
+ import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
78
+ import { TranslateHttpLoader } from '@ngx-translate/http-loader';
79
+
80
+ import { routes } from './app.routes';
81
+ import { authInterceptor } from '@core/interceptors/auth.interceptor';
82
+ import { errorInterceptor } from '@core/interceptors/error.interceptor';
83
+ import { loadingInterceptor } from '@core/interceptors/loading.interceptor';
84
+ import { cachingInterceptor } from '@core/interceptors/caching.interceptor';
85
+
86
+ // Translation loader factory
87
+ export function HttpLoaderFactory(http: HttpClient) {
88
+ return new TranslateHttpLoader(http, './assets/i18n/', '.json');
89
+ }
90
+
91
+ export const appConfig: ApplicationConfig = {
92
+ providers: [
93
+ provideZoneChangeDetection({ eventCoalescing: true }),
94
+ provideRouter(routes),
95
+ provideHttpClient(
96
+ withInterceptors([
97
+ authInterceptor,
98
+ cachingInterceptor,
99
+ loadingInterceptor,
100
+ errorInterceptor,
101
+ ])
102
+ ),
103
+ // Translation configuration
104
+ importProvidersFrom(
105
+ TranslateModule.forRoot({
106
+ loader: {
107
+ provide: TranslateLoader,
108
+ useFactory: HttpLoaderFactory,
109
+ deps: [HttpClient]
110
+ }
111
+ })
112
+ ),
113
+ ],
114
+ };`;
115
+
116
+ await fs.writeFile(
117
+ path.join(config.fullPath, "src/app/app.config.ts"),
118
+ appConfigFile
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Create app component
124
+ */
125
+ async function createAppComponent(config) {
126
+ const appTs = `import { Component, inject } from '@angular/core';
127
+ import { RouterOutlet } from '@angular/router';
128
+ import { ToastComponent } from '@shared/components/toast/toast.component';
129
+ import { ModalComponent } from '@shared/components/modal/modal.component';
130
+ import { TranslationService } from '@core/i18n/translation.service';
131
+
132
+ @Component({
133
+ selector: 'app-root',
134
+ imports: [RouterOutlet, ToastComponent, ModalComponent],
135
+ templateUrl: './app.html',
136
+ })
137
+ export class App {
138
+ // Inject translation service to initialize it at app startup
139
+ private translationService = inject(TranslationService);
140
+ title = '${config.projectName}';
141
+ }`;
142
+
143
+ const appHtml = `<router-outlet />
144
+ <app-toast />
145
+ <app-modal />
146
+ `;
147
+
148
+ await fs.writeFile(path.join(config.fullPath, "src/app/app.ts"), appTs);
149
+ await fs.writeFile(path.join(config.fullPath, "src/app/app.html"), appHtml);
150
+ }
151
+
152
+ /**
153
+ * Create global styles
154
+ */
155
+ async function createStyles(config) {
156
+ const stylesFile = `@import "tailwindcss";
157
+
158
+ /* Custom CSS Variables for theming */
159
+ @theme {
160
+ /* Primary colors */
161
+ --color-primary-50: #eff6ff;
162
+ --color-primary-100: #dbeafe;
163
+ --color-primary-200: #bfdbfe;
164
+ --color-primary-300: #93c5fd;
165
+ --color-primary-400: #60a5fa;
166
+ --color-primary-500: #3b82f6;
167
+ --color-primary-600: #2563eb;
168
+ --color-primary-700: #1d4ed8;
169
+ --color-primary-800: #1e40af;
170
+ --color-primary-900: #1e3a8a;
171
+ --color-primary-950: #172554;
172
+
173
+ /* Secondary colors */
174
+ --color-secondary-50: #f8fafc;
175
+ --color-secondary-100: #f1f5f9;
176
+ --color-secondary-200: #e2e8f0;
177
+ --color-secondary-300: #cbd5e1;
178
+ --color-secondary-400: #94a3b8;
179
+ --color-secondary-500: #64748b;
180
+ --color-secondary-600: #475569;
181
+ --color-secondary-700: #334155;
182
+ --color-secondary-800: #1e293b;
183
+ --color-secondary-900: #0f172a;
184
+ --color-secondary-950: #020617;
185
+
186
+ /* Accent colors */
187
+ --color-accent-50: #faf5ff;
188
+ --color-accent-100: #f3e8ff;
189
+ --color-accent-200: #e9d5ff;
190
+ --color-accent-300: #d8b4fe;
191
+ --color-accent-400: #c084fc;
192
+ --color-accent-500: #a855f7;
193
+ --color-accent-600: #9333ea;
194
+ --color-accent-700: #7e22ce;
195
+ --color-accent-800: #6b21a8;
196
+ --color-accent-900: #581c87;
197
+ --color-accent-950: #3b0764;
198
+
199
+ /* Success colors */
200
+ --color-success-50: #f0fdf4;
201
+ --color-success-100: #dcfce7;
202
+ --color-success-200: #bbf7d0;
203
+ --color-success-300: #86efac;
204
+ --color-success-400: #4ade80;
205
+ --color-success-500: #22c55e;
206
+ --color-success-600: #16a34a;
207
+ --color-success-700: #15803d;
208
+ --color-success-800: #166534;
209
+ --color-success-900: #14532d;
210
+ --color-success-950: #052e16;
211
+
212
+ /* Warning colors */
213
+ --color-warning-50: #fffbeb;
214
+ --color-warning-100: #fef3c7;
215
+ --color-warning-200: #fde68a;
216
+ --color-warning-300: #fcd34d;
217
+ --color-warning-400: #fbbf24;
218
+ --color-warning-500: #f59e0b;
219
+ --color-warning-600: #d97706;
220
+ --color-warning-700: #b45309;
221
+ --color-warning-800: #92400e;
222
+ --color-warning-900: #78350f;
223
+ --color-warning-950: #451a03;
224
+
225
+ /* Danger colors */
226
+ --color-danger-50: #fef2f2;
227
+ --color-danger-100: #fee2e2;
228
+ --color-danger-200: #fecaca;
229
+ --color-danger-300: #fca5a5;
230
+ --color-danger-400: #f87171;
231
+ --color-danger-500: #ef4444;
232
+ --color-danger-600: #dc2626;
233
+ --color-danger-700: #b91c1c;
234
+ --color-danger-800: #991b1b;
235
+ --color-danger-900: #7f1d1d;
236
+ --color-danger-950: #450a0a;
237
+
238
+ /* Info colors */
239
+ --color-info-50: #ecfeff;
240
+ --color-info-100: #cffafe;
241
+ --color-info-200: #a5f3fc;
242
+ --color-info-300: #67e8f9;
243
+ --color-info-400: #22d3ee;
244
+ --color-info-500: #06b6d4;
245
+ --color-info-600: #0891b2;
246
+ --color-info-700: #0e7490;
247
+ --color-info-800: #155e75;
248
+ --color-info-900: #164e63;
249
+ --color-info-950: #083344;
250
+ }
251
+
252
+ /* Smooth scrolling */
253
+ html {
254
+ scroll-behavior: smooth;
255
+ }
256
+
257
+ /* Custom scrollbar */
258
+ ::-webkit-scrollbar {
259
+ width: 8px;
260
+ height: 8px;
261
+ }
262
+
263
+ ::-webkit-scrollbar-track {
264
+ background: #f1f5f9;
265
+ }
266
+
267
+ ::-webkit-scrollbar-thumb {
268
+ background: #cbd5e1;
269
+ border-radius: 4px;
270
+ }
271
+
272
+ ::-webkit-scrollbar-thumb:hover {
273
+ background: #94a3b8;
274
+ }
275
+
276
+ /* RTL Support */
277
+ html[dir="rtl"] {
278
+ direction: rtl;
279
+ }
280
+
281
+ html[dir="ltr"] {
282
+ direction: ltr;
283
+ }`;
284
+
285
+ await fs.writeFile(path.join(config.fullPath, "src/styles.css"), stylesFile);
286
+ }
287
+
288
+ /**
289
+ * Install i18n packages
290
+ */
291
+ async function installI18nPackages(config) {
292
+ if (!config.skipInstall) {
293
+ const execa = require("execa");
294
+ await execa.command(
295
+ "npm install @ngx-translate/core@^15.0.0 @ngx-translate/http-loader@^8.0.0 --force",
296
+ {
297
+ cwd: config.fullPath,
298
+ stdio: "pipe",
299
+ }
300
+ );
301
+ } else {
302
+ // Add to package.json if skipInstall
303
+ const packageJsonPath = path.join(config.fullPath, "package.json");
304
+ const packageJson = await fs.readJson(packageJsonPath);
305
+ if (!packageJson.dependencies) {
306
+ packageJson.dependencies = {};
307
+ }
308
+ packageJson.dependencies["@ngx-translate/core"] = "^15.0.0";
309
+ packageJson.dependencies["@ngx-translate/http-loader"] = "^8.0.0";
310
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
311
+ }
312
+ }
313
+
314
+ module.exports = {
315
+ createRouting,
316
+ createAppConfig,
317
+ createAppComponent,
318
+ createStyles,
319
+ installI18nPackages,
320
+ };