diff --git a/angular.json b/angular.json index 666b77a..c0d44b9 100644 --- a/angular.json +++ b/angular.json @@ -25,7 +25,7 @@ "tsConfig": "tsconfig.app.json", "inlineStyleLanguage": "scss", "assets": [ - "src/favicon.ico", + "src/assets/favicon.ico", { "glob": "**/*", "input": "public" diff --git a/package-lock.json b/package-lock.json index 55b21eb..d82ef29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,26 +8,26 @@ "name": "playground-frontend", "version": "0.1.0", "dependencies": { - "@angular-devkit/build-angular": "~20.3.9", - "@angular/animations": "20.3.10", + "@angular-devkit/build-angular": "~20.3.12", + "@angular/animations": "20.3.14", "@angular/cdk": "20.2.11", - "@angular/common": "20.3.10", - "@angular/compiler": "20.3.10", - "@angular/core": "20.3.10", - "@angular/forms": "20.3.10", + "@angular/common": "~20.3.14", + "@angular/compiler": "20.3.14", + "@angular/core": "20.3.14", + "@angular/forms": "~20.3.14", "@angular/material": "20.2.11", - "@angular/platform-browser": "20.3.10", - "@angular/router": "20.3.10", + "@angular/platform-browser": "~20.3.14", + "@angular/router": "~20.3.14", "@ngx-translate/core": "~17.0.0", "@ngx-translate/http-loader": "~17.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, "devDependencies": { - "@angular/build": "20.3.9", - "@angular/cli": "20.3.9", - "@angular/compiler-cli": "20.3.10", - "@angular/platform-browser-dynamic": "20.3.10", + "@angular/build": "20.3.12", + "@angular/cli": "20.3.12", + "@angular/compiler-cli": "20.3.14", + "@angular/platform-browser-dynamic": "~20.3.14", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.9.0", "karma": "~6.4.0", @@ -261,12 +261,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2003.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.9.tgz", - "integrity": "sha512-p0GO2H8hiZjRHI9sm4tXTF3OpWaEnkqvB0GBGJfGp8RvpPfDA2t3j2NAUNtd75H+B0xdfyWLmNq9YJGpy6gznA==", + "version": "0.2003.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.12.tgz", + "integrity": "sha512-5H40lAFF4CKY32C4HOp6bTlOF1f4WsGCwe7FjFQp9A+T7yoCBiHpIWt2JKTwV4sBoTKVDZOnuf0GG+UVKjQT4A==", "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", + "@angular-devkit/core": "20.3.12", "rxjs": "7.8.2" }, "engines": { @@ -276,16 +276,16 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.9.tgz", - "integrity": "sha512-DCzHY+EQ98u0h1n8s9add1KVSNWco1RW/Rl8TRkEuGmRQ43MpOfTIZQvlnnqaeMcNH0fZ4zkybVBDj7korJbZg==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.12.tgz", + "integrity": "sha512-HPepPbJA5vprYTWJaSCfpk0s1bPT6Ui6VjFOSb9oY+p9iq+MGkuB1I+swNcRcMLttyMD+FpbMd27F8jSeX5XVw==", "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.9", - "@angular-devkit/build-webpack": "0.2003.9", - "@angular-devkit/core": "20.3.9", - "@angular/build": "20.3.9", + "@angular-devkit/architect": "0.2003.12", + "@angular-devkit/build-webpack": "0.2003.12", + "@angular-devkit/core": "20.3.12", + "@angular/build": "20.3.12", "@babel/core": "7.28.3", "@babel/generator": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", @@ -296,7 +296,7 @@ "@babel/preset-env": "7.28.3", "@babel/runtime": "7.28.3", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "20.3.9", + "@ngtools/webpack": "20.3.12", "ansi-colors": "4.1.3", "autoprefixer": "10.4.21", "babel-loader": "10.0.0", @@ -351,7 +351,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.9", + "@angular/ssr": "^20.3.12", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0 || ^30.2.0", @@ -408,12 +408,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.2003.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.9.tgz", - "integrity": "sha512-2VSKR4BR/M3g5VvAJpKdytAErPt8Oj+HzTKp+ujVeJEBs3U48bpb6mZJOMTxU1YFf2hvawDQo5aiwkondS1qLg==", + "version": "0.2003.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.12.tgz", + "integrity": "sha512-IkhCU0nAsXYBQOfHu2gQBcYBKhaV1c8wYtu7MmelBcN/iUrG8hRf1sZx+ppUgsdZuBYxCiDiLpcfRVRCIASkvw==", "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.9", + "@angular-devkit/architect": "0.2003.12", "rxjs": "7.8.2" }, "engines": { @@ -427,9 +427,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.9.tgz", - "integrity": "sha512-bXsAGIUb4p60x548YmvnMvjwd3FwWz6re1uTM7dV0XH8nQn3XMhOQ3Q3sAckzJHxkDuaRhB3K/a4kupoOmVfTQ==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.12.tgz", + "integrity": "sha512-ReFxd/UOoVDr3+kIUjmYILQZF89qg62POdY7a7OqBH7plmInFlYVSEDouJvGqj3LVCPiqTk2ZOSChbhS/eLxXA==", "license": "MIT", "dependencies": { "ajv": "8.17.1", @@ -454,13 +454,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.9.tgz", - "integrity": "sha512-oaIjAKPmHMZBTC0met5M7dbXBeZnCNwmHacT/kBHNVBAz/NI95fuAfb2P0Jxt7gWdQXejDSxWp0tL+sZIyO0xw==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.12.tgz", + "integrity": "sha512-JqJ1u59y+Ud51k/8MHYzSP+aQOeC2PJBaDmMnvqfWVaIt6n3x4gc/VtuhqhpJ0SKulbFuOWgAfI6QbPFrgUYQQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", + "@angular-devkit/core": "20.3.12", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -473,9 +473,9 @@ } }, "node_modules/@angular/animations": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.10.tgz", - "integrity": "sha512-WSKHyF82URlAQkYGWZjozZgSYj2ClH40GDunayz6kuRewup639iH91HE8sbFfVqKgqELKIAy2E0LhmtDKnMwZA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.14.tgz", + "integrity": "sha512-Sx3/XNu2rR+R8T8JkJEaIpZDZPk0IecS0Ayt6HTanNUZXuw0HVou3vkjR5B2St5nM4MXs0gh+S6aLNuArtqJTQ==", "license": "MIT", "peer": true, "dependencies": { @@ -485,17 +485,17 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.10" + "@angular/core": "20.3.14" } }, "node_modules/@angular/build": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.9.tgz", - "integrity": "sha512-Ulimvg6twPSCraaZECEmENfKBlD4M1yqeHlg6dCzFNM4xcwaGUnuG6O3cIQD59DaEvaG73ceM2y8ftYdxAwFow==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.12.tgz", + "integrity": "sha512-iAZve4VPviC8y6RFctyh3qFXSlP5mth9K46/0zasB4LV4pcmu8BrzIHERxIn/jCDNdVdPh973kxo1ksO4WpyuA==", "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.9", + "@angular-devkit/architect": "0.2003.12", "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -537,7 +537,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.9", + "@angular/ssr": "^20.3.12", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -603,19 +603,19 @@ } }, "node_modules/@angular/cli": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.9.tgz", - "integrity": "sha512-4eKpRDg96B20yrKJqjA24zgxYy1RiRd70FvF/KG1hqSowsWwtzydtEJ3VM6iFWS9t1D8truuVpKjMEnn1Y274A==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.12.tgz", + "integrity": "sha512-vqVyVjbFPCRMjA5evL7tV2JeR6Anuzb9WcXTMB17fr7uzKNNAvo7KyRaOJjp+TU4JDARTNyGPy0aywfPx7R60A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.9", - "@angular-devkit/core": "20.3.9", - "@angular-devkit/schematics": "20.3.9", + "@angular-devkit/architect": "0.2003.12", + "@angular-devkit/core": "20.3.12", + "@angular-devkit/schematics": "20.3.12", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.3.9", + "@schematics/angular": "20.3.12", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", "ini": "5.0.0", @@ -638,9 +638,9 @@ } }, "node_modules/@angular/common": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.10.tgz", - "integrity": "sha512-12fEzvKbEqjqy1fSk9DMYlJz6dF1MJVXuC5BB+oWWJpd+2lfh4xJ62pkvvLGAICI89hfM5n9Cy5kWnXwnqPZsA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.14.tgz", + "integrity": "sha512-OOUvjTtnpktJLsNupA+GFT2q5zNocPdpOENA8aSrXvAheNybLjgi+otO3U3sQsvB1VwaoEZ9GT5O3lZlstnA/A==", "license": "MIT", "peer": true, "dependencies": { @@ -650,14 +650,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.10", + "@angular/core": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.10.tgz", - "integrity": "sha512-cW939Lr8GZjPSYfbQKIDNrUaHWmn2M+zBbERThfq5skLuY+xM60bJFv4NqBekfX6YqKLCY62ilUZlnImYIXaqA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.14.tgz", + "integrity": "sha512-KFbfPPAbclzGDujCVruflCD9j4Zwwxvrg7Y4C9GJYs3LZ85t+BfIMDDnvpBUM07ZLnfY4TO4gQdHmJAcaGGXDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -667,9 +667,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.10.tgz", - "integrity": "sha512-9BemvpFxA26yIVdu8ROffadMkEdlk/AQQ2Jb486w7RPkrvUQ0pbEJukhv9aryJvhbMopT66S5H/j4ipOUMzmzQ==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.14.tgz", + "integrity": "sha512-lFg9ikwRClzDPjdFiwynbVFIi1RJZf/0i+OHa3Ns2gzXxJeHNKMJrHHjWZ2DU4N2UpxH0YAPe22N9Bie28IuQQ==", "license": "MIT", "peer": true, "dependencies": { @@ -690,7 +690,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.10", + "@angular/compiler": "20.3.14", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -700,9 +700,9 @@ } }, "node_modules/@angular/core": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.10.tgz", - "integrity": "sha512-g99Qe+NOVo72OLxowVF9NjCckswWYHmvO7MgeiZTDJbTjF9tXH96dMx7AWq76/GUinV10sNzDysVW16NoAbCRQ==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.14.tgz", + "integrity": "sha512-rpyEbhWF6Fj/xI9IvNLZh5QBUYnoXuF7vX54CCtyQ2MHALxRR/aa1WRxjRM96cF2OqodQ/Gj3oYW8ei8hlBh4w==", "license": "MIT", "peer": true, "dependencies": { @@ -712,7 +712,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.10", + "@angular/compiler": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -726,9 +726,9 @@ } }, "node_modules/@angular/forms": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.10.tgz", - "integrity": "sha512-9yWr51EUauTEINB745AaHwZNTHLpXIm4uxuykxzOg+g2QskEgVfH26uS8G2ogdNuwYpB8wnsXWr34qhM3qgOWw==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.14.tgz", + "integrity": "sha512-fGrJ589tU+AKoxf+kaRrEw7wlSfVr1/z/Fz625ggFCc6ySQEityKW3JsnLfNkh5qGrdxib4BOfF78f9J7Pyk+w==", "license": "MIT", "peer": true, "dependencies": { @@ -738,9 +738,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -762,9 +762,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.10.tgz", - "integrity": "sha512-UV8CGoB5P3FmJciI3/I/n3L7C3NVgGh7bIlZ1BaB/qJDtv0Wq0rRAGwmT/Z3gwmrRtfHZWme7/CeQ2CYJmMyUQ==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.14.tgz", + "integrity": "sha512-Lviz9GfsIyOIBDal8QhIBKU8OMH29A0RhFw2opTC50sqKadXLN9CD7iSaAwQbNLc4mc3JAF4zth0AzKdHLbz7Q==", "license": "MIT", "peer": true, "dependencies": { @@ -774,9 +774,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.3.10", - "@angular/common": "20.3.10", - "@angular/core": "20.3.10" + "@angular/animations": "20.3.14", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14" }, "peerDependenciesMeta": { "@angular/animations": { @@ -785,9 +785,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.10.tgz", - "integrity": "sha512-gtZPCuxfxxkMzHYBdTU9tJeTiHj+Aty3C408DJGtGU+7rZgKt9hDC14vQN9OVzB9Ly9Jwj2yr8u7AH80TxxCJw==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.14.tgz", + "integrity": "sha512-g9z/g8gIOrBCX1SQ/GWwB0+JXBC6CKe0+yRyy9GGeBLm/YXWZHxTkmnDmueXXfPtUl8TOAInE22wlLcfunWTrg==", "dev": true, "license": "MIT", "dependencies": { @@ -797,16 +797,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/compiler": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10" + "@angular/common": "20.3.14", + "@angular/compiler": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14" } }, "node_modules/@angular/router": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.10.tgz", - "integrity": "sha512-Z03cfH1jgQ7XMDJj4R8qAGqivcvhdG3wYBwaiN1K1ODBgPhbFKNeD4stKqYp7xBNtswmM2O2jMxrL/Djwju4Gg==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.14.tgz", + "integrity": "sha512-gi7/NuHRS9n9RCwh03VuVFizVMa2lKL/s+7yP3Ecq2nQ5uSeTMWb/91OmGEBwncI3wKPkYdQ9g3n6PvK/O8uDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -815,9 +815,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -2800,26 +2800,26 @@ } }, "node_modules/@inquirer/ansi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", - "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/checkbox": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", - "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2855,19 +2855,19 @@ } }, "node_modules/@inquirer/core": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", - "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2882,15 +2882,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.21", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", - "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2905,15 +2905,15 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", - "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2928,13 +2928,13 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", "dependencies": { - "chardet": "^2.1.0", + "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "engines": { @@ -2950,23 +2950,23 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", - "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", - "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2981,14 +2981,14 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", - "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3003,15 +3003,15 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", - "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3057,15 +3057,15 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", - "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3080,16 +3080,16 @@ } }, "node_modules/@inquirer/search": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", - "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3104,17 +3104,17 @@ } }, "node_modules/@inquirer/select": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", - "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3129,9 +3129,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", - "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "license": "MIT", "engines": { "node": ">=18" @@ -3956,9 +3956,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.9.tgz", - "integrity": "sha512-3h5laY9+kP7Tzociy3Lg5sMfpTTKMU+XbLQAHxnIvywHLD6r/fgVkwRli8GZf5JFMTwAkul0AQPKom9SCSWJLg==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.12.tgz", + "integrity": "sha512-ePuofHOtbgvEq2t+hcmL30s4q9HQ/nv9ABwpLiELdVIObcWUnrnizAvM7hujve/9CQL6gRCeEkxPLPS4ZrK9AQ==", "license": "MIT", "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -4179,9 +4179,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -4942,14 +4942,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.9.tgz", - "integrity": "sha512-XkgTwGhhrx+MVi2+TFO32d6Es5Uezzx7Y7B/e2ulDlj08bizxQj+9wkeLt5+bR8JWODHpEntZn/Xd5WvXnODGA==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.12.tgz", + "integrity": "sha512-ikl+nkWUab/Z4eSkBHgq9FLIUH8qh4OcYKeBQ0fyWqIUFHyjjK0JOfwmH1g/3zAmuUMtkthHCehAtyKzCTQjVA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", - "@angular-devkit/schematics": "20.3.9", + "@angular-devkit/core": "20.3.12", + "@angular-devkit/schematics": "20.3.12", "jsonc-parser": "3.3.1" }, "engines": { @@ -5209,9 +5209,9 @@ } }, "node_modules/@types/jasmine": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.12.tgz", - "integrity": "sha512-1BzPxNsFDLDfj9InVR3IeY0ZVf4o9XV+4mDqoCfyPkbsA7dYyKAPAb2co6wLFlHcvxPlt1wShm7zQdV7uTfLGA==", + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.13.tgz", + "integrity": "sha512-MYCcDkruFc92LeYZux5BC0dmqo2jk+M5UIZ4/oFnAPCXN9mCcQhLyj7F3/Za7rocVyt5YRr1MmqJqFlvQ9LVcg==", "dev": true, "license": "MIT" }, @@ -5228,9 +5228,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", - "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -5870,9 +5870,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.25", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz", - "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==", + "version": "2.8.31", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", + "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -5925,37 +5925,28 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/bonjour-service": { @@ -5998,9 +5989,9 @@ } }, "node_modules/browserslist": { - "version": "4.27.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", - "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", "funding": [ { "type": "opencollective", @@ -6018,10 +6009,10 @@ "license": "MIT", "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { @@ -6106,9 +6097,9 @@ } }, "node_modules/cacache/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -6215,9 +6206,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001754", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", - "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", + "version": "1.0.30001757", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", "funding": [ { "type": "opencollective", @@ -6582,16 +6573,17 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -6665,12 +6657,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", - "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", + "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.26.3" + "browserslist": "^4.28.0" }, "funding": { "type": "opencollective", @@ -6848,9 +6840,9 @@ } }, "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -6864,9 +6856,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "license": "MIT", "engines": { "node": ">=18" @@ -7037,9 +7029,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.245", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.245.tgz", - "integrity": "sha512-rdmGfW47ZhL/oWEJAY4qxRtdly2B98ooTJ0pdEI4jhVLZ6tNf8fPtov2wS1IRKwFJT92le3x4Knxiwzl7cPPpQ==", + "version": "1.5.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", + "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -8152,28 +8144,24 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-parser-js": { @@ -8381,9 +8369,9 @@ } }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", "engines": { @@ -8794,9 +8782,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -9141,6 +9129,23 @@ "node": ">= 6" } }, + "node_modules/karma/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/karma/node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -9272,6 +9277,16 @@ "node": ">=0.10.0" } }, + "node_modules/karma/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/karma/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -9508,6 +9523,7 @@ "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "license": "MIT", + "peer": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -9809,9 +9825,9 @@ } }, "node_modules/memfs": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.50.0.tgz", - "integrity": "sha512-N0LUYQMUA1yS5tJKmMtU9yprPm6ZIg24yr/OVv/7t6q0kKDIho4cBbXRi1XKttUmNYDYgF/q45qrKE/UhGO0CA==", + "version": "4.51.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.51.0.tgz", + "integrity": "sha512-4zngfkVM/GpIhC8YazOsM6E8hoB33NP0BCESPOA6z7qaL6umPJNqkO8CNYaLV2FB2MV6H1O3x2luHHOSqppv+A==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.11.0", @@ -9911,16 +9927,20 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-function": { @@ -10291,9 +10311,9 @@ "optional": true }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", + "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -10509,9 +10529,9 @@ } }, "node_modules/npm-packlist/node_modules/proc-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", - "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "dev": true, "license": "ISC", "engines": { @@ -10791,9 +10811,9 @@ } }, "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -11131,9 +11151,9 @@ } }, "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "dev": true, "license": "MIT", "engines": { @@ -11406,16 +11426,16 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" @@ -13359,6 +13379,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -13587,6 +13608,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -13827,6 +13849,22 @@ "node": ">= 6" } }, + "node_modules/webpack-dev-server/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", @@ -14489,13 +14527,13 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.6", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", - "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", + "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", "dev": true, "license": "ISC", "peerDependencies": { - "zod": "^3.24.1" + "zod": "^3.25 || ^4" } } } diff --git a/package.json b/package.json index c527292..e37b339 100644 --- a/package.json +++ b/package.json @@ -10,26 +10,26 @@ }, "private": true, "dependencies": { - "@angular-devkit/build-angular": "~20.3.9", - "@angular/animations": "20.3.10", + "@angular-devkit/build-angular": "~20.3.12", + "@angular/animations": "20.3.14", "@angular/cdk": "20.2.11", - "@angular/common": "20.3.10", - "@angular/compiler": "20.3.10", - "@angular/core": "20.3.10", - "@angular/forms": "20.3.10", + "@angular/common": "~20.3.14", + "@angular/compiler": "20.3.14", + "@angular/core": "20.3.14", + "@angular/forms": "~20.3.14", "@angular/material": "20.2.11", - "@angular/platform-browser": "20.3.10", - "@angular/router": "20.3.10", + "@angular/platform-browser": "~20.3.14", + "@angular/router": "~20.3.14", "@ngx-translate/core": "~17.0.0", "@ngx-translate/http-loader": "~17.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, "devDependencies": { - "@angular/build": "20.3.9", - "@angular/cli": "20.3.9", - "@angular/compiler-cli": "20.3.10", - "@angular/platform-browser-dynamic": "20.3.10", + "@angular/build": "20.3.12", + "@angular/cli": "20.3.12", + "@angular/compiler-cli": "20.3.14", + "@angular/platform-browser-dynamic": "~20.3.14", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.9.0", "karma": "~6.4.0", diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 8fe8c53..03c2f48 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -6,7 +6,7 @@ import {provideAnimations} from '@angular/platform-browser/animations'; import {provideHttpClient} from '@angular/common/http'; import {provideTranslateService} from '@ngx-translate/core'; import {provideTranslateHttpLoader} from '@ngx-translate/http-loader'; -import {Constants} from './constants/Constants'; +import {LocalStoreConstants} from './constants/LocalStoreConstants'; const INITIAL_LANG = getInitialLang(); @@ -30,7 +30,7 @@ export const appConfig: ApplicationConfig = { }; function getInitialLang(): string { - const saved = localStorage.getItem(Constants.LANGUAGE_KEY); + const saved = localStorage.getItem(LocalStoreConstants.LANGUAGE_KEY); if (saved) return saved; const nav = typeof navigator !== 'undefined' ? navigator.language?.toLowerCase() : 'en'; return nav?.startsWith('de') ? 'de' : 'en'; diff --git a/src/app/app.html b/src/app/app.html deleted file mode 100644 index e69f15c..0000000 --- a/src/app/app.html +++ /dev/null @@ -1,36 +0,0 @@ - - {{ 'APP.TITLE' | translate }} - - - - - - - - - {{ lang.lang() === 'de' ? ('LANG.DE' | translate) : ('LANG.EN' | translate) }} - - - - - - {{ 'LANG.DE' | translate }} - - - - - {{ 'LANG.EN' | translate }} - - - - - - - - -
- -
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index da126ee..4320e95 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,6 +1,10 @@ import { Routes } from '@angular/router'; -import {WelcomeComponent} from './features/welcome/welcome'; +import {AboutComponent} from './pages/about/about.component'; +import {ProjectsComponent} from './pages/projects/projects.component'; export const routes: Routes = [ - { path: '', component: WelcomeComponent }, + { path: '', component: AboutComponent }, + { path: 'about', component: AboutComponent}, + { path: 'projects', component: ProjectsComponent}, ]; + diff --git a/src/app/app.scss b/src/app/app.scss deleted file mode 100644 index 4120908..0000000 --- a/src/app/app.scss +++ /dev/null @@ -1,13 +0,0 @@ -.spacer { flex: 1 1 auto; } -.container { max-width: 960px; margin: 24px auto; padding: 0 16px; } -mat-form-field { --mdc-outlined-text-field-container-shape: 20px; } - -.flag-icon { - width: 20px; - height: 14px; - object-fit: cover; - border-radius: 2px; - box-shadow: 0 0 0 1px rgba(0,0,0,.08) inset; - vertical-align: -2px; -} -mat-option .flag-icon { margin-right: 8px; } diff --git a/src/app/app.ts b/src/app/app.ts deleted file mode 100644 index 7ed0683..0000000 --- a/src/app/app.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {Component, computed, effect, inject} from '@angular/core'; -import { RouterOutlet } from '@angular/router'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { MatSelectModule } from '@angular/material/select'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { FormsModule } from '@angular/forms'; - -import { TranslateModule } from '@ngx-translate/core'; -import { ThemeService } from './service/theme.service'; - -import {LanguageService} from './service/language.service'; - -@Component({ - selector: 'app-root', - standalone: true, - imports: [ - RouterOutlet, - MatToolbarModule, MatIconModule, MatButtonModule, - MatFormFieldModule, MatSelectModule, - FormsModule, - TranslateModule - ], - templateUrl: './app.html', - styleUrl: './app.scss', -}) -export class App { - readonly theme = inject(ThemeService); - readonly lang = inject(LanguageService); - readonly themeIcon = computed(() => this.theme.theme() === 'dark' ? 'light_mode' : 'dark_mode'); -} diff --git a/src/app/constants/AssetsConstants.ts b/src/app/constants/AssetsConstants.ts new file mode 100644 index 0000000..4727ef3 --- /dev/null +++ b/src/app/constants/AssetsConstants.ts @@ -0,0 +1,16 @@ +export class AssetsConstants { + + static readonly ME = '/assets/me.webp'; + static readonly LOGO = '/assets/favicon.ico'; + static readonly FLAG_DE = '/assets/flags/de.svg'; + static readonly FLAG_EN = '/assets/flags/gb.svg'; + + //logos + static readonly CHAMAELEON_LOGO = '/assets/logos/logo_chamaeleon.svg'; + static readonly TH_BINGEN_LOGO = '/assets/logos/bingen-logo-white.svg'; + static readonly ASSYST_LOG = '/assets/logos/assyst_gmbh_logo.jpg'; + static readonly COLORDIGITAL_LOGO = '/assets/logos/dmixcloud_logo.jpg'; + static readonly TERAPORT_LOGO = '/assets/logos/teraport_gmbh_logo.jpg'; + + static readonly CV: 'assets/cv/andreas-dahm-cv.pdf'; +} diff --git a/src/app/constants/Constants.ts b/src/app/constants/LocalStoreConstants.ts similarity index 80% rename from src/app/constants/Constants.ts rename to src/app/constants/LocalStoreConstants.ts index e1b8d9c..71d3b66 100644 --- a/src/app/constants/Constants.ts +++ b/src/app/constants/LocalStoreConstants.ts @@ -1,4 +1,4 @@ -export class Constants{ +export class LocalStoreConstants { static readonly THEME_KEY = 'theme'; static readonly LANGUAGE_KEY = 'lang'; diff --git a/src/app/constants/UrlConstants.ts b/src/app/constants/UrlConstants.ts new file mode 100644 index 0000000..ec5fe29 --- /dev/null +++ b/src/app/constants/UrlConstants.ts @@ -0,0 +1,4 @@ +export class UrlConstants { + static readonly LINKED_IN = 'https://www.linkedin.com/in/andreas-dahm-2395991ba'; + static readonly GIT_HUB = 'https://github.com/LoboTheDark'; +} diff --git a/src/app/features/welcome/welcome.html b/src/app/features/welcome/welcome.html deleted file mode 100644 index e20ab2d..0000000 --- a/src/app/features/welcome/welcome.html +++ /dev/null @@ -1,28 +0,0 @@ - - - {{ `WELCOME.TITLE` | translate }} - {{ `WELCOME.SUB` | translate }} - - - -

{{ `WELCOME.TEXT` | translate }}

-

- {{ `WELCOME.COUNTER` | translate }}: {{ count() }} -

-
- - - - - -
diff --git a/src/app/features/welcome/welcome.scss b/src/app/features/welcome/welcome.scss deleted file mode 100644 index c51b898..0000000 --- a/src/app/features/welcome/welcome.scss +++ /dev/null @@ -1,5 +0,0 @@ -mat-card { - margin-top: 2rem; - display: block; - background-color: var(--app-card-background); -} diff --git a/src/app/features/welcome/welcome.ts b/src/app/features/welcome/welcome.ts deleted file mode 100644 index f41e8a1..0000000 --- a/src/app/features/welcome/welcome.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component, signal } from '@angular/core'; -import { MatCardModule } from '@angular/material/card'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import {TranslatePipe} from '@ngx-translate/core'; - -@Component({ - selector: 'app-welcome', - standalone: true, - imports: [MatCardModule, MatButtonModule, MatIconModule, TranslatePipe], - templateUrl: './welcome.html', - styleUrl: './welcome.scss', -}) -export class WelcomeComponent { - readonly count = signal(0); - inc() { this.count.update(v => v + 1); } - reset() { this.count.set(0); } -} diff --git a/src/app/layout/app/app.component.html b/src/app/layout/app/app.component.html new file mode 100644 index 0000000..f236b2d --- /dev/null +++ b/src/app/layout/app/app.component.html @@ -0,0 +1,9 @@ + + +
+ +
+ + diff --git a/src/app/layout/app/app.component.scss b/src/app/layout/app/app.component.scss new file mode 100644 index 0000000..f3ee3d5 --- /dev/null +++ b/src/app/layout/app/app.component.scss @@ -0,0 +1,10 @@ +.container { max-width: 1100px; margin: 0 auto; padding: 1rem; } +.app-surface { + background: var(--app-bg); + color: var(--app-fg); + transition: background-color 220ms ease, color 220ms ease; +} +.foot { + border-top: 1px solid rgba(0,0,0,.08); + padding: 1rem; text-align: center; opacity: .8; +} diff --git a/src/app/layout/app/app.component.ts b/src/app/layout/app/app.component.ts new file mode 100644 index 0000000..5a5aef1 --- /dev/null +++ b/src/app/layout/app/app.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import {TopbarComponent} from '../topbar/topbar.component'; +import {TranslatePipe} from '@ngx-translate/core'; + + +@Component({ + selector: 'app-root', + standalone: true, + imports: [RouterOutlet, TopbarComponent, TranslatePipe], + templateUrl: './app.component.html', + styleUrl: './app.component.scss' +}) +export class AppComponent { + currentYear = new Date().getFullYear(); +} diff --git a/src/app/layout/topbar/topbar.component.html b/src/app/layout/topbar/topbar.component.html new file mode 100644 index 0000000..d42c9eb --- /dev/null +++ b/src/app/layout/topbar/topbar.component.html @@ -0,0 +1,58 @@ + + + + {{ 'APP.TITLE' | translate }} + + + + + + + + + + + + + + + diff --git a/src/app/layout/topbar/topbar.component.scss b/src/app/layout/topbar/topbar.component.scss new file mode 100644 index 0000000..a148769 --- /dev/null +++ b/src/app/layout/topbar/topbar.component.scss @@ -0,0 +1,73 @@ +.topbar { + position: sticky; top: 0; z-index: 100; + backdrop-filter: saturate(1.1) blur(8px); + background: + color-mix(in oklab, var(--app-bg) 80%, transparent); + border-bottom: 1px solid rgba(0,0,0,.08); + + .brand { + display:flex; align-items:center; gap:.6rem; + color: inherit; text-decoration: none; + .logo-dot { + width: 48px; height: 48px; border-radius: 50%; + } + .brand-text { font-weight: 600; letter-spacing:.2px; } + } + + .nav { display:flex; gap:.25rem; margin-left:.5rem; } + + .spacer { flex: 1; } + + .flag-icon { width: 18px; height: 18px; border-radius: 2px; margin-right:.5rem; } + + .menu-section { padding:.25rem .5rem .5rem; } + .menu-title { font-size:.75rem; opacity:.75; padding:.25rem .75rem .5rem; } + + .kbd { + margin-left:auto; font-size:.7rem; opacity:.65; border:1px solid currentColor; + border-radius:4px; padding:0 .35rem; + } +} + +::ng-deep .mat-mdc-menu-item .mdc-list-item__primary-text { + display: flex; + align-items: center; + gap: .5rem; +} + +::ng-deep .mat-mdc-menu-item .kbd { + margin-left: auto; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 11px; + line-height: 1.6; + padding: 0 .35rem; + border: 0px solid currentColor; + border-radius: 4px; + opacity: .65; +} + +::ng-deep .mat-mdc-menu-item .mat-icon { + width: 20px; height: 20px; font-size: 20px; +} + +::ng-deep .mat-mdc-menu-item .flag-icon { + width: 20px !important; + height: 14px !important; + object-fit: cover; + border-radius: 2px; + margin-right: .5rem; + vertical-align: middle; +} + +::ng-deep .mat-mdc-menu-panel { + border-radius: 10px !important; + border: 1px solid rgba(0,0,0,.14); +} +.dark ::ng-deep .mat-mdc-menu-panel { + border-color: rgba(255,255,255,.06); +} + +/* Responsive: Collapse navigation to icon if width is smaller than 760px */ +@media (max-width: 760px) { + .topbar .nav { display:none; } +} diff --git a/src/app/layout/topbar/topbar.component.ts b/src/app/layout/topbar/topbar.component.ts new file mode 100644 index 0000000..9dad819 --- /dev/null +++ b/src/app/layout/topbar/topbar.component.ts @@ -0,0 +1,44 @@ +import { Component, computed, inject } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TranslateModule } from '@ngx-translate/core'; +import { ThemeService } from '../../service/theme.service'; +import { LanguageService } from '../../service/language.service'; +import { MatDivider } from '@angular/material/divider'; +import {AssetsConstants} from '../../constants/AssetsConstants'; + +@Component({ + selector: 'app-topbar', + standalone: true, + imports: [ + RouterLink, + MatToolbarModule, MatIconModule, MatButtonModule, MatMenuModule, MatTooltipModule, + TranslateModule, MatDivider + ], + templateUrl: './topbar.component.html', + styleUrl: './topbar.component.scss' +}) +export class TopbarComponent { + readonly theme = inject(ThemeService); + readonly lang = inject(LanguageService); + + readonly themeIcon = computed(() => + this.theme.theme() === 'dark' ? 'light_mode' : 'dark_mode' + ); + + onKeydown(e: KeyboardEvent) { + const metaOrCtrl = e.metaKey || e.ctrlKey; + if (metaOrCtrl && (e.key.toLowerCase() === 'j')) { + e.preventDefault(); + this.theme.toggle(); + } + } + + setLang(code: 'de' | 'en') { this.lang.use(code); } + + protected readonly AssetsConstants = AssetsConstants; +} diff --git a/src/app/pages/about/about.component.html b/src/app/pages/about/about.component.html new file mode 100644 index 0000000..8c816ba --- /dev/null +++ b/src/app/pages/about/about.component.html @@ -0,0 +1,175 @@ +
+ +
+ {{ 'ABOUT.ALT.PROFILE' | translate }} +
+ +
+

{{ 'ABOUT.HELLO' | translate }}

+

+ {{ 'ABOUT.LEAD' | translate }} +

+ +
+
+ + {{ 'ABOUT.ROLE' | translate }} +
+
+ + {{ 'ABOUT.LOCATION' | translate }} +
+ +
+ + GitHub + · + LinkedIn +
+
+
+
+ + +

{{ 'ABOUT.SECTION.SKILLS' | translate }}

+
+
+

{{ 'ABOUT.SECTION.PRIMARY' | translate }}

+ + @for (s of primarySkills; track primarySkills) { + {{ s | translate }} + } + +
+ +
+

{{ 'ABOUT.SECTION.TOOLSET' | translate }}

+ + @for (t of toolset; track toolset) { + {{ t | translate }} + } + +
+
+
+ + +

{{ 'ABOUT.SECTION.EXPERIENCE' | translate }}

+
+ @for (entry of xpKeys; track entry) { +
+
+
+ +
+
+ {{ (entry.key + '.ROLE') | translate }} + {{ (entry.key + '.TIME') | translate }} +
+ +
+ {{ (entry.key + '.COMPANY') | translate }} +
+ +
+
+
    +
  • {{ entry.key + '.HIGHLIGHTS.P1' | translate }}
  • +
  • {{ entry.key + '.HIGHLIGHTS.P2' | translate }}
  • +
  • {{ entry.key + '.HIGHLIGHTS.P3' | translate }}
  • +
+
+
+ + @if(entry.key !== xpKeys.at(xpKeys.length-1)?.key) + { + + } + } +
+
+ +

{{ 'ABOUT.SECTION.PROJECTS' | translate }}

+ +
+ @for (entry of projectKeys; track entry) { +
+
+ {{ (entry.key + '.TITLE') | translate }} +
+
+ {{ (entry.key + '.DESCRIPTION') | translate }} +
+ + +
+
    +
  • {{ entry.key + '.HIGHLIGHTS.P1' | translate }}
  • +
  • {{ entry.key + '.HIGHLIGHTS.P2' | translate }}
  • +
  • {{ entry.key + '.HIGHLIGHTS.P3' | translate }}
  • +
+
+
+ + @if(entry.key !== projectKeys.at(projectKeys.length-1)?.key) + { + + } + } +
+
+ + +

{{ 'ABOUT.SECTION.EDUCATION' | translate }}

+ +
+
+ @for (entry of educationKeys; track entry) { +
+ {{ (entry.key + '.WHERE') | translate }} + {{ (entry.key + '.WHEN') | translate }} +
+
+ {{ (entry.key + '.WHAT') | translate }} +
+ + @if(entry.key !== educationKeys.at(educationKeys.length-1)?.key) + { + + } + } +
+
+
+
diff --git a/src/app/pages/about/about.component.scss b/src/app/pages/about/about.component.scss new file mode 100644 index 0000000..da02c8b --- /dev/null +++ b/src/app/pages/about/about.component.scss @@ -0,0 +1,217 @@ +.about { + display: grid; + gap: 1rem; +} + +/* Hero block: Photo + Intro */ +.hero { + display: grid; + grid-template-columns: 240px 1fr; + gap: 1.25rem; + border-radius: 16px; + background: var(--app-card-background); + + .photo { + align-items:flex-start; justify-content:center; + img { + display:block; + width: 100%; height: auto; + max-width: 220px; + border-radius: 12px; + box-shadow: 0 6px 24px rgba(0,0,0,.25); + object-fit: cover; + } + } + + .intro { + display:flex; flex-direction:column; gap:.5rem; + h1 { margin-top: .25rem } + .lead { opacity:.9; margin: .25rem 0 0.5rem; } + + .meta { + display:flex; flex-direction:column; gap:.25rem; margin-bottom: 0.5rem; + .row { + display:flex; align-items:center; gap:.4rem; + a { color: inherit; } + } + } + + .actions { + display:flex; gap:.5rem; flex-wrap:wrap; margin-top:.5rem; + .mat-icon { margin-right:.25rem; } + + } + } +} + +/* Skills block */ +.skills { + border-radius: 16px; + padding: 5px; + background: var(--app-card-background); + + h2 { margin-top: .25rem; margin-left: .25rem; } + .chip-groups { + margin-left: .25rem; + display:grid; gap:1rem; + grid-template-columns: 1fr 1fr; + margin-bottom: .5rem; + h3 { margin: .2rem 0 .4rem; font-size: .95rem; opacity:.85; } + mat-chip-set { + display:flex; flex-wrap:wrap; gap:.4rem; + } + } +} + +/* Experience block */ +.experience { + border-radius: 16px; + padding: 5px; + background: var(--app-card-background); + h2 { margin-top: .25rem;margin-left: .25rem; } + .xp-list { + margin-left: .25rem; + display: grid; gap: .75rem; + } + .xp-item { + .xp-head { + display:flex; align-items:baseline; gap:.5rem; + .time { opacity:.75; font-size:.9rem; } + } + .xp-sub { opacity:.9; margin-bottom:.25rem; } + ul { margin: .25rem 0 .5rem 1.15rem; } + } +} + +/* Experience block */ +.projects { + border-radius: 16px; + padding: 5px; + background: var(--app-card-background); + h2 { margin-top: .25rem;margin-left: .25rem; } + .xp-list { + margin-left: .25rem; + display: grid; gap: .75rem; + } + .xp-item { + .xp-head { + display:flex; align-items:baseline; gap:.5rem; + .time { opacity:.75; font-size:.9rem; } + } + .xp-sub { opacity:.9; margin-bottom:.25rem; } + ul { margin: .25rem 0 .5rem 1.15rem; } + } +} + +/* Experience block */ +.education { + border-radius: 16px; + padding: 5px; + background: var(--app-card-background); + h2 { margin-top: .25rem;margin-left: .25rem; } + .xp-list { + margin-left: .25rem; + display: grid; gap: .75rem; + } + .xp-item { + .xp-head { + display:flex; align-items:baseline; gap:.5rem; + .time { opacity:.75; font-size:.9rem; } + } + .xp-sub { opacity:.9; margin-bottom:.25rem; } + ul { margin: .25rem 0 .5rem 1.15rem; } + } +} + +/* Responsive */ +@media (max-width: 900px) { + .hero { grid-template-columns: 1fr; } + .hero .photo { justify-content: flex-start; } + .skills .chip-groups { grid-template-columns: 1fr; } +} + +.xp-head-grid { + display: grid; + grid-template-columns: calc(48px + .75rem) 1fr; /* 1: Logo, 2: Text */ + grid-template-rows: auto auto; /* 1: Role/Time, 2: Company */ + column-gap: .75rem; +} + +.logo-wrap { + grid-row: 1 / span 2; + grid-column: 1; + display: flex; + align-items: center; +} + +.company-logo { + width: 48px; + height: 48px; + object-fit: contain; + opacity: .9; + border-radius: 10%; + background-color: var(--app-logo-bg); +} + + +.head-row { + grid-row: 1; + grid-column: 2; + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: .5rem 1rem; + + strong { + font-size: 1rem; + } + .time { + opacity: .75; font-size: .9rem; + } +} + +.company-row { + grid-row: 2; + grid-column: 2; + margin-top: .1rem; + opacity: .85; +} + +.link-row { + grid-row: 2; + grid-column: 2; + margin-top: .1rem; + opacity: .85; + vertical-align: center; +} + +.link-with-icon { + display: inline-flex; + align-items: center; + gap: .35rem; + line-height: 1; +} + +.link-with-icon mat-icon { + font-size: 18px; + height: 18px; + width: 18px; +} + +.highlights { + margin-top: .4rem; + margin-left: .75rem; + padding-left: 1.2rem; + + li { + margin: .2rem 0; + } +} + +.highlights-noMargin { + margin-top: .4rem; + + li { + margin: .2rem 0; + } +} diff --git a/src/app/pages/about/about.component.ts b/src/app/pages/about/about.component.ts new file mode 100644 index 0000000..4a8ba67 --- /dev/null +++ b/src/app/pages/about/about.component.ts @@ -0,0 +1,139 @@ +import { Component} from '@angular/core'; +import { CommonModule, NgOptimizedImage } from '@angular/common'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; +import { TranslateModule } from '@ngx-translate/core'; +import {UrlConstants} from '../../constants/UrlConstants'; +import {AssetsConstants} from '../../constants/AssetsConstants'; + + +@Component({ + selector: 'app-about', + standalone: true, + imports: [ + CommonModule, NgOptimizedImage, + MatCardModule, MatChipsModule, MatIconModule, MatButtonModule, MatDividerModule, + TranslateModule + ], + templateUrl: './about.component.html', + styleUrl: './about.component.scss' +}) +export class AboutComponent { + cvHref = AssetsConstants.CV; + + xpKeys = [ + { + key: 'ABOUT.XP.COMPANY8', + logo: AssetsConstants.TERAPORT_LOGO + }, + { + key: 'ABOUT.XP.COMPANY7', + logo: AssetsConstants.COLORDIGITAL_LOGO + }, + { + key: 'ABOUT.XP.COMPANY6', + logo: AssetsConstants.COLORDIGITAL_LOGO + }, + { + key: 'ABOUT.XP.COMPANY5', + logo: AssetsConstants.ASSYST_LOG + }, + { + key: 'ABOUT.XP.COMPANY4', + logo: AssetsConstants.ASSYST_LOG + }, + { + key: 'ABOUT.XP.COMPANY3', + logo: AssetsConstants.ASSYST_LOG + }, + { + key: 'ABOUT.XP.COMPANY2', + logo: AssetsConstants.TH_BINGEN_LOGO + }, + { + key: 'ABOUT.XP.COMPANY1', + logo: AssetsConstants.TH_BINGEN_LOGO + }, + { + key: 'ABOUT.XP.COMPANY0', + logo: AssetsConstants.CHAMAELEON_LOGO + } + ]; + + projectKeys = [ + { + key: 'ABOUT.PROJECT.P2', + externalLink: 'https://andreas-dahm.eu/', + internalLink: 'projects' + }, + { + key: 'ABOUT.PROJECT.P1', + externalLink: 'https://store.steampowered.com/app/1532640/El_Mucho/', + internalLink: 'projects' + }, + { + key: 'ABOUT.PROJECT.P0', + externalLink: 'https://itch.io/c/6628860/lobos-collection', + internalLink: 'projects' + } + ]; + + educationKeys = [ + { + key: 'ABOUT.EDUCATION.E6' + }, + { + key: 'ABOUT.EDUCATION.E5' + }, + { + key: 'ABOUT.EDUCATION.E4' + }, + { + key: 'ABOUT.EDUCATION.E3' + }, + { + key: 'ABOUT.EDUCATION.E2' + }, + { + key: 'ABOUT.EDUCATION.E1' + }, + { + key: 'ABOUT.EDUCATION.E0' + } + ] + + primarySkills = [ + 'ABOUT.SKILLS.JAVA', + 'ABOUT.SKILLS.SPRING', + 'ABOUT.SKILLS.ANGULAR', + 'ABOUT.SKILLS.DOCKER', + 'ABOUT.SKILLS.UNITY', + 'ABOUT.SKILLS.PYTHON', + 'ABOUT.SKILLS.CSHARP', + 'ABOUT.SKILLS.TYPESCRIPT' + ]; + + toolset = [ + 'ABOUT.TOOLS.GIT', + 'ABOUT.TOOLS.GITHUB', + 'ABOUT.TOOLS.GITLAB', + 'ABOUT.TOOLS.JENKINS', + 'ABOUT.TOOLS.K8S', + 'ABOUT.TOOLS.POSTGRES', + 'ABOUT.TOOLS.MONGO', + 'ABOUT.TOOLS.GRAFANA', + ]; + + openMail(event: Event) { + event.preventDefault(); + const user = 'andreas.dahm'; + const domain = 'gmail.com'; + globalThis.location.href = `mailto:${user}@${domain}`; + } + + protected readonly UrlConstants = UrlConstants; + protected readonly AssetsConstants = AssetsConstants; +} diff --git a/src/app/pages/project-details/project-details.component.html b/src/app/pages/project-details/project-details.component.html new file mode 100644 index 0000000..cc13d82 --- /dev/null +++ b/src/app/pages/project-details/project-details.component.html @@ -0,0 +1 @@ +

project-details works!

diff --git a/src/app/pages/project-details/project-details.component.scss b/src/app/pages/project-details/project-details.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/pages/project-details/project-details.component.ts b/src/app/pages/project-details/project-details.component.ts new file mode 100644 index 0000000..47934ab --- /dev/null +++ b/src/app/pages/project-details/project-details.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-project-details', + imports: [], + templateUrl: './project-details.component.html', + styleUrl: './project-details.component.scss', +}) +export class ProjectDetailsComponent { + +} diff --git a/src/app/pages/projects/projects.component.html b/src/app/pages/projects/projects.component.html new file mode 100644 index 0000000..7fb276e --- /dev/null +++ b/src/app/pages/projects/projects.component.html @@ -0,0 +1 @@ +

Working in progress!

diff --git a/src/app/pages/projects/projects.component.scss b/src/app/pages/projects/projects.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/pages/projects/projects.component.ts b/src/app/pages/projects/projects.component.ts new file mode 100644 index 0000000..2b83d2e --- /dev/null +++ b/src/app/pages/projects/projects.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-projects', + imports: [], + templateUrl: './projects.component.html', + styleUrl: './projects.component.scss', +}) +export class ProjectsComponent { + +} diff --git a/src/app/service/language.service.ts b/src/app/service/language.service.ts index 4556eb1..908b62d 100644 --- a/src/app/service/language.service.ts +++ b/src/app/service/language.service.ts @@ -1,6 +1,6 @@ import { Injectable, inject, signal } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import {Constants} from '../constants/Constants'; +import {LocalStoreConstants} from '../constants/LocalStoreConstants'; type Lang = 'de' | 'en'; @@ -19,12 +19,12 @@ export class LanguageService { use(l: Lang) { this.lang.set(l); this.translate.use(l); - try { localStorage.setItem(Constants.LANGUAGE_KEY, l); } catch {} + try { localStorage.setItem(LocalStoreConstants.LANGUAGE_KEY, l); } catch {} } private getInitial(): Lang { try { - const stored = localStorage.getItem(Constants.LANGUAGE_KEY) as Lang | null; + const stored = localStorage.getItem(LocalStoreConstants.LANGUAGE_KEY) as Lang | null; if (stored === 'de' || stored === 'en') return stored; } catch {} const browser = (navigator.language || 'en').toLowerCase(); diff --git a/src/app/service/reload.service.ts b/src/app/service/reload.service.ts index e05c006..f6d0ce1 100644 --- a/src/app/service/reload.service.ts +++ b/src/app/service/reload.service.ts @@ -1,5 +1,5 @@ import { Injectable, NgZone, signal } from '@angular/core'; -import {Constants} from '../constants/Constants'; +import {LocalStoreConstants} from '../constants/LocalStoreConstants'; @Injectable({ providedIn: 'root' }) @@ -20,13 +20,13 @@ export class ReloadService { private informListeners(e: StorageEvent, zone: NgZone) { - if (e.key === Constants.LANGUAGE_KEY) { + if (e.key === LocalStoreConstants.LANGUAGE_KEY) { zone.run(() => this._languageChangedTick.update(v => v + 1)); } } bumpLanguageChanged(): void { this._reloadTick.update(v => v + 1); - localStorage.setItem(Constants.RELOAD_ALL_LANG_LISTENER_KEY, String(Date.now())); + localStorage.setItem(LocalStoreConstants.RELOAD_ALL_LANG_LISTENER_KEY, String(Date.now())); } } diff --git a/src/app/service/theme.service.ts b/src/app/service/theme.service.ts index 902bf78..4959abb 100644 --- a/src/app/service/theme.service.ts +++ b/src/app/service/theme.service.ts @@ -1,7 +1,7 @@ import { Injectable, effect, inject, signal } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { OverlayContainer } from '@angular/cdk/overlay'; -import {Constants} from '../constants/Constants'; +import {LocalStoreConstants} from '../constants/LocalStoreConstants'; type Theme = 'light' | 'dark'; @@ -20,13 +20,13 @@ export class ThemeService { body.classList.toggle('dark', isDark); overlayEl.classList.toggle('dark', isDark); - try { localStorage.setItem(Constants.THEME_KEY, this.theme()); } catch {} + try { localStorage.setItem(LocalStoreConstants.THEME_KEY, this.theme()); } catch {} }); try { const mm = globalThis.matchMedia('(prefers-color-scheme: dark)'); mm.addEventListener('change', e => { - const stored = localStorage.getItem(Constants.THEME_KEY) as Theme | null; + const stored = localStorage.getItem(LocalStoreConstants.THEME_KEY) as Theme | null; if (!stored) this.setTheme(e.matches ? 'dark' : 'light'); }); } catch {} @@ -37,7 +37,7 @@ export class ThemeService { private getInitialTheme(): Theme { try { - const stored = localStorage.getItem(Constants.THEME_KEY) as Theme | null; + const stored = localStorage.getItem(LocalStoreConstants.THEME_KEY) as Theme | null; if (stored === 'dark' || stored === 'light') return stored; } catch {} try { diff --git a/src/favicon.ico b/src/assets/favicon.ico similarity index 100% rename from src/favicon.ico rename to src/assets/favicon.ico diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index b2bee79..d60a82c 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -1,13 +1,219 @@ { - "APP": { "TITLE": "Playground" }, - "WELCOME": { - "TITLE": "Willkommen 👋", - "SUB": "Angular 20 + Material", - "TEXT": "Das ist eine einfache Start-Komponente als Basis.", - "COUNTER": "Zähler", - "INC": "Inkrementieren", - "RESET": "Zurücksetzen" + "APP": { + "TITLE": "Playground", + "COPYRIGHT": "Bilder urheberrechtlich geschützt, keine Nutzung ohne Zustimmung!" + }, + "TOPBAR": { + "ABOUT": "Über mich", + "CONTACT": "Kontakt", + "PROJECTS": "Projekte", + "HOBBY": "Hobbies", + "SETTINGS": "Einstellungen", + "LANGUAGE": "Sprache", + "APPEARANCE": "Darstellung" }, "THEME": { "LIGHT": "Hell", "DARK": "Dunkel" }, - "LANG": { "LABEL": "Sprache", "EN": "Englisch", "DE": "Deutsch" } + "LANG": { "LABEL": "Sprache", "EN": "Englisch", "DE": "Deutsch" }, + "ABOUT": { + "ALT": { "PROFILE": "Profilfoto von Andreas Dahm" }, + "HELLO": "Hallo, ich bin Andreas Dahm.", + "LEAD": "Bereits in meiner Ausbildung zum Fachinformatiker hat mich fasziniert, wie man durch Code komplexe Probleme elegant lösen kann. Nach meinem Studium der Angewandten Informatik an der FH Bingen konnte ich diese Begeisterung in verschiedensten Projekten vertiefen – von 3D-Simulationen bis zu modernen Web-Applikationen. Heute arbeite ich als Senior Software Developer und Architekt mit Fokus auf Java, Angular und DevOps. Danke, dass du vorbeischaust!", + "ROLE": "Senior Software Entwickler / Full-Stack Entwickler / Softwarearchitekt", + "LOCATION": "München · Remote", + "DOWNLOAD_CV": "Lebenslauf herunterladen", + "VIEW_PROJECTS": "Projekte ansehen", + "CONTACT_ME": "Kontaktiere mich", + "SECTION": { + "SKILLS": "Fähigkeiten & Stack", + "PRIMARY": "Schwerpunkte", + "TOOLSET": "Toolset", + "EXPERIENCE": "Erfahrung", + "PROJECTS": "Projekte", + "EDUCATION": "Ausbildung" + }, + "SKILLS": { + "JAVA": "Java 8/Java 21+", + "SPRING": "Spring Boot 2/3", + "ANGULAR": "Angular 20+", + "DOCKER": "Docker", + "UNITY": "Unity", + "PYTHON": "Python", + "CSHARP": "C#", + "TYPESCRIPT": "TypeScript" + }, + "TOOLS": { + "GIT": "Git", + "GITHUB": "Github", + "GITLAB": "Gitlab", + "JENKINS": "Jenkins", + "K8S": "Kubernetes / k3d", + "POSTGRES": "PostgreSQL", + "MONGO": "MongoDB", + "GRAFANA": "Grafana/Prometheus" + }, + "XP": { + "COMPANY8": { + "COMPANY": "Teraport GmbH", + "ROLE": "Senior Software Developer / Architect", + "TIME": "Feb. 2024 – heute", + "HIGHLIGHTS": { + "P1": "Architektur und Implementierung der Datenbankanbindung mit Hibernate 6.x.", + "P2": "Konzeption und Entwicklung einer Full-Stack-Webanwendung für Kollisionsanalysen (Angular + Spring Boot + Docker).", + "P3": "Entwicklung eines Kostenanalysetools mit dem Namen MIDO." + } + }, + "COMPANY7": { + "COMPANY": "ColorDigital GmbH", + "ROLE": "Lead Software Developer", + "TIME": "März 2023 – Dez. 2023", + "HIGHLIGHTS": { + "P1": "Planung einer neuen Cloud-Architektur zur Migration eines umfangreichen Legacy-Monolithen in eine moderne Microservice-Plattform.", + "P2": "Leitung eines Teams von drei bis vier Backend-Entwickler:innen.", + "P3": "Zusammenarbeit mit Partnern und Kund:innen bei der Integration ihrer Systeme in die DMIx-Cloud." + } + }, + "COMPANY6": { + "COMPANY": "ColorDigital GmbH", + "ROLE": "Senior Software Developer", + "TIME": "März 2021 – März 2023", + "HIGHLIGHTS": { + "P1": "Arbeit an der DMIx-Core-Cloud, darunter die Implementierung einer Elasticsearch-basierten Echtzeit-Suchfunktion.", + "P2": "Implementierung des neuen Browser-Tools „Moodboard“ (Node.js + Vue.js).", + "P3": "Entwicklung von „PAX“, einem Tool für den Datenaustausch zwischen der DMIx-Cloud und PLM/ERP-Systemen, inkl. CI/CD-Integration." + } + }, + "COMPANY5": { + "COMPANY": "Assyst GmbH", + "ROLE": "Teamleitung", + "TIME": "Sep. 2015 – Feb. 2021", + "HIGHLIGHTS": { + "P1": "Teamleitung der Vidya-Softwareabteilung, inkl. Personalverantwortung und Bewerbungsprozesse.", + "P2": "Leitung mehrerer Projekte mit externen Partnern und Freelancer:innen.", + "P3": "Steuerung strategischer Initiativen im Bereich 3D-Softwareentwicklung." + } + }, + "COMPANY4": { + "COMPANY": "Assyst GmbH", + "ROLE": "Software Engineer", + "TIME": "Apr. 2010 – Feb. 2021", + "HIGHLIGHTS": { + "P1": "Arbeit an Kerntechnologien wie Algorithmen, Simulation, Rendering und Kollisions­erkennung.", + "P2": "Einsatz verschiedener Technologien, u. a. Java, OpenCL, OpenGL, GLSL-Shader, C++ und REST-Schnittstellen.", + "P3": "Mitarbeit an nationalen und internationalen Forschungsprojekten (EU7 und ZIM)." + } + }, + "COMPANY3": { + "COMPANY": "Assyst GmbH", + "ROLE": "Praktikum und Diplomarbeit", + "TIME": "Apr. 2009 – Apr. 2010", + "HIGHLIGHTS": { + "P1": "Implementierung produktiver Funktionen in der Echtzeit-Kleidersimulationssoftware Vidya.", + "P2": "Durchführung von Recherchen und Literaturstudien für die Diplomarbeit.", + "P3": "Erfolgreiche Umsetzung des Diplomthemas in Vidya." + } + }, + "COMPANY2": { + "COMPANY": "TH Bingen (University of Applied Sciences)", + "ROLE": "Tutor für Grundlagen der Java-Programmierung", + "TIME": "Apr. 2008 – Aug. 2008", + "HIGHLIGHTS": { + "P1": "Erstellung praktischer und theoretischer Lehrmaterialien.", + "P2": "Durchführung einer 20-stündigen Vorlesungsreihe für den Bioinformatik-Studiengang.", + "P3": "Unterstützung bei praktischen Programmierübungen." + } + }, + "COMPANY1": { + "COMPANY": "TH Bingen (University of Applied Sciences)", + "ROLE": "Wissenschaftliche Hilfskraft", + "TIME": "Okt. 2007 – Apr. 2008", + "HIGHLIGHTS": { + "P1": "Evaluation verschiedener Web-2.0-Technologien.", + "P2": "Implementierung einer Java-basierten Schnittstelle zu Microsoft Excel.", + "P3": "Integration des MIT-Exhibit-Frameworks und Vorbereitung für die CeBIT 2008." + } + }, + "COMPANY0": { + "COMPANY": "Chamaeleon AG", + "ROLE": "Ausbildung Fachinformatiker Anwendungsentwicklung", + "TIME": "Jul. 2002 – Jun. 2005", + "HIGHLIGHTS": { + "P1": "Entwicklung in PERL, PHP und ASP.", + "P2": "Portierung, Wartung und Reengineering von bestender Software.", + "P3": "Regelmäßige Durchführung von Systemtests und Qualitätskontrollen, sowie deren Dokumentation." + } + } + }, + "PROJECT": { + "P2": { + "TITLE": "Playground", + "DESCRIPTION": "Dieses Projekt ist, wie der Name schon sagt, ein persönlicher Playground, der im Laufe der Zeit wachsen soll. Es präsentiert verschiedene private Projekte, an denen ich arbeite, und dokumentiert deren Fortschritt, zentrale Ideen und wichtige Meilensteine.", + "LINK_EXTERNAL": "andreas-dahm.eu", + "LINK_INTERNAL": "Projektdetails", + "HIGHLIGHTS": { + "P1": "Einsatz moderner Technologien und CI/CD-Pipelines (Angular 20+, Spring Boot 4, GitHub).", + "P2": "Präsentation persönlicher Projekte und kontinuierliche Verbesserung algorithmischer Fähigkeiten.", + "P3": "Vertiefung von JavaScript/TypeScript-, Angular- und Spring-Boot-Kenntnissen durch praktisches Arbeiten." + } + }, + "P1": { + "TITLE": "El Mucho", + "DESCRIPTION": "Dies ist mein erstes veröffentlichtes Spiel auf Steam. Ich habe es gemeinsam mit meinem Bruder entwickelt und damit eines meiner persönlichen Ziele erreicht: ein eigenes Videospiel zu erstellen und zu veröffentlichen.", + "LINK_EXTERNAL": "Steam Store", + "LINK_INTERNAL": "Projektdetails", + "HIGHLIGHTS": { + "P1": "Veröffentlichung eines Spiels auf Steam und Integration der Steam-API.", + "P2": "Konzeption, Planung und vollständige Entwicklung eines eigenen Spiels.", + "P3": "Implementierung komplexer Algorithmen wie einer eigenen A*-Pfadfindungslogik und Spiel-KI." + } + }, + "P0": { + "TITLE": "Game Jams", + "DESCRIPTION": "Dieser Bereich zeigt einige meiner bisherigen Game-Jam-Beiträge. Game Jams sind eine großartige Möglichkeit, neue Spielideen auszuprobieren und schnell zu überprüfen, ob ein Game-Loop funktioniert. Die engen Zeitvorgaben fördern den Fokus, es ist faszinierend, was man in so kurzer Zeit alles schaffen kann.", + "LINK_EXTERNAL": "Itch.io Sammlung", + "LINK_INTERNAL": "Projektdetails", + "HIGHLIGHTS": { + "P1": "Planung eines realistischen Projektumfangs mit einem Team, der innerhalb von 48 Stunden umsetzbar ist.", + "P2": "Lernen, fokussiert und effizient unter strengen Zeitvorgaben zu arbeiten.", + "P3": "Die Freude zu erleben, in kurzer Zeit ein spielbares Projekt zu erstellen und andere damit spielen zu sehen." + } + } + }, + "EDUCATION": { + "E6": { + "WHERE": "FH Bingen (University of Applied Sciences)", + "WHEN": "2006 - 2010", + "WHAT": "Diplom (FH), Angewandte Informatik (Schnitt 1.4)" + }, + "E5": { + "WHERE": "FH Koblenz (University of Applied Sciences)", + "WHEN": "2005 - 2006", + "WHAT": "1 Semester Ingenieurinformatik" + }, + "E4": { + "WHERE": "BBS Montabaur", + "WHEN": "2002 - 2005", + "WHAT": "Ausbildung zum Fachinformatiker Anwendungsentwicklung" + }, + "E3": { + "WHERE": "BBS Andernach - Höhere Berufsbachschule (Informatik)", + "WHEN": "2000 - 2002", + "WHAT": "Fachhochschulreife" + }, + "E2": { + "WHERE": "BBS Andernach - Berufsfachschule Technik (E-Technik)", + "WHEN": "1998 - 2000", + "WHAT": "Realschulabschluss" + }, + "E1": { + "WHERE": "Hauptschule Hinter Burg Mayen (Albert Schweitzer Realschule plus)", + "WHEN": "1995 - 1998 ", + "WHAT": "Hauptschulabschluss" + }, + "E0": { + "WHERE": "Albert Schweitzer Realschule Mayen", + "WHEN": "1993 - 1995", + "WHAT": "Kein Abschluss. Wechsel zur Hauptschule" + } + } + } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 3db395b..0d24dcc 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1,13 +1,209 @@ { - "APP": { "TITLE": "Playground" }, - "WELCOME": { - "TITLE": "Welcome 👋", - "SUB": "Angular 20 + Material", - "TEXT": "This is a simple start component.", - "COUNTER": "Counter", - "INC": "Increment", - "RESET": "Reset" + "APP": { + "TITLE": "Playground", + "COPYRIGHT": "Images protected by copyright, no use without permission!" + }, + "TOPBAR": { + "ABOUT": "About me", + "CONTACT": "Contact", + "PROJECTS": "Projects", + "HOBBY": "Hobby's", + "SETTINGS": "Settings", + "LANGUAGE": "Language", + "APPEARANCE": "Appearance" }, "THEME": { "LIGHT": "Light", "DARK": "Dark" }, - "LANG": { "LABEL": "Language", "EN": "English", "DE": "Deutsch" } + "LANG": { "LABEL": "Language", "EN": "English", "DE": "Deutsch" }, + "ABOUT": { + "ALT": { "PROFILE": "Profile photo of Andreas Dahm" }, + "HELLO": "Hello, I’m Andreas Dahm.", + "LEAD": "During my training as an application developer, I became fascinated by how complex problems can be solved elegantly through code. After studying Applied Computer Science at FH Bingen, I was able to deepen this passion in a wide variety of projects – from 3D simulations to modern web applications. Today, I work as a Senior Software Developer and Architect with a focus on Java, Angular, and DevOps. Thanks for stopping by!", + "ROLE": "Senior Software Developer / Full-Stack Developer / Software Architect", + "LOCATION": "Munich · Remote", + "DOWNLOAD_CV": "Download CV", + "VIEW_PROJECTS": "View projects", + "CONTACT_ME": "Contact me", + "SECTION": { + "SKILLS": "Skills & Stack", + "PRIMARY": "Core", + "TOOLSET": "Toolset", + "EXPERIENCE": "Experience", + "PROJECTS": "Projects", + "EDUCATION": "Education" + }, + "SKILLS": { + "JAVA": "Java 8/Java 21+", + "SPRING": "Spring Boot 2/3", + "ANGULAR": "Angular 20+", + "DOCKER": "Docker", + "UNITY": "Unity", + "PYTHON": "Python", + "CSHARP": "C#", + "TYPESCRIPT": "TypeScript" + }, + "TOOLS": { + "GIT": "Git", + "GITHUB": "Github", + "GITLAB": "Gitlab", + "JENKINS": "Jenkins", + "K8S": "Kubernetes / k3d", + "POSTGRES": "PostgreSQL", + "MONGO": "MongoDB", + "GRAFANA": "Grafana/Prometheus" + }, + "XP": { + "COMPANY8": { + "COMPANY": "Teraport GmbH", + "ROLE": "Senior Software Developer / Architect", + "TIME": "Feb. 2024 – now", + "HIGHLIGHTS": { + "P1": "Architecture and implementation of database connectivity using Hibernate 6.x.", + "P2": "Design and development of a full-stack web application for collision analysis (Angular + Spring Boot + Docker).", + "P3": "Development of a cost analysis tool called MIDO." + } + }, + "COMPANY7": { + "COMPANY": "ColorDigital GmbH", + "ROLE": "Lead Software Developer", + "TIME": "Mar. 2023 – Dec. 2023", + "HIGHLIGHTS": { + "P1": "Planning a new cloud architecture to migrate a large legacy monolith to a modern microservice-based platform.", + "P2": "Led the development team of three to four backend engineers.", + "P3": "Collaborated with partners and customers on integrating their systems with the DMIx." + } + }, + "COMPANY6": { + "COMPANY": "ColorDigital GmbH", + "ROLE": "Senior Software Developer", + "TIME": "Mar. 2021 – Mar. 2023", + "HIGHLIGHTS": { + "P1": "Worked on the DMIx core cloud, including the implementation of an Elasticsearch-based real-time search module.", + "P2": "Implementation of a new browser tool called 'Moodboard' (Node.js + Vue.js).", + "P3": "Development of 'PAX', a tool for data exchange between the DMIx cloud and customer PLM/ERP systems, including CI/CD integration." + } + }, + "COMPANY5": { + "COMPANY": "Assyst GmbH", + "ROLE": "Team leadership", + "TIME": "Sep. 2015 – Feb. 2021", + "HIGHLIGHTS": { + "P1": "Team lead of the Vidya software department, including disciplinary responsibility and interviews.", + "P2": "Led several projects with external partners and freelancers.", + "P3": "Managed strategic initiatives in 3D software development." + } + }, + "COMPANY4": { + "COMPANY": "Assyst GmbH", + "ROLE": "Software engineer", + "TIME": "Apr. 2010 – Feb. 2021", + "HIGHLIGHTS": { + "P1": "Worked on core technologies such as algorithms, simulation, rendering, and collision detection.", + "P2": "Used technologies including Java, OpenCL, OpenGL, GLSL shaders, C++, and REST interfaces.", + "P3": "Participated in national and international research projects (EU7 and ZIM)." + } + }, + "COMPANY3": { + "COMPANY": "Assyst GmbH", + "ROLE": "Internship and Diploma", + "TIME": "Apr. 2009 – Apr. 2010", + "HIGHLIGHTS": { + "P1": "Implemented production features in the real-time cloth simulation software Vidya.", + "P2": "Conducted research and literature review for the diploma thesis.", + "P3": "Successfully implemented the diploma topic in Vidya." + } + }, + "COMPANY2": { + "COMPANY": "TH Bingen (University of Applied Sciences)", + "ROLE": "Tutorial for fundamentals of Java programming", + "TIME": "Apr. 2008 – Aug. 2008", + "HIGHLIGHTS": { + "P1": "Preparation of practical and theoretical course material.", + "P2": "Held a 20-hour lecture series for the bioinformatics programme.", + "P3": "Provided assistance during practical programming exercises." + } + }, + "COMPANY1": { + "COMPANY": "TH Bingen (University of Applied Sciences)", + "ROLE": "Research Asssitent", + "TIME": "Oct. 2007 – Apr. 2008", + "HIGHLIGHTS": { + "P1": "Evaluation of various Web 2.0 technologies.", + "P2": "Implementation of a Java-based interface for Microsoft Excel.", + "P3": "Integration of the MIT Exhibit framework and preparation for CeBIT 2008." + } + } + }, + "PROJECT": { + "P2": { + "TITLE": "Playground", + "DESCRIPTION": "This project is, as the name suggests, a personal playground that will grow over time. It showcases various private projects I’m working on and documents their progress, key ideas, and milestones.", + "LINK_EXTERNAL": "andreas-dahm.eu", + "LINK_INTERNAL": "Project details", + "HIGHLIGHTS": { + "P1": "Using modern technologies and CI/CD pipelines (Angular 20+, Spring Boot 4, GitHub).", + "P2": "Showcasing personal projects and improving algorithmic skills over time.", + "P3": "Deepening knowledge in JavaScript/TypeScript, Angular, Spring Boot and related technologies through hands-on practice." + } + }, + "P1": { + "TITLE": "El Mucho", + "DESCRIPTION": "This is my first published game on Steam. I developed it together with my brother, fulfilling one of my personal goals: creating and releasing my own video game.", + "LINK_EXTERNAL": "Steam Store", + "LINK_INTERNAL": "Project details", + "HIGHLIGHTS": { + "P1": "Publishing a game on Steam and integrating the Steam API.", + "P2": "Designing, planning and developing a complete game from scratch.", + "P3": "Implementing complex algorithms, including a custom A* pathfinding system and game AI logic." + } + }, + "P0": { + "TITLE": "Game Jams", + "DESCRIPTION": "This section showcases several of my past game jam creations. Game jams are a great way to explore new game ideas and quickly validate whether a game loop works. The tight time constraints force you to focus, and it’s always exciting to see what can be achieved within such a short timeframe.", + "LINK_EXTERNAL": "Itch.io Collection", + "LINK_INTERNAL": "Project details", + "HIGHLIGHTS": { + "P1": "Planning a realistic project scope with a team that can be built within 48 hours.", + "P2": "Learning to stay focused and work effectively under strict time constraints.", + "P3": "Experiencing the joy of creating a playable game in a short timeframe and seeing others enjoy it." + } + } + }, + "EDUCATION": { + "E6": { + "WHERE": "FH Bingen (University of Applied Sciences)", + "WHEN": "2006 – 2010", + "WHAT": "Diploma (FH), Applied Computer Science (final grade 1.4)" + }, + "E5": { + "WHERE": "FH Koblenz (University of Applied Sciences)", + "WHEN": "2005 – 2006", + "WHAT": "1 semester of Engineering Informatics" + }, + "E4": { + "WHERE": "BBS Montabaur", + "WHEN": "2002 – 2005", + "WHAT": "Apprenticeship as IT Specialist for Application Development" + }, + "E3": { + "WHERE": "BBS Andernach – Higher Vocational School (Computer Science)", + "WHEN": "2000 – 2002", + "WHAT": "University entrance qualification (Fachhochschulreife)" + }, + "E2": { + "WHERE": "BBS Andernach – Vocational School for Technology (Electrical Engineering)", + "WHEN": "1998 – 2000", + "WHAT": "Secondary school certificate (Realschulabschluss)" + }, + "E1": { + "WHERE": "Hauptschule Hinter Burg Mayen (Albert Schweitzer Realschule Plus)", + "WHEN": "1995 – 1998", + "WHAT": "Lower secondary school certificate (Hauptschulabschluss)" + }, + "E0": { + "WHERE": "Albert Schweitzer Realschule Mayen", + "WHEN": "1993 – 1995", + "WHAT": "No degree (transferred to lower secondary school)" + } + } + } } diff --git a/src/assets/logos/assyst_gmbh_logo.jpg b/src/assets/logos/assyst_gmbh_logo.jpg new file mode 100644 index 0000000..97f27d4 Binary files /dev/null and b/src/assets/logos/assyst_gmbh_logo.jpg differ diff --git a/src/assets/logos/bingen-logo-white.svg b/src/assets/logos/bingen-logo-white.svg new file mode 100644 index 0000000..899f800 --- /dev/null +++ b/src/assets/logos/bingen-logo-white.svg @@ -0,0 +1,19 @@ + diff --git a/src/assets/logos/dmixcloud_logo.jpg b/src/assets/logos/dmixcloud_logo.jpg new file mode 100644 index 0000000..befd801 Binary files /dev/null and b/src/assets/logos/dmixcloud_logo.jpg differ diff --git a/src/assets/logos/logo_chamaeleon.svg b/src/assets/logos/logo_chamaeleon.svg new file mode 100644 index 0000000..6e62da4 --- /dev/null +++ b/src/assets/logos/logo_chamaeleon.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/logos/teraport_gmbh_logo.jpg b/src/assets/logos/teraport_gmbh_logo.jpg new file mode 100644 index 0000000..509c6d3 Binary files /dev/null and b/src/assets/logos/teraport_gmbh_logo.jpg differ diff --git a/src/assets/me.webp b/src/assets/me.webp new file mode 100644 index 0000000..87d37ae Binary files /dev/null and b/src/assets/me.webp differ diff --git a/src/index.html b/src/index.html index deaa5e4..cf4b896 100644 --- a/src/index.html +++ b/src/index.html @@ -2,10 +2,10 @@ - PlaygroundFrontend + Andreas Dahm - Playground - + diff --git a/src/main.ts b/src/main.ts index de803b6..b0ef0a7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,11 @@ import { bootstrapApplication } from '@angular/platform-browser'; import { appConfig } from './app/app.config'; -import { App } from './app/app'; import packageJson from '../package.json'; +import {AppComponent} from './app/layout/app/app.component'; if (packageJson.version) { console.log(`🌟 Frontend version: ${packageJson.version}`); } -bootstrapApplication(App, appConfig) +bootstrapApplication(AppComponent, appConfig) .catch((err) => console.error(err)); diff --git a/src/styles.scss b/src/styles.scss index c081341..97f7cb0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -26,11 +26,17 @@ $dark-theme: mat.define-theme(( --app-bg: #{mat.get-theme-color($light-theme, surface-container-low)}; --app-fg: #{mat.get-theme-color($light-theme, on-surface)}; --app-card-background: #fafafa; + --app-logo-bg: #313131; + --link-color: #38a7ff; + --link-color-hover: #66bfff; } .dark { --app-bg: #{mat.get-theme-color($dark-theme, surface-container-low)}; --app-fg: #{mat.get-theme-color($dark-theme, on-surface)}; --app-card-background: #313131; + --app-logo-bg: #313131; + --link-color: #6dbcff; + --link-color-hover: #9ad2ff; } /* ---- global background and tests ---- */ @@ -67,3 +73,15 @@ body { box-shadow 220ms ease, fill 220ms ease; } + +/* links */ +a { + color: var(--link-color); + text-decoration: none; + font-weight: 500; + + &:hover { + color: var(--link-color-hover); + text-decoration: underline; + } +}