diff --git a/README.md b/README.md
index c141eed..d2df6d3 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f
## Challenges
-Check [all 42 challenges](https://angular-challenges.vercel.app/)
+Check [all 43 challenges](https://angular-challenges.vercel.app/)
## Contributors ✨
diff --git a/apps/angular/signal-input/.eslintrc.json b/apps/angular/signal-input/.eslintrc.json
new file mode 100644
index 0000000..8ebcbfd
--- /dev/null
+++ b/apps/angular/signal-input/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/angular/signal-input/README.md b/apps/angular/signal-input/README.md
new file mode 100644
index 0000000..78ef74d
--- /dev/null
+++ b/apps/angular/signal-input/README.md
@@ -0,0 +1,13 @@
+# Signal Input
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-signal-input
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/43-signal-input/).
diff --git a/apps/angular/signal-input/project.json b/apps/angular/signal-input/project.json
new file mode 100644
index 0000000..00f1a67
--- /dev/null
+++ b/apps/angular/signal-input/project.json
@@ -0,0 +1,73 @@
+{
+ "name": "angular-signal-input",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/signal-input/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/signal-input",
+ "index": "apps/angular/signal-input/src/index.html",
+ "browser": "apps/angular/signal-input/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/signal-input/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/signal-input/src/favicon.ico",
+ "apps/angular/signal-input/src/assets"
+ ],
+ "styles": ["apps/angular/signal-input/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-signal-input:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-signal-input:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-signal-input:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint",
+ "outputs": ["{options.outputFile}"]
+ }
+ }
+}
diff --git a/apps/angular/signal-input/src/app/app.component.ts b/apps/angular/signal-input/src/app/app.component.ts
new file mode 100644
index 0000000..22e6438
--- /dev/null
+++ b/apps/angular/signal-input/src/app/app.component.ts
@@ -0,0 +1,45 @@
+import { JsonPipe } from '@angular/common';
+import { Component } from '@angular/core';
+import { UserComponent } from './user.component';
+
+@Component({
+ standalone: true,
+ imports: [UserComponent, JsonPipe],
+ selector: 'app-root',
+ template: `
+
+
+ Name:
+
+ @if (showUser && !name.value) {
+
name required
+ }
+
+
+ LastName:
+
+
+
+ Age:
+
+
+
+
+ @if (showUser && !!name.value) {
+
+ }
+ `,
+ host: {
+ class: 'p-10 block flex flex-col gap-10',
+ },
+})
+export class AppComponent {
+ showUser = false;
+}
diff --git a/apps/angular/signal-input/src/app/app.config.ts b/apps/angular/signal-input/src/app/app.config.ts
new file mode 100644
index 0000000..81a6edd
--- /dev/null
+++ b/apps/angular/signal-input/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig } from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [],
+};
diff --git a/apps/angular/signal-input/src/app/user.component.ts b/apps/angular/signal-input/src/app/user.component.ts
new file mode 100644
index 0000000..082638b
--- /dev/null
+++ b/apps/angular/signal-input/src/app/user.component.ts
@@ -0,0 +1,41 @@
+import { TitleCasePipe } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ Input,
+ OnChanges,
+} from '@angular/core';
+
+type Category = 'Youth' | 'Junior' | 'Open' | 'Senior';
+const ageToCategory = (age: number): Category => {
+ if (age < 10) return 'Youth';
+ else if (age < 18) return 'Junior';
+ else if (age < 35) return 'Open';
+ return 'Senior';
+};
+
+@Component({
+ selector: 'app-user',
+ standalone: true,
+ imports: [TitleCasePipe],
+ template: `
+ {{ fullName | titlecase }} plays tennis in the {{ category }} category!!
+ `,
+ host: {
+ class: 'text-xl text-green-800',
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class UserComponent implements OnChanges {
+ @Input({ required: true }) name!: string;
+ @Input() lastName?: string;
+ @Input() age?: string;
+
+ fullName = '';
+ category: Category = 'Junior';
+
+ ngOnChanges(): void {
+ this.fullName = `${this.name} ${this.lastName ?? ''}`;
+ this.category = ageToCategory(Number(this.age) ?? 0);
+ }
+}
diff --git a/apps/angular/signal-input/src/assets/.gitkeep b/apps/angular/signal-input/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/apps/angular/signal-input/src/favicon.ico b/apps/angular/signal-input/src/favicon.ico
new file mode 100644
index 0000000..317ebcb
Binary files /dev/null and b/apps/angular/signal-input/src/favicon.ico differ
diff --git a/apps/angular/signal-input/src/index.html b/apps/angular/signal-input/src/index.html
new file mode 100644
index 0000000..4fc2af8
--- /dev/null
+++ b/apps/angular/signal-input/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-signal-input
+
+
+
+
+
+
+
+
diff --git a/apps/angular/signal-input/src/main.ts b/apps/angular/signal-input/src/main.ts
new file mode 100644
index 0000000..f3a7223
--- /dev/null
+++ b/apps/angular/signal-input/src/main.ts
@@ -0,0 +1,7 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+import { appConfig } from './app/app.config';
+
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
+ console.error(err),
+);
diff --git a/apps/angular/signal-input/src/styles.scss b/apps/angular/signal-input/src/styles.scss
new file mode 100644
index 0000000..77e408a
--- /dev/null
+++ b/apps/angular/signal-input/src/styles.scss
@@ -0,0 +1,5 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/angular/signal-input/tailwind.config.js b/apps/angular/signal-input/tailwind.config.js
new file mode 100644
index 0000000..38183db
--- /dev/null
+++ b/apps/angular/signal-input/tailwind.config.js
@@ -0,0 +1,14 @@
+const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind');
+const { join } = require('path');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'),
+ ...createGlobPatternsForDependencies(__dirname),
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/apps/angular/signal-input/tsconfig.app.json b/apps/angular/signal-input/tsconfig.app.json
new file mode 100644
index 0000000..5822042
--- /dev/null
+++ b/apps/angular/signal-input/tsconfig.app.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"],
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/signal-input/tsconfig.editor.json b/apps/angular/signal-input/tsconfig.editor.json
new file mode 100644
index 0000000..4ee6393
--- /dev/null
+++ b/apps/angular/signal-input/tsconfig.editor.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {
+ "types": []
+ }
+}
diff --git a/apps/angular/signal-input/tsconfig.json b/apps/angular/signal-input/tsconfig.json
new file mode 100644
index 0000000..b94f883
--- /dev/null
+++ b/apps/angular/signal-input/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.editor.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/challenge-number.json b/challenge-number.json
index ac1eeb8..026eb8c 100644
--- a/challenge-number.json
+++ b/challenge-number.json
@@ -1,6 +1,6 @@
{
- "total": 42,
- "🟢": 15,
+ "total": 43,
+ "🟢": 16,
"🟠": 120,
"🔴": 207
}
diff --git a/docs/src/content/docs/challenges/angular/43-signal-input.md b/docs/src/content/docs/challenges/angular/43-signal-input.md
new file mode 100644
index 0000000..996458f
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/43-signal-input.md
@@ -0,0 +1,20 @@
+---
+title: 🟢 Signal Input
+description: Challenge 43 is about ...
+author: thomas-laforge
+challengeNumber: 43
+command: angular-signal-input
+sidebar:
+ order: 16
+ badge: New
+---
+
+:::note
+WIP: The following documentation need to be written.
+:::
+
+## Information
+
+## Statement
+
+## Constraints
diff --git a/docs/src/content/docs/challenges/nx/42-static-dynamic-import.md b/docs/src/content/docs/challenges/nx/42-static-dynamic-import.md
index dff79d4..62a149e 100644
--- a/docs/src/content/docs/challenges/nx/42-static-dynamic-import.md
+++ b/docs/src/content/docs/challenges/nx/42-static-dynamic-import.md
@@ -6,7 +6,6 @@ challengeNumber: 42
command: nx-static-dynamic-import
sidebar:
order: 15
- badge: New
---
## Information
diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx
index f094067..4cf03a9 100644
--- a/docs/src/content/docs/index.mdx
+++ b/docs/src/content/docs/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Go to the latest Challenge
- link: /challenges/nx/42-static-dynamic-import/
+ link: /challenges/angular/43-signal-input/
icon: rocket
- text: Give a star
link: https://github.com/tomalaforge/angular-challenges
@@ -25,8 +25,8 @@ import { Card, CardGrid } from '@astrojs/starlight/components';
import MyIcon from '../../components/MyIcon.astro';
-
- This repository gathers 42 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript.
+
+ This repository gathers 43 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript.
These challenges resolve around real-life issues or specific features to elevate your skills.
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 9f30ed8..e6d425a 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -68,6 +68,9 @@
"libs/shared/directives/src/index.ts"
],
"@angular-challenges/shared/utils": ["libs/shared/utils/src/index.ts"],
+ "@angular-challenges/static-dynamic-import/users": [
+ "libs/static-dynamic-import/users/src/index.ts"
+ ],
"@angular-challenges/testing-table/backend": [
"libs/testing-table/backend/src/index.ts"
],
@@ -76,9 +79,6 @@
],
"@tomalaforge/ngrx-callstate-store": [
"libs/shared/ngrx-callstate-store/src/index.ts"
- ],
- "@angular-challenges/static-dynamic-import/users": [
- "libs/static-dynamic-import/users/src/index.ts"
]
}
},