create-ng-tailwind 2.0.2 → 2.1.1

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.
@@ -62,6 +62,7 @@ src/app/
62
62
  ## ⚡ HTTP Interceptors (Pre-configured)
63
63
 
64
64
  Interceptors run in this order:
65
+
65
66
  1. **authInterceptor** → Adds JWT Bearer token to requests
66
67
  2. **cachingInterceptor** → Caches GET requests (5min TTL)
67
68
  3. **loadingInterceptor** → Shows/hides loading indicator
@@ -70,6 +71,7 @@ Interceptors run in this order:
70
71
  ## 🧩 Available Services (Use These!)
71
72
 
72
73
  ### ToastService
74
+
73
75
  \`\`\`typescript
74
76
  import { inject } from '@angular/core';
75
77
  import { ToastService } from '@core/services/toast.service';
@@ -82,6 +84,7 @@ toast.info('New message received');
82
84
  \`\`\`
83
85
 
84
86
  ### ModalService
87
+
85
88
  \`\`\`typescript
86
89
  import { inject } from '@angular/core';
87
90
  import { ModalService } from '@core/services/modal.service';
@@ -103,6 +106,7 @@ await modal.alert('Your session has expired', 'Session Timeout');
103
106
  \`\`\`
104
107
 
105
108
  ### ApiService
109
+
106
110
  \`\`\`typescript
107
111
  import { inject } from '@angular/core';
108
112
  import { ApiService } from '@core/services/api.service';
@@ -110,12 +114,12 @@ import { ApiService } from '@core/services/api.service';
110
114
  const api = inject(ApiService);
111
115
 
112
116
  // GET request
113
- api.get<User[]>('users').subscribe(users => {
117
+ api.get<User[]>('users').subscribe((users) => {
114
118
  console.log(users);
115
119
  });
116
120
 
117
121
  // POST request
118
- api.post<User>('users', userData).subscribe(newUser => {
122
+ api.post<User>('users', userData).subscribe((newUser) => {
119
123
  console.log('Created:', newUser);
120
124
  });
121
125
 
@@ -123,6 +127,7 @@ api.post<User>('users', userData).subscribe(newUser => {
123
127
  \`\`\`
124
128
 
125
129
  ### AuthService
130
+
126
131
  \`\`\`typescript
127
132
  import { inject } from '@angular/core';
128
133
  import { AuthService } from '@core/services/auth.service';
@@ -132,11 +137,11 @@ const auth = inject(AuthService);
132
137
  // Login
133
138
  auth.login({ email, password }).subscribe({
134
139
  next: () => router.navigate(['/dashboard']),
135
- error: (err) => console.error(err)
140
+ error: (err) => console.error(err),
136
141
  });
137
142
 
138
143
  // Check auth state (reactive)
139
- auth.isAuthenticated$.subscribe(isAuth => {
144
+ auth.isAuthenticated$.subscribe((isAuth) => {
140
145
  console.log('Authenticated:', isAuth);
141
146
  });
142
147
 
@@ -145,6 +150,7 @@ auth.logout();
145
150
  \`\`\`
146
151
 
147
152
  ### LoadingService
153
+
148
154
  \`\`\`typescript
149
155
  import { inject } from '@angular/core';
150
156
  import { LoadingService } from '@core/services/loading.service';
@@ -165,6 +171,7 @@ loading.hide();
165
171
  ## 📝 Coding Patterns
166
172
 
167
173
  ### Component Structure (Standalone)
174
+
168
175
  \`\`\`typescript
169
176
  import { Component, inject, signal } from '@angular/core';
170
177
  import { CommonModule } from '@angular/common';
@@ -175,15 +182,16 @@ import { ToastService } from '@core/services/toast.service';
175
182
  standalone: true,
176
183
  imports: [CommonModule],
177
184
  template: \`
178
- <div class="p-6 bg-white rounded-lg shadow">
179
- <h2 class="text-xl font-bold mb-4">{{ title() }}</h2>
185
+ <div class="rounded-lg bg-white p-6 shadow">
186
+ <h2 class="mb-4 text-xl font-bold">{{ title() }}</h2>
180
187
  <button
181
188
  (click)="handleClick()"
182
- class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
189
+ class="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
190
+ >
183
191
  Click Me ({{ count() }})
184
192
  </button>
185
193
  </div>
186
- \`
194
+ \`,
187
195
  })
188
196
  export class ExampleComponent {
189
197
  private toast = inject(ToastService);
@@ -193,13 +201,14 @@ export class ExampleComponent {
193
201
  count = signal(0);
194
202
 
195
203
  handleClick(): void {
196
- this.count.update(n => n + 1);
204
+ this.count.update((n) => n + 1);
197
205
  this.toast.success(\`Clicked \${this.count()} times\`);
198
206
  }
199
207
  }
200
208
  \`\`\`
201
209
 
202
210
  ### Service Creation
211
+
203
212
  \`\`\`typescript
204
213
  import { Injectable, inject, signal } from '@angular/core';
205
214
  import { ApiService } from '@core/services/api.service';
@@ -224,13 +233,14 @@ export class ItemService {
224
233
  this.items.set(data);
225
234
  this.loading.set(false);
226
235
  },
227
- error: () => this.loading.set(false)
236
+ error: () => this.loading.set(false),
228
237
  });
229
238
  }
230
239
  }
231
240
  \`\`\`
232
241
 
233
242
  ### Reactive Forms
243
+
234
244
  \`\`\`typescript
235
245
  import { Component, inject } from '@angular/core';
236
246
  import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@@ -241,29 +251,27 @@ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
241
251
  imports: [ReactiveFormsModule],
242
252
  template: \`
243
253
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
244
- <input formControlName="email" class="border p-2 rounded" />
254
+ <input formControlName="email" class="rounded border p-2" />
245
255
  @if (form.get('email')?.invalid && form.get('email')?.touched) {
246
- <span class="text-red-500 text-sm">Email is required</span>
256
+ <span class="text-sm text-red-500">Email is required</span>
247
257
  }
248
- <button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded">
249
- Submit
250
- </button>
258
+ <button type="submit" class="rounded bg-blue-500 px-4 py-2 text-white">Submit</button>
251
259
  </form>
252
- \`
260
+ \`,
253
261
  })
254
262
  export class ContactFormComponent {
255
263
  private fb = inject(FormBuilder);
256
264
 
257
265
  form = this.fb.group({
258
266
  email: ['', [Validators.required, Validators.email]],
259
- message: ['', [Validators.required, Validators.minLength(10)]]
267
+ message: ['', [Validators.required, Validators.minLength(10)]],
260
268
  });
261
269
 
262
270
  onSubmit(): void {
263
271
  if (this.form.valid) {
264
272
  console.log(this.form.value);
265
273
  } else {
266
- Object.keys(this.form.controls).forEach(key => {
274
+ Object.keys(this.form.controls).forEach((key) => {
267
275
  this.form.get(key)?.markAsTouched();
268
276
  });
269
277
  }
@@ -272,6 +280,7 @@ export class ContactFormComponent {
272
280
  \`\`\`
273
281
 
274
282
  ### Routing with Lazy Loading
283
+
275
284
  \`\`\`typescript
276
285
  import { Routes } from '@angular/router';
277
286
  import { authGuard } from '@core/guards/auth.guard';
@@ -279,15 +288,14 @@ import { authGuard } from '@core/guards/auth.guard';
279
288
  export const routes: Routes = [
280
289
  {
281
290
  path: '',
282
- loadComponent: () => import('./features/home/home.component')
283
- .then(c => c.HomeComponent)
291
+ loadComponent: () => import('./features/home/home.component').then((c) => c.HomeComponent),
284
292
  },
285
293
  {
286
294
  path: 'dashboard',
287
- loadComponent: () => import('./features/dashboard/dashboard.component')
288
- .then(c => c.DashboardComponent),
289
- canActivate: [authGuard]
290
- }
295
+ loadComponent: () =>
296
+ import('./features/dashboard/dashboard.component').then((c) => c.DashboardComponent),
297
+ canActivate: [authGuard],
298
+ },
291
299
  ];
292
300
  \`\`\`
293
301
 
@@ -296,26 +304,33 @@ export const routes: Routes = [
296
304
  **Always use Tailwind CSS classes. Do NOT write custom CSS.**
297
305
 
298
306
  Common patterns:
307
+
299
308
  \`\`\`html
300
309
  <!-- Layout -->
301
310
  <div class="container mx-auto px-4">
302
- <div class="flex items-center justify-between">
303
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
304
-
305
- <!-- Spacing -->
306
- <div class="p-4 mt-6 space-y-4">
307
-
308
- <!-- Colors -->
309
- <div class="bg-blue-500 text-white">
310
- <button class="bg-gray-100 hover:bg-gray-200 text-gray-900">
311
-
312
- <!-- Typography -->
313
- <h1 class="text-3xl font-bold">
314
- <p class="text-sm text-gray-600">
315
-
316
- <!-- Responsive -->
317
- <div class="hidden md:block">
318
- <div class="w-full md:w-1/2 lg:w-1/3">
311
+ <div class="flex items-center justify-between">
312
+ <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
313
+ <!-- Spacing -->
314
+ <div class="mt-6 space-y-4 p-4">
315
+ <!-- Colors -->
316
+ <div class="bg-blue-500 text-white">
317
+ <button class="bg-gray-100 text-gray-900 hover:bg-gray-200">
318
+ <!-- Typography -->
319
+ <h1 class="text-3xl font-bold">
320
+ <p class="text-sm text-gray-600">
321
+ <!-- Responsive -->
322
+ </p>
323
+
324
+ <div class="hidden md:block">
325
+ <div class="w-full md:w-1/2 lg:w-1/3"></div>
326
+ </div>
327
+ </h1>
328
+ </button>
329
+ </div>
330
+ </div>
331
+ </div>
332
+ </div>
333
+ </div>
319
334
  \`\`\`
320
335
 
321
336
  ## 🌍 Internationalization (i18n)
@@ -323,16 +338,19 @@ Common patterns:
323
338
  Support English and Arabic with RTL:
324
339
 
325
340
  **Add translations to both files:**
341
+
326
342
  - \`public/assets/i18n/en.json\`
327
343
  - \`public/assets/i18n/ar.json\`
328
344
 
329
345
  **In templates:**
346
+
330
347
  \`\`\`html
331
348
  <h1>{{ 'welcome.title' | translate }}</h1>
332
349
  <button>{{ 'common.save' | translate }}</button>
333
350
  \`\`\`
334
351
 
335
352
  **In components:**
353
+
336
354
  \`\`\`typescript
337
355
  import { inject } from '@angular/core';
338
356
  import { TranslateService } from '@ngx-translate/core';
@@ -379,6 +397,7 @@ const message = translate.instant('error.notFound');
379
397
  ## 🧪 Testing
380
398
 
381
399
  Write unit tests using Jasmine/Karma:
400
+
382
401
  \`\`\`typescript
383
402
  describe('ExampleComponent', () => {
384
403
  let component: ExampleComponent;
@@ -386,7 +405,7 @@ describe('ExampleComponent', () => {
386
405
 
387
406
  beforeEach(() => {
388
407
  TestBed.configureTestingModule({
389
- imports: [ExampleComponent]
408
+ imports: [ExampleComponent],
390
409
  });
391
410
  fixture = TestBed.createComponent(ExampleComponent);
392
411
  component = fixture.componentInstance;
@@ -416,8 +435,8 @@ describe('ExampleComponent', () => {
416
435
  const claudeDir = path.join(projectPath, ".claude");
417
436
  await fs.ensureDir(claudeDir);
418
437
 
419
- // Write claude.md inside .claude folder
420
- await fs.writeFile(path.join(claudeDir, "claude.md"), claudeMd);
438
+ // Write CLAUDE.md inside .claude folder (uppercase to match Angular CLI convention)
439
+ await fs.writeFile(path.join(claudeDir, "CLAUDE.md"), claudeMd);
421
440
  }
422
441
 
423
442
  // ==================== CURSOR-SPECIFIC CONFIG ====================
@@ -426,6 +445,7 @@ async function createCursorConfig(projectPath, projectName) {
426
445
  const cursorRules = `# ${projectName} - Cursor AI Rules
427
446
 
428
447
  ## Quick Reference
448
+
429
449
  - Angular 20+ standalone components
430
450
  - Tailwind CSS v4 (use utility classes only)
431
451
  - inject() for DI (not constructors)
@@ -433,6 +453,7 @@ async function createCursorConfig(projectPath, projectName) {
433
453
  - Path aliases: @core/, @shared/, @features/, @environments/
434
454
 
435
455
  ## Component Pattern
456
+
436
457
  \`\`\`typescript
437
458
  import { Component, inject, signal } from '@angular/core';
438
459
  import { CommonModule } from '@angular/common';
@@ -441,7 +462,7 @@ import { CommonModule } from '@angular/common';
441
462
  selector: 'app-name',
442
463
  standalone: true,
443
464
  imports: [CommonModule],
444
- template: \`<div class="p-4">{{ text() }}</div>\`
465
+ template: \`<div class="p-4">{{ text() }}</div>\`,
445
466
  })
446
467
  export class NameComponent {
447
468
  private service = inject(ServiceName);
@@ -450,6 +471,7 @@ export class NameComponent {
450
471
  \`\`\`
451
472
 
452
473
  ## Available Services (Use These!)
474
+
453
475
  - **ToastService** - \`toast.success('Message')\`
454
476
  - **ModalService** - \`await modal.confirm('Message')\`
455
477
  - **ApiService** - \`api.get<Type>('endpoint')\`
@@ -457,31 +479,37 @@ export class NameComponent {
457
479
  - **LoadingService** - \`loading.isLoading()\`
458
480
 
459
481
  ## HTTP Interceptors (Automatic)
482
+
460
483
  Auth → Cache → Loading → Error
461
484
 
462
485
  ## Forms: Use Reactive Forms
486
+
463
487
  \`\`\`typescript
464
488
  form = inject(FormBuilder).group({
465
- email: ['', [Validators.required, Validators.email]]
489
+ email: ['', [Validators.required, Validators.email]],
466
490
  });
467
491
  \`\`\`
468
492
 
469
493
  ## Routing: Use Lazy Loading
494
+
470
495
  \`\`\`typescript
471
496
  {
472
497
  path: 'feature',
473
- loadComponent: () => import('./feature/feature.component')
474
- .then(c => c.FeatureComponent)
498
+ loadComponent: () =>
499
+ import('./feature/feature.component').then((c) => c.FeatureComponent),
475
500
  }
476
501
  \`\`\`
477
502
 
478
503
  ## Styling: Tailwind Only
479
- Use: \`bg-blue-500 text-white p-4 rounded hover:bg-blue-600\`
504
+
505
+ Use: \`rounded bg-blue-500 p-4 text-white hover:bg-blue-600\`
480
506
 
481
507
  ## i18n: Support English + Arabic
508
+
482
509
  Add keys to \`public/assets/i18n/en.json\` and \`ar.json\`
483
510
 
484
511
  ## Don't
512
+
485
513
  - No NgModule
486
514
  - No constructor injection
487
515
  - No custom CSS
@@ -502,13 +530,14 @@ Angular 20+ | Tailwind CSS v4 | Standalone Components | Signals
502
530
 
503
531
  ## Quick Patterns
504
532
 
505
- Component:
533
+ **Component:**
534
+
506
535
  \`\`\`typescript
507
536
  @Component({
508
537
  selector: 'app-name',
509
538
  standalone: true,
510
539
  imports: [CommonModule],
511
- template: \`<div class="p-4">{{ state() }}</div>\`
540
+ template: \`<div class="p-4">{{ state() }}</div>\`,
512
541
  })
513
542
  export class NameComponent {
514
543
  private svc = inject(Service);
@@ -516,44 +545,54 @@ export class NameComponent {
516
545
  }
517
546
  \`\`\`
518
547
 
519
- Show Toast:
548
+ **Show Toast:**
549
+
520
550
  \`\`\`typescript
521
551
  inject(ToastService).success('Message');
522
552
  \`\`\`
523
553
 
524
- Open Modal:
554
+ **Open Modal:**
555
+
525
556
  \`\`\`typescript
526
557
  await inject(ModalService).confirm('Message');
527
558
  \`\`\`
528
559
 
529
- API Call:
560
+ **API Call:**
561
+
530
562
  \`\`\`typescript
531
563
  inject(ApiService).get<Type>('endpoint').subscribe(...);
532
564
  \`\`\`
533
565
 
534
- Form:
566
+ **Form:**
567
+
535
568
  \`\`\`typescript
536
569
  form = inject(FormBuilder).group({
537
- field: ['', Validators.required]
570
+ field: ['', Validators.required],
538
571
  });
539
572
  \`\`\`
540
573
 
541
574
  ## Path Aliases
575
+
542
576
  @core/ @shared/ @features/ @environments/
543
577
 
544
578
  ## Services Available
579
+
545
580
  ToastService, ModalService, ApiService, AuthService, LoadingService, CacheService
546
581
 
547
582
  ## HTTP Interceptors (Auto)
583
+
548
584
  Auth → Cache → Loading → Error
549
585
 
550
586
  ## Styling
551
- Tailwind only: bg-blue-500 text-white p-4 rounded
587
+
588
+ Tailwind only: rounded bg-blue-500 p-4 text-white
552
589
 
553
590
  ## i18n
591
+
554
592
  public/assets/i18n/en.json + ar.json
555
593
 
556
594
  ## Don't
595
+
557
596
  No NgModule, No constructors, No custom CSS, No 'any', No src/assets
558
597
  `;
559
598
 
@@ -585,7 +624,7 @@ async function createAIConfigs(projectPath, projectName, aiTools) {
585
624
  // Create tool-specific configs only if selected
586
625
  if (aiTools.includes("claude")) {
587
626
  await createClaudeConfig(projectPath, projectName);
588
- console.log(" ✓ .claude/claude.md created");
627
+ console.log(" ✓ .claude/CLAUDE.md created");
589
628
  }
590
629
 
591
630
  if (aiTools.includes("cursor")) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-ng-tailwind",
3
- "version": "2.0.2",
4
- "description": "🚀 Create Angular projects with Tailwind CSS in seconds - Zero configuration, modern setup, beautiful starter templates",
3
+ "version": "2.1.1",
4
+ "description": "🚀 A CLI tool to give starter template for angular project with tailwind css",
5
5
  "main": "bin/create-ng-tailwind.js",
6
6
  "bin": {
7
7
  "create-ng-tailwind": "./bin/create-ng-tailwind.js"
@@ -53,8 +53,7 @@
53
53
  "lib/",
54
54
  "README.md",
55
55
  "LICENSE",
56
- "CHANGELOG.md",
57
- "CLAUDE.md"
56
+ "CHANGELOG.md"
58
57
  ],
59
58
  "dependencies": {
60
59
  "chalk": "^4.1.2",
package/CLAUDE.md DELETED
@@ -1,178 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- `create-ng-tailwind` is a CLI tool that scaffolds Angular projects with Tailwind CSS preconfigured. It wraps the Angular CLI (`ng new`) and adds Tailwind v4 setup, templates, and best practices. The tool operates in two modes:
8
-
9
- 1. **Interactive Mode (Default)**: Prompts users for configuration like `ng new` does
10
- 2. **Fast Mode**: Accepts all options via CLI flags for CI/CD workflows
11
-
12
- ## Architecture
13
-
14
- The codebase follows a modular architecture with clear separation of concerns:
15
-
16
- ### Core Components
17
-
18
- 1. **CLI Layer** (`lib/cli/`)
19
- - `index.js`: Main CLI handler - parses arguments, orchestrates interactive prompts, delegates to ProjectManager
20
- - `interactive.js`: Interactive prompt logic
21
- - `validators.js`: Input validation utilities
22
-
23
- 2. **Manager Layer** (`lib/managers/`)
24
- - `ProjectManager.js`: Orchestrates project creation - wraps `ng new`, coordinates TailwindManager and TemplateManager
25
- - `TailwindManager.js`: Handles Tailwind v4 installation and PostCSS configuration
26
- - `TemplateManager.js`: Applies selected template to the project
27
-
28
- 3. **Template System** (`lib/templates/`)
29
- - `minimal/`: Minimal template (just Angular + Tailwind)
30
- - `starter/`: Professional foundation with components, routing, i18n, auth UI, services, interceptors, etc.
31
- - Templates export an `apply(config)` async function that modifies the generated Angular project
32
-
33
- 4. **Utilities** (`lib/utils/`)
34
- - `logger.js`: Styled CLI output with ora spinners
35
- - `helpers.js`: Shared utility functions
36
- - `constants.js`: Configuration constants
37
-
38
- ### Key Workflow
39
-
40
- ```
41
- bin/create-ng-tailwind.js → lib/cli/index.js → lib/managers/ProjectManager.js
42
- ├─> lib/managers/TailwindManager.js
43
- └─> lib/managers/TemplateManager.js
44
- └─> lib/templates/{minimal|starter}/index.js
45
- ```
46
-
47
- ## Development Commands
48
-
49
- ```bash
50
- # Test locally during development
51
- npm run dev my-test-app
52
-
53
- # Test with CLI flags (skip prompts for fast testing)
54
- npm run dev my-app -- --template=starter
55
-
56
- # Test interactive mode (will prompt for all options)
57
- npm run dev my-app
58
-
59
- # Quick demo
60
- npm run demo
61
-
62
- # Link for global testing
63
- npm link
64
- create-ng-tailwind test-app
65
-
66
- # Unlink when done testing
67
- npm unlink -g create-ng-tailwind
68
- ```
69
-
70
- ## Key Technical Details
71
-
72
- ### Tailwind v4 Setup
73
-
74
- The tool uses Tailwind v4's modern PostCSS plugin approach:
75
- - `.postcssrc.json` with `@tailwindcss/postcss` plugin
76
- - `styles.css` with `@import "tailwindcss";` directive
77
- - Dependencies: `tailwindcss`, `@tailwindcss/postcss`, `postcss`
78
-
79
- ### Angular CLI Integration
80
-
81
- The tool passes configuration to `ng new`:
82
- - `--routing`: Enable/disable routing (default: true)
83
- - `--style=css`: Always uses CSS (Tailwind v4 official approach, no preprocessors)
84
- - `--ssr`: Server-Side Rendering
85
- - `--zoneless`: Create zoneless app
86
- - `--ai-config`: AI tool configurations (multiple flags supported)
87
- - Always uses: `--skip-git --package-manager=npm --interactive=false`
88
-
89
- ### Starter Template Features
90
-
91
- The starter template (`lib/templates/starter/`) includes:
92
- - Standalone Angular 20+ architecture with signals
93
- - **i18n System**: Full internationalization with English/Arabic translations
94
- - RTL (Right-to-Left) support for Arabic
95
- - Language switcher in header (desktop & mobile)
96
- - Uses `@ngx-translate/core` and `@ngx-translate/http-loader`
97
- - Translation files in `public/assets/i18n/`
98
- - Auto-detects browser language with localStorage persistence
99
- - **Layout System**:
100
- - Main layout (header with navigation + footer)
101
- - Auth layout (for login/register pages)
102
- - **Shared Components**: Button, Card, LoadingSpinner (with Tailwind styling)
103
- - **Auth UI Pages**: Login, Register, Forgot Password (with form validation)
104
- - **Example Pages**: Home, About, Contact (with reactive forms and validation)
105
- - **Core Services**: API service, Auth service, i18n service, Translation service
106
- - **Routing**: Auth guards, lazy loading examples
107
- - **TypeScript**: Models, interfaces, strongly-typed services
108
- - **Assets**: Organized in `public/assets/` (images, i18n, icons)
109
- - **Path Aliases**: `@core`, `@shared`, `@features` configured in tsconfig.json
110
-
111
- ## File Locations
112
-
113
- - **CLI entry point**: `bin/create-ng-tailwind.js` - Minimal wrapper that instantiates CLIHandler
114
- - **Main package config**: `package.json`
115
- - **Library code**: `lib/` (modular architecture)
116
- - `lib/cli/index.js` - Main CLIHandler class
117
- - `lib/managers/` - ProjectManager, TailwindManager, TemplateManager
118
- - `lib/templates/` - Template definitions (minimal, starter)
119
- - `lib/utils/` - Logger, helpers, constants
120
- - **Generated projects**: Use `public/assets/` for assets (Angular 17+ convention, not `src/assets/`)
121
-
122
- ## Publishing
123
-
124
- Before publishing:
125
- 1. Update version in `package.json`
126
- 2. Update `CHANGELOG.md`
127
- 3. Run `npm publish`
128
-
129
- See `PUBLISHING.md` for detailed publishing instructions.
130
-
131
- ## Common Development Patterns
132
-
133
- ### Adding a New Template
134
-
135
- 1. Create `lib/templates/your-template/index.js`
136
- 2. Export an object with an `apply(config)` async function:
137
- ```javascript
138
- module.exports = {
139
- async apply(config) {
140
- // config contains: projectName, template, style (always "css"), routing, ssr, zoneless, aiConfig, skipInstall, fullPath
141
- // Modify the generated Angular project here
142
- }
143
- };
144
- ```
145
- 3. Register in `lib/templates/index.js`
146
- 4. Update CLI prompt choices in `lib/cli/index.js:getTemplateChoice()`
147
-
148
- ### Modifying Angular CLI Behavior
149
-
150
- Edit `lib/managers/ProjectManager.js:createAngularProject()` to adjust the `ng new` command construction. The method builds a command string with flags based on config options.
151
-
152
- ### Changing Tailwind Configuration
153
-
154
- - **PostCSS setup**: Edit `lib/managers/TailwindManager.js:createPostCSSConfig()`
155
- - **Stylesheet imports**: Edit `lib/managers/TailwindManager.js:updateStyles()`
156
- - **Version/dependencies**: Edit `TailwindManager.js:addTailwindToPackageJson()`
157
-
158
- ### Adding CLI Options
159
-
160
- 1. Add option to `lib/cli/index.js:parseOptions()` using commander
161
- 2. Add prompt in appropriate method (e.g., `getConfigurationOptions()`)
162
- 3. Include in config object in `buildConfiguration()`
163
- 4. Use in managers or templates via `config` parameter
164
-
165
- ## Important Constraints and Best Practices
166
-
167
- - **Node.js 18+** required (specified in package.json engines)
168
- - **Angular CLI**: Relies on `@angular/cli@latest` being available via npx
169
- - **Module System**: Uses CommonJS (not ESM) for Node.js compatibility
170
- - **Tailwind v4 Dependencies**: Must be in `dependencies`, NOT `devDependencies` (required at runtime)
171
- - **CSS-Only Approach**: Only CSS is supported (Tailwind v4 no longer supports SCSS/Sass/Less preprocessors due to LightningCSS)
172
- - **CLI Output**: All user-facing messages must use the Logger utility (`lib/utils/logger.js`) for consistent styling with chalk, ora spinners, and inquirer prompts
173
- - **Stylesheet Format**: Always uses CSS (`config.style` is always `"css"`) - `TailwindManager.js:updateStyles()` writes to `styles.css`
174
- - **Interactive Mode**: Default behavior - CLI prompts for options not provided via flags
175
- - **Fast Mode**: All prompts can be skipped by providing complete CLI flags
176
- - **AI Config**: Handled by Angular CLI's `--ai-config` flag, our CLI just passes it through (supports multiple tools)
177
- - **Assets Location**: Generated projects use `public/assets/` (Angular 17+ convention), not `src/assets/`
178
- - **Angular v20 ESLint Fix**: The starter template's ESLint config includes `"suffixes": ["Component", "App"]` for the `@angular-eslint/component-class-suffix` rule to support Angular v20's new `app.ts` naming convention (class `App` instead of `AppComponent`)