From 98746c9281f2e953ae798a6fb8c2217efd3a77f2 Mon Sep 17 00:00:00 2001
From: "thibault.capt" <thibault.capt@etu.hesge.ch>
Date: Tue, 28 Jan 2025 17:20:58 +0100
Subject: [PATCH] add garage

---
 garage-workspace/garage/.editorconfig         |  17 +++
 .../garage/.editorconfig:Zone.Identifier      |   0
 garage-workspace/garage/.gitignore            |  42 +++++++
 .../garage/.gitignore:Zone.Identifier         |   0
 garage-workspace/garage/.nvmrc                |   1 +
 .../garage/.nvmrc:Zone.Identifier             |   0
 garage-workspace/garage/.postcssrc.json       |   5 +
 .../garage/.postcssrc.json:Zone.Identifier    |   0
 garage-workspace/garage/.prettierignore       |   4 +
 .../garage/.prettierignore:Zone.Identifier    |   0
 garage-workspace/garage/.prettierrc.json      |   1 +
 .../garage/.prettierrc.json:Zone.Identifier   |   0
 garage-workspace/garage/README.md             |  59 +++++++++
 .../garage/README.md:Zone.Identifier          |   0
 garage-workspace/garage/angular.json          | 113 ++++++++++++++++++
 .../garage/angular.json:Zone.Identifier       |   0
 garage-workspace/garage/eslint.config.js      |  43 +++++++
 .../garage/eslint.config.js:Zone.Identifier   |   0
 garage-workspace/garage/package.json          |  55 +++++++++
 .../garage/package.json:Zone.Identifier       |   0
 .../projects/garage-ui/eslint.config.js       |  32 +++++
 .../eslint.config.js:Zone.Identifier          |   0
 .../projects/garage-ui/public/favicon.ico     | Bin 0 -> 15086 bytes
 .../public/favicon.ico:Zone.Identifier        |   0
 .../garage-ui/src/app/app.component.ts        |  10 ++
 .../src/app/app.component.ts:Zone.Identifier  |   0
 .../projects/garage-ui/src/app/app.config.ts  |  29 +++++
 .../src/app/app.config.ts:Zone.Identifier     |   0
 .../projects/garage-ui/src/app/app.routes.ts  |   8 ++
 .../src/app/app.routes.ts:Zone.Identifier     |   0
 .../cars/adapters/in-memory-car.gateway.ts    |  16 +++
 .../in-memory-car.gateway.ts:Zone.Identifier  |   0
 .../src/app/core/cars/models/car.model.ts     |   9 ++
 .../cars/models/car.model.ts:Zone.Identifier  |   0
 .../src/app/core/cars/ports/car.gateway.ts    |   6 +
 .../cars/ports/car.gateway.ts:Zone.Identifier |   0
 .../src/app/features/cars/cars.component.html |  28 +++++
 .../cars/cars.component.html:Zone.Identifier  |   0
 .../src/app/features/cars/cars.component.scss |   0
 .../cars/cars.component.scss:Zone.Identifier  |   0
 .../src/app/features/cars/cars.component.ts   |  15 +++
 .../cars/cars.component.ts:Zone.Identifier    |   0
 .../environments/environment.development.ts   |   1 +
 ...environment.development.ts:Zone.Identifier |   0
 .../garage-ui/src/environments/environment.ts |   1 +
 .../environment.ts:Zone.Identifier            |   0
 .../garage/projects/garage-ui/src/index.html  |  13 ++
 .../garage-ui/src/index.html:Zone.Identifier  |   0
 .../garage/projects/garage-ui/src/main.ts     |   7 ++
 .../garage-ui/src/main.ts:Zone.Identifier     |   0
 .../garage/projects/garage-ui/src/styles.scss |   7 ++
 .../garage-ui/src/styles.scss:Zone.Identifier |   0
 .../projects/garage-ui/tsconfig.app.json      |  11 ++
 .../tsconfig.app.json:Zone.Identifier         |   0
 .../projects/garage-ui/tsconfig.spec.json     |  10 ++
 .../tsconfig.spec.json:Zone.Identifier        |   0
 garage-workspace/garage/tsconfig.json         |  35 ++++++
 .../garage/tsconfig.json:Zone.Identifier      |   0
 58 files changed, 578 insertions(+)
 create mode 100644 garage-workspace/garage/.editorconfig
 create mode 100644 garage-workspace/garage/.editorconfig:Zone.Identifier
 create mode 100644 garage-workspace/garage/.gitignore
 create mode 100644 garage-workspace/garage/.gitignore:Zone.Identifier
 create mode 100644 garage-workspace/garage/.nvmrc
 create mode 100644 garage-workspace/garage/.nvmrc:Zone.Identifier
 create mode 100644 garage-workspace/garage/.postcssrc.json
 create mode 100644 garage-workspace/garage/.postcssrc.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/.prettierignore
 create mode 100644 garage-workspace/garage/.prettierignore:Zone.Identifier
 create mode 100644 garage-workspace/garage/.prettierrc.json
 create mode 100644 garage-workspace/garage/.prettierrc.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/README.md
 create mode 100644 garage-workspace/garage/README.md:Zone.Identifier
 create mode 100644 garage-workspace/garage/angular.json
 create mode 100644 garage-workspace/garage/angular.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/eslint.config.js
 create mode 100644 garage-workspace/garage/eslint.config.js:Zone.Identifier
 create mode 100644 garage-workspace/garage/package.json
 create mode 100644 garage-workspace/garage/package.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/eslint.config.js
 create mode 100644 garage-workspace/garage/projects/garage-ui/eslint.config.js:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/public/favicon.ico
 create mode 100644 garage-workspace/garage/projects/garage-ui/public/favicon.ico:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.component.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.component.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.config.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.config.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/environments/environment.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/environments/environment.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/index.html
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/index.html:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/main.ts
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/main.ts:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/styles.scss
 create mode 100644 garage-workspace/garage/projects/garage-ui/src/styles.scss:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/tsconfig.app.json
 create mode 100644 garage-workspace/garage/projects/garage-ui/tsconfig.app.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/projects/garage-ui/tsconfig.spec.json
 create mode 100644 garage-workspace/garage/projects/garage-ui/tsconfig.spec.json:Zone.Identifier
 create mode 100644 garage-workspace/garage/tsconfig.json
 create mode 100644 garage-workspace/garage/tsconfig.json:Zone.Identifier

diff --git a/garage-workspace/garage/.editorconfig b/garage-workspace/garage/.editorconfig
new file mode 100644
index 000000000..f166060da
--- /dev/null
+++ b/garage-workspace/garage/.editorconfig
@@ -0,0 +1,17 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+ij_typescript_use_double_quotes = false
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/garage-workspace/garage/.editorconfig:Zone.Identifier b/garage-workspace/garage/.editorconfig:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/.gitignore b/garage-workspace/garage/.gitignore
new file mode 100644
index 000000000..cc7b14135
--- /dev/null
+++ b/garage-workspace/garage/.gitignore
@@ -0,0 +1,42 @@
+# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db
diff --git a/garage-workspace/garage/.gitignore:Zone.Identifier b/garage-workspace/garage/.gitignore:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/.nvmrc b/garage-workspace/garage/.nvmrc
new file mode 100644
index 000000000..ee09fac75
--- /dev/null
+++ b/garage-workspace/garage/.nvmrc
@@ -0,0 +1 @@
+v20.11.1
diff --git a/garage-workspace/garage/.nvmrc:Zone.Identifier b/garage-workspace/garage/.nvmrc:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/.postcssrc.json b/garage-workspace/garage/.postcssrc.json
new file mode 100644
index 000000000..e092dc7c1
--- /dev/null
+++ b/garage-workspace/garage/.postcssrc.json
@@ -0,0 +1,5 @@
+{
+  "plugins": {
+    "@tailwindcss/postcss": {}
+  }
+}
diff --git a/garage-workspace/garage/.postcssrc.json:Zone.Identifier b/garage-workspace/garage/.postcssrc.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/.prettierignore b/garage-workspace/garage/.prettierignore
new file mode 100644
index 000000000..6bf7e4cec
--- /dev/null
+++ b/garage-workspace/garage/.prettierignore
@@ -0,0 +1,4 @@
+dist/
+node_modules/
+package-lock.json
+pnpm-lock.yaml
\ No newline at end of file
diff --git a/garage-workspace/garage/.prettierignore:Zone.Identifier b/garage-workspace/garage/.prettierignore:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/.prettierrc.json b/garage-workspace/garage/.prettierrc.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/garage-workspace/garage/.prettierrc.json
@@ -0,0 +1 @@
+{}
diff --git a/garage-workspace/garage/.prettierrc.json:Zone.Identifier b/garage-workspace/garage/.prettierrc.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/README.md b/garage-workspace/garage/README.md
new file mode 100644
index 000000000..19af0f718
--- /dev/null
+++ b/garage-workspace/garage/README.md
@@ -0,0 +1,59 @@
+# Garage
+
+This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.1.4.
+
+## Development server
+
+To start a local development server, run:
+
+```bash
+ng serve
+```
+
+Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
+
+## Code scaffolding
+
+Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
+
+```bash
+ng generate component component-name
+```
+
+For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
+
+```bash
+ng generate --help
+```
+
+## Building
+
+To build the project run:
+
+```bash
+ng build
+```
+
+This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
+
+## Running unit tests
+
+To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
+
+```bash
+ng test
+```
+
+## Running end-to-end tests
+
+For end-to-end (e2e) testing, run:
+
+```bash
+ng e2e
+```
+
+Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
+
+## Additional Resources
+
+For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
diff --git a/garage-workspace/garage/README.md:Zone.Identifier b/garage-workspace/garage/README.md:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/angular.json b/garage-workspace/garage/angular.json
new file mode 100644
index 000000000..0b120bbec
--- /dev/null
+++ b/garage-workspace/garage/angular.json
@@ -0,0 +1,113 @@
+{
+  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+  "version": 1,
+  "cli": {
+    "packageManager": "pnpm",
+    "schematicCollections": ["angular-eslint"]
+  },
+  "newProjectRoot": "projects",
+  "projects": {
+    "garage-ui": {
+      "projectType": "application",
+      "schematics": {
+        "@schematics/angular:component": {
+          "style": "scss"
+        }
+      },
+      "root": "projects/garage-ui",
+      "sourceRoot": "projects/garage-ui/src",
+      "prefix": "app",
+      "architect": {
+        "build": {
+          "builder": "@angular-devkit/build-angular:application",
+          "options": {
+            "outputPath": "dist/garage-ui",
+            "index": "projects/garage-ui/src/index.html",
+            "browser": "projects/garage-ui/src/main.ts",
+            "polyfills": ["zone.js"],
+            "tsConfig": "projects/garage-ui/tsconfig.app.json",
+            "inlineStyleLanguage": "scss",
+            "assets": [
+              {
+                "glob": "**/*",
+                "input": "projects/garage-ui/public"
+              }
+            ],
+            "styles": ["projects/garage-ui/src/styles.scss"],
+            "scripts": []
+          },
+          "configurations": {
+            "production": {
+              "budgets": [
+                {
+                  "type": "initial",
+                  "maximumWarning": "500kB",
+                  "maximumError": "1MB"
+                },
+                {
+                  "type": "anyComponentStyle",
+                  "maximumWarning": "4kB",
+                  "maximumError": "8kB"
+                }
+              ],
+              "outputHashing": "all"
+            },
+            "development": {
+              "optimization": false,
+              "extractLicenses": false,
+              "sourceMap": true,
+              "fileReplacements": [
+                {
+                  "replace": "projects/garage-ui/src/environments/environment.ts",
+                  "with": "projects/garage-ui/src/environments/environment.development.ts"
+                }
+              ]
+            }
+          },
+          "defaultConfiguration": "production"
+        },
+        "serve": {
+          "builder": "@angular-devkit/build-angular:dev-server",
+          "configurations": {
+            "production": {
+              "buildTarget": "garage-ui:build:production"
+            },
+            "development": {
+              "buildTarget": "garage-ui:build:development"
+            }
+          },
+          "defaultConfiguration": "development"
+        },
+        "extract-i18n": {
+          "builder": "@angular-devkit/build-angular:extract-i18n"
+        },
+        "test": {
+          "builder": "@angular-devkit/build-angular:karma",
+          "options": {
+            "polyfills": ["zone.js", "zone.js/testing"],
+            "tsConfig": "projects/garage-ui/tsconfig.spec.json",
+            "inlineStyleLanguage": "scss",
+            "assets": [
+              {
+                "glob": "**/*",
+                "input": "projects/garage-ui/public"
+              }
+            ],
+            "styles": ["projects/garage-ui/src/styles.scss"],
+            "scripts": []
+          }
+        },
+        "lint": {
+          "builder": "@angular-eslint/builder:lint",
+          "options": {
+            "lintFilePatterns": [
+              "projects/garage-ui/**/*.ts",
+              "projects/garage-ui/**/*.html"
+            ],
+            "eslintConfig": "projects/garage-ui/eslint.config.js"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/garage-workspace/garage/angular.json:Zone.Identifier b/garage-workspace/garage/angular.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/eslint.config.js b/garage-workspace/garage/eslint.config.js
new file mode 100644
index 000000000..8379fae3b
--- /dev/null
+++ b/garage-workspace/garage/eslint.config.js
@@ -0,0 +1,43 @@
+// @ts-check
+const eslint = require("@eslint/js");
+const tseslint = require("typescript-eslint");
+const angular = require("angular-eslint");
+
+module.exports = tseslint.config(
+  {
+    files: ["**/*.ts"],
+    extends: [
+      eslint.configs.recommended,
+      ...tseslint.configs.recommended,
+      ...tseslint.configs.stylistic,
+      ...angular.configs.tsRecommended,
+    ],
+    processor: angular.processInlineTemplates,
+    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: [
+      ...angular.configs.templateRecommended,
+      ...angular.configs.templateAccessibility,
+    ],
+    rules: {},
+  },
+);
diff --git a/garage-workspace/garage/eslint.config.js:Zone.Identifier b/garage-workspace/garage/eslint.config.js:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/package.json b/garage-workspace/garage/package.json
new file mode 100644
index 000000000..52755a34e
--- /dev/null
+++ b/garage-workspace/garage/package.json
@@ -0,0 +1,55 @@
+{
+  "name": "garage",
+  "version": "0.0.0",
+  "scripts": {
+    "ng": "ng",
+    "start": "ng dev",
+    "build": "ng build",
+    "watch": "ng build --watch --configuration development",
+    "test": "ng test",
+    "lint": "ng lint && prettier --check .",
+    "format": "prettier --write ."
+  },
+  "private": true,
+  "dependencies": {
+    "@angular/animations": "^19.1.0",
+    "@angular/common": "^19.1.0",
+    "@angular/compiler": "^19.1.0",
+    "@angular/core": "^19.1.0",
+    "@angular/forms": "^19.1.0",
+    "@angular/platform-browser": "^19.1.0",
+    "@angular/platform-browser-dynamic": "^19.1.0",
+    "@angular/router": "^19.1.0",
+    "@fortawesome/angular-fontawesome": "1.0.0",
+    "@fortawesome/free-brands-svg-icons": "^6.7.1",
+    "@fortawesome/free-regular-svg-icons": "^6.7.1",
+    "@fortawesome/free-solid-svg-icons": "^6.7.1",
+    "rxjs": "~7.8.0",
+    "tslib": "^2.3.0",
+    "zone.js": "~0.15.0"
+  },
+  "devDependencies": {
+    "@angular-devkit/build-angular": "^19.1.4",
+    "@angular/cli": "^19.1.4",
+    "@angular/compiler-cli": "^19.1.0",
+    "@tailwindcss/postcss": "^4.0.0",
+    "@types/jasmine": "~5.1.0",
+    "angular-eslint": "19.0.2",
+    "daisyui": "5.0.0-beta.2",
+    "eslint": "^9.16.0",
+    "eslint-config-prettier": "^10.0.1",
+    "eslint-plugin-prettier": "^5.2.3",
+    "jasmine-core": "~5.5.0",
+    "karma": "~6.4.0",
+    "karma-chrome-launcher": "~3.2.0",
+    "karma-coverage": "~2.2.0",
+    "karma-jasmine": "~5.1.0",
+    "karma-jasmine-html-reporter": "~2.1.0",
+    "postcss": "^8.5.1",
+    "prettier": "^3.4.2",
+    "prettier-eslint": "^16.3.0",
+    "tailwindcss": "^4.0.0",
+    "typescript": "~5.7.2",
+    "typescript-eslint": "8.18.0"
+  }
+}
diff --git a/garage-workspace/garage/package.json:Zone.Identifier b/garage-workspace/garage/package.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/eslint.config.js b/garage-workspace/garage/projects/garage-ui/eslint.config.js
new file mode 100644
index 000000000..3614e9328
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/eslint.config.js
@@ -0,0 +1,32 @@
+// @ts-check
+const tseslint = require("typescript-eslint");
+const rootConfig = require("../../eslint.config.js");
+
+module.exports = tseslint.config(
+  ...rootConfig,
+  {
+    files: ["**/*.ts"],
+    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"],
+    rules: {},
+  },
+);
diff --git a/garage-workspace/garage/projects/garage-ui/eslint.config.js:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/eslint.config.js:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/public/favicon.ico b/garage-workspace/garage/projects/garage-ui/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..57614f9c967596fad0a3989bec2b1deff33034f6
GIT binary patch
literal 15086
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
T3=HiL85kZPXJGh!pMe1YLpWDK

literal 0
HcmV?d00001

diff --git a/garage-workspace/garage/projects/garage-ui/public/favicon.ico:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/public/favicon.ico:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.component.ts b/garage-workspace/garage/projects/garage-ui/src/app/app.component.ts
new file mode 100644
index 000000000..6a3f56ccb
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/app.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+
+@Component({
+  selector: 'app-root',
+  imports: [RouterOutlet],
+  template: `<router-outlet />`,
+  styleUrl: './app.component.scss',
+})
+export class AppComponent {}
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.component.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/app.component.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.config.ts b/garage-workspace/garage/projects/garage-ui/src/app/app.config.ts
new file mode 100644
index 000000000..cad493aae
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/app.config.ts
@@ -0,0 +1,29 @@
+import {
+  type ApplicationConfig,
+  provideZoneChangeDetection,
+} from '@angular/core';
+import { provideRouter } from '@angular/router';
+
+import { provideHttpClient } from '@angular/common/http';
+import { routes } from './app.routes';
+import { CarGateway } from '@core/cars/ports/car.gateway';
+import { InMemoryCarGateway } from '@core/cars/adapters/in-memory-car.gateway';
+
+export const appConfig: ApplicationConfig = {
+  providers: [
+    provideZoneChangeDetection({ eventCoalescing: true }),
+    provideRouter(routes),
+    provideHttpClient(),
+    {
+      provide: CarGateway,
+      useFactory: () =>
+        new InMemoryCarGateway().withCars(
+          [
+            { id: 1, brand: 'Audi', model: 'A3', year: 2019, color: 'red' },
+            { id: 2, brand: 'Audi', model: 'RS3', year: 2024, color: 'black' },
+            { id: 3, brand: 'Audi', model: 'Q2', year: 2016, color: 'yellow' },
+          ]
+        ),
+    },
+  ],
+};
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.config.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/app.config.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts b/garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts
new file mode 100644
index 000000000..0ffb48756
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts
@@ -0,0 +1,8 @@
+import type { Routes } from '@angular/router';
+import CarsComponent from "@features/cars/cars.component";
+
+export const routes: Routes = [
+  { path: '', redirectTo: 'car', pathMatch: 'full' },
+  { path: 'car', component: CarsComponent },
+  { path: '**', redirectTo: 'car', pathMatch: 'full' },
+];
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/app.routes.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts
new file mode 100644
index 000000000..6caf67f92
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts
@@ -0,0 +1,16 @@
+import { CarGateway } from '@core/cars/ports/car.gateway';
+import { Observable, of } from 'rxjs';
+import { Cars } from '@core/cars/models/car.model';
+
+export class InMemoryCarGateway extends CarGateway {
+  private cars: Cars = [];
+
+  withCars(cars: Cars): InMemoryCarGateway {
+    this.cars = cars;
+    return this;
+  }
+
+  getAll(): Observable<Cars> {
+    return of(this.cars);
+  }
+}
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/adapters/in-memory-car.gateway.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts
new file mode 100644
index 000000000..bbf61cb7e
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts
@@ -0,0 +1,9 @@
+export interface Car {
+  id: number;
+  brand: string;
+  model: string;
+  year: number;
+  color: string;
+}
+
+export type Cars = Car[];
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/models/car.model.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts
new file mode 100644
index 000000000..ef890e4a0
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts
@@ -0,0 +1,6 @@
+import { Observable } from 'rxjs';
+import { Cars } from '@core/cars/models/car.model';
+
+export abstract class CarGateway {
+  abstract getAll(): Observable<Cars>;
+}
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/ports/car.gateway.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html
new file mode 100644
index 000000000..3287aeb05
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html
@@ -0,0 +1,28 @@
+<div class="container mx-auto py-6">
+  <h1 class="text-4xl font-bold text-center mb-6">My cars</h1>
+
+  <div class="overflow-x-auto">
+    <table class="table table-zebra w-full">
+      <thead>
+      <tr>
+        <th>#</th>
+        <th>Brand</th>
+        <th>Model</th>
+        <th>Year</th>
+        <th>Color</th>
+        <th>Actions</th>
+      </tr>
+      </thead>
+    @for (car of cars(); track car.id) {
+      <tr>
+        <td>{{ car.id }}</td>
+        <td>{{ car.brand }}</td>
+        <td>{{ car.model }}</td>
+        <td>{{ car.year }}</td>
+        <td>{{ car.color }}</td>
+        <td>Modify | Delete</td>
+      </tr>
+    }
+    </table>
+  </div>
+</div>
\ No newline at end of file
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.scss:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts
new file mode 100644
index 000000000..ddc06943a
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts
@@ -0,0 +1,15 @@
+import { Component, inject } from "@angular/core";
+import { CarGateway } from "@core/cars/ports/car.gateway";
+import { toSignal } from "@angular/core/rxjs-interop";
+import { AsyncPipe } from "@angular/common";
+
+@Component({
+  selector: 'app-cars',
+  imports: [],
+  templateUrl: './cars.component.html',
+  styleUrl: './cars.component.scss',
+})
+export default class CarsComponent {
+  private readonly carGateway = inject(CarGateway);
+  cars = toSignal(this.carGateway.getAll());
+}
diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts b/garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts
new file mode 100644
index 000000000..f274e5edf
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts
@@ -0,0 +1 @@
+export const environment = {};
diff --git a/garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/environments/environment.development.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/environments/environment.ts b/garage-workspace/garage/projects/garage-ui/src/environments/environment.ts
new file mode 100644
index 000000000..f274e5edf
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/environments/environment.ts
@@ -0,0 +1 @@
+export const environment = {};
diff --git a/garage-workspace/garage/projects/garage-ui/src/environments/environment.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/environments/environment.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/index.html b/garage-workspace/garage/projects/garage-ui/src/index.html
new file mode 100644
index 000000000..2163e364e
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/index.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html data-theme="light" lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>GarageUi</title>
+    <base href="/" />
+    <meta content="width=device-width, initial-scale=1" name="viewport" />
+    <link href="favicon.ico" rel="icon" type="image/x-icon" />
+  </head>
+  <body>
+    <app-root></app-root>
+  </body>
+</html>
diff --git a/garage-workspace/garage/projects/garage-ui/src/index.html:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/index.html:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/main.ts b/garage-workspace/garage/projects/garage-ui/src/main.ts
new file mode 100644
index 000000000..f3a7223da
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/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/garage-workspace/garage/projects/garage-ui/src/main.ts:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/main.ts:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/src/styles.scss b/garage-workspace/garage/projects/garage-ui/src/styles.scss
new file mode 100644
index 000000000..811169a27
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/src/styles.scss
@@ -0,0 +1,7 @@
+@use "tailwindcss";
+
+@plugin "daisyui" {
+  themes:
+    light --default,
+    black --prefersdark;
+}
diff --git a/garage-workspace/garage/projects/garage-ui/src/styles.scss:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/src/styles.scss:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/tsconfig.app.json b/garage-workspace/garage/projects/garage-ui/tsconfig.app.json
new file mode 100644
index 000000000..3f672ccab
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/tsconfig.app.json
@@ -0,0 +1,11 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "extends": "../../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../out-tsc/app",
+    "types": []
+  },
+  "files": ["src/main.ts"],
+  "include": ["src/**/*.d.ts"]
+}
diff --git a/garage-workspace/garage/projects/garage-ui/tsconfig.app.json:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/tsconfig.app.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/projects/garage-ui/tsconfig.spec.json b/garage-workspace/garage/projects/garage-ui/tsconfig.spec.json
new file mode 100644
index 000000000..4fd89a209
--- /dev/null
+++ b/garage-workspace/garage/projects/garage-ui/tsconfig.spec.json
@@ -0,0 +1,10 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "extends": "../../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../out-tsc/spec",
+    "types": ["jasmine"]
+  },
+  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/garage-workspace/garage/projects/garage-ui/tsconfig.spec.json:Zone.Identifier b/garage-workspace/garage/projects/garage-ui/tsconfig.spec.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
diff --git a/garage-workspace/garage/tsconfig.json b/garage-workspace/garage/tsconfig.json
new file mode 100644
index 000000000..f3656be67
--- /dev/null
+++ b/garage-workspace/garage/tsconfig.json
@@ -0,0 +1,35 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "compileOnSave": false,
+  "compilerOptions": {
+    "baseUrl": "./projects/garage-ui/src",
+    "paths": {
+      "@app/*": ["app/*"],
+      "@env/*": ["environments/*"],
+      "@core/*": ["app/core/*"],
+      "@shared/*": ["app/shared/*"],
+      "@features/*": ["app/features/*"]
+    },
+    "outDir": "./dist/out-tsc",
+    "strict": true,
+    "noImplicitOverride": true,
+    "noPropertyAccessFromIndexSignature": true,
+    "noImplicitReturns": true,
+    "noFallthroughCasesInSwitch": true,
+    "skipLibCheck": true,
+    "isolatedModules": true,
+    "esModuleInterop": true,
+    "experimentalDecorators": true,
+    "moduleResolution": "bundler",
+    "importHelpers": true,
+    "target": "ES2022",
+    "module": "ES2022"
+  },
+  "angularCompilerOptions": {
+    "enableI18nLegacyMessageIdFormat": false,
+    "strictInjectionParameters": true,
+    "strictInputAccessModifiers": true,
+    "strictTemplates": true
+  }
+}
diff --git a/garage-workspace/garage/tsconfig.json:Zone.Identifier b/garage-workspace/garage/tsconfig.json:Zone.Identifier
new file mode 100644
index 000000000..e69de29bb
-- 
GitLab