@iconsulting-dev/forgekit 1.1.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 (110) hide show
  1. package/README.md +203 -0
  2. package/dist/commands/new.d.ts +3 -0
  3. package/dist/commands/new.d.ts.map +1 -0
  4. package/dist/commands/new.js +120 -0
  5. package/dist/commands/new.js.map +1 -0
  6. package/dist/config.d.ts +4 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +21 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/generators/backend/index.d.ts +4 -0
  11. package/dist/generators/backend/index.d.ts.map +1 -0
  12. package/dist/generators/backend/index.js +69 -0
  13. package/dist/generators/backend/index.js.map +1 -0
  14. package/dist/generators/base-generator.d.ts +9 -0
  15. package/dist/generators/base-generator.d.ts.map +1 -0
  16. package/dist/generators/base-generator.js +13 -0
  17. package/dist/generators/base-generator.js.map +1 -0
  18. package/dist/generators/ci/index.d.ts +3 -0
  19. package/dist/generators/ci/index.d.ts.map +1 -0
  20. package/dist/generators/ci/index.js +18 -0
  21. package/dist/generators/ci/index.js.map +1 -0
  22. package/dist/generators/claude-code/index.d.ts +4 -0
  23. package/dist/generators/claude-code/index.d.ts.map +1 -0
  24. package/dist/generators/claude-code/index.js +47 -0
  25. package/dist/generators/claude-code/index.js.map +1 -0
  26. package/dist/generators/docker/index.d.ts +3 -0
  27. package/dist/generators/docker/index.d.ts.map +1 -0
  28. package/dist/generators/docker/index.js +14 -0
  29. package/dist/generators/docker/index.js.map +1 -0
  30. package/dist/generators/frontend/index.d.ts +4 -0
  31. package/dist/generators/frontend/index.d.ts.map +1 -0
  32. package/dist/generators/frontend/index.js +60 -0
  33. package/dist/generators/frontend/index.js.map +1 -0
  34. package/dist/generators/git.d.ts +2 -0
  35. package/dist/generators/git.d.ts.map +1 -0
  36. package/dist/generators/git.js +16 -0
  37. package/dist/generators/git.js.map +1 -0
  38. package/dist/generators/root/index.d.ts +4 -0
  39. package/dist/generators/root/index.d.ts.map +1 -0
  40. package/dist/generators/root/index.js +29 -0
  41. package/dist/generators/root/index.js.map +1 -0
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +11 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/prompts/project.d.ts +3 -0
  47. package/dist/prompts/project.d.ts.map +1 -0
  48. package/dist/prompts/project.js +70 -0
  49. package/dist/prompts/project.js.map +1 -0
  50. package/dist/templates/backend/ApiError.java.hbs +4 -0
  51. package/dist/templates/backend/Application.java.hbs +12 -0
  52. package/dist/templates/backend/ApplicationTests.java.hbs +12 -0
  53. package/dist/templates/backend/GlobalExceptionHandler.java.hbs +27 -0
  54. package/dist/templates/backend/OpenApiConfig.java.hbs +19 -0
  55. package/dist/templates/backend/PageResponse.java.hbs +12 -0
  56. package/dist/templates/backend/SecurityConfig.java.hbs +43 -0
  57. package/dist/templates/backend/application-dev.yml.hbs +7 -0
  58. package/dist/templates/backend/application.yml.hbs +37 -0
  59. package/dist/templates/backend/gitignore.hbs +16 -0
  60. package/dist/templates/backend/maven-wrapper.properties.hbs +2 -0
  61. package/dist/templates/backend/mvnw.cmd.hbs +4 -0
  62. package/dist/templates/backend/mvnw.hbs +17 -0
  63. package/dist/templates/backend/pom.xml.hbs +136 -0
  64. package/dist/templates/ci/ci.yml.hbs +87 -0
  65. package/dist/templates/claude-code/CLAUDE.md.hbs +79 -0
  66. package/dist/templates/claude-code/settings.json.hbs +9 -0
  67. package/dist/templates/docker/docker-compose.yml.hbs +34 -0
  68. package/dist/templates/frontend/angular.json.hbs +71 -0
  69. package/dist/templates/frontend/app.component.ts.hbs +11 -0
  70. package/dist/templates/frontend/app.config.ts.hbs +16 -0
  71. package/dist/templates/frontend/app.routes.ts.hbs +14 -0
  72. package/dist/templates/frontend/auth.guard.ts.hbs +14 -0
  73. package/dist/templates/frontend/auth.interceptor.ts.hbs +13 -0
  74. package/dist/templates/frontend/auth.service.ts.hbs +18 -0
  75. package/dist/templates/frontend/environment.development.ts.hbs +4 -0
  76. package/dist/templates/frontend/environment.ts.hbs +4 -0
  77. package/dist/templates/frontend/error.interceptor.ts.hbs +14 -0
  78. package/dist/templates/frontend/gitignore.hbs +4 -0
  79. package/dist/templates/frontend/index.html.hbs +13 -0
  80. package/dist/templates/frontend/layout.component.ts.hbs +42 -0
  81. package/dist/templates/frontend/main.ts.hbs +6 -0
  82. package/dist/templates/frontend/package.json.hbs +35 -0
  83. package/dist/templates/frontend/sidebar.component.ts.hbs +58 -0
  84. package/dist/templates/frontend/styles.scss.hbs +8 -0
  85. package/dist/templates/frontend/topbar.component.ts.hbs +59 -0
  86. package/dist/templates/frontend/tsconfig.app.json.hbs +13 -0
  87. package/dist/templates/frontend/tsconfig.json.hbs +24 -0
  88. package/dist/templates/root/README.md.hbs +37 -0
  89. package/dist/templates/root/gitignore.hbs +12 -0
  90. package/dist/types.d.ts +15 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +2 -0
  93. package/dist/types.js.map +1 -0
  94. package/dist/utils/__tests__/validation.test.d.ts +2 -0
  95. package/dist/utils/__tests__/validation.test.d.ts.map +1 -0
  96. package/dist/utils/__tests__/validation.test.js +59 -0
  97. package/dist/utils/__tests__/validation.test.js.map +1 -0
  98. package/dist/utils/template-engine.d.ts +5 -0
  99. package/dist/utils/template-engine.d.ts.map +1 -0
  100. package/dist/utils/template-engine.js +23 -0
  101. package/dist/utils/template-engine.js.map +1 -0
  102. package/dist/utils/validation.d.ts +3 -0
  103. package/dist/utils/validation.d.ts.map +1 -0
  104. package/dist/utils/validation.js +19 -0
  105. package/dist/utils/validation.js.map +1 -0
  106. package/dist/versions.d.ts +18 -0
  107. package/dist/versions.d.ts.map +1 -0
  108. package/dist/versions.js +91 -0
  109. package/dist/versions.js.map +1 -0
  110. package/package.json +60 -0
@@ -0,0 +1,87 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+
9
+ jobs:
10
+ changes:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ pull-requests: read
14
+ outputs:
15
+ {{#if backend}}
16
+ backend: $\{{ steps.filter.outputs.backend }}
17
+ {{/if}}
18
+ {{#if frontend}}
19
+ frontend: $\{{ steps.filter.outputs.frontend }}
20
+ {{/if}}
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: dorny/paths-filter@v3
24
+ id: filter
25
+ with:
26
+ filters: |
27
+ {{#if backend}}
28
+ backend:
29
+ - 'backend/**'
30
+ {{/if}}
31
+ {{#if frontend}}
32
+ frontend:
33
+ - 'frontend/**'
34
+ {{/if}}
35
+
36
+ {{#if backend}}
37
+ backend:
38
+ needs: changes
39
+ if: needs.changes.outputs.backend == 'true'
40
+ runs-on: ubuntu-latest
41
+ defaults:
42
+ run:
43
+ working-directory: backend
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+
47
+ - name: Set up Java 21
48
+ uses: actions/setup-java@v4
49
+ with:
50
+ distribution: corretto
51
+ java-version: '21'
52
+ cache: maven
53
+
54
+ - name: Build & Test
55
+ run: ./mvnw verify --batch-mode --no-transfer-progress
56
+ {{/if}}
57
+
58
+ {{#if frontend}}
59
+ frontend:
60
+ needs: changes
61
+ if: needs.changes.outputs.frontend == 'true'
62
+ runs-on: ubuntu-latest
63
+ defaults:
64
+ run:
65
+ working-directory: frontend
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+
69
+ - name: Set up Node 22
70
+ uses: actions/setup-node@v4
71
+ with:
72
+ node-version: '22'
73
+ cache: npm
74
+ cache-dependency-path: frontend/package-lock.json
75
+
76
+ - name: Install dependencies
77
+ run: npm ci
78
+
79
+ - name: Lint
80
+ run: npm run lint
81
+
82
+ - name: Test
83
+ run: npm run test -- --watch=false --browsers=ChromeHeadless
84
+
85
+ - name: Build
86
+ run: npm run build
87
+ {{/if}}
@@ -0,0 +1,79 @@
1
+ # {{name}}
2
+
3
+ {{description}}
4
+
5
+ ## Project Structure
6
+
7
+ ```
8
+ {{name}}/
9
+ {{#if backend}}
10
+ ├── backend/ # Spring Boot API
11
+ {{/if}}
12
+ {{#if frontend}}
13
+ ├── frontend/ # Angular SPA
14
+ {{/if}}
15
+ {{#if docker}}
16
+ ├── docker-compose.yml
17
+ {{/if}}
18
+ └── README.md
19
+ ```
20
+
21
+ {{#if backend}}
22
+ ## Backend — Spring Boot {{versions.springBoot}}
23
+
24
+ - **Java 21** with records, pattern matching, sealed classes
25
+ - **Architecture:** Feature-based package structure
26
+ - **DB:** PostgreSQL, Flyway migrations in `backend/src/main/resources/db/migration/`
27
+ - **Conventions:** Records for DTOs, Lombok where useful, MapStruct for mappings
28
+ - **Validation:** Jakarta Bean Validation
29
+ - **Logging:** SLF4J
30
+
31
+ ### Commands
32
+
33
+ ```bash
34
+ cd backend
35
+ ./mvnw spring-boot:run # Start dev server
36
+ ./mvnw test # Run tests
37
+ ./mvnw package -DskipTests # Build JAR
38
+ ```
39
+
40
+ {{/if}}
41
+ {{#if frontend}}
42
+ ## Frontend — Angular
43
+
44
+ - **Angular {{versions.angular}}** with strict mode, standalone components, signals
45
+ - **UI:** PrimeNG {{versions.primeng}}, theme Aura, PrimeFlex
46
+ - **State:** NgRx SignalStore
47
+ - **Conventions:** OnPush change detection, `input()`/`output()` functions, `inject()` for DI
48
+ - **Control flow:** `@if`, `@for` (not *ngIf/*ngFor)
49
+ - **Indentation:** 2 spaces
50
+
51
+ ### Commands
52
+
53
+ ```bash
54
+ cd frontend
55
+ npm install # Install dependencies
56
+ ng serve # Start dev server (port 4200)
57
+ ng build # Production build
58
+ ng test # Run tests
59
+ ```
60
+
61
+ {{/if}}
62
+ {{#if docker}}
63
+ ## Infrastructure
64
+
65
+ ```bash
66
+ docker compose up -d # Start PostgreSQL + pgAdmin
67
+ docker compose down # Stop services
68
+ ```
69
+
70
+ - **PostgreSQL:** localhost:5432
71
+ - **pgAdmin:** localhost:5050 (admin@admin.com / admin)
72
+
73
+ {{/if}}
74
+ ## Conventions
75
+
76
+ - **Git:** Conventional commits (`feat:`, `fix:`, `refactor:`, `chore:`)
77
+ - **Branches:** `feature/`, `fix/`, `refactor/`, `chore/`
78
+ - **DB:** snake_case naming
79
+ - **Security:** Never commit secrets, use environment variables
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ {{#each allowedCommands}}
5
+ "{{this}}"{{#unless @last}},{{/unless}}
6
+ {{/each}}
7
+ ]
8
+ }
9
+ }
@@ -0,0 +1,34 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:17
4
+ container_name: {{dbName}}_postgres
5
+ restart: unless-stopped
6
+ environment:
7
+ POSTGRES_DB: {{dbName}}
8
+ POSTGRES_USER: postgres
9
+ POSTGRES_PASSWORD: postgres
10
+ ports:
11
+ - "5432:5432"
12
+ volumes:
13
+ - postgres_data:/var/lib/postgresql/data
14
+ healthcheck:
15
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
16
+ interval: 10s
17
+ timeout: 5s
18
+ retries: 5
19
+
20
+ pgadmin:
21
+ image: dpage/pgadmin4:latest
22
+ container_name: {{dbName}}_pgadmin
23
+ restart: unless-stopped
24
+ environment:
25
+ PGADMIN_DEFAULT_EMAIL: admin@admin.com
26
+ PGADMIN_DEFAULT_PASSWORD: admin
27
+ ports:
28
+ - "5050:80"
29
+ depends_on:
30
+ postgres:
31
+ condition: service_healthy
32
+
33
+ volumes:
34
+ postgres_data:
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+ "version": 1,
4
+ "newProjectRoot": "projects",
5
+ "projects": {
6
+ "{{projectName}}": {
7
+ "projectType": "application",
8
+ "root": "",
9
+ "sourceRoot": "src",
10
+ "prefix": "app",
11
+ "architect": {
12
+ "build": {
13
+ "builder": "@angular/build:application",
14
+ "options": {
15
+ "outputPath": "dist/{{projectName}}",
16
+ "index": "src/index.html",
17
+ "browser": "src/main.ts",
18
+ "tsConfig": "tsconfig.app.json",
19
+ "inlineStyleLanguage": "scss",
20
+ "styles": [
21
+ "node_modules/primeicons/primeicons.css",
22
+ "node_modules/primeflex/primeflex.css",
23
+ "src/styles.scss"
24
+ ]
25
+ },
26
+ "configurations": {
27
+ "production": {
28
+ "budgets": [
29
+ {
30
+ "type": "initial",
31
+ "maximumWarning": "500kB",
32
+ "maximumError": "1MB"
33
+ },
34
+ {
35
+ "type": "anyComponentStyle",
36
+ "maximumWarning": "4kB",
37
+ "maximumError": "8kB"
38
+ }
39
+ ],
40
+ "outputHashing": "all"
41
+ },
42
+ "development": {
43
+ "optimization": false,
44
+ "extractLicenses": false,
45
+ "sourceMap": true,
46
+ "fileReplacements": [
47
+ {
48
+ "replace": "src/environments/environment.ts",
49
+ "with": "src/environments/environment.development.ts"
50
+ }
51
+ ]
52
+ }
53
+ },
54
+ "defaultConfiguration": "production"
55
+ },
56
+ "serve": {
57
+ "builder": "@angular/build:dev-server",
58
+ "configurations": {
59
+ "production": {
60
+ "buildTarget": "{{projectName}}:build:production"
61
+ },
62
+ "development": {
63
+ "buildTarget": "{{projectName}}:build:development"
64
+ }
65
+ },
66
+ "defaultConfiguration": "development"
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,11 @@
1
+ import { Component, ChangeDetectionStrategy } from '@angular/core';
2
+ import { RouterOutlet } from '@angular/router';
3
+
4
+ @Component({
5
+ selector: 'app-root',
6
+ standalone: true,
7
+ imports: [RouterOutlet],
8
+ template: '<router-outlet />',
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ })
11
+ export class AppComponent {}
@@ -0,0 +1,16 @@
1
+ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
2
+ import { provideRouter, withComponentInputBinding } from '@angular/router';
3
+ import { provideHttpClient, withInterceptors } from '@angular/common/http';
4
+ import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
5
+ import { routes } from './app.routes';
6
+ import { authInterceptor } from './core/interceptors/auth.interceptor';
7
+ import { errorInterceptor } from './core/interceptors/error.interceptor';
8
+
9
+ export const appConfig: ApplicationConfig = {
10
+ providers: [
11
+ provideZoneChangeDetection({ eventCoalescing: true }),
12
+ provideRouter(routes, withComponentInputBinding()),
13
+ provideHttpClient(withInterceptors([authInterceptor, errorInterceptor])),
14
+ provideAnimationsAsync(),
15
+ ],
16
+ };
@@ -0,0 +1,14 @@
1
+ import { Routes } from '@angular/router';
2
+ import { LayoutComponent } from './layout/layout.component';
3
+
4
+ export const routes: Routes = [
5
+ {
6
+ path: '',
7
+ component: LayoutComponent,
8
+ children: [
9
+ // Add feature routes here with lazy loading:
10
+ // { path: 'dashboard', loadComponent: () => import('./features/dashboard/dashboard.component').then(m => m.DashboardComponent) },
11
+ { path: '', redirectTo: 'home', pathMatch: 'full' },
12
+ ],
13
+ },
14
+ ];
@@ -0,0 +1,14 @@
1
+ import { inject } from '@angular/core';
2
+ import { CanActivateFn, Router } from '@angular/router';
3
+ import { AuthService } from '../services/auth.service';
4
+
5
+ export const authGuard: CanActivateFn = () => {
6
+ const authService = inject(AuthService);
7
+ const router = inject(Router);
8
+
9
+ if (authService.isAuthenticated()) {
10
+ return true;
11
+ }
12
+
13
+ return router.createUrlTree(['/login']);
14
+ };
@@ -0,0 +1,13 @@
1
+ import { HttpInterceptorFn } from '@angular/common/http';
2
+
3
+ export const authInterceptor: HttpInterceptorFn = (req, next) => {
4
+ const token = localStorage.getItem('access_token');
5
+
6
+ if (token) {
7
+ req = req.clone({
8
+ setHeaders: { Authorization: `Bearer ${token}` },
9
+ });
10
+ }
11
+
12
+ return next(req);
13
+ };
@@ -0,0 +1,18 @@
1
+ import { Injectable, signal, computed } from '@angular/core';
2
+
3
+ @Injectable({ providedIn: 'root' })
4
+ export class AuthService {
5
+ private readonly token = signal<string | null>(localStorage.getItem('access_token'));
6
+
7
+ readonly isAuthenticated = computed(() => !!this.token());
8
+
9
+ login(token: string): void {
10
+ localStorage.setItem('access_token', token);
11
+ this.token.set(token);
12
+ }
13
+
14
+ logout(): void {
15
+ localStorage.removeItem('access_token');
16
+ this.token.set(null);
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ export const environment = {
2
+ production: false,
3
+ apiUrl: 'http://localhost:8080/api',
4
+ };
@@ -0,0 +1,4 @@
1
+ export const environment = {
2
+ production: true,
3
+ apiUrl: '/api',
4
+ };
@@ -0,0 +1,14 @@
1
+ import { HttpInterceptorFn } from '@angular/common/http';
2
+ import { catchError, throwError } from 'rxjs';
3
+
4
+ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
5
+ return next(req).pipe(
6
+ catchError((error) => {
7
+ if (error.status === 401) {
8
+ localStorage.removeItem('access_token');
9
+ window.location.href = '/login';
10
+ }
11
+ return throwError(() => error);
12
+ }),
13
+ );
14
+ };
@@ -0,0 +1,4 @@
1
+ /dist
2
+ /node_modules
3
+ /.angular
4
+ .DS_Store
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>{{name}}</title>
6
+ <base href="/">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
9
+ </head>
10
+ <body>
11
+ <app-root></app-root>
12
+ </body>
13
+ </html>
@@ -0,0 +1,42 @@
1
+ import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
2
+ import { RouterOutlet } from '@angular/router';
3
+ import { SidebarComponent } from './sidebar/sidebar.component';
4
+ import { TopbarComponent } from './topbar/topbar.component';
5
+
6
+ @Component({
7
+ selector: 'app-layout',
8
+ standalone: true,
9
+ imports: [RouterOutlet, SidebarComponent, TopbarComponent],
10
+ template: `
11
+ <div class="layout-wrapper">
12
+ <app-topbar (toggleSidebar)="sidebarVisible.set(!sidebarVisible())" />
13
+ <div class="layout-content-wrapper">
14
+ <app-sidebar [visible]="sidebarVisible()" />
15
+ <main class="layout-main">
16
+ <router-outlet />
17
+ </main>
18
+ </div>
19
+ </div>
20
+ `,
21
+ styles: `
22
+ .layout-wrapper {
23
+ display: flex;
24
+ flex-direction: column;
25
+ height: 100vh;
26
+ }
27
+ .layout-content-wrapper {
28
+ display: flex;
29
+ flex: 1;
30
+ overflow: hidden;
31
+ }
32
+ .layout-main {
33
+ flex: 1;
34
+ padding: 1.5rem;
35
+ overflow-y: auto;
36
+ }
37
+ `,
38
+ changeDetection: ChangeDetectionStrategy.OnPush,
39
+ })
40
+ export class LayoutComponent {
41
+ sidebarVisible = signal(true);
42
+ }
@@ -0,0 +1,6 @@
1
+ import { bootstrapApplication } from '@angular/platform-browser';
2
+ import { appConfig } from './app/app.config';
3
+ import { AppComponent } from './app/app.component';
4
+
5
+ bootstrapApplication(AppComponent, appConfig)
6
+ .catch((err) => console.error(err));
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "{{projectName}}-frontend",
3
+ "version": "0.0.0",
4
+ "scripts": {
5
+ "ng": "ng",
6
+ "start": "ng serve",
7
+ "build": "ng build",
8
+ "watch": "ng build --watch --configuration development",
9
+ "test": "ng test"
10
+ },
11
+ "private": true,
12
+ "dependencies": {
13
+ "@angular/animations": "^{{versions.angular}}",
14
+ "@angular/common": "^{{versions.angular}}",
15
+ "@angular/compiler": "^{{versions.angular}}",
16
+ "@angular/core": "^{{versions.angular}}",
17
+ "@angular/forms": "^{{versions.angular}}",
18
+ "@angular/platform-browser": "^{{versions.angular}}",
19
+ "@angular/platform-browser-dynamic": "^{{versions.angular}}",
20
+ "@angular/router": "^{{versions.angular}}",
21
+ "@ngrx/signals": "^{{versions.ngrxSignals}}",
22
+ "primeng": "^{{versions.primeng}}",
23
+ "primeicons": "^{{versions.primeicons}}",
24
+ "primeflex": "^{{versions.primeflex}}",
25
+ "rxjs": "~{{versions.rxjs}}",
26
+ "tslib": "^2.8.0",
27
+ "zone.js": "~{{versions.zoneJs}}"
28
+ },
29
+ "devDependencies": {
30
+ "@angular/build": "^{{versions.angular}}",
31
+ "@angular/cli": "^{{versions.angular}}",
32
+ "@angular/compiler-cli": "^{{versions.angular}}",
33
+ "typescript": "~{{versions.typescript}}"
34
+ }
35
+ }
@@ -0,0 +1,58 @@
1
+ import { Component, ChangeDetectionStrategy, input } from '@angular/core';
2
+ import { RouterLink, RouterLinkActive } from '@angular/router';
3
+
4
+ @Component({
5
+ selector: 'app-sidebar',
6
+ standalone: true,
7
+ imports: [RouterLink, RouterLinkActive],
8
+ template: `
9
+ @if (visible()) {
10
+ <aside class="layout-sidebar">
11
+ <nav>
12
+ <ul class="sidebar-menu">
13
+ <li>
14
+ <a routerLink="/home" routerLinkActive="active-link">
15
+ <i class="pi pi-home"></i>
16
+ <span>Accueil</span>
17
+ </a>
18
+ </li>
19
+ </ul>
20
+ </nav>
21
+ </aside>
22
+ }
23
+ `,
24
+ styles: `
25
+ .layout-sidebar {
26
+ width: 250px;
27
+ background: var(--surface-card);
28
+ border-right: 1px solid var(--surface-border);
29
+ padding: 1rem;
30
+ }
31
+ .sidebar-menu {
32
+ list-style: none;
33
+ padding: 0;
34
+ margin: 0;
35
+ }
36
+ .sidebar-menu a {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.75rem;
40
+ padding: 0.75rem 1rem;
41
+ border-radius: var(--border-radius);
42
+ color: var(--text-color);
43
+ text-decoration: none;
44
+ transition: background 0.2s;
45
+ }
46
+ .sidebar-menu a:hover {
47
+ background: var(--surface-hover);
48
+ }
49
+ .active-link {
50
+ background: var(--primary-color) !important;
51
+ color: var(--primary-color-text) !important;
52
+ }
53
+ `,
54
+ changeDetection: ChangeDetectionStrategy.OnPush,
55
+ })
56
+ export class SidebarComponent {
57
+ visible = input(true);
58
+ }
@@ -0,0 +1,8 @@
1
+ @use 'primeng/resources/themes/aura-light-blue/theme.css';
2
+ @use 'primeng/resources/primeng.css';
3
+
4
+ html, body {
5
+ height: 100%;
6
+ margin: 0;
7
+ font-family: var(--font-family);
8
+ }
@@ -0,0 +1,59 @@
1
+ import { Component, ChangeDetectionStrategy, output } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'app-topbar',
5
+ standalone: true,
6
+ template: `
7
+ <header class="layout-topbar">
8
+ <div class="topbar-left">
9
+ <button class="topbar-menu-btn" (click)="toggleSidebar.emit()">
10
+ <i class="pi pi-bars"></i>
11
+ </button>
12
+ <span class="topbar-title">ForgeKit App</span>
13
+ </div>
14
+ <div class="topbar-right">
15
+ <button class="topbar-avatar">
16
+ <i class="pi pi-user"></i>
17
+ </button>
18
+ </div>
19
+ </header>
20
+ `,
21
+ styles: `
22
+ .layout-topbar {
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: space-between;
26
+ padding: 0 1.5rem;
27
+ height: 60px;
28
+ background: var(--surface-card);
29
+ border-bottom: 1px solid var(--surface-border);
30
+ }
31
+ .topbar-left {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: 1rem;
35
+ }
36
+ .topbar-menu-btn, .topbar-avatar {
37
+ background: none;
38
+ border: none;
39
+ cursor: pointer;
40
+ font-size: 1.25rem;
41
+ color: var(--text-color);
42
+ padding: 0.5rem;
43
+ border-radius: 50%;
44
+ transition: background 0.2s;
45
+ }
46
+ .topbar-menu-btn:hover, .topbar-avatar:hover {
47
+ background: var(--surface-hover);
48
+ }
49
+ .topbar-title {
50
+ font-size: 1.25rem;
51
+ font-weight: 600;
52
+ color: var(--text-color);
53
+ }
54
+ `,
55
+ changeDetection: ChangeDetectionStrategy.OnPush,
56
+ })
57
+ export class TopbarComponent {
58
+ toggleSidebar = output();
59
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./out-tsc/app",
5
+ "types": []
6
+ },
7
+ "files": [
8
+ "src/main.ts"
9
+ ],
10
+ "include": [
11
+ "src/**/*.d.ts"
12
+ ]
13
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compileOnSave": false,
3
+ "compilerOptions": {
4
+ "outDir": "./dist/out-tsc",
5
+ "strict": true,
6
+ "noUnusedLocals": true,
7
+ "noUnusedParameters": true,
8
+ "noImplicitReturns": true,
9
+ "noFallthroughCasesInSwitch": true,
10
+ "sourceMap": true,
11
+ "declaration": false,
12
+ "downlevelIteration": true,
13
+ "experimentalDecorators": true,
14
+ "moduleResolution": "node",
15
+ "importHelpers": true,
16
+ "target": "ES2022",
17
+ "module": "ES2022",
18
+ "lib": [
19
+ "ES2022",
20
+ "dom"
21
+ ],
22
+ "useDefineForClassFields": false
23
+ }
24
+ }