Merge branch 'tomalaforge:main' into rxjs-catch-error

This commit is contained in:
Devesh Chaudhari
2023-10-17 08:24:26 +05:30
committed by GitHub
57 changed files with 902 additions and 1169 deletions

View File

@@ -46,6 +46,11 @@ export default defineConfig({
`,
},
],
components: {
MarkdownContent: './src/components/Content.astro',
TableOfContents: './src/components/TableOfContents.astro',
PageTitle: './src/components/PageTitle.astro',
},
}),
],
});

639
docs/package-lock.json generated
View File

@@ -8,7 +8,7 @@
"name": "angular-challenges-docs",
"version": "0.0.1",
"dependencies": {
"@astrojs/starlight": "^0.10.0",
"@astrojs/starlight": "^0.11.0",
"@fontsource/ibm-plex-serif": "^5.0.8",
"astro": "^3.0.6",
"sharp": "^0.32.5"
@@ -32,9 +32,9 @@
"integrity": "sha512-Mp+qrNhly+27bL/Zq8lGeUY+YrdoU0eDfIlAeGIPrzt0PnI/jGpvPUdCaugv4zbCrDkOUScFfcbeEiYumrdJnw=="
},
"node_modules/@astrojs/internal-helpers": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.2.0.tgz",
"integrity": "sha512-NQ4ppp1CM0HNkKbJNM4saVSfmUYzGlRalF6wx7F6T/MYHYSWGuojY89/oFTy4t8VlOGUCUijlsVNNeziWaUo5g=="
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.2.1.tgz",
"integrity": "sha512-06DD2ZnItMwUnH81LBLco3tWjcZ1lGU9rLCCBaeUCGYe9cI0wKyY2W3kDyoW1I6GmcWgt1fu+D1CTvz+FIKf8A=="
},
"node_modules/@astrojs/markdown-remark": {
"version": "3.2.0",
@@ -109,19 +109,19 @@
}
},
"node_modules/@astrojs/starlight": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.10.0.tgz",
"integrity": "sha512-pYbtbGc2p3WoaFSERj/H55QSOKVZvOMPK457D2gwQkPHsNkFkuls2LpAsJgSSV/OCd7O+IWcB7vjV1KGVfExGA==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.11.0.tgz",
"integrity": "sha512-ZnYB1AHetRujy25fSW4uvJTn2ry8nFspMCySWkeB1VT7QzTTgol9y19o1HTWVessViJhlavayHAjd42Pru1rww==",
"dependencies": {
"@astrojs/mdx": "^1.0.0",
"@astrojs/mdx": "^1.1.0",
"@astrojs/sitemap": "^3.0.0",
"@pagefind/default-ui": "^1.0.2",
"@pagefind/default-ui": "^1.0.3",
"@types/mdast": "^3.0.11",
"bcp-47": "^2.1.0",
"execa": "^7.1.1",
"hast-util-select": "^5.0.5",
"hastscript": "^7.2.0",
"pagefind": "^1.0.2",
"pagefind": "^1.0.3",
"rehype": "^12.0.1",
"remark-directive": "^2.0.1",
"unified": "^10.1.2",
@@ -130,13 +130,13 @@
"vfile": "^5.3.7"
},
"peerDependencies": {
"astro": "^3.0.0"
"astro": "^3.2.0"
}
},
"node_modules/@astrojs/telemetry": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.2.tgz",
"integrity": "sha512-ef+jqCkqopCzjGfsMsr+8p56Nj6F9ZzouWcWZt+dKsqbRccI3c8K3jfkLcdq4AyfFZtKBDB6N4ZuI68g33oiOg==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.3.tgz",
"integrity": "sha512-j19Cf5mfyLt9hxgJ9W/FMdAA5Lovfp7/CINNB/7V71GqvygnL7KXhRC3TzfB+PsVQcBtgWZzCXhUWRbmJ64Raw==",
"dependencies": {
"ci-info": "^3.8.0",
"debug": "^4.3.4",
@@ -144,7 +144,6 @@
"dset": "^3.1.2",
"is-docker": "^3.0.0",
"is-wsl": "^3.0.0",
"undici": "^5.23.0",
"which-pm-runs": "^1.1.0"
},
"engines": {
@@ -924,9 +923,9 @@
}
},
"node_modules/@pagefind/darwin-arm64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.0.2.tgz",
"integrity": "sha512-saHinnIbchShIeT7+fFe77k3cbtXxbLcK4m+MjZA8VM/lrLeTaS+UYUYCzpKmV4U+APeELnquL4fhDquFAcScQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.0.3.tgz",
"integrity": "sha512-vsHDtvao3W4iFCxVc4S0BVhpj3E2MAoIVM7RmuQfGp1Ng22nGLRaMP6FguLO8TMabRJdvp4SVr227hL4WGKOHA==",
"cpu": [
"arm64"
],
@@ -936,9 +935,9 @@
]
},
"node_modules/@pagefind/darwin-x64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.0.2.tgz",
"integrity": "sha512-CAyPARt41lHPpHD8O7O2zv8MJa06iPa6nrGt+o9puY47OcNM6x8GxCAKPR1OTfEsiuwPovAdi7rvwJ35z3tnrA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.0.3.tgz",
"integrity": "sha512-NhEXHHYmB/hT6lx5rCcmnVTxH+uIkMAd43bzEqMwHQosqTZEIQfwihmV39H+m8yo7jFvz3zRbJNzhAh7G4PiwA==",
"cpu": [
"x64"
],
@@ -948,14 +947,14 @@
]
},
"node_modules/@pagefind/default-ui": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.0.2.tgz",
"integrity": "sha512-KrzZi7hNQ+BoxREeA5TD502M8RSjJWhYRyGa70RVIIPgw1MVZbTKr4Kmk6YdmKNPlBmPWXtv9IHC+e3IPUcVSg=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.0.3.tgz",
"integrity": "sha512-WieFJXvezyvjZh49I8j7a7Kz3LsXYY2Uep3IWvG5NG05mmiurURXjXc+KyrpIp/iAycSnjrC1TDJ8CdES/ee3A=="
},
"node_modules/@pagefind/linux-arm64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.0.2.tgz",
"integrity": "sha512-bGpLKV2WLkLH/Qn/ibHJj7oTPvMcpJMwcjdPWk+tWqBl5xoBK1l4k45Gi70deCdIjKom5TcXuS8mgcXY8tSJ0A==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.0.3.tgz",
"integrity": "sha512-RGsMt4AmGT8WxCSeP09arU7Za6Vf/We4TWHVSbY7vDMuwWql9Ngoib/q1cP9dIAIMdkXh9ePG/S3mGnJYsdzuQ==",
"cpu": [
"arm64"
],
@@ -965,9 +964,9 @@
]
},
"node_modules/@pagefind/linux-x64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.0.2.tgz",
"integrity": "sha512-59beym/0riPCTjNeT91ksqlBToW0FFeFAHKxvM0nmvzEeNYurgoZY+8fJz9Xvz8icXhi2NxLirDgclAMsahWWQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.0.3.tgz",
"integrity": "sha512-o+VCKaqImL42scSH1n5gUfppYSNyu3BuGTvtKKgWHmycbL+A3fkFH+ZOFbaLeN7LVTvJqJIOYbk4j2yaq9784Q==",
"cpu": [
"x64"
],
@@ -977,9 +976,9 @@
]
},
"node_modules/@pagefind/windows-x64": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.0.2.tgz",
"integrity": "sha512-lwae3p7xOVihaTv6D8gJJLl05U4lDvkyMN9azlpjlWbfhBJXJnvD2CQTDwzZxK+u6ZDJUR1Qcz2oVeedyQpMjQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.0.3.tgz",
"integrity": "sha512-S+Yq4FyvXJm4F+iN/wRiLvEEF8Xs9lTKGtQGaRHXJslQyl65dytDDPIULXJXIadrDbnMrnTt4C2YHmEUIyUIHg==",
"cpu": [
"x64"
],
@@ -1062,11 +1061,6 @@
"@types/unist": "^2"
}
},
"node_modules/@types/json5": {
"version": "0.0.30",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz",
"integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA=="
},
"node_modules/@types/mdast": {
"version": "3.0.12",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz",
@@ -1103,11 +1097,6 @@
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz",
"integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g=="
},
"node_modules/@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
},
"node_modules/@types/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz",
@@ -1121,6 +1110,11 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz",
"integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw=="
},
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
},
"node_modules/acorn": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
@@ -1252,14 +1246,14 @@
}
},
"node_modules/astro": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/astro/-/astro-3.1.3.tgz",
"integrity": "sha512-l76kWE0MJKzUZE8TzhIWafvJ+3nYwFfSiG9c6edNLZ3ZtVsuuuatATmg+gaAXY1zN6bh3WSwJgmAWTsWlZNFtw==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/astro/-/astro-3.3.0.tgz",
"integrity": "sha512-O3MsXULamxQMy6sBgv07iVe5teJ41o+9tVScB/Yo2Io0XwvLXVhjVrjAxKpulBcKpU3/LyOpVfj/x63fcONbPA==",
"dependencies": {
"@astrojs/compiler": "^2.1.0",
"@astrojs/internal-helpers": "0.2.0",
"@astrojs/markdown-remark": "3.2.0",
"@astrojs/telemetry": "3.0.2",
"@astrojs/internal-helpers": "0.2.1",
"@astrojs/markdown-remark": "3.3.0",
"@astrojs/telemetry": "3.0.3",
"@babel/core": "^7.22.10",
"@babel/generator": "^7.22.10",
"@babel/parser": "^7.22.10",
@@ -1300,11 +1294,10 @@
"resolve": "^1.22.4",
"semver": "^7.5.4",
"server-destroy": "^1.0.1",
"shiki": "^0.14.3",
"shikiji": "^0.6.8",
"string-width": "^6.1.0",
"strip-ansi": "^7.1.0",
"tsconfig-resolver": "^3.0.1",
"undici": "^5.23.0",
"tsconfck": "3.0.0-next.9",
"unist-util-visit": "^4.1.2",
"vfile": "^5.3.7",
"vite": "^4.4.9",
@@ -1324,6 +1317,30 @@
"sharp": "^0.32.5"
}
},
"node_modules/astro/node_modules/@astrojs/markdown-remark": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-3.3.0.tgz",
"integrity": "sha512-ezFzEiZygc/ASe2Eul9v1yrTbNGqSbR348UGNXQ4Dtkx8MYRwfiBfmPm6VnEdfIGkW+bi5qIUReKfc7mPVUkIg==",
"dependencies": {
"@astrojs/prism": "^3.0.0",
"github-slugger": "^2.0.0",
"import-meta-resolve": "^3.0.0",
"mdast-util-definitions": "^6.0.0",
"rehype-raw": "^6.1.1",
"rehype-stringify": "^9.0.4",
"remark-gfm": "^3.0.1",
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0",
"remark-smartypants": "^2.0.0",
"shikiji": "^0.6.8",
"unified": "^10.1.2",
"unist-util-visit": "^4.1.2",
"vfile": "^5.3.7"
},
"peerDependencies": {
"astro": "^3.3.0"
}
},
"node_modules/astro/node_modules/execa": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
@@ -1573,17 +1590,6 @@
"ieee754": "^1.2.1"
}
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/camelcase": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz",
@@ -1704,9 +1710,9 @@
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"node_modules/ci-info": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
"integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
"funding": [
{
"type": "github",
@@ -1927,6 +1933,18 @@
"resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz",
"integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg=="
},
"node_modules/devlop": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
"integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
"dependencies": {
"dequal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/diff": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
@@ -1983,6 +2001,17 @@
"once": "^1.4.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-module-lexer": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz",
@@ -2249,11 +2278,6 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -2342,12 +2366,9 @@
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dependencies": {
"function-bind": "^1.1.1"
},
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
"integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
"engines": {
"node": ">= 0.4.0"
}
@@ -4453,18 +4474,18 @@
}
},
"node_modules/pagefind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.0.2.tgz",
"integrity": "sha512-UxZgvmknPrH25qXZL7aK5fUOj1GrZxEQb2Mdd4l2m/PtdKJfrszxOR2EI1349bCYZ+OxiPn7wz2NCRNzb3QPpA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.0.3.tgz",
"integrity": "sha512-ws7kmMxW6OuxzsOjj3YAx6TYq/54MiE3wfyBM3J5CInbZyBBvM2Z8c8IYvnMkBcb5v2EoB9DewXEekOEiDRu5g==",
"bin": {
"pagefind": "lib/runner/bin.cjs"
},
"optionalDependencies": {
"@pagefind/darwin-arm64": "1.0.2",
"@pagefind/darwin-x64": "1.0.2",
"@pagefind/linux-arm64": "1.0.2",
"@pagefind/linux-x64": "1.0.2",
"@pagefind/windows-x64": "1.0.2"
"@pagefind/darwin-arm64": "1.0.3",
"@pagefind/darwin-x64": "1.0.3",
"@pagefind/linux-arm64": "1.0.3",
"@pagefind/linux-x64": "1.0.3",
"@pagefind/windows-x64": "1.0.3"
}
},
"node_modules/parse-entities": {
@@ -5023,9 +5044,9 @@
}
},
"node_modules/resolve": {
"version": "1.22.6",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
"integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
@@ -5319,6 +5340,385 @@
"vscode-textmate": "^8.0.0"
}
},
"node_modules/shikiji": {
"version": "0.6.10",
"resolved": "https://registry.npmjs.org/shikiji/-/shikiji-0.6.10.tgz",
"integrity": "sha512-WE+A5Y2ntM5hL3iJQujk97qr5Uj7PSIRXpQfrZ6h+JWPXZ8KBEDhFXc4lqNriaRq1WGOVPUT83XMOzmHiH3W8A==",
"dependencies": {
"hast-util-to-html": "^9.0.0"
}
},
"node_modules/shikiji/node_modules/@types/hast": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.1.tgz",
"integrity": "sha512-hs/iBJx2aydugBQx5ETV3ZgeSS0oIreQrFJ4bjBl0XvM4wAmDjFEALY7p0rTSLt2eL+ibjRAAs9dTPiCLtmbqQ==",
"dependencies": {
"@types/unist": "*"
}
},
"node_modules/shikiji/node_modules/@types/mdast": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.1.tgz",
"integrity": "sha512-IlKct1rUTJ1T81d8OHzyop15kGv9A/ff7Gz7IJgrk6jDb4Udw77pCJ+vq8oxZf4Ghpm+616+i1s/LNg/Vh7d+g==",
"dependencies": {
"@types/unist": "*"
}
},
"node_modules/shikiji/node_modules/@types/unist": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz",
"integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w=="
},
"node_modules/shikiji/node_modules/hast-util-from-parse5": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz",
"integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/unist": "^3.0.0",
"devlop": "^1.0.0",
"hastscript": "^8.0.0",
"property-information": "^6.0.0",
"vfile": "^6.0.0",
"vfile-location": "^5.0.0",
"web-namespaces": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hast-util-parse-selector": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
"integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
"dependencies": {
"@types/hast": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hast-util-raw": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.1.tgz",
"integrity": "sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/unist": "^3.0.0",
"@ungap/structured-clone": "^1.0.0",
"hast-util-from-parse5": "^8.0.0",
"hast-util-to-parse5": "^8.0.0",
"html-void-elements": "^3.0.0",
"mdast-util-to-hast": "^13.0.0",
"parse5": "^7.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0",
"web-namespaces": "^2.0.0",
"zwitch": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hast-util-to-html": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.0.tgz",
"integrity": "sha512-IVGhNgg7vANuUA2XKrT6sOIIPgaYZnmLx3l/CCOAK0PtgfoHrZwX7jCSYyFxHTrGmC6S9q8aQQekjp4JPZF+cw==",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/unist": "^3.0.0",
"ccount": "^2.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-raw": "^9.0.0",
"hast-util-whitespace": "^3.0.0",
"html-void-elements": "^3.0.0",
"mdast-util-to-hast": "^13.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0",
"stringify-entities": "^4.0.0",
"zwitch": "^2.0.4"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hast-util-to-parse5": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz",
"integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==",
"dependencies": {
"@types/hast": "^3.0.0",
"comma-separated-tokens": "^2.0.0",
"devlop": "^1.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0",
"web-namespaces": "^2.0.0",
"zwitch": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hast-util-whitespace": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
"integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
"dependencies": {
"@types/hast": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/hastscript": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz",
"integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==",
"dependencies": {
"@types/hast": "^3.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-parse-selector": "^4.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/html-void-elements": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
"integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/shikiji/node_modules/mdast-util-to-hast": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.0.2.tgz",
"integrity": "sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/mdast": "^4.0.0",
"@ungap/structured-clone": "^1.0.0",
"devlop": "^1.0.0",
"micromark-util-sanitize-uri": "^2.0.0",
"trim-lines": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/micromark-util-character": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz",
"integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==",
"funding": [
{
"type": "GitHub Sponsors",
"url": "https://github.com/sponsors/unifiedjs"
},
{
"type": "OpenCollective",
"url": "https://opencollective.com/unified"
}
],
"dependencies": {
"micromark-util-symbol": "^2.0.0",
"micromark-util-types": "^2.0.0"
}
},
"node_modules/shikiji/node_modules/micromark-util-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz",
"integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==",
"funding": [
{
"type": "GitHub Sponsors",
"url": "https://github.com/sponsors/unifiedjs"
},
{
"type": "OpenCollective",
"url": "https://opencollective.com/unified"
}
]
},
"node_modules/shikiji/node_modules/micromark-util-sanitize-uri": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz",
"integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==",
"funding": [
{
"type": "GitHub Sponsors",
"url": "https://github.com/sponsors/unifiedjs"
},
{
"type": "OpenCollective",
"url": "https://opencollective.com/unified"
}
],
"dependencies": {
"micromark-util-character": "^2.0.0",
"micromark-util-encode": "^2.0.0",
"micromark-util-symbol": "^2.0.0"
}
},
"node_modules/shikiji/node_modules/micromark-util-symbol": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz",
"integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==",
"funding": [
{
"type": "GitHub Sponsors",
"url": "https://github.com/sponsors/unifiedjs"
},
{
"type": "OpenCollective",
"url": "https://opencollective.com/unified"
}
]
},
"node_modules/shikiji/node_modules/micromark-util-types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz",
"integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==",
"funding": [
{
"type": "GitHub Sponsors",
"url": "https://github.com/sponsors/unifiedjs"
},
{
"type": "OpenCollective",
"url": "https://opencollective.com/unified"
}
]
},
"node_modules/shikiji/node_modules/parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"dependencies": {
"entities": "^4.4.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/shikiji/node_modules/unist-util-is": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
"integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==",
"dependencies": {
"@types/unist": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/unist-util-position": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
"integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
"dependencies": {
"@types/unist": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/unist-util-stringify-position": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
"integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
"dependencies": {
"@types/unist": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/unist-util-visit": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
"integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-is": "^6.0.0",
"unist-util-visit-parents": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/unist-util-visit-parents": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz",
"integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-is": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/vfile": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz",
"integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-stringify-position": "^4.0.0",
"vfile-message": "^4.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/vfile-location": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz",
"integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==",
"dependencies": {
"@types/unist": "^3.0.0",
"vfile": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/shikiji/node_modules/vfile-message": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
"integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-stringify-position": "^4.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -5463,14 +5863,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/streamx": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz",
@@ -5531,14 +5923,6 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/strip-bom": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
"integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
"engines": {
"node": ">=8"
}
},
"node_modules/strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
@@ -5653,31 +6037,23 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/tsconfig-resolver": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tsconfig-resolver/-/tsconfig-resolver-3.0.1.tgz",
"integrity": "sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==",
"dependencies": {
"@types/json5": "^0.0.30",
"@types/resolve": "^1.17.0",
"json5": "^2.1.3",
"resolve": "^1.17.0",
"strip-bom": "^4.0.0",
"type-fest": "^0.13.1"
"node_modules/tsconfck": {
"version": "3.0.0-next.9",
"resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.0.0-next.9.tgz",
"integrity": "sha512-bgVlu3qcRUZpm9Au1IHiPDkb8XU+72bRkXrBaJsiAjIlixtkbKLe4q1odrrqG0rVHvh0Q4R3adT/nh1FwzftXA==",
"bin": {
"tsconfck": "bin/tsconfck.js"
},
"funding": {
"url": "https://github.com/sponsors/ifiokjr"
}
},
"node_modules/tsconfig-resolver/node_modules/type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"engines": {
"node": ">=10"
"node": "^18 || >=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
"peerDependencies": {
"typescript": "^5.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/tunnel-agent": {
@@ -5702,17 +6078,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/undici": {
"version": "5.25.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.25.2.tgz",
"integrity": "sha512-tch8RbCfn1UUH1PeVCXva4V8gDpGAud/w0WubD6sHC46vYQ3KDxL+xv1A2UxK0N6jrVedutuPHxe1XIoqerwMw==",
"dependencies": {
"busboy": "^1.6.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/unherit": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.1.tgz",

View File

@@ -10,7 +10,7 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.10.0",
"@astrojs/starlight": "^0.11.0",
"@fontsource/ibm-plex-serif": "^5.0.8",
"astro": "^3.0.6",
"sharp": "^0.32.5"

View File

@@ -0,0 +1,58 @@
---
import VideoButton from './VideoButton.astro'
const {author, challengeNumber, title, blogLink, videoLink, command} = Astro.props.entry.data;
const authorLink = `https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A${challengeNumber}+label%3A"answer+author"`;
const authorDescription = `${title} solution author`;
const communityLink = `https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A${challengeNumber}+label%3Aanswer`;
const communityDescription = `${title} community solutions`;
---
<div class="separator"></div>
{command &&
<aside aria-label="Note" class="starlight-aside starlight-aside--note"><p class="starlight-aside__title" aria-hidden="true"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" class="starlight-aside__icon"><path d="M12 11C11.7348 11 11.4804 11.1054 11.2929 11.2929C11.1054 11.4804 11 11.7348 11 12V16C11 16.2652 11.1054 16.5196 11.2929 16.7071C11.4804 16.8946 11.7348 17 12 17C12.2652 17 12.5196 16.8946 12.7071 16.7071C12.8946 16.5196 13 16.2652 13 16V12C13 11.7348 12.8946 11.4804 12.7071 11.2929C12.5196 11.1054 12.2652 11 12 11ZM12.38 7.08C12.1365 6.97998 11.8635 6.97998 11.62 7.08C11.4973 7.12759 11.3851 7.19896 11.29 7.29C11.2017 7.3872 11.1306 7.49882 11.08 7.62C11.024 7.73868 10.9966 7.86882 11 8C10.9992 8.13161 11.0245 8.26207 11.0742 8.38391C11.124 8.50574 11.1973 8.61656 11.29 8.71C11.3872 8.79833 11.4988 8.86936 11.62 8.92C11.7715 8.98224 11.936 9.00632 12.099 8.99011C12.2619 8.97391 12.4184 8.91792 12.5547 8.82707C12.691 8.73622 12.8029 8.61328 12.8805 8.46907C12.9582 8.32486 12.9992 8.16378 13 8C12.9963 7.73523 12.8927 7.48163 12.71 7.29C12.6149 7.19896 12.5028 7.12759 12.38 7.08ZM12 2C10.0222 2 8.08879 2.58649 6.4443 3.6853C4.79981 4.78412 3.51809 6.3459 2.76121 8.17317C2.00433 10.0004 1.8063 12.0111 2.19215 13.9509C2.578 15.8907 3.53041 17.6725 4.92894 19.0711C6.32746 20.4696 8.10929 21.422 10.0491 21.8079C11.9889 22.1937 13.9996 21.9957 15.8268 21.2388C17.6541 20.4819 19.2159 19.2002 20.3147 17.5557C21.4135 15.9112 22 13.9778 22 12C22 10.6868 21.7413 9.38642 21.2388 8.17317C20.7363 6.95991 19.9997 5.85752 19.0711 4.92893C18.1425 4.00035 17.0401 3.26375 15.8268 2.7612C14.6136 2.25866 13.3132 2 12 2ZM12 20C10.4178 20 8.87104 19.5308 7.55544 18.6518C6.23985 17.7727 5.21447 16.5233 4.60897 15.0615C4.00347 13.5997 3.84504 11.9911 4.15372 10.4393C4.4624 8.88743 5.22433 7.46197 6.34315 6.34315C7.46197 5.22433 8.88743 4.4624 10.4393 4.15372C11.9911 3.84504 13.5997 4.00346 15.0615 4.60896C16.5233 5.21447 17.7727 6.23984 18.6518 7.55544C19.5308 8.87103 20 10.4177 20 12C20 14.1217 19.1572 16.1566 17.6569 17.6569C16.1566 19.1571 14.1217 20 12 20Z"></path></svg>Note</p><section class="starlight-aside__content">
<p>Start the project by running: <code class="code" dir="auto">npx nx serve {command}</code>.</p></section></aside>
}
<aside aria-label="Reminder" class="starlight-aside starlight-aside--tip"><p class="starlight-aside__title" aria-hidden="true"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" class="starlight-aside__icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.43909 8.85483L1.44039 8.85354L4.96668 5.33815C5.30653 4.99386 5.7685 4.79662 6.2524 4.78972L6.26553 4.78963L12.9014 4.78962L13.8479 3.84308C16.9187 0.772319 20.0546 0.770617 21.4678 0.975145C21.8617 1.02914 22.2271 1.21053 22.5083 1.4917C22.7894 1.77284 22.9708 2.13821 23.0248 2.53199C23.2294 3.94517 23.2278 7.08119 20.1569 10.1521L19.2107 11.0983V17.7338L19.2106 17.7469C19.2037 18.2308 19.0067 18.6933 18.6624 19.0331L15.1456 22.5608C14.9095 22.7966 14.6137 22.964 14.29 23.0449C13.9663 23.1259 13.6267 23.1174 13.3074 23.0204C12.9881 22.9235 12.7011 22.7417 12.4771 22.4944C12.2533 22.2473 12.1006 21.9441 12.0355 21.6171L11.1783 17.3417L6.65869 12.822L4.34847 12.3589L2.38351 11.965C2.05664 11.8998 1.75272 11.747 1.50564 11.5232C1.25835 11.2992 1.07653 11.0122 0.979561 10.6929C0.882595 10.3736 0.874125 10.034 0.955057 9.7103C1.03599 9.38659 1.20328 9.09092 1.43909 8.85483ZM6.8186 10.8724L2.94619 10.096L6.32006 6.73268H10.9583L6.8186 10.8724ZM15.2219 5.21703C17.681 2.75787 20.0783 2.75376 21.1124 2.8876C21.2462 3.92172 21.2421 6.31895 18.783 8.77812L12.0728 15.4883L8.51172 11.9272L15.2219 5.21703ZM13.9042 21.0538L13.1279 17.1811L17.2676 13.0414V17.68L13.9042 21.0538Z"></path><path d="M9.31827 18.3446C9.45046 17.8529 9.17864 17.3369 8.68945 17.1724C8.56178 17.1294 8.43145 17.1145 8.30512 17.1243C8.10513 17.1398 7.91519 17.2172 7.76181 17.3434C7.62613 17.455 7.51905 17.6048 7.45893 17.7835C6.97634 19.2186 5.77062 19.9878 4.52406 20.4029C4.08525 20.549 3.6605 20.644 3.29471 20.7053C3.35607 20.3395 3.45098 19.9148 3.59711 19.476C4.01221 18.2294 4.78141 17.0237 6.21648 16.5411C6.39528 16.481 6.54504 16.3739 6.65665 16.2382C6.85126 16.0016 6.92988 15.678 6.84417 15.3647C6.83922 15.3466 6.83373 15.3286 6.82767 15.3106C6.74106 15.053 6.55701 14.8557 6.33037 14.7459C6.10949 14.6389 5.84816 14.615 5.59715 14.6994C5.47743 14.7397 5.36103 14.7831 5.24786 14.8294C3.22626 15.6569 2.2347 17.4173 1.75357 18.8621C1.49662 19.6337 1.36993 20.3554 1.30679 20.8818C1.27505 21.1464 1.25893 21.3654 1.25072 21.5213C1.24662 21.5993 1.24448 21.6618 1.24337 21.7066L1.243 21.7226L1.24235 21.7605L1.2422 21.7771L1.24217 21.7827L1.24217 21.7856C1.24217 22.3221 1.67703 22.7579 2.2137 22.7579L2.2155 22.7579L2.22337 22.7578L2.23956 22.7577C2.25293 22.7575 2.27096 22.7572 2.29338 22.7567C2.33821 22.7555 2.40073 22.7534 2.47876 22.7493C2.63466 22.7411 2.85361 22.725 3.11822 22.6932C3.64462 22.6301 4.36636 22.5034 5.13797 22.2464C6.58274 21.7653 8.3431 20.7738 9.17063 18.7522C9.21696 18.639 9.26037 18.5226 9.30064 18.4029C9.30716 18.3835 9.31304 18.364 9.31827 18.3446Z"></path></svg>Reminder</p><section class="starlight-aside__content">
<p>Your PR title must start with <b>Answer:{challengeNumber}</b>.</p></section></aside>
<div class="article-footer">
<a
href={communityLink}
alt={communityDescription}>
❖ Community Answers
</a>
<a
href={authorLink}
alt={authorDescription}>
▶︎ Author Answer
</a>
{blogLink && <a
href={blogLink}
target="_blank"
rel="noopener noreferrer"
alt={`${title} blog article`}>
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>}
{videoLink && <VideoButton {...videoLink} />}
</div>
<style>
.separator {
border-top: solid 1px var(--sl-color-hairline);
margin-top: 2rem;
margin-bottom: 1rem;
}
.code {
background-color: var(--sl-color-bg-inline-code);
margin-block: -0.125rem;
padding: 0.125rem 0.375rem;
font-size: var(--sl-text-code-sm);
}
</style>

View File

@@ -0,0 +1,29 @@
---
---
<div class="separator"></div>
<script src="https://giscus.app/client.js"
data-repo="tomalaforge/angular-challenges"
data-repo-id="R_kgDOIXXIfw"
data-category="Announcements"
data-category-id="DIC_kwDOIXXIf84CSZF_"
data-mapping="title"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="preferred_color_scheme"
data-lang="en"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>
<style>
.separator {
border-top: solid 1px var(--sl-color-hairline);
margin: 3rem 0px;
}
</style>

View File

@@ -0,0 +1,26 @@
---
import ChallengeFooter from './ChallengeFooter.astro'
import CommentSection from './CommentSection.astro'
import type { Props } from '@astrojs/starlight/props';
import Default from '@astrojs/starlight/components/MarkdownContent.astro';
const {challengeNumber, author} = Astro.props.entry.data;
const renderCommentSection = !Astro.props.entry.data.noCommentSection;
---
{ challengeNumber && author && <p class="author">Created by {author}</p> }
<Default {...Astro.props}><slot /></Default>
{challengeNumber && <ChallengeFooter {...Astro.props} />}
{ renderCommentSection && <CommentSection /> }
<style>
.author {
margin-top: -1rem;
font-size: var(--sl-text-xs);
color: var(--sl-color-gray-3);
}
</style>

View File

@@ -0,0 +1,39 @@
---
import type { Props } from '@astrojs/starlight/props';
import Default from '@astrojs/starlight/components/PageTitle.astro';
const challengeNumber = Astro.props.entry.data.challengeNumber;
---
<div class="page-title-content">
<Default {...Astro.props}><slot /></Default>
{challengeNumber && <div class="chip">Challenge #{challengeNumber}</div> }
</div>
<style>
.page-title-content {
display: flex;
justify-content: space-between;
align-items: center;
}
@media (max-width: 1010px) {
.page-title-content {
flex-direction: column;
align-items: flex-start;
}
}
.chip {
border-width: 1px;
border-style: solid;
border-color: var(--color-chip-border);
border-radius: 6px;
padding: 2px 8px;
background-color: var(--color-chip);
color: var(--sl-color-text);
width: fit-content;
height: fit-content;
margin-top: 1rem;
}
</style>

View File

@@ -0,0 +1,31 @@
---
import Default from '@astrojs/starlight/components/TableOfContents.astro';
import { Icon } from '@astrojs/starlight/components';
---
<Default {...Astro.props}><slot /></Default>
<a class="action-button" href='https://github.com/tomalaforge/angular-challenges'>
<div>Give a star</div>
<Icon name='github' size="1.5rem" />
</a>
<style>
.action-button {
display: flex!important;
justify-content: center;
width: fit-content;
gap: 0.5em;
align-items: center;
border-radius: 999rem;
color: var(--sl-color-white)!important;
line-height: 1.1875;
text-decoration: none;
font-size: var(--sl-text-sm)!important;
border: 1px solid;
font-size: var(--sl-text-base);
padding: 0.5rem 0.8rem;
}
</style>

View File

@@ -0,0 +1,16 @@
---
const { link, alt, flag } = Astro.props;
const isFR = flag === 'FR';
---
<a
href={link}
target="_blank"
rel="noopener noreferrer"
alt={alt}>
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M23.5 6.2A3 3 0 0 0 21.4 4c-1.9-.5-9.4-.5-9.4-.5s-7.5 0-9.4.5A3 3 0 0 0 .5 6.3C0 8 0 12 0 12s0 4 .5 5.8A3 3 0 0 0 2.6 20c1.9.6 9.4.6 9.4.6s7.5 0 9.4-.6a3 3 0 0 0 2.1-2c.5-2 .5-5.9.5-5.9s0-4-.5-5.8zm-14 9.4V8.4l6.3 3.6-6.3 3.6z"></path></svg>
Video
{isFR && <span class="flag">🇫🇷<span>}
</a>

View File

@@ -1,7 +1,23 @@
import { defineCollection } from 'astro:content';
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
import { defineCollection, z } from 'astro:content';
export const collections = {
docs: defineCollection({ schema: docsSchema() }),
docs: defineCollection({
schema: (ctx) =>
docsSchema()(ctx).extend({
noCommentSection: z.boolean().optional().default(false),
challengeNumber: z.union([z.number(), z.boolean()]).default(false),
author: z.string().optional(),
command: z.string().optional(),
blogLink: z.string().optional(),
videoLink: z
.object({
link: z.string(),
alt: z.string(),
flag: z.enum(['FR']).optional(),
})
.optional(),
}),
}),
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
};

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Optimize Change Detection
description: Challenge 12 about optimizing the number of change detection cycle while scrolling
author: Thomas Laforge
challengeNumber: 12
command: scroll-cd
sidebar:
order: 107
---
<div class="chip">Challenge #12</div>
## Information
In Angular, there is a library called <b>Zone.js</b> that performs a lot of magic to simplify a developer's life. Zone.js monkey patches all DOM events so that it will recheck and rerender the view when something has changed inside the application. The developer doesn't have to manually trigger change detection.
@@ -35,26 +36,3 @@ Your goal for this challenge is to avoid all unnecessary change detection cycles
## Constraint:
You cannot opt-out of Zone.js globally. If this code is part of a large project and you opt out of Zone.js, you will break your application without any doubt.
---
:::note
Start the project by running: `npx nx serve scroll-cd`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:12</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A12+label%3Aanswer"
alt="Optimize Change Detection community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A{challenge number}+label%3A"answer+author"'
alt="Optimize Change Detection solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟢 Default vs OnPush
description: Challenge 34 is about learning the difference between Default and OnPush Change Detection Strategy.
author: Thomas Laforge
challengeNumber: 34
command: performance-default-onpush
sidebar:
order: 7
---
<div class="chip">Challenge #34</div>
## Information
In this challenge, we will explore the differences and impacts of using `ChangeDetectionStrategy.Default` versus `ChangeDetectionStrategy.OnPush`.
@@ -52,26 +53,3 @@ Use `ChangeDetectionStrategy.OnPush` but this will not be enough.
Create smaller components to better separate the input field from the list.
</details>
---
:::note
Start the project by running: `npx nx serve performance-default-onpush`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:34</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A34+label%3Aanswer"
alt="Default vs OnPush community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A34+label%3A"answer+author"'
alt="Default vs OnPush solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Memoization
description: Challenge 35 is about learning how pure pipe works
author: Thomas Laforge
challengeNumber: 35
command: performance-memoized
sidebar:
order: 8
---
@@ -45,26 +48,3 @@ The goal of this challenge is to understand what is causing this latency and to
Use `Pipes` to memoize the Fibonnaci computation.
</details>
---
:::note
Start the project by running: `npx nx serve performance-memoized`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:35</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A35+label%3Aanswer"
alt="Memoization community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A35+label%3A"answer+author"'
alt="Memoization solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟢 NgFor Optimization
description: Challenge 36 is about learning how trackby works
author: Thomas Laforge
challengeNumber: 36
command: performance-ngfor-optimize
sidebar:
order: 13
---
<div class="chip">Challenge #36</div>
## Information
In this application, we have a list of individuals that we can add, delete or update. If you open the developer Chrome panel by pressing **F12**, go to he <b>source</b> tab, and expand the element to see the list, you will notice that each time, you add, delete or update a list item, the entire DOM elements are destroyed and initialized again. (See video below).
@@ -28,26 +29,3 @@ If you need more information about `NgFor`, I invite you to read the [documentat
## Statement
The goal of this challenge is to understand what is causing this DOM refresh and to solve it.
---
:::note
Start the project by running: `npx nx serve performance-ngfor-optimize`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:36</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A36+label%3Aanswer"
alt="NgFor Optimization community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A36+label%3A"answer+author"'
alt="NgFor Optimization solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Optimize Big List
description: Challenge 37 is about learning how virtualization optimize big list rendering
author: Thomas Laforge
challengeNumber: 37
command: performance-ngfor-biglist
sidebar:
order: 117
---
<div class="chip">Challenge #37</div>
## Information
In this application, we will render a list of 100,000 individuals by clicking on the **loadList** button. If you open the Chrome developer panel by pressing **F12**, go to the <b>Source</b> tab, and expand the element to see the list, you will notice that all 100,000 elements are rendered in the DOM, even though we can only see about 20 elements in the viewport. This process takes a lot of time, which is why the application is very slow at displaying the list.
@@ -32,26 +33,3 @@ The goal of this challenge is to implement a better alternative to display big l
If you're unsure where to begin, I recommend reading the [Angular CDK virtualization documentation](https://material.angular.io/cdk/scrolling/overview)
</details>
---
:::note
Start the project by running: `npx nx serve performance-ngfor-biglist`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:37</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A37+label%3Aanswer"
alt="NgFor optimize big list community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A37+label%3A"answer+author"'
alt="NgFor optimize big list solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -3,6 +3,7 @@ title: Angular Performance
prev: false
next: false
description: Learn how to use the Angular Devtool chrome extension.
noCommentSection: true
sidebar:
order: 1
---

View File

@@ -1,12 +1,18 @@
---
title: 🟢 Projection
description: Challenge 1 is about learning how to project DOM element through components
author: Thomas Laforge
challengeNumber: 1
command: projection
blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
videoLink:
link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
alt: Projection video by Arthur Lannelucq
flag: FR
sidebar:
order: 1
---
<div class="chip">Challenge #1</div>
## Information
In Angular, content projection is a powerful technique for creating highly customizable components. Utilizing and understanding the concepts of <b>ng-content</b> and <b>ngTemplateOutlet</b> can sighificantly enhance your ability to create shareable components.
@@ -29,43 +35,3 @@ While the application works, the developer experience is far from being optimal.
- The `NgFor` directive must be declared and remain inside the `CardComponent`. You might be tempted to move it to the `CardComponent` but avoid doing so.
- `CardComponent` should not contain any `NgIf` or `NgSwitch`.
- CSS: try to avoid using `::ng-deep`. Find a better way to handle CSS styling.
---
:::note
Start the project by running: `npx nx serve projection`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:1</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A1+label%3Aanswer"
alt="Projection community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A1+label%3A"answer+author"'
alt="Projection solution author">
▶︎ Author Answer
</a>
<a
href="https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5"
target="_blank"
rel="noopener noreferrer"
alt="Projection blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
<a
href="https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq"
target="_blank"
rel="noopener noreferrer"
alt="Projection video by Arthur Lannelucq">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M23.5 6.2A3 3 0 0 0 21.4 4c-1.9-.5-9.4-.5-9.4-.5s-7.5 0-9.4.5A3 3 0 0 0 .5 6.3C0 8 0 12 0 12s0 4 .5 5.8A3 3 0 0 0 2.6 20c1.9.6 9.4.6 9.4.6s7.5 0 9.4-.6a3 3 0 0 0 2.1-2c.5-2 .5-5.9.5-5.9s0-4-.5-5.8zm-14 9.4V8.4l6.3 3.6-6.3 3.6z"></path></svg>
Video
<span class="flag">🇫🇷<span>
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🔴 Utility Wrapper Pipe
description: Challenge 10 is about creating a pipe to wrap utilities
author: Thomas Laforge
challengeNumber: 10
command: pipe-hard
sidebar:
order: 202
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #10</div>
The goal of this serie of 3 pipe challenges is to master PIPES in Angular.
Pure pipe are a very useful way to transform data from your template. The difference between calling a function and a pipe is that pure pire are memoized. So they won't be recalculated every change detection cycle if the inputs hasn't changed.
@@ -22,26 +23,3 @@ In this third exercice, you want to access utils functions. Currently we cannot
## Constraints:
- must be strongly typed
---
:::note
Start the project by running: `npx nx serve pipe-hard`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:10</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A10+label%3Aanswer"
alt="Utility Wrapper Pipe community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A10+label%3A"answer+author"'
alt="Utility Wrapper Pipe solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟠 Highly Customizable CSS
description: Challenge 13 is about creating highly customizable CSS styles
author: Thomas Laforge
challengeNumber: 13
command: styling
sidebar:
order: 104
---
@@ -24,26 +27,3 @@ In this challenge, you will need to use both CSS variables and :host-context to
## Constraints:
- In your final submission, your component should not contain any lines of code. All styling should be handled within the decorator _(or external css files if you prefer)_
---
:::note
Start the project by running: `npx nx serve styling`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:13</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A13+label%3Aanswer"
alt="Highly Customizable CSS community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A13+label%3A"answer+author"'
alt="Highly Customizable CSS solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🔴 Master Dependancy Injection
description: Challenge 16 is about masjering how dependancy injection works
author: Thomas Laforge
challengeNumber: 16
command: di
sidebar:
order: 203
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #16</div>
## Information
To successfully complete this challenge, you will need to have a good understanding of how Dependency Injection works inside Angular.
@@ -27,26 +28,3 @@ One way to achieve this is by adding a second argument to the pipe, but this is
- You cannot modify the pipe.
- You cannot wrap the row inside a component, as this will break the layout.
---
:::note
Start the project by running: `npx nx serve di`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:16</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A16+label%3Aanswer"
alt="Master Dependancy Injection community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A16+label%3A"answer+author"'
alt="Master Dependancy Injection solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Anchor Navigation
description: Challenge 21 is about navigating inside the page with anchor
author: Thomas Laforge
challengeNumber: 21
command: anchor-scrolling
sidebar:
order: 4
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #21</div>
## Information
You begin with an application that has basic navigation and anchor navigation in the `HomeComponent`. However, using `href` recreates the path each time and refreshes the page.
@@ -19,26 +20,3 @@ You begin with an application that has basic navigation and anchor navigation in
- Your task is to refactor this application to use the built-in navigation tool to better fit within the Angular Framework. You can explore the router, but it's better to stay within the template and use the `RouterLink` directive.
- To improve the user experience, add smooth scrolling.
---
:::note
Start the project by running: `npx nx serve anchor-scrolling`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:21</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A21+label%3Aanswer"
alt="Anchor Navigation community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A21+label%3A"answer+author"'
alt="Anchor Navigation solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,14 @@
---
title: 🟢 @RouterInput()
description: Challenge 22 is about using the @Input decorator to retreive router params.
author: Thomas Laforge
challengeNumber: 22
command: router-input
blogLink: https://medium.com/ngconf/accessing-route-params-in-angular-1f8e12770617
sidebar:
order: 5
---
<div class="chip">Challenge #22</div>
## Information
In this application, we retrieve three pieces of information inside our `TestComponent` provided by the router:
@@ -23,34 +25,3 @@ In version 16, Angular introduced a new `Input` that can listen to route data. Y
## Statement
The goal of this exercice is to refactor the code to use the new `RouterInput` strategy.
---
:::note
Start the project by running: `npx nx serve router-input`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:22</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A22+label%3Aanswer"
alt="@RouterInput() community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A22+label%3A"answer+author"'
alt="@RouterInput() solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/ngconf/accessing-route-params-in-angular-1f8e12770617'
target="_blank"
rel="noopener noreferrer"
alt="@RouterInput() blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Directive Enhancement
description: Challenge 3 is about enhancing a built-in directive
author: Thomas Laforge
challengeNumber: 3
command: ngfor-enhancement
blogLink: https://medium.com/@thomas.laforge/ngfor-enhancement-716b44656a6c
sidebar:
order: 101
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #3</div>
## Information
Directive is a very powerful tool only offered by the Angular framework. You can apply the DRY principal by having shared logic inside a directive and applying it to any component you want.
@@ -42,34 +44,3 @@ We want to get rid of the ng-container by writing :
```
The goal is to **improve the ngFor directive**
---
:::note
Start the project by running: `npx nx serve ngfor-enhancement`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:3</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A3+label%3Aanswer"
alt="Directive Enhancement community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A3+label%3A"answer+author"'
alt="Directive Enhancement solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/@thomas.laforge/ngfor-enhancement-716b44656a6c'
target="_blank"
rel="noopener noreferrer"
alt="Directive Enhancement blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🔴 Interoperability Rxjs/Signal
description: Challenge 30 is about learning how to mix signal with Rxjs
author: Thomas Laforge
challengeNumber: 30
command: interop-rxjs-signal
sidebar:
order: 204
---
@@ -16,26 +19,3 @@ WIP: The following documentation will be reviewed and improved. However, you can
In this challenge, we have a small reactive application using RxJS and NgRx/Component-Store.
The goal of this challenge is to use the new **Signal API** introduced in Angular v16. However, we should not convert everything. Certain portions of the code are better suited for RxJS rather than Signal. It is up to you to determine the threshold and observe how **Signal and RxJS coexist**, as well as how the interoperability is achieved in Angular.
---
:::note
Start the project by running: `npx nx serve interop-rxjs-signal`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:30</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A30+label%3Aanswer"
alt="Interoperability Rxjs/Signal community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A30+label%3A"answer+author"'
alt="Interoperability Rxjs/Signal solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Module to Standalone
description: Challenge 31 is about migrating a module based application to a standalone application.
author: Thomas Laforge
challengeNumber: 31
command: module-to-standalone
sidebar:
order: 6
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #31</div>
## Information
In v14, standalone components were released and made stable in v15. If you haven't played with them, it's never too late. You can try them out in this challenge.
@@ -24,26 +25,3 @@ After completing this challenge, standalone components will no longer hold any s
## Statement
The goal of this challenge is to migrate your application from module based components to standalone components.
---
:::note
Start the project by running: `npx nx serve module-to-standalone`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:31</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A31+label%3Aanswer"
alt="Module to Standalone community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A31+label%3A"answer+author"'
alt="Module to Standalone solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Change Detection Bug
description: Challenge 32 is about debugging an application that has issue when change detection is triggered
author: Thomas Laforge
challengeNumber: 32
command: bug-cd
blogLink: https://medium.com/ngconf/function-calls-inside-template-are-dangerous-15f9822a6629
sidebar:
order: 105
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #32</div>
:::note
This challenge is inspired by a real-life example that I simplified to create this nice challenge.
:::
@@ -37,34 +39,3 @@ The goal of the challenge is to debug this application and make it work.
If you open the [`RouterLinkActive` source code](https://github.com/angular/angular/blob/main/packages/router/src/directives/router_link_active.ts) and go to **line 196**, Angular is calling `this.cdr.markForCheck` inside a microTask which triggers a new CD cycle. If you comment out this line, the application loads again, however the bug is not inside the Angular Framework. 😅😯
</details>
---
:::note
Start the project by running: `npx nx serve bug-cd`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:32</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A32+label%3Aanswer"
alt="Change Detection Bug community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A32+label%3A"answer+author"'
alt="Change Detection Bug solution author">
▶︎ Author Answer
</a>
<a
href="https://medium.com/ngconf/function-calls-inside-template-are-dangerous-15f9822a6629"
target="_blank"
rel="noopener noreferrer"
alt="Change Detection Bug blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟠 Decoupling Components
description: Challenge 33 is about decoupling two strongly coupled components using Injection Token
author: Thomas Laforge
challengeNumber: 33
command: decoupling
sidebar:
order: 106
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #33</div>
> Big thanks to **Robin Goetz** and his [Spartan Project](https://github.com/goetzrobin/spartan).
> This challenge was proposed by Robin and is strongly inspired by his project.
@@ -32,26 +33,3 @@ The goal of this challenge is to find a way to decouple both Directives.
<summary>Hint 1</summary>
Carefully read the title of the challenge 😇
</details>
---
:::note
Start the project by running: `npx nx serve decoupling`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:33</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A33+label%3Aanswer"
alt="Decoupling Components community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A33+label%3A"answer+author"'
alt="Decoupling Components solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🔴 Typed ContextOutlet
description: Challenge 4 is about strongly typing ngContextOutlet directives
author: Thomas Laforge
challengeNumber: 4
command: context-outlet-type
blogLink: https://medium.com/@thomas.laforge/ngtemplateoutlet-type-checking-5d2dcb07a2c6
sidebar:
order: 201
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #4</div>
## Information
Angular offer the static function **ngTemplateContextGuard** to strongly type structural directive.
@@ -40,34 +42,3 @@ Currently we have the following piece of code.
As we can see, student is of type "any". We want to infer the correct type.
But in this part, we can pass to ListComponent, a list of **any object**. And we still want the correct type to be infered.
---
:::note
Start the project by running: `npx nx serve context-outlet-type`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:4</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A4+label%3Aanswer"
alt="Typed ContextOutlet community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A4+label%3A"answer+author"'
alt="Typed ContextOutlet solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/@thomas.laforge/ngtemplateoutlet-type-checking-5d2dcb07a2c6'
target="_blank"
rel="noopener noreferrer"
alt="Typed ContextOutlet blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Crud application
description: Challenge 5 is about refactoring a crud application
author: Thomas Laforge
challengeNumber: 5
command: crud
sidebar:
order: 2
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #5</div>
## Information
Communicating and having a global/local state in sync with your backend is the heart of any application. You will need to master those following best practises to build strong and reliable Angular Application.
@@ -54,26 +55,3 @@ this.todos = [...this.todos.filter((t) => t.id !== todoUpdated.id), todoUpdated]
- Use the **component store of ngrx** as a local state of your component. _(or any other 3rd Party lib)_
- Have a **localize** Loading/Error indicator, e.g. only on the Todo being processed and **disable** all buttons of the processed Todo. _(Hint: you will need to create an ItemComponent)_
---
:::note
Start the project by running: `npx nx serve crud`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:5</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A5+label%3Aanswer"
alt="Crud application community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A5+label%3A"answer+author"'
alt="Crud application solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Structural Directive
description: Challenge 6 is about creating a structural directive to handle permissions
author: Thomas Laforge
challengeNumber: 6
command: permissions
blogLink: https://medium.com/@thomas.laforge/create-a-custom-structural-directive-to-manage-permissions-like-a-pro-11a1acad30ad
sidebar:
order: 102
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #6</div>
## Information
Structural directive is an important concept you will need to master to improve your angular skills and knowledge. This will be the first part of this challenge.
@@ -55,34 +57,3 @@ You should end up with something like below:
## Step 2
In **Routes.ts**, route all user to the correct **DashboardComponent** using **CanMatch** guard.
---
:::note
Start the project by running: `npx nx serve permissions`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:6</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A6+label%3Aanswer"
alt="Structural Directive community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A6+label%3A"answer+author"'
alt="Structural Directive solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/@thomas.laforge/create-a-custom-structural-directive-to-manage-permissions-like-a-pro-11a1acad30ad'
target="_blank"
rel="noopener noreferrer"
alt="Structural Directive blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟢 Pure Pipe
description: Challenge 8 is about creating a pure pipe
author: Thomas Laforge
challengeNumber: 8
command: pipe-easy
blogLink: https://medium.com/ngconf/deep-dive-into-angular-pipes-c040588cd15d
sidebar:
order: 3
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #8</div>
The goal of this serie of 3 pipe challenges is to master PIPES in Angular.
Pure pipe are a very useful way to transform data from your template. The difference between calling a function and a pipe is that pure pire are memoized. So they won't be recalculated every change detection cycle if the inputs hasn't changed.
@@ -22,34 +24,3 @@ In this first exercice, you add calling a simple function inside your template.
## Constraints:
- must be strongly typed
---
:::note
Start the project by running: `npx nx serve pipe-easy`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:8</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A8+label%3Aanswer"
alt="Pure Pipe community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A8+label%3A"answer+author"'
alt="Pure Pipe solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/ngconf/deep-dive-into-angular-pipes-c040588cd15d'
target="_blank"
rel="noopener noreferrer"
alt="Pure Pipe blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Wrap Function Pipe
description: Challenge 9 is about creating a pipe to wrap component fonctions
author: Thomas Laforge
challengeNumber: 9
command: pipe-intermediate
blogLink: https://medium.com/ngconf/boost-your-apps-performance-by-wrapping-your-functions-inside-a-pipe-7e889a901d1d
sidebar:
order: 103
---
@@ -23,34 +27,3 @@ The goal is to create a `wrapFn` pipe to wrap your callback function though a pi
## Constraints:
- must be strongly typed
---
:::note
Start the project by running: `npx nx serve pipe-intermediate`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:9</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A9+label%3Aanswer"
alt="Wrap Function Pipe community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A9+label%3A"answer+author"'
alt="Wrap Function Pipe solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/ngconf/boost-your-apps-performance-by-wrapping-your-functions-inside-a-pipe-7e889a901d1d'
target="_blank"
rel="noopener noreferrer"
alt="Wrap Function Pipe blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Effect vs Selector
description: Challenge 2 is about learning the difference between effects and selectors in NgRx
author: Thomas Laforge
challengeNumber: 2
command: ngrx-1
blogLink: https://medium.com/@thomas.laforge/ngrx-effect-vs-reducer-vs-selector-58337ab59043
sidebar:
order: 113
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #2</div>
For this exercice, you will have a dashboard of activities displaying the name, the main teacher and a list of subtitutes.
## Information
@@ -30,34 +32,3 @@ You will have to Refactor this working example of a dashboard of activities.
- Only **one action** should be dispatched from a component
- Status effect is useless. Using **combineLatest** should be a red flag. And Effect are made for side effect, not transforming data. That's a selector role
- Status state might not be useful, it's only a **derived state** of existing state.
---
:::note
Start the project by running: `npx nx serve ngrx-1`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:2</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A2+label%3Aanswer"
alt="Effect vs Selector community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A2+label%3A"answer+author"'
alt="Effect vs Selector solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/@thomas.laforge/ngrx-effect-vs-reducer-vs-selector-58337ab59043'
target="_blank"
rel="noopener noreferrer"
alt="Effect vs Selector blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🔴 Power of Effect
description: Challenge 7 is about creating an Ngrx effect with another Rxjs Hot observable
author: Thomas Laforge
challengeNumber: 7
command: ngrx-notification
sidebar:
order: 206
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #7</div>
## Information
NgRx Effect is a very powerful library develop by the NgRx team. Effects subscribe to a HOT Observable and listen to any event dispatch from any place inside the application.
@@ -33,26 +34,3 @@ create one ngrx effect, or component store effect for each push type, and implem
load your effect only when necessary.
the application contain a root route, a lazy loaded route and a component with a local state (implemented with Component store)
---
:::note
Start the project by running: `npx nx serve ngrx-notification`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:7</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A7+label%3Aanswer"
alt="Power of Effect community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A7+label%3A"answer+author"'
alt="Power of Effect solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,8 @@
---
title: 🔴 Extend Lib Generator
description: Challenge 25 is about creating a Nx generator to extend the built-in Library Generator
author: Thomas Laforge
challengeNumber: 25
sidebar:
order: 207
---
@@ -53,22 +55,3 @@ export default {
`eslintrc.json`
add this rule `"@typescript-eslint/member-ordering": "off"` inside the rules properties of ts files.
---
:::tip[Reminder]
Your PR title must start with <b>Answer:25</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A25+label%3Aanswer"
alt="Extend Lib Generator community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A25+label%3A"answer+author"'
alt="Extend Lib Generator solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,8 @@
---
title: 🟠 Component Generator
description: Challenge 26 is about creating a Nx generator to create a custom component
author: Thomas Laforge
challengeNumber: 26
sidebar:
order: 116
---
@@ -141,22 +143,3 @@ export interface User {
name: string;
}
```
---
:::tip[Reminder]
Your PR title must start with <b>Answer:26</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A26+label%3Aanswer"
alt="Component Generator community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A26+label%3A"answer+author"'
alt="Component Generator solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,8 @@
---
title: 🟢 Custom Eslint Rule
description: Challenge 27 is about creating a custom Eslint Rule to forbid enums
author: Thomas Laforge
challengeNumber: 27
sidebar:
order: 12
---
@@ -22,22 +24,3 @@ To test the rule inside your project, add `"@nrwl/nx/workspace/forbidden-enum":
To assist you with AST (Abstract Syntax Tree) definitions, you can visit the [AST explorer](https://astexplorer.net/) and use JavaScript, @typescript-eslint/parser, and Eslint-v8 as the transformation method. However, please note that you will only get the type information there. The transformation function may not work for TypeScript types since the editor is in JavaScript.
You can also check this [repo](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/rules) for eslint rule examples.
---
:::tip[Reminder]
Your PR title must start with <b>Answer:27</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A27+label%3Aanswer"
alt="Custom Eslint Rule community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A27+label%3A"answer+author"'
alt="Custom Eslint Rule solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟠 High Order Operator Bug
description: Challenge 11 is about resolving a Rxjs bug because of high order operators
author: Thomas Laforge
challengeNumber: 11
command: rxjs-pipe-bu
sidebar:
order: 114
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #11</div>
Let's dive inside the wonderful word of RxJs.
This challenge is inspired by a real-life example.
@@ -30,26 +31,3 @@ We can only pass one object to our DB for deletion at the time. The DB will resp
The QA team reports a **bug**. The UI shows **All [topic] have been deleted** all the time, even if some deletions fail.
👉 Spot the bug and correct it.
---
:::note
Start the project by running: `npx nx serve rxjs-pipe-bug`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:11</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A11+label%3Aanswer"
alt="High Order Operator Bug community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A11+label%3A"answer+author"'
alt="High Order Operator Bug solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Race Condition
description: Challenge 14 is about race condition in Rxjs
author: Thomas Laforge
challengeNumber: 14
command: rxjs-race-condition
sidebar:
order: 11
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #14</div>
## Information
The goal of this application is to display a list of topics in a modal when a button is clicked. The application functions correctly. However, your tech lead has asked you to add tests and they are failing.
@@ -28,26 +29,3 @@ Correct your application to pass the test
HEADLESS : `npx nx component-test rxjs-race-condition`
WATCH MODE : `npx nx component-test rxjs-race-condition --watch`
---
:::note
Start the project by running: `npx nx serve rxjs-race-condition`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:14</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A14+label%3Aanswer"
alt="Race Condition community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A14+label%3A"answer+author"'
alt="Race Condition solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Router
description: Challenge 17 is about testing the router
author: Thomas Laforge
challengeNumber: 17
command: testing-router-outlet
sidebar:
order: 108
---
<div class="chip">Challenge #17</div>
## Information
We have a functional application that lists available books for borrowing inside a library. If the book you searched for is available, you will be directed to the corresponding book(s), otherwise, you will end up on an error page.
@@ -22,26 +23,3 @@ The goal is to test multiple behaviors of the application described in each test
:::note
I have created some `it` blocks but feel free to add more tests if you want.
:::
---
:::note
Start the project by running: `npx nx serve testing-router-outlet`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:17</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A17+label%3Aanswer"
alt="Router community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A17+label%3A"answer+author"'
alt="Router solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Nested Components
description: Challenge 18 is about testing nested components
author: Thomas Laforge
challengeNumber: 18
command: testing-nested
sidebar:
order: 109
---
<div class="chip">Challenge #18</div>
## Information
We have a small application that sends a title, typed into an input to a fake backend.
@@ -26,26 +27,3 @@ The goal is to test multiple behaviors of the application describe inside each t
:::note
I have created some `it` blocks but feel free to add more tests if you want.
:::
---
:::note
Start the project by running: `npx nx serve testing-nested`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:18</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A18+label%3Aanswer"
alt="Nested Components community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A18+label%3A"answer+author"'
alt="Nested Components solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Input Output
description: Challenge 19 is about testing inputs and ouputs
author: Thomas Laforge
challengeNumber: 19
command: testing-input-output
sidebar:
order: 110
---
<div class="chip">Challenge #19</div>
## Information:
We have a small counter application that increments or decrements a number. The `CounterComponent` takes an initial value as an `@Input` and emits the result of the counter as an `@Output` when we click on the **Send** button. Since we are testing our component as a black box, we only have access to our inputs and listen to the output values. <b>We should not rely on any internal implementation details!!!</b>
@@ -24,26 +25,3 @@ The goal is to test multiple behaviors of the application describe inside each t
:::note
I have created some `it` blocks but feel free to add more tests if you want.
:::
---
:::note
Start the project by running: `npx nx serve testing-input-output`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:19</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A19+label%3Aanswer"
alt="Input Output community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A19+label%3A"answer+author"'
alt="Input Output solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟠 Modal
description: Challenge 20 is about testing modals
author: Thomas Laforge
challengeNumber: 20
command: testing-modal
sidebar:
order: 111
---
<div class="chip">Challenge #20</div>
## Information:
In this small application, you have an input prompting you to enter a name, and a **Confirm** button to submit your form.
@@ -28,26 +29,3 @@ The goal is to test multiple behaviors of the application describe inside each t
:::note
I have created some `it` blocks but feel free to add more tests if you want.
:::
---
:::note
Start the project by running: `npx nx serve testing-modal`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:20</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A20+label%3Aanswer"
alt="Modal community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A20+label%3A"answer+author"'
alt="Modal solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟢 Harness
description: Challenge 23 is about testing with component harnesses
author: Thomas Laforge
challengeNumber: 23
command: testing-harness
sidebar:
order: 9
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #23</div>
## Statement:
The objective of this challenge is to have a better understanding of the CDK test harness API. In this initial challenge, we will only use Angular Material's built-in harnesses.
@@ -21,26 +22,3 @@ The goal is to test the functionality of `child.component.ts`. I have prepared a
Documentation for CDK Component Harness is [here](https://material.angular.io/cdk/test-harnesses/overview#api-for-test-authors)
Documentation for Angular Material component is [here](https://material.angular.io/components/button/overview)
---
:::note
Start the project by running: `npx nx serve testing-harness`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:23</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A23+label%3Aanswer"
alt="Harness community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A23+label%3A"answer+author"'
alt="Harness solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,6 +1,9 @@
---
title: 🟠 Harness Creation
description: Challenge 24 is about creating a component harness.
author: Thomas Laforge
challengeNumber: 24
command: create-harness
sidebar:
order: 112
---
@@ -9,8 +12,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #24</div>
## Information
The goal of this challenge is to create a test harness for `slider.component.ts`. The harness file, `slider.harness.ts`, has already been created.
@@ -45,26 +46,3 @@ Lastly, you will need to create the test suite for `app.component`. Some default
> Angular Material documentation can be found [here](https://material.angular.io/cdk/test-harnesses/overview)
Good luck !!! 💪
---
:::note
Start the project by running: `npx nx serve create-harness`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:24</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A24+label%3Aanswer"
alt="Harness Creation community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A24+label%3A"answer+author"'
alt="Harness Creation solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🟢 Checkbox
description: Challenge 28 is about testing a simple checkbox
author: Thomas Laforge
challengeNumber: 10
command: testing-checkbox
sidebar:
order: 10
---
<div class="chip">Challenge #28</div>
## Information
This application is very simple. It consists of a checkbox that enables or disables a button. The primary goal of this application is to become familiar with the debug API of Testing Library. Knowing how to debug your tests is a crucial tool you need to have in your toolkit.
@@ -22,26 +23,3 @@ The main functions to remember are as follows:
## Statement
The goal of this challenge is not to submit an answer, but you can if you want. It's more about using the debugging API to play around. These tools will be of great help for the upcoming testing challenges.
---
:::note
Start the project by running: `npx nx serve testing-checkbox`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:28</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A28+label%3Aanswer"
alt="Checkbox community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A28+label%3A"answer+author"'
alt="Checkbox solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -1,12 +1,13 @@
---
title: 🔴 Real-life Application
description: Challenge 29 is about testing a real-life application
author: Thomas Laforge
challengeNumber: 29
command: testing-todos-list
sidebar:
order: 205
---
<div class="chip">Challenge #29</div>
## Information:
This application presents a greater challenge because it closely resembles a real-life application that you might encounter in your day-to-day activities as an Angular developer. What makes it more difficult is the need to handle asynchronous tasks and create appropriate mocks.
@@ -30,26 +31,3 @@ The goal is to test multiple behaviors of the application describe inside each t
:::note
I have created some `it` blocks but feel free to add more tests if you want.
:::
---
:::note
Start the project by running: `npx nx serve testing-todos-list`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:29</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A29+label%3Aanswer"
alt="Real-life Application community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A29+label%3A"answer+author"'
alt="Real-life Application solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -3,6 +3,7 @@ title: Testing
prev: false
next: false
description: Introduction to testing challenges.
noCommentSection: true
sidebar:
order: 1
---

View File

@@ -1,6 +1,10 @@
---
title: 🟠 Function Overload
description: Challenge 15 is about creating overload functions
author: Thomas Laforge
challengeNumber: 15
command: overload
blogLink: https://medium.com/ngconf/function-overloading-in-typescript-8236706b2c05
sidebar:
order: 115
---
@@ -9,8 +13,6 @@ sidebar:
WIP: The following documentation will be reviewed and improved. However, you can still take on the challenge. If you don't understand a certain part, please feel free to reach out or create an issue.
:::
<div class="chip">Challenge #15</div>
## Information
Angular uses TypeScript, and mastering TypeScript can help you avoid runtime errors by catching them at compile time.
@@ -24,34 +26,3 @@ To achieve this, we will use overload functions.
## Statement
- Use function overload
---
:::note
Start the project by running: `npx nx serve overload``.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:15</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A15+label%3Aanswer"
alt="Function Overload community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A15+label%3A"answer+author"'
alt="Function Overload solution author">
▶︎ Author Answer
</a>
<a
href='https://medium.com/ngconf/function-overloading-in-typescript-8236706b2c05'
target="_blank"
rel="noopener noreferrer"
alt="Function Overload blog article">
<svg aria-hidden="true" class="astro-yzt5nm4y astro-lq7oo3uf" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"></path></svg>
Blog Post
</a>
</div>

View File

@@ -2,6 +2,7 @@
title: Welcome to Angular Challenges
description: Get started by resolving those challenges and becoming a better Angular FrontEnd engineer.
template: splash
noCommentSection: true
hero:
tagline: Start now and become an Angular Expert!
image:

View File

@@ -49,17 +49,6 @@
margin: 0px 2px;
}
.chip {
border-width: 1px;
border-style: solid;
border-color: var(--color-chip-border);
border-radius: 6px;
padding: 2px 8px;
background-color: var(--color-chip);
color: var(--sl-color-text);
width: fit-content;
}
.article-footer {
margin-top: 3rem !important;
display: flex;
@@ -120,3 +109,18 @@ starlight-menu-button svg {
padding: 1px 2px;
border-radius: 999px;
}
.right-sidebar-panel {
height: 100%;
}
.right-sidebar-panel > div {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
/* .content-panel {
padding-top: 2px;
} */