ez claps 01-04
This commit is contained in:
parent
6219a98f9a
commit
0641a268b8
4
.vscode/extensions.json
vendored
4
.vscode/extensions.json
vendored
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
|
||||||
"recommendations": ["angular.ng-template"]
|
|
||||||
}
|
|
20
.vscode/launch.json
vendored
20
.vscode/launch.json
vendored
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "ng serve",
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "npm: start",
|
|
||||||
"url": "http://localhost:4200/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ng test",
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "npm: test",
|
|
||||||
"url": "http://localhost:9876/debug.html"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
42
.vscode/tasks.json
vendored
42
.vscode/tasks.json
vendored
@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "npm",
|
|
||||||
"script": "start",
|
|
||||||
"isBackground": true,
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "typescript",
|
|
||||||
"pattern": "$tsc",
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": {
|
|
||||||
"regexp": "(.*?)"
|
|
||||||
},
|
|
||||||
"endsPattern": {
|
|
||||||
"regexp": "bundle generation complete"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "npm",
|
|
||||||
"script": "test",
|
|
||||||
"isBackground": true,
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "typescript",
|
|
||||||
"pattern": "$tsc",
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": {
|
|
||||||
"regexp": "(.*?)"
|
|
||||||
},
|
|
||||||
"endsPattern": {
|
|
||||||
"regexp": "bundle generation complete"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -24,7 +24,8 @@
|
|||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "public"
|
"input": "public"
|
||||||
}
|
},
|
||||||
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.css"
|
"src/styles.css"
|
||||||
|
276
package-lock.json
generated
276
package-lock.json
generated
@ -450,6 +450,34 @@
|
|||||||
"typescript": ">=5.4 <5.6"
|
"typescript": ">=5.4 <5.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@angular/compiler-cli/node_modules/chokidar": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"readdirp": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@angular/compiler-cli/node_modules/readdirp": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@angular/core": {
|
"node_modules/@angular/core": {
|
||||||
"version": "18.2.8",
|
"version": "18.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.8.tgz",
|
||||||
@ -5531,19 +5559,39 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "4.0.1",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||||
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readdirp": "^4.0.1"
|
"anymatch": "~3.1.2",
|
||||||
|
"braces": "~3.0.2",
|
||||||
|
"glob-parent": "~5.1.2",
|
||||||
|
"is-binary-path": "~2.1.0",
|
||||||
|
"is-glob": "~4.0.1",
|
||||||
|
"normalize-path": "~3.0.0",
|
||||||
|
"readdirp": "~3.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.16.0"
|
"node": ">= 8.10.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chokidar/node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chownr": {
|
"node_modules/chownr": {
|
||||||
@ -8773,31 +8821,6 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/karma/node_modules/chokidar": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"anymatch": "~3.1.2",
|
|
||||||
"braces": "~3.0.2",
|
|
||||||
"glob-parent": "~5.1.2",
|
|
||||||
"is-binary-path": "~2.1.0",
|
|
||||||
"is-glob": "~4.0.1",
|
|
||||||
"normalize-path": "~3.0.0",
|
|
||||||
"readdirp": "~3.6.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8.10.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "~2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/karma/node_modules/cliui": {
|
"node_modules/karma/node_modules/cliui": {
|
||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
@ -8837,19 +8860,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/karma/node_modules/glob-parent": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"is-glob": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/karma/node_modules/is-fullwidth-code-point": {
|
"node_modules/karma/node_modules/is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
@ -8860,32 +8870,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/karma/node_modules/picomatch": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/karma/node_modules/readdirp": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"picomatch": "^2.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/karma/node_modules/source-map": {
|
"node_modules/karma/node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
@ -11410,17 +11394,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "4.0.2",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.16.0"
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readdirp/node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "individual",
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/reflect-metadata": {
|
"node_modules/reflect-metadata": {
|
||||||
@ -11853,70 +11847,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass/node_modules/chokidar": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"anymatch": "~3.1.2",
|
|
||||||
"braces": "~3.0.2",
|
|
||||||
"glob-parent": "~5.1.2",
|
|
||||||
"is-binary-path": "~2.1.0",
|
|
||||||
"is-glob": "~4.0.1",
|
|
||||||
"normalize-path": "~3.0.0",
|
|
||||||
"readdirp": "~3.6.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8.10.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "~2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sass/node_modules/glob-parent": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"is-glob": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sass/node_modules/picomatch": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sass/node_modules/readdirp": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"picomatch": "^2.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sax": {
|
"node_modules/sax": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||||
@ -14102,31 +14032,6 @@
|
|||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/chokidar": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"anymatch": "~3.1.2",
|
|
||||||
"braces": "~3.0.2",
|
|
||||||
"glob-parent": "~5.1.2",
|
|
||||||
"is-binary-path": "~2.1.0",
|
|
||||||
"is-glob": "~4.0.1",
|
|
||||||
"normalize-path": "~3.0.0",
|
|
||||||
"readdirp": "~3.6.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8.10.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "~2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webpack-dev-server/node_modules/glob": {
|
"node_modules/webpack-dev-server/node_modules/glob": {
|
||||||
"version": "10.4.5",
|
"version": "10.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||||
@ -14148,19 +14053,6 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/glob-parent": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"is-glob": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
|
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
|
||||||
@ -14202,32 +14094,6 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/picomatch": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webpack-dev-server/node_modules/readdirp": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"picomatch": "^2.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webpack-dev-server/node_modules/rimraf": {
|
"node_modules/webpack-dev-server/node_modules/rimraf": {
|
||||||
"version": "5.0.10",
|
"version": "5.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
|
import {provideHttpClient} from '@angular/common/http';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
|
providers: [
|
||||||
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
|
provideRouter(routes),
|
||||||
|
provideHttpClient(),
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import {ProductListComponent} from './product-list/product-list.component';
|
import {ProductListComponent} from './product/product-list/product-list.component';
|
||||||
|
import {ProductDetailComponent} from './product/product-detail/product-detail.component';
|
||||||
|
import {CartComponent} from './product/cart/cart.component';
|
||||||
|
import {ShippingComponent} from './product/shipping/shipping.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: '', component: ProductListComponent },
|
{ path: '', component: ProductListComponent },
|
||||||
|
{ path: 'products/:productId', component: ProductDetailComponent },
|
||||||
|
{ path: 'cart', component: CartComponent },
|
||||||
|
{ path: 'shipping', component: ShippingComponent },
|
||||||
];
|
];
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<h2>Products</h2>
|
|
@ -1,17 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { products } from '../products';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-product-list',
|
|
||||||
standalone: true,
|
|
||||||
imports: [],
|
|
||||||
templateUrl: './product-list.component.html',
|
|
||||||
styleUrl: './product-list.component.css'
|
|
||||||
})
|
|
||||||
export class ProductListComponent {
|
|
||||||
products = [...products];
|
|
||||||
|
|
||||||
share() {
|
|
||||||
window.alert('The product has been shared!');
|
|
||||||
}
|
|
||||||
}
|
|
25
src/app/product/cart/cart.component.html
Normal file
25
src/app/product/cart/cart.component.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<a [routerLink]="['/shipping']">Shipping Prices</a>
|
||||||
|
|
||||||
|
<ng-container *ngFor="let product of _items">
|
||||||
|
<h3>{{ product.name }}</h3>
|
||||||
|
<p>{{ product.price | currency }}</p>
|
||||||
|
<hr>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
|
||||||
|
<div>
|
||||||
|
<label for="name">
|
||||||
|
Name
|
||||||
|
</label>
|
||||||
|
<input id="name" type="text" formControlName="name">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="address">
|
||||||
|
Address
|
||||||
|
</label>
|
||||||
|
<input id="address" type="text" formControlName="address">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<button class="button" type="submit">Purchase</button>
|
||||||
|
</form>
|
23
src/app/product/cart/cart.component.spec.ts
Normal file
23
src/app/product/cart/cart.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CartComponent } from './cart.component';
|
||||||
|
|
||||||
|
describe('CartComponent', () => {
|
||||||
|
let component: CartComponent;
|
||||||
|
let fixture: ComponentFixture<CartComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CartComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(CartComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
44
src/app/product/cart/cart.component.ts
Normal file
44
src/app/product/cart/cart.component.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {CartService} from '../service/cart.service';
|
||||||
|
import {CurrencyPipe, NgForOf} from '@angular/common';
|
||||||
|
import {Product} from '../products';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {FormBuilder, FormGroup, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-cart',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgForOf,
|
||||||
|
CurrencyPipe,
|
||||||
|
RouterLink,
|
||||||
|
ReactiveFormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './cart.component.html',
|
||||||
|
styleUrl: './cart.component.css'
|
||||||
|
})
|
||||||
|
export class CartComponent implements OnInit {
|
||||||
|
protected _items: Product[] = [];
|
||||||
|
|
||||||
|
protected checkoutForm!: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _cartService: CartService,
|
||||||
|
private _formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this._items = this._cartService.items;
|
||||||
|
this.checkoutForm = this._formBuilder.group({
|
||||||
|
name: '',
|
||||||
|
address: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
this._items = this._cartService.clearCart();
|
||||||
|
console.warn('Your order has been submitted', this.checkoutForm.value);
|
||||||
|
this.checkoutForm.reset();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
<p *ngIf="product && product.price > 700">
|
||||||
|
<button type="button" (click)="notify.emit()">Notify Me</button>
|
||||||
|
</p>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductAlertsComponent } from './product-alerts.component';
|
||||||
|
|
||||||
|
describe('ProductAlertsComponent', () => {
|
||||||
|
let component: ProductAlertsComponent;
|
||||||
|
let fixture: ComponentFixture<ProductAlertsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProductAlertsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProductAlertsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
18
src/app/product/product-alerts/product-alerts.component.ts
Normal file
18
src/app/product/product-alerts/product-alerts.component.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||||
|
import {Product} from '../products';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-alerts',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgIf
|
||||||
|
],
|
||||||
|
templateUrl: './product-alerts.component.html',
|
||||||
|
styleUrl: './product-alerts.component.css'
|
||||||
|
})
|
||||||
|
export class ProductAlertsComponent {
|
||||||
|
@Input() product: Product | undefined;
|
||||||
|
|
||||||
|
@Output() notify: EventEmitter<null> = new EventEmitter();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<ng-container *ngIf="_product">
|
||||||
|
<p>{{_product.name}}</p>
|
||||||
|
<p>{{_product.description}}</p>
|
||||||
|
<p>Price: {{_product.price | currency }}</p>
|
||||||
|
<button (click)="addToCart(_product)">Add to Cart</button>
|
||||||
|
</ng-container>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductDetailComponent } from './product-detail.component';
|
||||||
|
|
||||||
|
describe('ProductDetailComponent', () => {
|
||||||
|
let component: ProductDetailComponent;
|
||||||
|
let fixture: ComponentFixture<ProductDetailComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProductDetailComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProductDetailComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
39
src/app/product/product-detail/product-detail.component.ts
Normal file
39
src/app/product/product-detail/product-detail.component.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {Product, products} from '../products';
|
||||||
|
import {CurrencyPipe, NgIf} from '@angular/common';
|
||||||
|
import {ActivatedRoute} from '@angular/router';
|
||||||
|
import {CartService} from '../service/cart.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-detail',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgIf,
|
||||||
|
CurrencyPipe
|
||||||
|
],
|
||||||
|
templateUrl: './product-detail.component.html',
|
||||||
|
styleUrl: './product-detail.component.css'
|
||||||
|
})
|
||||||
|
export class ProductDetailComponent implements OnInit{
|
||||||
|
_product: Product | undefined;
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private cartService: CartService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const routeParams = this.route.snapshot.paramMap;
|
||||||
|
const productIdFromRoute = Number(routeParams.get('productId'));
|
||||||
|
|
||||||
|
this._product = products.find(product => product.id === productIdFromRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
addToCart(product: Product) {
|
||||||
|
console.log(product)
|
||||||
|
this.cartService.addToCart(product);
|
||||||
|
|
||||||
|
window.alert('Your product has been added to the cart!');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
17
src/app/product/product-list/product-list.component.html
Normal file
17
src/app/product/product-list/product-list.component.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<h2>Products</h2>
|
||||||
|
<ng-container *ngFor="let product of products">
|
||||||
|
<h3>
|
||||||
|
<a
|
||||||
|
[title]="product.name + 'details'"
|
||||||
|
[routerLink]="['/products', product.id]"
|
||||||
|
>
|
||||||
|
{{ product.name }}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<p *ngIf="product.description">
|
||||||
|
{{ product.description }}
|
||||||
|
</p>
|
||||||
|
<button (click)="share()">Share</button>
|
||||||
|
<app-product-alerts [product]="product" (notify)="onNotify()" />
|
||||||
|
<hr>
|
||||||
|
</ng-container>
|
32
src/app/product/product-list/product-list.component.ts
Normal file
32
src/app/product/product-list/product-list.component.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { products } from '../products';
|
||||||
|
import {ProductDetailComponent} from '../product-detail/product-detail.component';
|
||||||
|
import {NgForOf, NgIf} from '@angular/common';
|
||||||
|
import {ProductAlertsComponent} from '../product-alerts/product-alerts.component';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ProductDetailComponent,
|
||||||
|
NgForOf,
|
||||||
|
NgIf,
|
||||||
|
ProductAlertsComponent,
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './product-list.component.html',
|
||||||
|
styleUrl: './product-list.component.css'
|
||||||
|
})
|
||||||
|
export class ProductListComponent {
|
||||||
|
products = [...products];
|
||||||
|
|
||||||
|
share() {
|
||||||
|
window.alert('The product has been shared!');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onNotify() {
|
||||||
|
window.alert('You will be notified when the product goes on sale');
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ export interface Product {
|
|||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const products = [
|
export const products: Product[] = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Phone XL',
|
name: 'Phone XL',
|
16
src/app/product/service/cart.service.spec.ts
Normal file
16
src/app/product/service/cart.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CartService } from './cart.service';
|
||||||
|
|
||||||
|
describe('CartService', () => {
|
||||||
|
let service: CartService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(CartService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
33
src/app/product/service/cart.service.ts
Normal file
33
src/app/product/service/cart.service.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {Product} from '../products';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {Shipping} from '../shipping';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CartService {
|
||||||
|
private _items: Product[] = [];
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public addToCart(product: Product): void {
|
||||||
|
this._items.push(product);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get items() {
|
||||||
|
return this._items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearCart(): Product[] {
|
||||||
|
this._items = [];
|
||||||
|
|
||||||
|
return this._items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getShippingPrices(): Observable<Shipping[]> {
|
||||||
|
return this.http.get<Shipping[]>('/assets/shipping.json');
|
||||||
|
}
|
||||||
|
}
|
4
src/app/product/shipping.ts
Normal file
4
src/app/product/shipping.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface Shipping {
|
||||||
|
type: string;
|
||||||
|
price: number;
|
||||||
|
}
|
0
src/app/product/shipping/shipping.component.css
Normal file
0
src/app/product/shipping/shipping.component.css
Normal file
5
src/app/product/shipping/shipping.component.html
Normal file
5
src/app/product/shipping/shipping.component.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<h3>Shipping Prices</h3>
|
||||||
|
<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
|
||||||
|
<span>{{ shipping.type }}</span>
|
||||||
|
<span>{{ shipping.price | currency }}</span>
|
||||||
|
</div>
|
23
src/app/product/shipping/shipping.component.spec.ts
Normal file
23
src/app/product/shipping/shipping.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ShippingComponent } from './shipping.component';
|
||||||
|
|
||||||
|
describe('ShippingComponent', () => {
|
||||||
|
let component: ShippingComponent;
|
||||||
|
let fixture: ComponentFixture<ShippingComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ShippingComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ShippingComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
28
src/app/product/shipping/shipping.component.ts
Normal file
28
src/app/product/shipping/shipping.component.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {CartService} from '../service/cart.service';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {Shipping} from '../shipping';
|
||||||
|
import {AsyncPipe, CurrencyPipe, NgForOf} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-shipping',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
AsyncPipe,
|
||||||
|
CurrencyPipe,
|
||||||
|
NgForOf
|
||||||
|
],
|
||||||
|
templateUrl: './shipping.component.html',
|
||||||
|
styleUrl: './shipping.component.css'
|
||||||
|
})
|
||||||
|
export class ShippingComponent implements OnInit {
|
||||||
|
protected shippingCosts!: Observable<Shipping[]>;
|
||||||
|
|
||||||
|
constructor(private cartService: CartService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.shippingCosts = this.cartService.getShippingPrices();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
<a [routerLink]="['/']">
|
<a [routerLink]="['/']">
|
||||||
<h1>My Store</h1>
|
<h1>My Store</h1>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="button fancy-button" [routerLink]="['/cart']"><em class="material-icons">shopping_cart</em>Checkout</a>
|
||||||
<a class="button fancy-button"><em class="material-icons">shopping_cart</em>Checkout</a>
|
|
||||||
|
Reference in New Issue
Block a user