mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-13 18:21:57 +08:00
Compare commits
1 Commits
fix/count
...
feat/resou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2440f31ec |
@@ -3,6 +3,6 @@
|
||||
"enabled": false
|
||||
},
|
||||
"_variables": {
|
||||
"lastUpdateCheck": 1724925726721
|
||||
"lastUpdateCheck": 1723855511353
|
||||
}
|
||||
}
|
||||
1
.astro/types.d.ts
vendored
1
.astro/types.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="astro/client" />
|
||||
16
.github/workflows/cloudfront-api-cache.yml
vendored
16
.github/workflows/cloudfront-api-cache.yml
vendored
@@ -1,16 +0,0 @@
|
||||
name: Clears API Cloudfront Cache
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
aws_costs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clear Cloudfront Caching
|
||||
run: |
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GH_PAT }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \
|
||||
-d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront-api", "is_verbose": false } }'
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Clears Frontend Cloudfront Cache
|
||||
name: Clears Cloudfront Cache
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
35
.github/workflows/deployment.yml
vendored
35
.github/workflows/deployment.yml
vendored
@@ -1,26 +1,24 @@
|
||||
name: Deploy to EC2
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
workflow_dispatch: # allow manual run
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
- uses: pnpm/action-setup@v4.0.0
|
||||
- uses: pnpm/action-setup@v3.0.0
|
||||
with:
|
||||
version: 9
|
||||
version: 8.15.6
|
||||
|
||||
# -------------------
|
||||
# --------------------
|
||||
# Setup configuration
|
||||
# -------------------
|
||||
# --------------------
|
||||
- name: Prepare configuration files
|
||||
run: |
|
||||
git clone https://${{ secrets.GH_PAT }}@github.com/roadmapsh/infra-config.git configuration --depth 1
|
||||
@@ -28,14 +26,13 @@ jobs:
|
||||
run: |
|
||||
cp configuration/dist/github/developer-roadmap.env .env
|
||||
|
||||
# -----------------
|
||||
# Prepare the Build
|
||||
# -----------------
|
||||
- name: Install Dependencies
|
||||
# --------------------
|
||||
# Prepare the build
|
||||
# --------------------
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pnpm install
|
||||
|
||||
- name: Generate Production Build
|
||||
- name: Generate build
|
||||
run: |
|
||||
git clone https://${{ secrets.GH_PAT }}@github.com/roadmapsh/web-draw.git .temp/web-draw --depth 1
|
||||
npm run generate-renderer
|
||||
@@ -48,7 +45,7 @@ jobs:
|
||||
- uses: webfactory/ssh-agent@v0.7.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.EC2_PRIVATE_KEY }}
|
||||
- name: Deploy Application to EC2
|
||||
- name: Deploy app to EC2
|
||||
run: |
|
||||
rsync -apvz --delete --no-times --exclude "configuration" -e "ssh -o StrictHostKeyChecking=no" -p ./ ${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}:/var/www/roadmap.sh/
|
||||
- name: Restart PM2
|
||||
@@ -61,9 +58,9 @@ jobs:
|
||||
cd /var/www/roadmap.sh
|
||||
sudo pm2 restart web-roadmap
|
||||
|
||||
# ----------------------
|
||||
# --------------------
|
||||
# Clear cloudfront cache
|
||||
# ----------------------
|
||||
# --------------------
|
||||
- name: Clear Cloudfront Caching
|
||||
run: |
|
||||
curl -L \
|
||||
|
||||
10
.github/workflows/label-issue.yml
vendored
10
.github/workflows/label-issue.yml
vendored
@@ -1,15 +1,13 @@
|
||||
name: Label Issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [ opened, edited ]
|
||||
|
||||
jobs:
|
||||
label-topic-change-issue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add Labels To Issue
|
||||
uses: actions/github-script@v7
|
||||
- name: Add roadmap slug to issue as label
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
@@ -20,7 +18,7 @@ jobs:
|
||||
if (issue.labels.some(label => label.name === 'topic-change')) {
|
||||
if (roadmapUrl) {
|
||||
const roadmapSlug = new URL(roadmapUrl[0]).pathname.replace(/\//, '');
|
||||
github.rest.issues.addLabels({
|
||||
github.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
@@ -30,7 +28,7 @@ jobs:
|
||||
|
||||
// Close the issue if it has no roadmap URL
|
||||
if (!roadmapUrl) {
|
||||
github.rest.issues.update({
|
||||
github.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
name: Refresh Roadmap Content JSON
|
||||
name: Refreshes roadmap content JSON
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_dispatch: # allow manual run
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
- cron: '0 0 * * *' # every day at midnight
|
||||
|
||||
jobs:
|
||||
refresh-content:
|
||||
upgrade-deps:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm@v9
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: false
|
||||
|
||||
- name: Setup Node.js Version 20 (LTS)
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install Dependencies and Generate Content JSON
|
||||
- name: Install dependencies and generate content JSON
|
||||
run: |
|
||||
pnpm install
|
||||
npm run generate:roadmap-content-json
|
||||
|
||||
- name: Create PR
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
delete-branch: false
|
||||
branch: "chore/update-content-json"
|
||||
@@ -37,16 +37,9 @@ jobs:
|
||||
labels: |
|
||||
dependencies
|
||||
automated pr
|
||||
reviewers: kamranahmedse
|
||||
reviewers: kamranahmedse,arikchakma
|
||||
commit-message: "chore: update roadmap content json"
|
||||
title: "Updated Roadmap Content JSON - Automated"
|
||||
title: "Update roadmap content json"
|
||||
body: |
|
||||
## Updated Roadmap Content JSON
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This PR Updates the Roadmap Content JSON files stored in the `public` directory.
|
||||
>
|
||||
> Commit: ${{ github.sha }}
|
||||
> Workflow Path: ${{ github.workflow_ref }}
|
||||
|
||||
**Please Review the Changes and Merge the PR if everything is fine.**
|
||||
Updates the roadmap content JSON files in the `public` folder.
|
||||
Please review the changes and merge if everything looks good.
|
||||
|
||||
38
.github/workflows/update-deps.yml
vendored
Normal file
38
.github/workflows/update-deps.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Update dependencies
|
||||
|
||||
on:
|
||||
workflow_dispatch: # allow manual run
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # every sunday at midnight
|
||||
|
||||
jobs:
|
||||
upgrade-deps:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- uses: pnpm/action-setup@v2.2.2
|
||||
with:
|
||||
version: 7.13.4
|
||||
- name: Upgrade dependencies
|
||||
run: |
|
||||
pnpm install
|
||||
npm run upgrade
|
||||
pnpm install --lockfile-only
|
||||
- name: Create PR
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
delete-branch: false
|
||||
branch: "update-deps"
|
||||
base: "master"
|
||||
labels: |
|
||||
dependencies
|
||||
automated pr
|
||||
reviewers: kamranahmedse
|
||||
commit-message: "chore: update dependencies to latest"
|
||||
title: "Upgrade dependencies to latest"
|
||||
body: |
|
||||
Updates all dependencies to latest versions.
|
||||
Please review the changes and merge if everything looks good.
|
||||
51
.github/workflows/upgrade-dependencies.yml
vendored
51
.github/workflows/upgrade-dependencies.yml
vendored
@@ -1,51 +0,0 @@
|
||||
name: Upgrade Dependencies
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
upgrade-deps:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js Version 20 (LTS)
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Setup pnpm@v9
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Install & Upgrade Dependencies
|
||||
run: |
|
||||
pnpm install
|
||||
npm run upgrade
|
||||
pnpm install --lockfile-only
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
delete-branch: false
|
||||
branch: "update-deps"
|
||||
base: "master"
|
||||
labels: |
|
||||
dependencies
|
||||
automated pr
|
||||
reviewers: kamranahmedse
|
||||
commit-message: "chore: update dependencies to latest"
|
||||
title: "Upgrade Dependencies To Latest - Automated"
|
||||
body: |
|
||||
## Updated all Dependencies to Latest Versions.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This PR Upgrades the Dependencies to the Latest Their Versions.
|
||||
>
|
||||
> Commit: ${{ github.sha }}
|
||||
> Workflow Path: ${{ github.workflow_ref }}
|
||||
|
||||
**Please Review the Changes and Merge the PR if everything is fine.**
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contribution
|
||||
|
||||
First of all, thank you for considering to contribute. Please look at the details below:
|
||||
First of all thank you for considering to contribute. Please look at the details below:
|
||||
|
||||
- [New Roadmaps](#new-roadmaps)
|
||||
- [Existing Roadmaps](#existing-roadmaps)
|
||||
@@ -25,22 +25,22 @@ For the existing roadmaps, please follow the details listed for the nature of co
|
||||
|
||||
## Adding Projects
|
||||
|
||||
If you have a project idea that you think we should add to the roadmap, feel free to open an issue with as many details about the project as possible and the roadmap you think it should be added to.
|
||||
If you have a project idea that you think we should add to the roadmap, feel free to open an issue with as much details about the project as possible and the roadmap you think it should be added to.
|
||||
|
||||
The detailed format for the issue should be as follows:
|
||||
The detailed format for issue should be as follows:
|
||||
|
||||
```
|
||||
## What is this project about?
|
||||
|
||||
(Add an introduction to the project.)
|
||||
(Add introduction to the project)
|
||||
|
||||
## Skills this Project Covers
|
||||
|
||||
(Comma separated list of skills, e.g. Programming Knowledge, Database, etc.)
|
||||
(Comma separated list of skills e.g. Programming Knowledge, Database,)
|
||||
|
||||
## Requirements
|
||||
|
||||
( Detailed list of requirements, i.e. input, output, hints to help build this, etc.)
|
||||
( Detailed list of requirements, i.e. input, output, an hints to help build this etc)
|
||||
```
|
||||
|
||||
Have a look at this project to get an idea of [what we are looking for](https://roadmap.sh/projects/github-user-activity).
|
||||
@@ -67,7 +67,7 @@ Visit the following resources to learn more:
|
||||
- [@type@Description of link](Link)
|
||||
```
|
||||
|
||||
`@type@` must be one of the following and describe the type of content you are adding:
|
||||
`@type@` must be one of the following and describes the type of content you are adding:
|
||||
|
||||
- `@official@`
|
||||
- `@opensource@`
|
||||
@@ -82,11 +82,11 @@ It's important to add a valid type, this will help us categorize the content and
|
||||
|
||||
- <p><strong>Please don't use the project for self-promotion!</strong><br />
|
||||
|
||||
We believe this project is a valuable asset to the developer community, and it includes numerous helpful resources. We kindly ask you to avoid submitting pull requests for the sole purpose of self-promotion. We appreciate contributions that genuinely add value, such as guides from maintainers of well-known frameworks, and will consider accepting these even if they're self authored. Thank you for your understanding and cooperation!
|
||||
We believe this project is a valuable asset to the developer community and it includes numerous helpful resources. We kindly ask you to avoid submitting pull requests for the sole purpose of self-promotion. We appreciate contributions that genuinely add value, such as guides from maintainers of well-known frameworks, and will consider accepting these even if they're self authored. Thank you for your understanding and cooperation!
|
||||
|
||||
- <p><strong>Adding everything available out there is not the goal!</strong><br />
|
||||
|
||||
The roadmaps represent the skillset most valuable today, i.e., if you were to enter any of the listed fields today, what would you learn? There might be things that are of-course being used today, but prioritize the things that are most in demand today, e.g., agree that lots of people are using angular.js today, but you wouldn't want to learn that instead of React, Angular, or Vue. Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included.</p>
|
||||
The roadmaps represent the skillset most valuable today, i.e., if you were to enter any of the listed fields today, what would you learn? There might be things that are of-course being used today but prioritize the things that are most in demand today, e.g., agreed that lots of people are using angular.js today but you wouldn't want to learn that instead of React, Angular, or Vue. Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included.</p>
|
||||
|
||||
- <p><strong>Do not add things you have not evaluated personally!</strong><br />
|
||||
|
||||
@@ -98,12 +98,12 @@ It's important to add a valid type, this will help us categorize the content and
|
||||
|
||||
- <p><strong>Write meaningful commit messages</strong><br >
|
||||
|
||||
Meaningful commit messages help speed up the review process as well as help other contributors gain a good overview of the repositories commit history without having to dive into every commit.
|
||||
Meaningful commit messages help speed up the review process as well as help other contributors in gaining a good overview of the repositories commit history without having to dive into every commit.
|
||||
|
||||
</p>
|
||||
- <p><strong>Look at the existing issues/pull requests before opening new ones</strong></p>
|
||||
|
||||
### Good vs. Not So Good Contributions
|
||||
### Good vs Not So Good Contributions
|
||||
|
||||
<strong>Good</strong>
|
||||
|
||||
@@ -117,5 +117,5 @@ It's important to add a valid type, this will help us categorize the content and
|
||||
- Adding whitespace that doesn't add to the readability of the content.
|
||||
- Rewriting content in a way that doesn't add any value.
|
||||
- Non-English content.
|
||||
- PR's that don't follow our style guide, have no description, and a default title.
|
||||
- PR's that don't follow our style guide, have no description and a default title.
|
||||
- Links to your own blog articles.
|
||||
|
||||
377
package-lock.json
generated
377
package-lock.json
generated
@@ -8,8 +8,8 @@
|
||||
"name": "roadmap.sh",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^8.3.3",
|
||||
"@astrojs/react": "^3.6.2",
|
||||
"@astrojs/node": "^8.3.2",
|
||||
"@astrojs/react": "^3.6.1",
|
||||
"@astrojs/sitemap": "^3.1.6",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.14.6",
|
||||
"astro": "^4.13.0",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.12",
|
||||
"dom-to-image": "^2.6.0",
|
||||
@@ -132,9 +132,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/node": {
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-8.3.3.tgz",
|
||||
"integrity": "sha512-idrKhnnPSi0ABV+PCQsRQqVNwpOvVDF/+fkwcIiE8sr9J8EMvW9g/oyAt8T4X2OBJ8FUzYPL8klfCdG7r0eB5g==",
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-8.3.2.tgz",
|
||||
"integrity": "sha512-Upv0D+9b3RXp7XViQTtrijaDqihHWbVHLdJQ2sxtPOEtw2GDrVxuC6LmXIUew5YvJ9Ylmpst6KizVwO8d/K9/Q==",
|
||||
"dependencies": {
|
||||
"send": "^0.18.0",
|
||||
"server-destroy": "^1.0.1"
|
||||
@@ -263,11 +263,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz",
|
||||
"integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz",
|
||||
"integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.4",
|
||||
"@babel/types": "^7.25.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
@@ -402,11 +402,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz",
|
||||
"integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
|
||||
"integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.4"
|
||||
"@babel/types": "^7.25.2"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -489,15 +489,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz",
|
||||
"integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz",
|
||||
"integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.25.4",
|
||||
"@babel/parser": "^7.25.4",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.4",
|
||||
"@babel/types": "^7.25.2",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -506,9 +506,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz",
|
||||
"integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
|
||||
"integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.24.8",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
@@ -2047,36 +2047,10 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
|
||||
"integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils/node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz",
|
||||
"integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz",
|
||||
"integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2086,9 +2060,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz",
|
||||
"integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz",
|
||||
"integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2098,9 +2072,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz",
|
||||
"integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz",
|
||||
"integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2110,9 +2084,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz",
|
||||
"integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz",
|
||||
"integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2122,9 +2096,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz",
|
||||
"integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz",
|
||||
"integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2134,9 +2108,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz",
|
||||
"integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz",
|
||||
"integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2146,9 +2120,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz",
|
||||
"integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz",
|
||||
"integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2158,9 +2132,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz",
|
||||
"integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz",
|
||||
"integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2170,9 +2144,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz",
|
||||
"integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz",
|
||||
"integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -2182,9 +2156,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz",
|
||||
"integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz",
|
||||
"integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -2194,9 +2168,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz",
|
||||
"integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz",
|
||||
"integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -2206,9 +2180,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz",
|
||||
"integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz",
|
||||
"integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2218,9 +2192,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz",
|
||||
"integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz",
|
||||
"integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2230,9 +2204,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz",
|
||||
"integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz",
|
||||
"integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2242,9 +2216,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz",
|
||||
"integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz",
|
||||
"integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2254,9 +2228,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz",
|
||||
"integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz",
|
||||
"integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2266,9 +2240,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@shikijs/core": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz",
|
||||
"integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.13.0.tgz",
|
||||
"integrity": "sha512-Mj5NVfbAXcD1GnwOTSPl8hBn/T8UDpfFQTptp+p41n/CbUcJtOq98WaRD7Lz3hCglYotUTHUWtzu3JhK6XlkAA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.4"
|
||||
}
|
||||
@@ -2900,22 +2874,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/astro": {
|
||||
"version": "4.14.6",
|
||||
"resolved": "https://registry.npmjs.org/astro/-/astro-4.14.6.tgz",
|
||||
"integrity": "sha512-MIDyNhtu3L4uakHvlTprh21eQPehYOtZSuSLtd+r6xZcl3lB+mlBz/hs1W3iHEQAORyJnKArWSY/aVOBKUyflA==",
|
||||
"version": "4.13.4",
|
||||
"resolved": "https://registry.npmjs.org/astro/-/astro-4.13.4.tgz",
|
||||
"integrity": "sha512-uoW961qyU5xxCiUzITVX8wYmdWbSH1zeog9UomoWC5uNpnIbH6WxOPv/qYu2m7W4r2PCxdRqfVXoYjZhFyGfTA==",
|
||||
"dependencies": {
|
||||
"@astrojs/compiler": "^2.10.3",
|
||||
"@astrojs/compiler": "^2.10.2",
|
||||
"@astrojs/internal-helpers": "0.4.1",
|
||||
"@astrojs/markdown-remark": "5.2.0",
|
||||
"@astrojs/telemetry": "3.1.0",
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/generator": "^7.25.5",
|
||||
"@babel/parser": "^7.25.4",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@babel/plugin-transform-react-jsx": "^7.25.2",
|
||||
"@babel/traverse": "^7.25.4",
|
||||
"@babel/types": "^7.25.4",
|
||||
"@babel/traverse": "^7.25.3",
|
||||
"@babel/types": "^7.25.2",
|
||||
"@oslojs/encoding": "^0.4.1",
|
||||
"@rollup/pluginutils": "^5.1.0",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"acorn": "^8.12.1",
|
||||
@@ -2946,10 +2919,8 @@
|
||||
"js-yaml": "^4.1.0",
|
||||
"kleur": "^4.1.5",
|
||||
"magic-string": "^0.30.11",
|
||||
"micromatch": "^4.0.8",
|
||||
"mrmime": "^2.0.0",
|
||||
"neotraverse": "^0.6.18",
|
||||
"ora": "^8.1.0",
|
||||
"ora": "^8.0.1",
|
||||
"p-limit": "^6.1.0",
|
||||
"p-queue": "^8.0.1",
|
||||
"path-to-regexp": "^6.2.2",
|
||||
@@ -2957,20 +2928,18 @@
|
||||
"prompts": "^2.4.2",
|
||||
"rehype": "^13.0.1",
|
||||
"semver": "^7.6.3",
|
||||
"shiki": "^1.14.1",
|
||||
"shiki": "^1.12.1",
|
||||
"string-width": "^7.2.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tsconfck": "^3.1.1",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vfile": "^6.0.3",
|
||||
"vite": "^5.4.2",
|
||||
"vfile": "^6.0.2",
|
||||
"vite": "^5.4.0",
|
||||
"vitefu": "^0.2.5",
|
||||
"which-pm": "^3.0.0",
|
||||
"xxhash-wasm": "^1.0.2",
|
||||
"yargs-parser": "^21.1.1",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.23.2",
|
||||
"zod-to-ts": "^1.2.0"
|
||||
"zod-to-json-schema": "^3.23.2"
|
||||
},
|
||||
"bin": {
|
||||
"astro": "astro.js"
|
||||
@@ -3353,14 +3322,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cli-cursor": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
|
||||
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
|
||||
"integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
|
||||
"dependencies": {
|
||||
"restore-cursor": "^5.0.0"
|
||||
"restore-cursor": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
@@ -6075,9 +6044,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
@@ -6129,17 +6098,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
||||
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -6223,14 +6181,6 @@
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/neotraverse": {
|
||||
"version": "0.6.18",
|
||||
"resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz",
|
||||
"integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/nlcst-to-string": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz",
|
||||
@@ -6438,18 +6388,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ora": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-8.1.0.tgz",
|
||||
"integrity": "sha512-GQEkNkH/GHOhPFXcqZs3IDahXEQcQxsSjEkK4KvEEST4t7eNzoMjxTzef+EZ+JluDEV+Raoi3WQ2CflnRdSVnQ==",
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz",
|
||||
"integrity": "sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==",
|
||||
"dependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"cli-cursor": "^5.0.0",
|
||||
"cli-cursor": "^4.0.0",
|
||||
"cli-spinners": "^2.9.2",
|
||||
"is-interactive": "^2.0.0",
|
||||
"is-unicode-supported": "^2.0.0",
|
||||
"log-symbols": "^6.0.0",
|
||||
"stdin-discarder": "^0.2.2",
|
||||
"string-width": "^7.2.0",
|
||||
"stdin-discarder": "^0.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -7432,34 +7382,47 @@
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
||||
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
|
||||
"integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
|
||||
"dependencies": {
|
||||
"onetime": "^7.0.0",
|
||||
"signal-exit": "^4.1.0"
|
||||
"onetime": "^5.1.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor/node_modules/mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor/node_modules/onetime": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
|
||||
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||
"dependencies": {
|
||||
"mimic-function": "^5.0.0"
|
||||
"mimic-fn": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor/node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||
},
|
||||
"node_modules/retext": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz",
|
||||
@@ -7532,9 +7495,9 @@
|
||||
"integrity": "sha512-IQejjIfr9RIvesNwp3SyhEq1DMQ2RdJfJhgsb1AyPuKXsfJgOG8F++Cz1p3SIcY0bnB57Q16Ke2VJLjiUVwI3Q=="
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz",
|
||||
"integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==",
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz",
|
||||
"integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.5"
|
||||
},
|
||||
@@ -7546,22 +7509,22 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.21.1",
|
||||
"@rollup/rollup-android-arm64": "4.21.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.21.1",
|
||||
"@rollup/rollup-darwin-x64": "4.21.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.21.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.21.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.21.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.21.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.21.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.21.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.21.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.21.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.21.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.21.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.21.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.21.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.18.1",
|
||||
"@rollup/rollup-android-arm64": "4.18.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.18.1",
|
||||
"@rollup/rollup-darwin-x64": "4.18.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.18.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.18.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.18.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.18.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.18.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.18.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.18.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.18.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.18.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.18.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.18.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.18.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -7792,11 +7755,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz",
|
||||
"integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.13.0.tgz",
|
||||
"integrity": "sha512-e0dWfnONbEv6xl7FJy3XIhsVHQ/65XHDZl92+6H9+4xWjfdo7pmkqG7Kg47KWtDiEtzM5Z+oEfb4vtRvoZ/X9w==",
|
||||
"dependencies": {
|
||||
"@shikijs/core": "1.14.1",
|
||||
"@shikijs/core": "1.13.0",
|
||||
"@types/hast": "^3.0.4"
|
||||
}
|
||||
},
|
||||
@@ -8792,19 +8755,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.5.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
@@ -9014,11 +8964,12 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/vfile": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
|
||||
"integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz",
|
||||
"integrity": "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-stringify-position": "^4.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
@@ -9053,13 +9004,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz",
|
||||
"integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==",
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz",
|
||||
"integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.41",
|
||||
"rollup": "^4.20.0"
|
||||
"postcss": "^8.4.40",
|
||||
"rollup": "^4.13.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -9354,11 +9305,6 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/xxhash-wasm": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz",
|
||||
"integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A=="
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
@@ -9415,15 +9361,6 @@
|
||||
"zod": "^3.23.3"
|
||||
}
|
||||
},
|
||||
"node_modules/zod-to-ts": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz",
|
||||
"integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==",
|
||||
"peerDependencies": {
|
||||
"typescript": "^4.9.4 || ^5.0.2",
|
||||
"zod": "^3"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.4.tgz",
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^8.3.3",
|
||||
"@astrojs/react": "^3.6.2",
|
||||
"@astrojs/node": "^8.3.2",
|
||||
"@astrojs/react": "^3.6.1",
|
||||
"@astrojs/sitemap": "^3.1.6",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
||||
@@ -39,7 +39,7 @@
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.14.6",
|
||||
"astro": "^4.13.0",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.12",
|
||||
"dom-to-image": "^2.6.0",
|
||||
|
||||
666
pnpm-lock.yaml
generated
666
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -199,19 +199,8 @@
|
||||
},
|
||||
"3fFNMhQIuuh-NRzSXYpXO": {
|
||||
"title": "Constraint",
|
||||
"description": "Lets you create large, complex layouts with a flat view hierarchy—no nested view groups. It's similar to `RelativeLayout` in that all views are laid out according to relationships between sibling views and the parent layout, but it's more flexible than RelativeLayout and easier to use. Its available on xml and jetpack compose.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: ConstraintLayout in xml",
|
||||
"url": "https://developer.android.com/develop/ui/views/layout/constraint-layout",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Android developers: ContraintLayout in compose",
|
||||
"url": "https://developer.android.com/develop/ui/compose/layouts/constraintlayout",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"xIvplWfe-uDr9iHjPT1Mx": {
|
||||
"title": "RecycleView",
|
||||
@@ -248,14 +237,8 @@
|
||||
},
|
||||
"boMz0HZlMAsLdCZlpUo-H": {
|
||||
"title": "EditText",
|
||||
"description": "`EditText` is a fundamental UI element in Android Studio, used for allowing users to input and edit text within an application. It is a subclass of `TextView` that provides additional features to handle user input.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: EditText",
|
||||
"url": "https://developer.android.com/reference/android/widget/EditText",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"Mtx0bY0drmaTw8sCM5YTl": {
|
||||
"title": "Dialogs",
|
||||
@@ -292,79 +275,33 @@
|
||||
},
|
||||
"A4rtNULX_MoV93IH1Lgqw": {
|
||||
"title": "ImageView",
|
||||
"description": "Displays image resources, for example Bitmap or Drawable resources. ImageView is also commonly used to apply tints to an image and handle image scaling.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: ImageView",
|
||||
"url": "https://developer.android.com/reference/android/widget/ImageView",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"Z4Tbd5ClnqCXGPGG09F-G": {
|
||||
"title": "Bottom Sheet",
|
||||
"description": "`Bottom sheets` are surfaces containing supplementary content that are anchored to the bottom of the screen.\n\nThere are several attributes that can be used to adjust the behavior of both standard and modal bottom sheets. Behavior attributes can be applied to standard bottom sheets in xml by setting them on a child View set to `app:layout_behavior` or programmatically.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: Bottom sheets",
|
||||
"url": "https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetDialog",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"EzLjX4iRT7AxkAOsJYnSU": {
|
||||
"title": "ListView",
|
||||
"description": "Displays a vertically-scrollable collection of views, where each view is positioned immediatelybelow the previous view in the list.\n\nFor a more modern, flexible, and performant approach to displaying lists, use `RecyclerView`.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: ListView",
|
||||
"url": "https://developer.android.com/reference/android/widget/ListView",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"amTxz7mS98lkhOrNMJXG_": {
|
||||
"title": "Drawer",
|
||||
"description": "The **Navigation Drawer** in Android is a sliding menu from the left that simplifies navigation between important app links. It opens by sliding or via an icon in the `ActionBar`. It’s an overlay panel that replaces a screen dedicated to displaying options.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: DrawerLayout",
|
||||
"url": "https://developer.android.com/reference/androidx/drawerlayout/widget/DrawerLayout",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Navigate Drawer Tutorial",
|
||||
"url": "https://www.digitalocean.com/community/tutorials/android-navigation-drawer-example-tutorial",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"pEBpXv3Jf1AzBNHlvVrG8": {
|
||||
"title": "Tabs",
|
||||
"description": "Tabs in Android Studio are a UI component used to organize content into multiple sections, allowing users to navigate between them by selecting the corresponding tab. This component is commonly used when there is a need to present different types of content in a single screen, like different categories, settings, or pages within an app.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Android developers: Material Tabs",
|
||||
"url": "https://developer.android.com/reference/com/google/android/material/tabs/package-summary",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"Xn1VQ-xOT67ZfJJTM4r1p": {
|
||||
"title": "Animations",
|
||||
"description": "`Animations` can add visual cues that notify users about what's going on in your app. They are especially useful when the UI changes state, such as when new content loads or new actions become available. Animations also add a polished look to your app, which gives it a higher quality look and feel.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Google developers: Animations",
|
||||
"url": "https://developer.android.com/develop/ui/views/animations/overview",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Google developers: Animations",
|
||||
"url": "https://www.youtube.com/watch?v=N_x7SV3I3P0",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"60Vm-77rseUqpMiFvp-dA": {
|
||||
"title": "Jetpack Compose",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -798,7 +798,7 @@
|
||||
"description": "Stoplight is an advanced tool that offers a comprehensive platform for technical teams to handle all aspects of API design. Leveraging Stoplight, teams can design, document and develop APIs in a more collaborative and streamlined manner. It uses an OpenAPI specification and allows users to design APIs visually, making API development easier. With its ability to auto-generate API documentation, performing API mock testing, and providing API management features, Stoplight plays a crucial role in adopting a design-first approach in API development. By using Stoplight, APIs can be designed to be easy-to-use, scalable, and robust from the outset, which ultimately improves the overall development process and quality of the APIs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "stoplightio",
|
||||
"title": "/stoplightio",
|
||||
"url": "https://github.com/stoplightio",
|
||||
"type": "opensource"
|
||||
},
|
||||
@@ -1259,7 +1259,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is API mocking (What is API Mocking? Definition, Guide, and Best Practices)",
|
||||
"title": "@articleWhat is API mocking (What is API Mocking? Definition, Guide, and Best Practices)",
|
||||
"url": "https://blog.postman.com/what-is-api-mocking/",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -191,21 +191,41 @@
|
||||
},
|
||||
"8-lO-v6jCYYoklEJXULxN": {
|
||||
"title": "JavaScript",
|
||||
"description": "JavaScript allows you to add interactivity to your pages. Common examples that you may have seen on the websites are sliders, click interactions, popups and so on.\n\nVisit the following resources to learn more:",
|
||||
"description": "Apart from being used in the browser, JavaScript is also used in backend e.g. using [Node.js](https://nodejs.org/) or [Deno](https://deno.land/) for writing server-side code in JavaScript.\n\nIf you pick up JavaScript for the Backend, my personal recommendation would be to learn [JavaScript](/javascript) and then go with [Node.js](/nodejs) as it is the most popular and widely used option. Also, I would recommend learning TypeScript later on as you continue with your backend development Journey; it's a superset of JavaScript and is used in many projects.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "You Dont Know JS Yet (book series) ",
|
||||
"url": "https://github.com/getify/You-Dont-Know-JS",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated JavaScript Roadmap",
|
||||
"url": "/javascript",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools – JavaScript Tutorial",
|
||||
"url": "https://www.w3schools.com/js/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Modern JavaScript Tutorial",
|
||||
"url": "https://javascript.info/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Build 30 Javascript projects in 30 days",
|
||||
"url": "https://javascript30.com/",
|
||||
"title": "Eloquent Javascript - Book",
|
||||
"url": "https://eloquentjavascript.net/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated Node.js Roadmap",
|
||||
"url": "/nodejs",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official JavaScript Documentation",
|
||||
"url": "https://www.javascript.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -215,7 +235,17 @@
|
||||
},
|
||||
{
|
||||
"title": "JavaScript Crash Course for Beginners",
|
||||
"url": "https://youtu.be/hdI2bqOjy3c?t=2",
|
||||
"url": "https://youtu.be/hdI2bqOjy3c",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Node.js Crash Course",
|
||||
"url": "https://www.youtube.com/watch?v=fBNz5xF-Kx4",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Node.js Tutorial for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=TlB_eWDSMt4",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3954,7 +3954,7 @@
|
||||
]
|
||||
},
|
||||
"ETEUA7jaEGyOEX8tAVNWs": {
|
||||
"title": "Processes and Threads",
|
||||
"title": "Porcesses and Threads",
|
||||
"description": "Processes and threads are the basic building blocks of a computer program. They are the smallest units of execution in a program. A process is an instance of a program that is being executed. A thread is a sequence of instructions within a process that can be executed independently of other code.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
},
|
||||
"fUBNKHNPXbemRYrnzH3VT": {
|
||||
"title": "WiFi",
|
||||
"description": "**WiFi** stands for \"wireless fidelity\" and is a popular way to connect to the internet without the need for physical cables. It uses radio frequency (RF) technology to communicate between devices, such as routers, computers, tablets, smartphones, and other hardware.\n\nAdvantages of WiFi\n------------------\n\nWiFi has several advantages over wired connections, including:\n\n* **Convenience**: Users can access the internet from anywhere within the WiFi signal's range, providing flexibility and mobility.\n \n* **Easy Setup**: WiFi devices connect to the internet simply by entering a password once, without the need for any additional cables or adapters.\n \n* **Scalability**: WiFi networks can easily expand to accommodate additional devices without the need for significant infrastructure changes.\n \n\nSecurity Risks and WiFi Threats\n-------------------------------\n\nDespite its numerous benefits, WiFi also brings potential security risks. Some common threats include:\n\n* **Eavesdropping**: Hackers can intercept data transmitted over a WiFi connection, potentially accessing sensitive information such as personal or financial details.\n \n* **Rogue access points**: An unauthorized user could set up a fake WiFi network that appears legitimate, tricking users into connecting and providing access to their devices.\n \n* **Man-in-the-middle attacks**: An attacker intercepts data transmission between your device and the WiFi network, potentially altering data or injecting malware.\n \n\nBest Practices for Secure WiFi Connections\n------------------------------------------\n\nTo protect yourself and your devices, follow these best practices:\n\n* **Use strong encryption**: Ensure your WiFi network uses the latest available encryption standards, such as WPA3 or, at minimum, WPA2.\n \n* **Change default credentials**: Change the default username and password for your WiFi router to prevent unauthorized access and configuration.\n \n* **Keep your router firmware up to date**: Regularly check for and install any available firmware updates to prevent potential security vulnerabilities.\n \n* **Create a guest network**: If you have visitors or clients, set up a separate guest network for them to use. This ensures your primary network remains secure.\n \n* **Disable WiFi Protected Setup (WPS)**: Although WPS can simplify the connection process, it may also create security vulnerabilities. Disabling it forces users to connect via the more secure password method.\n \n* **Use a Virtual Private Network (VPN)**: Connect to the internet using a VPN, which provides a secure, encrypted tunnel for data transmission.\n \n\nBy understanding the potential security risks associated with WiFi connections and following these best practices, you can enjoy the convenience, flexibility, and mobility of WiFi while ensuring a secure browsing experience.\n\nVisit the following resources to learn more:",
|
||||
"description": "**WiFi** stands for \"wireless fidelity\" and is a popular way to connect to the internet without the need for physical cables. It uses radio frequency (RF) technology to communicate between devices, such as routers, computers, tablets, smartphones, and other hardware.\n\nAdvantages of WiFi\n------------------\n\nWiFi has several advantages over wired connections, including:\n\n* **Convenience**: Users can access the internet from anywhere within the WiFi signal's range, providing flexibility and mobility.\n \n* **Easy Setup**: WiFi devices connect to the internet simply by entering a password once, without the need for any additional cables or adapters.\n \n* **Scalability**: WiFi networks can easily expand to accommodate additional devices without the need for significant infrastructure changes.\n \n\nSecurity Risks and WiFi Threats\n-------------------------------\n\nDespite its numerous benefits, WiFi also brings potential security risks. Some common threats include:\n\n* **Eavesdropping**: Hackers can intercept data transmitted over a WiFi connection, potentially accessing sensitive information such as personal or financial details.\n \n* **Rogue access points**: An unauthorized user could set up a fake WiFi network that appears legitimate, tricking users into connecting and providing access to their devices.\n \n* **Man-in-the-middle attacks**: An attacker intercepts data transmission between your device and the WiFi network, potentially altering data or injecting malware.\n \n\nBest Practices for Secure WiFi Connections\n------------------------------------------\n\nTo protect yourself and your devices, follow these best practices:\n\n* **Use strong encryption**: Ensure your WiFi network uses the latest available encryption standards, such as WPA3 or, at minimum, WPA2.\n \n* **Change default credentials**: Change the default username and password for your WiFi router to prevent unauthorized access and configuration.\n \n* **Keep your router firmware up to date**: Regularly check for and install any available firmware updates to prevent potential security vulnerabilities.\n \n* **Create a guest network**: If you have visitors or clients, set up a separate guest network for them to use. This ensures your primary network remains secure.\n \n* **Disable WiFi Protected Setup (WPS)**: Although WPS can simplify the connection process, it may also create security vulnerabilities. Disabling it forces users to connect via the more secure password method.\n \n* **Use a Virtual Private Network (VPN)**: Connect to the internet using a VPN, which provides a secure, encrypted tunnel for data transmission.\n \n\nBy understanding the potential security risks associated with WiFi connections and following these best practices, you can enjoy the convenience, flexibility, and mobility of WiFi while ensuring a secure browsing experience.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Wireless Networks - Howstuffworks",
|
||||
@@ -123,11 +123,6 @@
|
||||
"title": "That's How Wi-Fi Works",
|
||||
"url": "https://youtu.be/hePLDVbULZc",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Wireless Networking Explained",
|
||||
"url": "https://www.youtube.com/watch?v=Uz-RTurph3c",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -750,19 +745,8 @@
|
||||
},
|
||||
"gTozEpxJeG1NTkVBHH-05": {
|
||||
"title": "VPN",
|
||||
"description": "A **Virtual Private Network** (VPN) is a technology that provides secure and encrypted connections between devices over a public network, such as the internet. VPNs are primarily used to protect your internet activity and privacy from being accessed or monitored by external parties, such as hackers or government agencies.\n\nThe main components of a VPN are:\n\n* **VPN client**: The software installed on your device that connects to the VPN server.\n* **VPN server**: A remote server that handles and encrypts your internet traffic before sending it to its intended destination.\n* **Encryption**: The process of converting your data into unreadable code to protect it from unauthorized access.\n\nWhen you connect to a VPN, your device's IP address is replaced with the VPN server's IP address, making it seem as if your internet activity is coming from the server's location. This allows you to access content and websites that may be blocked or restricted in your region, and also helps to protect your identity and location online.\n\nUsing a reliable VPN service is an essential part of maintaining good cyber security, especially when using public Wi-Fi networks or accessing sensitive information online.\n\nKeep in mind, however, that not all VPNs are created equal. Make sure to do your research and choose a reputable VPN provider with a strong focus on privacy and security. Some popular and trusted VPN services include ExpressVPN, NordVPN, and CyberGhost.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "VPN (Virtual Private Network) Explained",
|
||||
"url": "https://www.youtube.com/watch?v=R-JUOpCgTZc",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Virtual Private Networks - Professor Messer",
|
||||
"url": "https://www.youtube.com/watch?v=YFyt8aY8PfI",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "A **Virtual Private Network** (VPN) is a technology that provides secure and encrypted connections between devices over a public network, such as the internet. VPNs are primarily used to protect your internet activity and privacy from being accessed or monitored by external parties, such as hackers or government agencies.\n\nThe main components of a VPN are:\n\n* **VPN client**: The software installed on your device that connects to the VPN server.\n* **VPN server**: A remote server that handles and encrypts your internet traffic before sending it to its intended destination.\n* **Encryption**: The process of converting your data into unreadable code to protect it from unauthorized access.\n\nWhen you connect to a VPN, your device's IP address is replaced with the VPN server's IP address, making it seem as if your internet activity is coming from the server's location. This allows you to access content and websites that may be blocked or restricted in your region, and also helps to protect your identity and location online.\n\nUsing a reliable VPN service is an essential part of maintaining good cyber security, especially when using public Wi-Fi networks or accessing sensitive information online.\n\nKeep in mind, however, that not all VPNs are created equal. Make sure to do your research and choose a reputable VPN provider with a strong focus on privacy and security. Some popular and trusted VPN services include ExpressVPN, NordVPN, and CyberGhost.",
|
||||
"links": []
|
||||
},
|
||||
"LrwTMH_1fTd8iB9wJg-0t": {
|
||||
"title": "MAN",
|
||||
@@ -781,29 +765,8 @@
|
||||
},
|
||||
"QCVYF1rmPsMVtklBNDNaB": {
|
||||
"title": "WLAN",
|
||||
"description": "A **Wireless Local Area Network (WLAN)** is a type of local area network that uses wireless communication to connect devices, such as computers and smartphones, within a specific area. Unlike a wired network, which requires physical cables to establish connections, WLANs facilitate connections through radio frequency (RF) signals, providing a more flexible networking option.\n\nKey Components of WLAN\n----------------------\n\nThere are two main components in a WLAN:\n\n* **Wireless Access Point (WAP)**: A WAP is a networking device that enables wireless devices to connect to the network. It acts as a bridge between the devices and the wired network, converting RF signals into data that can travel through a wired connection.\n* **Wireless Client**: Wireless clients are devices like laptops, smartphones, and tablets that are fitted with WLAN adapters. These adapters enable devices to send and receive wireless signals to connect with the WAP.\n\nKey WLAN Standards\n------------------\n\nThere are several WLAN standards, defined by the Institute of Electrical and Electronics Engineers (IEEE) 802.11 series. Some of the most common standards include:\n\n* **802.11a**: Supports throughput up to 54 Mbps in the 5 GHz frequency band.\n* **802.11b**: Supports throughput up to 11 Mbps in the 2.4 GHz frequency band.\n* **802.11g**: Supports throughput up to 54 Mbps in the 2.4 GHz frequency band and is backward compatible with 802.11b.\n* **802.11n**: Supports throughput up to 600 Mbps and operates in both 2.4 GHz and 5 GHz frequency bands.\n* **802.11ac**: Supports throughput up to several Gigabits per second and operates in the 5 GHz frequency band. This is currently the most widely adopted standard.\n\nWLAN Security\n-------------\n\nAs WLANs use wireless signals to transmit data, they can be susceptible to various security threats. Some essential security measures include:\n\n* **Wired Equivalent Privacy (WEP)**: An early security protocol that uses encryption to protect wireless communications. Due to several security flaws, it has been replaced by more secure protocols.\n \n* **Wi-Fi Protected Access (WPA)**: WPA is an enhanced security protocol that addressed the vulnerabilities of WEP. It uses Temporal Key Integrity Protocol (TKIP) for encryption and provides better authentication and encryption methods.\n \n* **Wi-Fi Protected Access II (WPA2)**: WPA2 is an advanced security protocol that uses Advanced Encryption Standard (AES) encryption and replaces TKIP from WPA. This protocol provides a high level of security and is currently the recommended standard for securing WLANs.\n \n* **Wi-Fi Protected Access 3 (WPA3)**: WPA3 is the latest security standard with enhanced encryption and authentication features. It addresses the vulnerabilities in WPA2 and provides even stronger security for WLANs.\n \n\nTo maintain a secure WLAN, it's essential to use the appropriate security standard, change default settings, and regularly update firmware to address any security vulnerabilities.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Wireless Technologies",
|
||||
"url": "https://www.youtube.com/watch?v=_VwpcLiBkAQ",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Wireless Networking",
|
||||
"url": "https://www.youtube.com/watch?v=NeTwL-040ds",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Wireless Encryption",
|
||||
"url": "https://www.youtube.com/watch?v=YNcobcHXnnY&",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Wireless Attacks",
|
||||
"url": "https://www.youtube.com/watch?v=tSLqrKhUvts",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "A **Wireless Local Area Network (WLAN)** is a type of local area network that uses wireless communication to connect devices, such as computers and smartphones, within a specific area. Unlike a wired network, which requires physical cables to establish connections, WLANs facilitate connections through radio frequency (RF) signals, providing a more flexible networking option.\n\nKey Components of WLAN\n----------------------\n\nThere are two main components in a WLAN:\n\n* **Wireless Access Point (WAP)**: A WAP is a networking device that enables wireless devices to connect to the network. It acts as a bridge between the devices and the wired network, converting RF signals into data that can travel through a wired connection.\n* **Wireless Client**: Wireless clients are devices like laptops, smartphones, and tablets that are fitted with WLAN adapters. These adapters enable devices to send and receive wireless signals to connect with the WAP.\n\nKey WLAN Standards\n------------------\n\nThere are several WLAN standards, defined by the Institute of Electrical and Electronics Engineers (IEEE) 802.11 series. Some of the most common standards include:\n\n* **802.11a**: Supports throughput up to 54 Mbps in the 5 GHz frequency band.\n* **802.11b**: Supports throughput up to 11 Mbps in the 2.4 GHz frequency band.\n* **802.11g**: Supports throughput up to 54 Mbps in the 2.4 GHz frequency band and is backward compatible with 802.11b.\n* **802.11n**: Supports throughput up to 600 Mbps and operates in both 2.4 GHz and 5 GHz frequency bands.\n* **802.11ac**: Supports throughput up to several Gigabits per second and operates in the 5 GHz frequency band. This is currently the most widely adopted standard.\n\nWLAN Security\n-------------\n\nAs WLANs use wireless signals to transmit data, they can be susceptible to various security threats. Some essential security measures include:\n\n* **Wired Equivalent Privacy (WEP)**: An early security protocol that uses encryption to protect wireless communications. Due to several security flaws, it has been replaced by more secure protocols.\n \n* **Wi-Fi Protected Access (WPA)**: WPA is an enhanced security protocol that addressed the vulnerabilities of WEP. It uses Temporal Key Integrity Protocol (TKIP) for encryption and provides better authentication and encryption methods.\n \n* **Wi-Fi Protected Access II (WPA2)**: WPA2 is an advanced security protocol that uses Advanced Encryption Standard (AES) encryption and replaces TKIP from WPA. This protocol provides a high level of security and is currently the recommended standard for securing WLANs.\n \n* **Wi-Fi Protected Access 3 (WPA3)**: WPA3 is the latest security standard with enhanced encryption and authentication features. It addresses the vulnerabilities in WPA2 and provides even stronger security for WLANs.\n \n\nTo maintain a secure WLAN, it's essential to use the appropriate security standard, change default settings, and regularly update firmware to address any security vulnerabilities.",
|
||||
"links": []
|
||||
},
|
||||
"R5HEeh6jwpQDo27rz1KSH": {
|
||||
"title": "DHCP",
|
||||
@@ -1139,14 +1102,8 @@
|
||||
},
|
||||
"HavEL0u65ZxHt92TfbLzk": {
|
||||
"title": "Core Concepts of Zero Trust",
|
||||
"description": "_Zero Trust_ is a modern security framework that addresses the ever-evolving threat landscape in the digital world. It emphasizes the idea of \"never trust, always verify\". This approach requires organizations to abandon the traditional perimeter-based security models and adopt a more comprehensive, holistic approach to protecting their data and assets.\n\nCore Principles\n---------------\n\n* **Deny trust by default**: Assume all network traffic, both inside and outside the organization, is potentially malicious. Do not trust any user, device, or application just because they are within the network perimeter.\n \n* **Verify every request**: Authenticate and authorize all requests (even for those from within the network) before granting access to any resource. Ensure that each user, device, or application is properly identified, and their access to resources is appropriate based on their role, rights, and privileges.\n \n* **Apply least privilege**: Limit users, applications, and devices to the minimum level of access required to perform their functions. This minimizes the risk of unauthorized access, and reduces the potential attack surface.\n \n* **Segment networks**: Isolate and segregate different parts of the network to limit the potential impact of a breach. If an attacker gains access to one segment, they should not be able to move laterally across the network and access other sensitive data.\n \n* **Inspect and log all traffic**: Actively monitor, analyze, and log network traffic to identify potential security incidents and perform forensic investigations. This provides valuable insights for security teams to continuously improve their security posture and detect early signs of malicious activities.\n \n\nBenefits\n--------\n\n* **Reduced attack surface**: Limiting access to sensitive resources and segmenting the network makes it more challenging for attackers to compromise systems and access valuable data.\n \n* **Enhanced visibility and monitoring**: By continuously inspecting and logging all traffic, security teams can gain unprecedented levels of visibility, helping them identify potential threats and attacks more effectively.\n \n* **Improved compliance and governance**: Implementing a Zero Trust model reinforces an organization's compliance and governance posture, ensuring access to sensitive data is only granted to authorized users.\n \n* **Adaptability**: A Zero Trust approach can be applied to a wide range of environments and can be tailored to meet the specific security needs and objectives of an organization.\n \n\nBy implementing a Zero Trust framework, an organization can strengthen its security posture, safeguard against internal and external threats, and maintain control over their critical assets in an increasingly interconnected world.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Zero Trust - Professor Messer",
|
||||
"url": "https://www.youtube.com/watch?v=zC_Pndpg8-c",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "_Zero Trust_ is a modern security framework that addresses the ever-evolving threat landscape in the digital world. It emphasizes the idea of \"never trust, always verify\". This approach requires organizations to abandon the traditional perimeter-based security models and adopt a more comprehensive, holistic approach to protecting their data and assets.\n\nCore Principles\n---------------\n\n* **Deny trust by default**: Assume all network traffic, both inside and outside the organization, is potentially malicious. Do not trust any user, device, or application just because they are within the network perimeter.\n \n* **Verify every request**: Authenticate and authorize all requests (even for those from within the network) before granting access to any resource. Ensure that each user, device, or application is properly identified, and their access to resources is appropriate based on their role, rights, and privileges.\n \n* **Apply least privilege**: Limit users, applications, and devices to the minimum level of access required to perform their functions. This minimizes the risk of unauthorized access, and reduces the potential attack surface.\n \n* **Segment networks**: Isolate and segregate different parts of the network to limit the potential impact of a breach. If an attacker gains access to one segment, they should not be able to move laterally across the network and access other sensitive data.\n \n* **Inspect and log all traffic**: Actively monitor, analyze, and log network traffic to identify potential security incidents and perform forensic investigations. This provides valuable insights for security teams to continuously improve their security posture and detect early signs of malicious activities.\n \n\nBenefits\n--------\n\n* **Reduced attack surface**: Limiting access to sensitive resources and segmenting the network makes it more challenging for attackers to compromise systems and access valuable data.\n \n* **Enhanced visibility and monitoring**: By continuously inspecting and logging all traffic, security teams can gain unprecedented levels of visibility, helping them identify potential threats and attacks more effectively.\n \n* **Improved compliance and governance**: Implementing a Zero Trust model reinforces an organization's compliance and governance posture, ensuring access to sensitive data is only granted to authorized users.\n \n* **Adaptability**: A Zero Trust approach can be applied to a wide range of environments and can be tailored to meet the specific security needs and objectives of an organization.\n \n\nBy implementing a Zero Trust framework, an organization can strengthen its security posture, safeguard against internal and external threats, and maintain control over their critical assets in an increasingly interconnected world.",
|
||||
"links": []
|
||||
},
|
||||
"kqT0FRLt9Ak9P8PhHldO-": {
|
||||
"title": "Roles of Compliance and Auditors",
|
||||
@@ -1284,30 +1241,13 @@
|
||||
},
|
||||
"cvI8-sxY5i8lpelW9iY_5": {
|
||||
"title": "Privilege Escalation",
|
||||
"description": "Privilege escalation attacks occur when an attacker gains unauthorized access to a system and then elevates their privileges to perform actions that they should not have been able to do. There are two main types of privilege escalation:\n\n* **Horizontal Privilege Escalation**: In this type of attack, an attacker gains unauthorized access to a user account with the same privilege level as their own, but is able to perform actions or access data that belongs to another user.\n \n* **Vertical Privilege Escalation**: Also known as \"Privilege Elevation,\" this type of attack involves an attacker gaining unauthorized access to a system and then elevating their privilege level from a regular user to an administrator, system owner, or root user. This provides the attacker with greater control over the system and its resources.\n \n\nTo protect your systems and data from privilege escalation attacks, consider implementing the following best practices:\n\n* **Principle of Least Privilege**: Assign the minimum necessary access and privileges to each user account, and regularly review and update access permissions as required.\n \n* **Regularly Update and Patch Software**: Keep your software and systems up-to-date with the latest security patches to address known vulnerabilities that could be exploited in privilege escalation attacks.\n \n* **Implement Strong Authentication and Authorization**: Use strong authentication methods (e.g., multi-factor authentication) and ensure proper access controls are in place to prevent unauthorized access to sensitive data or system resources.\n \n* **Conduct Security Audits**: Regularly check for any misconfigurations, vulnerabilities or outdated software that could be exploited in privilege escalation attacks.\n \n* **Monitor and Log System Activities**: Implement logging and monitoring systems to detect suspicious account activities or changes in user privileges that may indicate a privilege escalation attack.\n \n\nBy understanding the types of privilege escalation attacks and following these best practices, you can create a more secure environment for your data and systems, and reduce the risk of unauthorized users gaining unrestricted access.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Privilege Escalation",
|
||||
"url": "https://www.youtube.com/watch?v=ksjU3Iu195Q",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "Privilege escalation attacks occur when an attacker gains unauthorized access to a system and then elevates their privileges to perform actions that they should not have been able to do. There are two main types of privilege escalation:\n\n* **Horizontal Privilege Escalation**: In this type of attack, an attacker gains unauthorized access to a user account with the same privilege level as their own, but is able to perform actions or access data that belongs to another user.\n \n* **Vertical Privilege Escalation**: Also known as \"Privilege Elevation,\" this type of attack involves an attacker gaining unauthorized access to a system and then elevating their privilege level from a regular user to an administrator, system owner, or root user. This provides the attacker with greater control over the system and its resources.\n \n\nTo protect your systems and data from privilege escalation attacks, consider implementing the following best practices:\n\n* **Principle of Least Privilege**: Assign the minimum necessary access and privileges to each user account, and regularly review and update access permissions as required.\n \n* **Regularly Update and Patch Software**: Keep your software and systems up-to-date with the latest security patches to address known vulnerabilities that could be exploited in privilege escalation attacks.\n \n* **Implement Strong Authentication and Authorization**: Use strong authentication methods (e.g., multi-factor authentication) and ensure proper access controls are in place to prevent unauthorized access to sensitive data or system resources.\n \n* **Conduct Security Audits**: Regularly check for any misconfigurations, vulnerabilities or outdated software that could be exploited in privilege escalation attacks.\n \n* **Monitor and Log System Activities**: Implement logging and monitoring systems to detect suspicious account activities or changes in user privileges that may indicate a privilege escalation attack.\n \n\nBy understanding the types of privilege escalation attacks and following these best practices, you can create a more secure environment for your data and systems, and reduce the risk of unauthorized users gaining unrestricted access.",
|
||||
"links": []
|
||||
},
|
||||
"fyOYVqiBqyKC4aqc6-y0q": {
|
||||
"title": "Web Based Attacks and OWASP10",
|
||||
"description": "The Open Web Application Security Project (OWASP) is a non-profit organization focused on improving the security of software. One of their most well-known projects is the **OWASP Top 10**, which is a list of the most critical web application security risks. The Top 10 project aims to raise awareness and provide businesses, developers, and security teams with guidance on how to address these risks effectively.\n\nThe OWASP Top 10 is updated periodically, with the most recent version released in 2021. Here is a brief summary of the current top 10 security risks:\n\n* **Injection**: Injection flaws, such as SQL, NoSQL, or OS command injection, occur when untrusted data is sent to an interpreter as part of a command or query, allowing an attacker to execute malicious commands or access unauthorized data.\n \n* **Broken Authentication**: Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or exploit other implementation flaws to assume users' identities.\n \n* **Sensitive Data Exposure**: Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, or personally identifiable information (PII). Attackers can steal or modify this data to conduct crimes like identity theft or credit card fraud.\n \n* **XML External Entities (XXE)**: Poorly configured XML parsers can be vulnerable to external entity attacks, allowing attackers to access unauthorized data, perform server-side request forgery (SSRF), or launch denial-of-service (DoS) attacks.\n \n* **Broken Access Control**: Restrictions on what authenticated users are allowed to do often fail to be properly enforced. Attackers can exploit these flaws to access unauthorized functionality or data, modify user access, or perform other unauthorized actions.\n \n* **Security Misconfiguration**: Insecure default configurations, incomplete or ad hoc configurations, misconfigured HTTP headers, and verbose error messages can provide attackers with valuable information to exploit vulnerabilities.\n \n* **Cross-Site Scripting (XSS)**: XSS flaws occur when an application includes untrusted data in a web page without proper validation or escaping. Attackers can execute malicious scripts in the context of the user's browser, leading to account takeover, defacement, or redirection to malicious sites.\n \n* **Insecure Deserialization**: Insecure deserialization flaws can enable an attacker to execute arbitrary code, conduct injection attacks, elevate privileges, or perform other malicious actions.\n \n* **Using Components with Known Vulnerabilities**: Applications and APIs using components with known vulnerabilities may compromise the system if those vulnerabilities are exploited.\n \n* **Insufficient Logging & Monitoring**: Insufficient logging and monitoring, coupled with inadequate integration with incident response, allow attackers to maintain their presence within a system, move laterally, and exfiltrate or tamper with data.\n \n\nTo mitigate these risks, the OWASP Top 10 project provides detailed information, including how to test for each risk, code examples for various programming languages, and specific steps to prevent or remediate the issues. By understanding and implementing the recommended practices, organizations can improve their web application security and protect their users' data.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "OWASP Top Ten",
|
||||
"url": "https://owasp.org/www-project-top-ten/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "OWASP Top Ten",
|
||||
"url": "https://youtube.com/playlist?list=PLyqga7AXMtPOguwtCCXGZUKvd2CDCmUgQ&si=ZYRbcDSRvqTOnDOo",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "The Open Web Application Security Project (OWASP) is a non-profit organization focused on improving the security of software. One of their most well-known projects is the **OWASP Top 10**, which is a list of the most critical web application security risks. The Top 10 project aims to raise awareness and provide businesses, developers, and security teams with guidance on how to address these risks effectively.\n\nThe OWASP Top 10 is updated periodically, with the most recent version released in 2021. Here is a brief summary of the current top 10 security risks:\n\n* **Injection**: Injection flaws, such as SQL, NoSQL, or OS command injection, occur when untrusted data is sent to an interpreter as part of a command or query, allowing an attacker to execute malicious commands or access unauthorized data.\n \n* **Broken Authentication**: Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or exploit other implementation flaws to assume users' identities.\n \n* **Sensitive Data Exposure**: Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, or personally identifiable information (PII). Attackers can steal or modify this data to conduct crimes like identity theft or credit card fraud.\n \n* **XML External Entities (XXE)**: Poorly configured XML parsers can be vulnerable to external entity attacks, allowing attackers to access unauthorized data, perform server-side request forgery (SSRF), or launch denial-of-service (DoS) attacks.\n \n* **Broken Access Control**: Restrictions on what authenticated users are allowed to do often fail to be properly enforced. Attackers can exploit these flaws to access unauthorized functionality or data, modify user access, or perform other unauthorized actions.\n \n* **Security Misconfiguration**: Insecure default configurations, incomplete or ad hoc configurations, misconfigured HTTP headers, and verbose error messages can provide attackers with valuable information to exploit vulnerabilities.\n \n* **Cross-Site Scripting (XSS)**: XSS flaws occur when an application includes untrusted data in a web page without proper validation or escaping. Attackers can execute malicious scripts in the context of the user's browser, leading to account takeover, defacement, or redirection to malicious sites.\n \n* **Insecure Deserialization**: Insecure deserialization flaws can enable an attacker to execute arbitrary code, conduct injection attacks, elevate privileges, or perform other malicious actions.\n \n* **Using Components with Known Vulnerabilities**: Applications and APIs using components with known vulnerabilities may compromise the system if those vulnerabilities are exploited.\n \n* **Insufficient Logging & Monitoring**: Insufficient logging and monitoring, coupled with inadequate integration with incident response, allow attackers to maintain their presence within a system, move laterally, and exfiltrate or tamper with data.\n \n\nTo mitigate these risks, the OWASP Top 10 project provides detailed information, including how to test for each risk, code examples for various programming languages, and specific steps to prevent or remediate the issues. By understanding and implementing the recommended practices, organizations can improve their web application security and protect their users' data.",
|
||||
"links": []
|
||||
},
|
||||
"v7CD_sHqLWbm9ibXXESIK": {
|
||||
"title": "Learn how Malware works and Types",
|
||||
@@ -1503,7 +1443,7 @@
|
||||
},
|
||||
"c2kY3wZVFKZYxMARhLIwO": {
|
||||
"title": "SIEM",
|
||||
"description": "SIEM, short for Security Information and Event Manager, is a term used to describe tools that greatly increases visibility into a network or system. It does this by monitoring, filtering, collecting, normalizing, and correlating vast amounts of data such as logs, and neatly presents it via an interface/dashboard.\n\nOrganizations leverage SIEMs to monitor and thus identify, protect, and respond to potential threats in their environment.\n\nFor hands-on experience, you should consider setting up a SIEM in your own environment. There are some commercial tools that you can try out for free, and there are also open source alternatives, such as Wazuh or LevelBlue OSSIM (AlienVault).\n\nVisit the following resources to learn more:",
|
||||
"description": "SIEM, short for Security Information and Event Manager, is a term used to describe tools that greatly increases visibility into a network or system. It does this by monitoring, filtering, collecting, normalizing, and correlating vast amounts of data such as logs, and neatly presents it via an interface/dashboard.\n\nOrganizations leverage SIEMs to monitor and thus identify, protect, and respond to potential threats in their environment.\n\nFor hands-on experience, you should consider setting up a SIEM in your own environment. A common stack widely used for various purposes across the industry is the ELK-stack.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Security 101: What is a SIEM? - Microsoft",
|
||||
@@ -1511,22 +1451,12 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SIEM Explained - Professor Messer",
|
||||
"url": "https://www.youtube.com/watch?v=JEcETdy5WxU",
|
||||
"type": "video"
|
||||
"title": "Using the ELK stack for SIEM",
|
||||
"url": "https://logz.io/blog/elk-siem/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Wazuh | Open source SIEM",
|
||||
"url": "https://www.youtube.com/watch?v=3CaG2GI1kn0",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Splunk | The Complete Beginner Tutorial",
|
||||
"url": "https://www.youtube.com/playlist?list=PLY2f3p7xyMiTUbUo0A_lBFEwj6KdH0nFy",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Elastic Security | Build a powerful home SIEM",
|
||||
"title": "Build a powerful home SIEM",
|
||||
"url": "https://www.youtube.com/watch?v=2XLzMb9oZBI",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1709,7 +1639,7 @@
|
||||
},
|
||||
"9rmDvycXFcsGOq3v-_ziD": {
|
||||
"title": "S/MIME",
|
||||
"description": "**S/MIME** stands for Secure/Multipurpose Internet Mail Extensions, and it is a cryptographic protocol that enhances the security of business emails through encryption and digital signatures. It allows users to encrypt emails and digitally sign them to verify the sender’s identity.\n\nAdvantages of S/MIME\n--------------------\n\n* **Verification**: Confirms the sender’s identity.\n \n* **Confidentiality**: Protects the content from unauthorized access.\n \n* **Integrity**: Ensures the message has not been altered.\n \n* **Secure Data Transfer**: Safely transmits files like images, audio, videos, and documents.\n \n* **Non-repudiation**: Prevents the sender from denying the origin of the message.\n \n\nHow S/MIME Works\n----------------\n\nS/MIME enables the transmission of non-ASCII data via the Secure Mail Transfer Protocol (SMTP). It securely sends various data files, including music, video, and images, using encryption. Data encrypted with a public key can only be decrypted by the recipient’s private key, ensuring secure end-to-end communication.",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"3140n5prZYySsuBHjqGOJ": {
|
||||
@@ -1841,7 +1771,7 @@
|
||||
},
|
||||
"rxzcAzHjzIc9lkWSw0fef": {
|
||||
"title": "VirusTotal",
|
||||
"description": "VirusTotal's main feature is multi-scanning using over 70 antivirus scanners to generate a cumulative report on whether a file is malicious. It also stores file hashes, eliminating the need to rescan previously uploaded files. Researchers can comment in the community, sharing their analysis and insights into malware for others to benefit from.\n\nVirusTotal's aggregated data comes from various antivirus engines, website scanners, file and URL analysis tools, and user contributions. These tools serve diverse purposes, including heuristic engines, known-bad signatures, metadata extraction, and identification of malicious signals.\n\nAdditionally, VirusTotal offers services to search by file hash, IP address, and URL, which are also scanned. For more comprehensive features, VirusTotal provides Premium services such as Intelligence & Hunting.\n\nVisit the following resources to learn more:",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"h__KxKa0Q74_egY7GOe-L": {
|
||||
@@ -1861,14 +1791,8 @@
|
||||
},
|
||||
"lMiW2q-b72KUl-2S7M6Vb": {
|
||||
"title": "urlscan",
|
||||
"description": "**[urlscan.io](http://urlscan.io)** is a free service to scan and analyze websites. When a URL is submitted to [urlscan.io](http://urlscan.io), an automated process will browse to the URL like a regular user and record the activity that this page navigation creates. This includes the domains and IPs contacted, the resources (JavaScript, CSS, etc) requested from those domains, as well as additional information about the page itself. [urlscan.io](http://urlscan.io) will take a screenshot of the page, record the DOM content, JavaScript global variables, cookies created by the page, and a myriad of other observations. If the site is targeting the users one of the more than 900 brands tracked by [urlscan.io](http://urlscan.io), it will be highlighted as potentially malicious in the scan results.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "urlscan.io",
|
||||
"url": "https://urlscan.io/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"-RnlvUltJ9IDtH0HEnMbN": {
|
||||
"title": "WHOIS",
|
||||
@@ -1919,19 +1843,8 @@
|
||||
},
|
||||
"KSwl6sX2W47vUmytpm8LH": {
|
||||
"title": "Whaling",
|
||||
"description": "Whaling is a specific type of phishing attack that targets high-profile individuals within an organization, such as executives, CEOs, or other senior leaders. The term \"whaling\" is derived from the idea of hunting large \"whales,\" as opposed to the more common \"phishing,\" which targets a broader range of users. Whaling attacks are highly sophisticated and often involve personalized emails or communications that appear legitimate, making them difficult to detect.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a Whaling Attack?",
|
||||
"url": "https://usa.kaspersky.com/resource-center/definitions/what-is-a-whaling-attack",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is a whaling attack and how to stay protected",
|
||||
"url": "https://www.youtube.com/watch?v=jQONycdUOAA",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"d4U6Jq-CUB1nNN2OCFoum": {
|
||||
"title": "Smishing",
|
||||
@@ -1940,40 +1853,13 @@
|
||||
},
|
||||
"cbEMUyg_btIPjdx-XqIM5": {
|
||||
"title": "Spam vs Spim",
|
||||
"description": "Spam refers to unsolicited and often irrelevant messages sent over email, typically to a large number of recipients, with the purpose of advertising, phishing, spreading malware, or other malicious activities. Spam emails are usually sent by automated bots and are characterized by their bulk nature.\n\nSpim is a type of spam that specifically targets instant messaging (IM) platforms rather than email. Spim messages are unsolicited and typically used for advertising, phishing, or spreading malware. As instant messaging apps have grown in popularity, so too has the prevalence of Spim.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What Is Spam?",
|
||||
"url": "https://www.proofpoint.com/us/threat-reference/spam",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"FD0bkmxNpPXiUB_NevEUf": {
|
||||
"title": "Shoulder Surfing",
|
||||
"description": "In a Shoulder Surfing Attack, an attacker tries to get information when you are unaware of where the attacker looks over your shoulder or from your back to see what you're doing on your device and obtain sensitive information. Shoulder Surfing attacks are accomplished by observing the content \"over the victim's shoulder\". It is a social engineering attack where the attackers physically view the device screen and keypad to obtain personal information. This attack is mostly done when you are in a public place or crowded area. Sometimes attackers attack when you are busy on your device and the attacker could be your friend, someone you know or it may be some stranger.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Shoulder Surfing",
|
||||
"url": "https://www.geeksforgeeks.org/what-is-shoulder-surfing-in-cyber-security/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is shoulder surfing, and how can you avoid it?",
|
||||
"url": "https://nordvpn.com/blog/shoulder-surfing/?srsltid=AfmBOorl5NPpW_Tnhas9gB2HiblorqwXyK0NJae7uaketrnDwbjJmiYV",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Shoulder Surfing?",
|
||||
"url": "https://www.mcafee.com/learn/what-is-shoulder-surfing/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Shoulder Surfing? 9 ways to protect yourself",
|
||||
"url": "https://www.bigrock.in/blog/products/security/what-is-shoulder-surfing-9-ways-to-protect-yourself-from-shoulder-surfing/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"Iu0Qtk13RjrhHpSlm0uyh": {
|
||||
"title": "Dumpster Diving",
|
||||
@@ -1993,25 +1879,13 @@
|
||||
},
|
||||
"v9njgIxZyabJZ5iND3JGc": {
|
||||
"title": "Zero day",
|
||||
"description": "A **zero-day** is the technique used by an attacker to infiltrate a system that has a vulnerability that is not publicly known. The term \"zero day\" signifies that the attack occurs before the target becomes aware of the existing vulnerability. In this scenario, the attacker deploys malware prior to the developer or vendor having the chance to issue a patch to rectify the flaw.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Zero-day Vulnerabilities",
|
||||
"url": "https://www.youtube.com/watch?v=FDFxGLnZtoY",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"O1VceThdxRlgQ6DcGyY7Y": {
|
||||
"title": "Social Engineering",
|
||||
"description": "Social Engineering is a manipulation technique that exploits human psychology to gain access to confidential information, systems, or physical locations. Unlike traditional hacking methods that rely on technical skills, social engineering primarily focuses on deceiving or tricking individuals into revealing sensitive information or performing actions that compromise security.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What Is Social Engineering?",
|
||||
"url": "https://www.cisco.com/c/en/us/products/security/what-is-social-engineering.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"UU_inxa8Y2lLP2BRhdLDT": {
|
||||
"title": "Reconnaissance",
|
||||
@@ -2059,25 +1933,13 @@
|
||||
},
|
||||
"0LeDwj_tMaXjQBBOUJ5CL": {
|
||||
"title": "Typo Squatting",
|
||||
"description": "Typosquatting is a form of cyberattack that exploits common typing errors made by users when entering website URLs into their browsers. Attackers create malicious websites with URLs that are very similar to legitimate ones, often differing by just a single letter, number, or symbol. When a user accidentally mistypes a URL, they may be redirected to the malicious site, where they can be subjected to phishing attacks, malware downloads, or other forms of cyber exploitation.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Typosquatting",
|
||||
"url": "https://www.mcafee.com/learn/what-is-typosquatting/#:~:text=Typosquatting%2C%20also%20known%20as%20URL,%E2%80%9CGoogle.com%E2%80%9D",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"Q0i-plPQkb_NIvOQBVaDd": {
|
||||
"title": "Brute Force vs Password Spray",
|
||||
"description": "What is Brute Force?\n--------------------\n\nBrute Force is a method of password cracking where an attacker systematically tries all possible combinations of characters until the correct password is found. This method is highly resource-intensive, as it involves attempting numerous password variations in a relatively short period of time.\n\nWhat is Password Spray?\n-----------------------\n\nPassword Spray is a more targeted and stealthy method of password cracking where an attacker tries a small number of common passwords across many different accounts. Instead of bombarding a single account with numerous password attempts (as in brute force), password spraying involves using one or a few passwords against multiple accounts.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Brute force vs. Password Spray attack",
|
||||
"url": "https://www.inspark.nl/brute-force-vs-password-spray-attack-in-azure-sentinel/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"IF5H0ZJ72XnqXti3jRWYF": {
|
||||
"title": "DoS vs DDoS",
|
||||
@@ -2107,24 +1969,13 @@
|
||||
},
|
||||
"urtsyYWViEzbqYLoNfQAh": {
|
||||
"title": "DNS Poisoning",
|
||||
"description": "DNS spoofing or DNS cache poisoning, occurs when fake information is inserted into a DNS server’s cache.This causes DNS queries to return incorrect IP addresses, directing users to the wrong websites. Hackers exploit this to reroute traffic to malicious sites. The issue persists until the cached information is corrected.When the cache is poisoned, it misdirects traffic until the incorrect information is fixed. This technique exploits vulnerabilities in the DNS system and can spread to other servers, causing widespread issues.\n\nVisit the following resources to learn more:",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"LfWJJaT3fv0p6fUeS8b84": {
|
||||
"title": "Deauth Attack",
|
||||
"description": "A Deauthentication (Deauth) Attack is a type of denial-of-service (DoS) attack specific to wireless networks. It involves sending fake deauthentication frames to a Wi-Fi client or access point, forcing the client to disconnect from the network. The attacker uses this technique to disrupt the communication between the client and the access point, often with the intention of capturing data, launching further attacks, or simply causing disruption.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Wi-Fi Deauthentication Attack",
|
||||
"url": "https://medium.com/@balaramapunna123/wi-fi-deauthentication-attack-76cdd91d5fc",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Deauthentication Attacks",
|
||||
"url": "https://www.baeldung.com/cs/deauthentication-attacks",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"u4hySof6if5hiONSaW-Uf": {
|
||||
"title": "VLAN Hopping",
|
||||
@@ -2133,18 +1984,12 @@
|
||||
},
|
||||
"Ee7LfbhwJbiWjJ3b_bbni": {
|
||||
"title": "Rogue Access Point",
|
||||
"description": "A Rogue Access Point (Rogue AP) is an unauthorized wireless access point installed on a secure network without the network administrator's knowledge or consent. These devices can be set up by malicious actors to intercept, steal, or manipulate network traffic, or by employees who unintentionally compromise network security by setting up their own wireless access points.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Rogue access points",
|
||||
"url": "https://www.khanacademy.org/computing/computers-and-internet/xcae6f4a7ff015e7d:online-data-security/xcae6f4a7ff015e7d:cyber-attacks/a/rogue-access-points-mitm-attacks",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"n8ZOZxNhlnw7DpzoXe_f_": {
|
||||
"title": "Buffer Overflow",
|
||||
"description": "A Buffer Overflow is a type of vulnerability that occurs when a program or process attempts to write more data to a buffer—a temporary storage area in memory—than it can hold. This overflow can cause the extra data to overwrite adjacent memory locations, potentially leading to unintended behavior, crashes, or security breaches.\n\nVisit the following resources to learn more:",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"nOND14t7ISgSH3zNpV3F8": {
|
||||
@@ -2154,24 +1999,8 @@
|
||||
},
|
||||
"2jo1r9O_rCnDwRv1_4Wo-": {
|
||||
"title": "XSS",
|
||||
"description": "Cross-site scripting (XSS) is a security vulnerability that affects web applications, allowing attackers to inject malicious scripts into web pages viewed by other users. These scripts can then be executed by the browsers of unsuspecting users who visit the compromised web page. The danger of XSS lies in its ability to access cookies, session tokens, and other sensitive information that the user's browser handles, potentially leading to unauthorized actions being performed on behalf of the user.\n\nTypes of XSS\n------------\n\n* **Stored XSS**: occurs when a malicious script is permanently stored on a target server, such as in a database, message forum, visitor log, or comment field.\n \n* **Reflected XSS**: The attack is called \"reflected\" because the malicious script is reflected off the web server, such as in an error message or search result, rather than being stored on the server.\n \n* **DOM-based XSS** is a type of attack where the vulnerability exists in the client-side script itself rather than the server-side code.\n \n\nHow to prevent XSS\n------------------\n\nPrevention strategies involve a combination of validating and sanitizing input, employing security features of web frameworks, and implementing Content Security Policies (CSP). Techniques such as output encoding and HTML sanitization are essential to ensure that user-supplied data does not execute as code in browsers, thus mitigating potential attacks.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Cross Site Scripting (XSS) - OWASP",
|
||||
"url": "https://owasp.org/www-community/attacks/xss/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Cross Site Scripting Prevention Cheat Sheet",
|
||||
"url": "https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Cross-site Scripting",
|
||||
"url": "https://www.youtube.com/watch?v=PKgw0CLZIhE",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"P-Am25WJV8cFd_KsX7cdj": {
|
||||
"title": "SQL Injection",
|
||||
@@ -2191,14 +2020,8 @@
|
||||
},
|
||||
"mIX8PsIGuwgPCGQZ6ok2H": {
|
||||
"title": "Replay Attack",
|
||||
"description": "A Replay Attack is a type of network attack where an attacker intercepts and retransmits legitimate communication data, often with the aim of gaining unauthorized access to a system or performing unauthorized actions. In this attack, the attacker captures a valid data transmission and then \"replays\" it later, without needing to decrypt or alter the data, to trick the recipient into thinking it's a legitimate request.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What Is a Replay Attack?",
|
||||
"url": "https://usa.kaspersky.com/resource-center/definitions/replay-attack",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"sMuKqf27y4iG0GrCdF5DN": {
|
||||
"title": "Pass the Hash",
|
||||
@@ -2207,55 +2030,13 @@
|
||||
},
|
||||
"L0ROYh2DNlkybNDO2ezJY": {
|
||||
"title": "Directory Traversal",
|
||||
"description": "Directory Traversal, also known as Path Traversal, is a vulnerability that allows attackers to read files on a system without proper authorization. These attacks typically exploit unsecured paths using \"../\" (dot-dot-slash) sequences and their variations, or absolute file paths. The attack is also referred to as \"dot-dot-slash,\" \"directory climbing,\" or \"backtracking.\"\n\nWhile Directory Traversal is sometimes combined with other vulnerabilities like Local File Inclusion (LFI) or Remote File Inclusion (RFI), the key difference is that Directory Traversal doesn't execute code, whereas LFI and RFI usually do.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TryHackMe's room on Path Traversal & File Inclusion",
|
||||
"url": "https://tryhackme.com/r/room/filepathtraversal",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "HackTheBox Academy's module on File Inclusion & Path Traversal",
|
||||
"url": "https://academy.hackthebox.com/course/preview/file-inclusion",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Portswigger's guide on File Path Traversal",
|
||||
"url": "https://portswigger.net/web-security/file-path-traversal",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "OWASP's article on Path Traversal",
|
||||
"url": "https://owasp.org/www-community/attacks/Path_Traversal",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Acunetix's article on directory traversal",
|
||||
"url": "https://www.acunetix.com/websitesecurity/directory-traversal/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"lv6fI3WeJawuCbwKtMRIh": {
|
||||
"title": "Stakeholders",
|
||||
"description": "Stakeholders are individuals or organizations with a right, share, claim, or interest in a system or its characteristics that meet their needs and expectations.\n\n### External Stakeholders:\n\n* Government agencies\n* Policy regulators\n* Partners\n* Suppliers\n\n### Internal Stakeholders:\n\n* Subject matter experts\n* Legal\n* Compliance\n* Senior management\n\nStakeholders vary based on the organization, making their identification essential. They must be notified according to the organization's playbook for escalating problems and providing updates. Not all stakeholders are equal, some may require a less technical report highlighting the main points, while others will need a full technical report.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TryHackMe room on Cyber Governance and regulation",
|
||||
"url": "https://tryhackme.com/r/room/cybergovernanceregulation",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "NIST Publication on Engineering Trustworthy Secure Systems",
|
||||
"url": "https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-160v1r1.pdf",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NIST Glossary",
|
||||
"url": "https://csrc.nist.gov/glossary/term/stakeholder",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"05tH6WhToC615JTFN-TPc": {
|
||||
"title": "HR",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"3xp2fogAVmwXQhdzhZDWR": {
|
||||
"title": "Introduction",
|
||||
"description": "Data Analysis plays a crucial role in today's data-centric world. It involves the practice of inspecting, cleansing, transforming, and modeling data to extract valuable insights for decision-making. A **Data Analyst** is a professional primarily tasked with collecting, processing, and performing statistical analysis on large datasets. They discover how data can be used to answer questions and solve problems. With the rapid expansion of data in modern firms, the role of a data analyst has been evolving greatly, making them a significant asset in business strategy and decision-making processes.",
|
||||
"description": "Data Analysis plays a crucial role in today's data-centric world. It involves the practice of inspecting, cleansing, transforming, and modeling data to extract valuable insights for decision-making. A **Data Analyst** is a professional primarily tasked with collecting, processing, and performing statistical analysis on large datasets. They discover how data can be used to answer questions and solve problems. With the rapid expansion of data in modern firms, the role of a data analyst has been evolving greatly, making them a significant asset in business strategy and decision-making processes.\n\nLearn more from the following resources:",
|
||||
"links": []
|
||||
},
|
||||
"yCnn-NfSxIybUQ2iTuUGq": {
|
||||
@@ -11,29 +11,8 @@
|
||||
},
|
||||
"Lsapbmg-eMIYJAHpV97nO": {
|
||||
"title": "Types of Data Analytics",
|
||||
"description": "Data Analytics has proven to be a critical part of decision-making in modern business ventures. It is responsible for discovering, interpreting, and transforming data into valuable information. Different types of data analytics look at past, present, or predictive views of business operations.\n\nData Analysts, as ambassadors of this domain, employ these types, to answer various questions:\n\n* Descriptive Analytics _(what happened in the past?)_\n* Diagnostic Analytics _(why did it happened in the past?)_\n* Predictive Analytics _(what will happen in the future?)_\n* Prescriptive Analytics _(how can we make it happen?)_\n\nUnderstanding these types gives data analysts the power to transform raw datasets into strategic insights.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Analytics and its type",
|
||||
"url": "https://www.geeksforgeeks.org/data-analytics-and-its-type/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The 4 Types of Data Analysis: Ultimate Guide",
|
||||
"url": "https://careerfoundry.com/en/blog/data-analytics/different-types-of-data-analysis/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Descriptive vs Diagnostic vs Predictive vs Prescriptive Analytics: What's the Difference?",
|
||||
"url": "https://www.youtube.com/watch?v=QoEpC7jUb9k",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Types of Data Analytics",
|
||||
"url": "https://www.youtube.com/watch?v=lsZnSgxMwBA",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "Data Analytics has proven to be a critical part of decision-making in modern business ventures. It is responsible for discovering, interpreting, and transforming data into valuable information. Different types of data analytics look at past, present, or predictive views of business operations.\n\nData Analysts, as ambassadors of this domain, employ these types, which are namely Descriptive Analytics, Diagnostic Analytics, Predictive Analytics and Prescriptive Analytics, to answer various questions — What happened? Why did it happen? What could happen? And what should we do next? Understanding these types gives data analysts the power to transform raw datasets into strategic insights.",
|
||||
"links": []
|
||||
},
|
||||
"hWDh0ooidbqZb000ENVok": {
|
||||
"title": "Descriptive Analytics",
|
||||
@@ -157,12 +136,12 @@
|
||||
"description": "The visualization of data is an essential skill in the toolkit of every data analyst. This practice is about transforming complex raw data into a graphical format that allows for an easier understanding of large data sets, trends, outliers, and important patterns. Whether pie charts, line graphs, bar graphs, or heat maps, data visualization techniques not only streamline data analysis, but also facilitate a more effective communication of the findings to others. This key concept underscores the importance of presenting data in a digestible and visually appealing manner to drive data-informed decision making in an organization.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data visualization beginner's guide",
|
||||
"title": "Data visualisation beginner's guide",
|
||||
"url": "https://www.tableau.com/en-gb/learn/articles/data-visualization",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Data Visualization in 2024",
|
||||
"title": "Data Visualisation in 2024",
|
||||
"url": "https://www.youtube.com/watch?v=loYuxWSsLNc",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -204,11 +183,6 @@
|
||||
"title": "Analaysis / Reporting with Excel",
|
||||
"description": "Excel is a powerful tool utilized by data analysts worldwide to store, manipulate, and analyze data. It offers a vast array of features such as pivot tables, graphs and a powerful suite of formulas and functions to help sift through large sets of data. A data analyst uses Excel to perform a wide range of tasks, from simple data entry and cleaning, to more complex statistical analysis and predictive modeling. Proficiency in Excel is often a key requirement for a data analyst, as its versatility and ubiquity make it an indispensable tool in the field of data analysis.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Microsoft Excel Course",
|
||||
"url": "https://support.microsoft.com/en-us/office/excel-video-training-9bc05390-e94c-46af-a5b3-d7c22f6990bb",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools - Excel",
|
||||
"url": "https://www.w3schools.com/excel/index.php",
|
||||
@@ -240,11 +214,6 @@
|
||||
"title": "DATEDIF function",
|
||||
"url": "https://support.microsoft.com/en-gb/office/datedif-function-25dba1a4-2812-480b-84dd-8b32a451b35c",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to use DATEDIF in Excel",
|
||||
"url": "https://www.excel-easy.com/examples/datedif.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -434,16 +403,15 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"i4VCwFm-wc9cqE73i-BIb": {
|
||||
"title": "Learn SQL",
|
||||
"description": "Structured Query Language, or SQL, is an essential tool for every data analyst. As a domain-specific language used in programming and designed for managing data held in relational database management systems, SQL allows analysts to manipulate and analyse large volumes of data efficiently. Understanding SQL allows a data analyst to extract insights from data stored in databases, conduct complex queries, and create elaborate data reports. SQL is recognized for its effectiveness in data manipulation and its compatibility with other coding languages, making it a fundamental competency in the data analytics field.",
|
||||
"links": []
|
||||
},
|
||||
"i2uEcaO4bJhcZ5ayRs2CQ": {
|
||||
"title": "Learn a Programming Lang.",
|
||||
"description": "We have two main programming languages when it comes to data analysis: Python and R. Both have extensive libraries to help with decision-making processes in various situations, assisting in manipulating, modeling, and visualizing data. Python is a versatile language, used not only for data analysis but also for web development, automation, artificial intelligence, and more. R, on the other hand, was specifically created for statistical analysis and data visualization, making it an excellent choice for statisticians and researchers. It is known for its advanced visualization capabilities, allowing the creation of highly customizable and sophisticated graphs and plots.\n\nWith potential doubts about which language to choose to advance in a data career, it is ideal to consider your goals and/or the current market needs and choose which language to learn. If you are more interested in a career that combines data analysis with software development, automation, or artificial intelligence, Python may be the best choice. If your focus is purely on statistics and data visualization, R might be more suitable.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Python Data Science Handbook",
|
||||
"url": "https://jakevdp.github.io/PythonDataScienceHandbook/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "We have two main programming languages when it comes to data analysis: Python and R. Both have extensive libraries to help with decision-making processes in various situations, assisting in manipulating, modeling, and visualizing data. Python is a versatile language, used not only for data analysis but also for web development, automation, artificial intelligence, and more. R, on the other hand, was specifically created for statistical analysis and data visualization, making it an excellent choice for statisticians and researchers. It is known for its advanced visualization capabilities, allowing the creation of highly customizable and sophisticated graphs and plots.\n\nWith potential doubts about which language to choose to advance in a data career, it is ideal to consider your goals and/or the current market needs and choose which language to learn. If you are more interested in a career that combines data analysis with software development, automation, or artificial intelligence, Python may be the best choice. If your focus is purely on statistics and data visualization, R might be more suitable.",
|
||||
"links": []
|
||||
},
|
||||
"g_EBQizZsIe-vn8ir6FTv": {
|
||||
"title": "R",
|
||||
@@ -523,11 +491,6 @@
|
||||
"title": "Ggplot2",
|
||||
"description": "When it comes to data visualization in R programming, ggplot2 stands tall as one of the primary tools for data analysts. This data visualization library, which forms part of the tidyverse suite of packages, facilitates the creation of complex and sophisticated visual narratives. With its grammar of graphics philosophy, ggplot2 enables analysts to build graphs and charts layer by layer, thereby offering detailed control over graphical features and design. Its versatility in creating tailored and aesthetically pleasing graphics is a vital asset for any data analyst tackling exploratory data analysis, reporting, or dashboard building.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "ggplot2 website",
|
||||
"url": "https://ggplot2.tidyverse.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Make beautiful graphs in R",
|
||||
"url": "https://www.youtube.com/watch?v=qnw1xDnt_Ec",
|
||||
@@ -656,11 +619,6 @@
|
||||
"title": "Data Transformation",
|
||||
"description": "Data Transformation, also known as Data Wrangling, is an essential part of a Data Analyst's role. This process involves the conversion of data from a raw format into another format to make it more appropriate and valuable for a variety of downstream purposes such as analytics. Data Analysts transform data to make the data more suitable for analysis, ensure accuracy, and to improve data quality. The right transformation techniques can give the data a structure, multiply its value, and enhance the accuracy of the analytics performed by serving meaningful results.",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is data transformation?",
|
||||
"url": "https://www.qlik.com/us/data-management/data-transformation",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Data Analysis",
|
||||
"url": "https://app.daily.dev/tags/data-analysis?ref=roadmapsh",
|
||||
@@ -721,14 +679,9 @@
|
||||
"description": "Dispersion in descriptive analysis, specifically for a data analyst, offers a crucial way to understand the variability or spread in a set of data. Descriptive analysis focus on describing and summarizing data to find patterns, relationships, or trends. Distinct measures of dispersion such as range, variance, standard deviation, and interquartile range gives data analysts insight into how spread out data points are, and how reliable any patterns detected may be. This understanding of dispersion helps data analysts in identifying outliers, drawing meaningful conclusions, and making informed predictions.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is dispersion?",
|
||||
"url": "https://www.investopedia.com/terms/d/dispersion.asp",
|
||||
"title": "Standard Deviation and Variance",
|
||||
"url": "https://www.mathsisfun.com/data/standard-deviation.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Statistics 101 - Measures of Dispersion",
|
||||
"url": "https://www.youtube.com/watch?v=goXdWMZxlqM",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -798,19 +751,8 @@
|
||||
},
|
||||
"yn1sstYMO9du3rpfQqNs9": {
|
||||
"title": "Average",
|
||||
"description": "When focusing on data analysis, understanding key statistical concepts is crucial. Amongst these, central tendency is a foundational element. Central Tendency refers to the measure that determines the center of a distribution. The average is a commonly used statistical tool by which data analysts discern trends and patterns. As one of the most recognized forms of central tendency, figuring out the \"average\" involves summing all values in a data set and dividing by the number of values. This provides analysts with a 'typical' value, around which the remaining data tends to cluster, facilitating better decision-making based on existing data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to calculate the average",
|
||||
"url": "https://support.microsoft.com/en-gb/office/calculate-the-average-of-a-group-of-numbers-e158ef61-421c-4839-8290-34d7b1e68283#:~:text=Average%20This%20is%20the%20arithmetic,by%206%2C%20which%20is%205.",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Average Formula",
|
||||
"url": "https://www.cuemath.com/average-formula/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "When focusing on data analysis, understanding key statistical concepts is crucial. Amongst these, central tendency is a foundational element. Central Tendency refers to the measure that determines the center of a distribution. The average is a commonly used statistical tool by which data analysts discern trends and patterns. As one of the most recognized forms of central tendency, figuring out the \"average\" involves summing all values in a data set and dividing by the number of values. This provides analysts with a 'typical' value, around which the remaining data tends to cluster, facilitating better decision-making based on existing data.",
|
||||
"links": []
|
||||
},
|
||||
"tSxtyJhL5wjU0XJcjsJmm": {
|
||||
"title": "Range",
|
||||
@@ -828,12 +770,12 @@
|
||||
"description": "Data analysts heavily rely on statistical concepts to analyze and interpret data, and one such fundamental concept is variance. Variance, an essential measure of dispersion, quantifies the spread of data, providing insight into the level of variability within the dataset. Understanding variance is crucial for data analysts as the reliability of many statistical models depends on the assumption of constant variance across observations. In other words, it helps analysts determine how much data points diverge from the expected value or mean, which can be pivotal in identifying outliers, understanding data distribution, and driving decision-making processes. However, variance can't be interpreted in the original units of measurement due to its squared nature, which is why it is often used in conjunction with its square root, the standard deviation.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is variance?",
|
||||
"title": "",
|
||||
"url": "https://www.investopedia.com/terms/v/variance.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to calculate variance",
|
||||
"title": "https://www.scribbr.co.uk/stats/variance-meaning/",
|
||||
"url": "https://www.scribbr.co.uk/stats/variance-meaning/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -874,11 +816,6 @@
|
||||
"title": "Kurtosis: Definition, Types, and Importance",
|
||||
"url": "https://www.investopedia.com/terms/k/kurtosis.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Kurtosis?",
|
||||
"url": "https://www.youtube.com/watch?v=AsxEDBhESJg",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -932,19 +869,8 @@
|
||||
},
|
||||
"tvDdXwaRPsUSTqJGaLS3P": {
|
||||
"title": "Matplotlib",
|
||||
"description": "For a Data Analyst, understanding data and being able to represent it in a visually insightful form is a crucial part of effective decision-making in any organization. Matplotlib, a plotting library for the Python programming language, is an extremely useful tool for this purpose. It presents a versatile framework for generating line plots, scatter plots, histogram, bar charts and much more in a very straightforward manner. This library also allows for comprehensive customizations, offering a high level of control over the look and feel of the graphics it produces, which ultimately enhances the quality of data interpretation and communication.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Matplotlib Website",
|
||||
"url": "https://matplotlib.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn Matplotlib in 6 minutes",
|
||||
"url": "https://www.youtube.com/watch?v=nzKy9GY12yo",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "For a Data Analyst, understanding data and being able to represent it in a visually insightful form is a crucial part of effective decision-making in any organization. Matplotlib, a plotting library for the Python programming language, is an extremely useful tool for this purpose. It presents a versatile framework for generating line plots, scatter plots, histogram, bar charts and much more in a very straightforward manner. This library also allows for comprehensive customizations, offering a high level of control over the look and feel of the graphics it produces, which ultimately enhances the quality of data interpretation and communication.",
|
||||
"links": []
|
||||
},
|
||||
"-cJb8gEBvdVFf7FlgG3Ud": {
|
||||
"title": "Seaborn",
|
||||
@@ -964,19 +890,8 @@
|
||||
},
|
||||
"n3M49lgNPn28hm7kzki-a": {
|
||||
"title": "ggplot2",
|
||||
"description": "ggplot2 is an important and powerful tool in the data analyst's toolkit, especially for visualizing and understanding complex datasets. Built within the R programming language, it provides a flexible, cohesive environment for creating graphs. The main strength of ggplot2 lies in its ability to produce sophisticated and tailored visualizations. This allows data analysts to communicate data-driven findings in an efficient and effective manner, enabling clear communication to stakeholders about relevant insights and patterns identified within the data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "ggplot2 website",
|
||||
"url": "https://ggplot2.tidyverse.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Make beautiful graphs in R",
|
||||
"url": "https://www.youtube.com/watch?v=qnw1xDnt_Ec",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "ggplot2 is an important and powerful tool in the data analyst's toolkit, especially for visualizing and understanding complex datasets. Built within the R programming language, it provides a flexible, cohesive environment for creating graphs. The main strength of ggplot2 lies in its ability to produce sophisticated and tailored visualizations. This allows data analysts to communicate data-driven findings in an efficient and effective manner, enabling clear communication to stakeholders about relevant insights and patterns identified within the data.",
|
||||
"links": []
|
||||
},
|
||||
"EVk1H-QLtTlpG7lVEenDt": {
|
||||
"title": "Bar Charts",
|
||||
@@ -1140,11 +1055,6 @@
|
||||
"title": "Correlation",
|
||||
"url": "https://www.mathsisfun.com/data/correlation.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is correlation analysis?",
|
||||
"url": "https://blog.flexmr.net/correlation-analysis-definition-exploration",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1323,8 +1233,8 @@
|
||||
"description": "K-Nearest Neighbors (KNN) is a simple yet powerful algorithm used in the field of machine learning, which a Data Analyst might employ for tasks such as classification or regression. It works based on the principle of proximity, where the prediction of new instance's category depends upon the category of its nearest neighbors. For a Data Analyst working with complex data sets, it's crucial to understand how the KNN algorithm operates, its applicability, pros, and cons. This will facilitate making well-informed decisions about when to utilize it for the best possible outcome in data analysis.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is the k-nearest neighbors (KNN) algorithm?",
|
||||
"url": "https://www.ibm.com/topics/knn#:~:text=The%20k%2Dnearest%20neighbors%20KNN,used%20in%20machine%20learning%20today.",
|
||||
"title": "https://www.ibm.com/topics/knn#:~:text=The k-nearest neighbors (KNN,used in machine learning today.)",
|
||||
"url": "https://www.ibm.com/topics/knn#:~:text=The%20k%2Dnearest%20neighbors%20(KNN,used%20in%20machine%20learning%20today.)",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -1549,18 +1459,7 @@
|
||||
},
|
||||
"iTmtpXe7dR4XKslgpsk2q": {
|
||||
"title": "Data Storage Solutions",
|
||||
"description": "As a business enterprise expands, so does its data. For data analysts, the surge in information means they need efficient and scalable data storage solutions to manage vast volumes of structured and unstructured data, collectively referred to as Big Data. Big Data storage solutions are critical in preserving the integrity of data while also providing quick and easy access to the data when needed. These solutions use software and hardware components to securely store massive amounts of information across numerous servers, allowing data analysts to perform robust data extraction, data processing and complex data analyses. There are several options, from the traditional Relational Database Management Systems (RDBMS) to the more recent NoSQL databases, Hadoop ecosystems, and Cloud storage solutions, each offering unique capabilities and benefits to cater for different big data needs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SQL Roadmap",
|
||||
"url": "https://roadmap.sh/sql",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Roadmap",
|
||||
"url": "https://roadmap.sh/postgresql-dba",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "As a business enterprise expands, so does its data. For data analysts, the surge in information means they need efficient and scalable data storage solutions to manage vast volumes of structured and unstructured data, collectively referred to as Big Data. Big Data storage solutions are critical in preserving the integrity of data while also providing quick and easy access to the data when needed. These solutions use software and hardware components to securely store massive amounts of information across numerous servers, allowing data analysts to perform robust data extraction, data processing and complex data analyses. There are several options, from the traditional Relational Database Management Systems (RDBMS) to the more recent NoSQL databases, Hadoop ecosystems, and Cloud storage solutions, each offering unique capabilities and benefits to cater for different big data needs.",
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
@@ -1037,11 +1037,6 @@
|
||||
"title": "Docker",
|
||||
"description": "Docker is a platform for working with containerized applications. Among its features are a daemon and client for managing and interacting with containers, registries for storing images, and a desktop application to package all these features together.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Visit Dedicated Docker Roadmap",
|
||||
"url": "https://roadmap.sh/docker",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Docker Documentation",
|
||||
"url": "https://docs.docker.com/",
|
||||
|
||||
@@ -235,11 +235,36 @@
|
||||
"title": "HTML",
|
||||
"description": "HTML stands for HyperText Markup Language. It is used on the frontend and gives the structure to the webpage which you can style using CSS and make interactive using JavaScript.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Interactive HTML Course",
|
||||
"url": "https://github.com/denysdovhan/learnyouhtml",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools: Learn HTML",
|
||||
"url": "https://www.w3schools.com/html/html_intro.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "htmlreference.io: All HTML elements at a glance",
|
||||
"url": "https://htmlreference.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "HTML For Beginners The Easy Way",
|
||||
"url": "https://html.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Web Development Basics",
|
||||
"url": "https://internetingishard.netlify.app/html-and-css/index.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "You don't need JavaScript for that",
|
||||
"url": "https://www.htmhell.dev/adventcalendar/2023/2/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about HTML",
|
||||
"url": "https://app.daily.dev/tags/html?ref=roadmapsh",
|
||||
@@ -254,6 +279,11 @@
|
||||
"title": "HTML Full Course - Build a Website Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=pQN-pnXPaVg",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML Tutorial for Beginners: HTML Crash Course",
|
||||
"url": "https://www.youtube.com/watch?v=qz0aGYrrlhU",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -266,15 +296,30 @@
|
||||
"url": "https://www.w3schools.com/html/html_intro.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "MDN Docs: Getting Started with HTML ",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "web.dev: Learn HTML",
|
||||
"url": "https://web.dev/learn/html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "HTML Cheatsheet",
|
||||
"url": "https://htmlcheatsheet.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "HTML Full Course - Build a Website Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=pQN-pnXPaVg",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML Tutorial for Beginners: HTML Crash Course",
|
||||
"url": "https://www.youtube.com/watch?v=qz0aGYrrlhU",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -292,6 +337,16 @@
|
||||
"url": "https://www.w3schools.com/html/html5_semantic_elements.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How To Write Semantic HTML",
|
||||
"url": "https://hackernoon.com/how-to-write-semantic-html-dkq3ulo",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Semantic HTML: What It Is and How It Improves Your Site",
|
||||
"url": "https://blog.hubspot.com/website/semantic-html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Semantic Markup",
|
||||
"url": "https://html.com/semantic-markup",
|
||||
@@ -301,6 +356,11 @@
|
||||
"title": "Semantic HTML - web.dev",
|
||||
"url": "https://web.dev/learn/html/semantic-html/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about HTML",
|
||||
"url": "https://app.daily.dev/tags/html?ref=roadmapsh",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -339,11 +399,31 @@
|
||||
"url": "https://www.w3schools.com/accessibility/index.php",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "A Complete Guide To Accessible Front-End Components",
|
||||
"url": "https://www.smashingmagazine.com/2021/03/complete-guide-accessible-front-end-components/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "MDN Accessibility",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/Accessibility",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Accessibility for Developers by Google",
|
||||
"url": "https://web.dev/accessibility",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Web Accessibility by Udacity",
|
||||
"url": "https://www.udacity.com/course/web-accessibility--ud891",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Accessibility as an Essential Part of the Inclusive Developer Experience",
|
||||
"url": "https://thenewstack.io/accessibility-as-an-essential-part-of-the-inclusive-developer-experience/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Accessibility",
|
||||
"url": "https://app.daily.dev/tags/accessibility?ref=roadmapsh",
|
||||
@@ -360,11 +440,31 @@
|
||||
"title": "SEO Basics",
|
||||
"description": "SEO or Search Engine Optimization is the technique used to optimize your website for better rankings on search engines such as Google, Bing etc.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SEO Guide",
|
||||
"url": "https://github.com/seo/guide",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Google Search Central — SEO Docs",
|
||||
"url": "https://developers.google.com/search/docs",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "8 Must-Know SEO Best Practices For Developers",
|
||||
"url": "https://neilpatel.com/blog/seo-developers/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SEO for Developers",
|
||||
"url": "https://medium.com/welldone-software/seo-for-developers-a-quick-overview-5b5b7ce34679",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learning SEO",
|
||||
"url": "https://learningseo.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about SEO",
|
||||
"url": "https://app.daily.dev/tags/seo?ref=roadmapsh",
|
||||
@@ -386,16 +486,46 @@
|
||||
"title": "CSS",
|
||||
"description": "CSS or Cascading Style Sheets is the language used to style the frontend of any website. CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "The Odin Project",
|
||||
"url": "https://www.theodinproject.com//",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What The Flexbox!",
|
||||
"url": "https://flexbox.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools — Learn CSS",
|
||||
"url": "https://www.w3schools.com/css/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "cssreference.io: All CSS properties at a glance",
|
||||
"url": "https://cssreference.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Web.dev by Google — Learn CSS",
|
||||
"url": "https://web.dev/learn/css/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn to Code HTML & CSS",
|
||||
"url": "https://learn.shayhowe.com/html-css/building-your-first-web-page/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Joshw Comeaus CSS Hack Blog Posts",
|
||||
"url": "https://www.joshwcomeau.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "100 Days CSS Challenge",
|
||||
"url": "https://100dayscss.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about CSS",
|
||||
"url": "https://app.daily.dev/tags/css?ref=roadmapsh",
|
||||
@@ -406,10 +536,20 @@
|
||||
"url": "https://youtu.be/n4R2E7O-Ngo",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "CSS Crash Course For Absolute Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=yfoY53QXEnI",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML and CSS Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=D-h8L5hgW-w",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "CSS Masterclass - Tutorial & Course for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=FqmB-Zj2-PA",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -453,6 +593,11 @@
|
||||
"title": "Making Layouts",
|
||||
"description": "Float, grid, flexbox, positioning, display and box model are some of the key topics that are used for making layouts. Use the resources below to learn about these topics:\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn CSS Grid for free",
|
||||
"url": "https://scrimba.com/learn/cssgrid",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Learn and Practice Flexbox",
|
||||
"url": "https://flexboxfroggy.com/",
|
||||
@@ -540,16 +685,41 @@
|
||||
"title": "JavaScript",
|
||||
"description": "JavaScript allows you to add interactivity to your pages. Common examples that you may have seen on the websites are sliders, click interactions, popups and so on.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "You Dont Know JS Yet (book series) ",
|
||||
"url": "https://github.com/getify/You-Dont-Know-JS",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Learn the basics of JavaScript",
|
||||
"url": "https://github.com/workshopper/javascripting",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated JavaScript Roadmap",
|
||||
"url": "/javascript",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools – JavaScript Tutorial",
|
||||
"url": "https://www.w3schools.com/js/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Modern JavaScript Tutorial",
|
||||
"url": "https://javascript.info/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn JavaScript: Covered many topics",
|
||||
"url": "https://www.javascripttutorial.net/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Eloquent JavaScript textbook",
|
||||
"url": "https://eloquentjavascript.net/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Build 30 Javascript projects in 30 days",
|
||||
"url": "https://javascript30.com/",
|
||||
@@ -564,6 +734,11 @@
|
||||
"title": "JavaScript Crash Course for Beginners",
|
||||
"url": "https://youtu.be/hdI2bqOjy3c?t=2",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Build a Netflix Landing Page Clone with HTML, CSS & JS",
|
||||
"url": "https://youtu.be/P7t13SGytRk?t=22",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1911,16 +2086,46 @@
|
||||
"title": "TypeScript",
|
||||
"description": "TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Scrimba — TypeScript Basics",
|
||||
"url": "https://scrimba.com/learn/typescript",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Official Website",
|
||||
"url": "https://www.typescriptlang.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Docs for Deep Dives",
|
||||
"url": "https://www.typescriptlang.org/docs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The TypeScript Handbook",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/intro.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "TypeScript Tutorial",
|
||||
"url": "https://www.tutorialspoint.com/typescript/index.htm",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What Is TypeScript?",
|
||||
"url": "https://thenewstack.io/what-is-typescript/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "TypeScript Tutorial: Go beyond ‘Hello, World!’",
|
||||
"url": "https://thenewstack.io/typescript-tutorial-go-beyond-hello-world/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "A Guide to Using the Programming Language",
|
||||
"url": "https://thenewstack.io/typescript-tutorial-a-guide-to-using-the-programming-language/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about TypeScript",
|
||||
"url": "https://app.daily.dev/tags/typescript?ref=roadmapsh",
|
||||
@@ -2906,39 +3111,8 @@
|
||||
},
|
||||
"h26uS3muFCabe6ekElZcI": {
|
||||
"title": "SWC",
|
||||
"description": "**SWC** (Speedy Web Compiler) is a JavaScript and TypeScript compiler and bundler built in Rust. Unlike Babel, which is JavaScript-based, SWC leverages Rust for blazing-fast performance, making it an ideal choice for large-scale projects. It focuses on speed while offering modern features like tree shaking, JSX transformation, and module bundling, catering to frontend development and build optimization.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SWC Website",
|
||||
"url": "https://swc.rs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SWC Documentation",
|
||||
"url": "https://swc.rs/docs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SWC vs Babel: A Rust-Powered Speed Revolution",
|
||||
"url": "https://blog.logrocket.com/swc-vs-babel/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Why SWC is the Future of JavaScript Tooling",
|
||||
"url": "https://dev.to/somelink/why-swc-is-the-future-of-javascript-tooling",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about SWC",
|
||||
"url": "https://app.daily.dev/tags/swc?ref=roadmapsh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Introduction to SWC",
|
||||
"url": "https://www.youtube.com/watch?v=wlmbNWC3yB8",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"wA2fSYsbBYU02VJXAvUz8": {
|
||||
"title": "Astro",
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
"title": "HTML",
|
||||
"description": "HTML stands for HyperText Markup Language. It is used on the frontend and gives the structure to the webpage which you can style using CSS and make interactive using JavaScript.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Interactive HTML Course",
|
||||
"url": "https://github.com/denysdovhan/learnyouhtml",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools: Learn HTML",
|
||||
"url": "https://www.w3schools.com/html/html_intro.asp",
|
||||
@@ -14,13 +19,18 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "HTML Full Course for Beginners",
|
||||
"url": "https://youtu.be/mJgBOIoGihA",
|
||||
"title": "HTML Full Course - Build a Website Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=pQN-pnXPaVg",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML Full Course - Build a Website Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=pQN-pnXPaVg",
|
||||
"title": "HTML Tutorial for Beginners: HTML Crash Course",
|
||||
"url": "https://www.youtube.com/watch?v=qz0aGYrrlhU",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML and CSS Full Course - Beginner To Pro",
|
||||
"url": "https://youtu.be/a_iQb1lnAEQ",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
@@ -35,8 +45,13 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Web.dev by Google — Learn CSS",
|
||||
"url": "https://web.dev/learn/css/",
|
||||
"title": "Learn to Code HTML & CSS",
|
||||
"url": "https://learn.shayhowe.com/html-css/building-your-first-web-page/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What The Flexbox!",
|
||||
"url": "https://flexbox.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -45,24 +60,29 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CSS Complete Course",
|
||||
"url": "https://youtu.be/n4R2E7O-Ngo",
|
||||
"title": "CSS Crash Course For Absolute Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=yfoY53QXEnI",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "HTML and CSS Tutorial",
|
||||
"url": "https://www.youtube.com/watch?v=D-h8L5hgW-w",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "CSS Masterclass - Tutorial & Course for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=FqmB-Zj2-PA",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"T9PB6WQf-Fa9NXKKvVOy_": {
|
||||
"title": "JavaScript",
|
||||
"description": "JavaScript allows you to add interactivity to your pages. Common examples that you may have seen on the websites are sliders, click interactions, popups and so on.\n\nVisit the following resources to learn more:",
|
||||
"description": "JavaScript allows you to add interactivity to your pages. Common examples that you may have seen on the websites are sliders, click interactions, popups and so on.\n\nVisit the following resources to learn more:\n\nWe also have this [JavaScript roadmap](/javascript). You don't need to follow it right now, just learn from some courses and revisit the roadmap later in your journey.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Visit Dedicated JavaScript Roadmap",
|
||||
"url": "/javascript",
|
||||
"title": "W3Schools – JavaScript Tutorial",
|
||||
"url": "https://www.w3schools.com/js/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -71,8 +91,8 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Build 30 Javascript projects in 30 days",
|
||||
"url": "https://javascript30.com/",
|
||||
"title": "Exploring JS: JavaScript books for programmers",
|
||||
"url": "https://exploringjs.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -84,6 +104,11 @@
|
||||
"title": "JavaScript Crash Course for Beginners",
|
||||
"url": "https://youtu.be/hdI2bqOjy3c?t=2",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Build a Netflix Landing Page Clone with HTML, CSS & JS",
|
||||
"url": "https://youtu.be/P7t13SGytRk",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -400,14 +400,8 @@
|
||||
},
|
||||
"lIb5MeDoqVj6HycveOgTS": {
|
||||
"title": "Computer Graphics",
|
||||
"description": "Computer Graphics is a subfield of computer science that studies methods for digitally synthesizing and manipulating visual content. It involves creating and manipulating visual content using specialized computer software and hardware. This field is primarily used in the creation of digital and video games, CGI in films, and also in visual effects for commercials. The field is divided into two major categories: **Raster graphics** and **Vector graphics**. Raster graphics, also known as bitmap, involve the representation of images through a dot matrix data structure, while Vector graphics involve the use of polygons to represent images in computer graphics. Both of these methods have their unique usage scenarios. Other concepts integral to the study of computer graphics include rendering (including both real-time rendering and offline rendering), animation, and 3D modeling. Generally, computer graphics skills are essential for game developers and animation experts.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How do Video Game Graphics Work?",
|
||||
"url": "https://www.youtube.com/watch?v=C8YtdC8mxTU",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "Computer Graphics is a subfield of computer science that studies methods for digitally synthesizing and manipulating visual content. It involves creating and manipulating visual content using specialized computer software and hardware. This field is primarily used in the creation of digital and video games, CGI in films, and also in visual effects for commercials. The field is divided into two major categories: **Raster graphics** and **Vector graphics**. Raster graphics, also known as bitmap, involve the representation of images through a dot matrix data structure, while Vector graphics involve the use of polygons to represent images in computer graphics. Both of these methods have their unique usage scenarios. Other concepts integral to the study of computer graphics include rendering (including both real-time rendering and offline rendering), animation, and 3D modeling. Generally, computer graphics skills are essential for game developers and animation experts.",
|
||||
"links": []
|
||||
},
|
||||
"JW5c_0JEtO-OiBoXUia6A": {
|
||||
"title": "Ray Tracing",
|
||||
@@ -436,14 +430,8 @@
|
||||
},
|
||||
"WVgozaQPFbYthZLWMbNUg": {
|
||||
"title": "Rendering Equation",
|
||||
"description": "The **Render Equation**, also known as the **Rendering Equation**, is a fundamental principle in computer graphics that serves as the basis for most advanced lighting algorithms today. First introduced by James Kajiya in 1986, it defines how light interacts with physical objects in a given environment. The equation tries to simulate light's behavior, taking into account aspects such as transmission, absorption, scattering, and emission. The equation can be computationally intensive to solve accurately. It's worth mentioning, however, that many methods have been developed to approximate and solve it, allowing the production of highly realistic images in computer graphics.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Interactive Graphics 12 - The Rendering Equation",
|
||||
"url": "https://www.youtube.com/watch?v=wawf7Am6xy0",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "The **Render Equation**, also known as the **Rendering Equation**, is a fundamental principle in computer graphics that serves as the basis for most advanced lighting algorithms today. First introduced by James Kajiya in 1986, it defines how light interacts with physical objects in a given environment. The equation tries to simulate light's behavior, taking into account aspects such as transmission, absorption, scattering, and emission. The equation can be computationally intensive to solve accurately. It's worth mentioning, however, that many methods have been developed to approximate and solve it, allowing the production of highly realistic images in computer graphics.",
|
||||
"links": []
|
||||
},
|
||||
"eI2jym4AAz3ani-lreSKE": {
|
||||
"title": "Reflection",
|
||||
@@ -492,14 +480,8 @@
|
||||
},
|
||||
"WK6fLWJq9Vh2ySVrSqd-U": {
|
||||
"title": "Color",
|
||||
"description": "In the realm of computer graphics, color plays an integral role. It can be defined in various color models such as RGB (Red, Green, Blue), CYMK (Cyan, Yellow, Magenta, Black), and others. RGB is a color model that combines the primary colors (red, green, blue) in different amounts to produce a spectrum of colors. This model is often used in digital displays. In contrast, CMYK is a color model used in color printing. It uses cyan, magyenta, yellow, and black as the primary colors. HSL (Hue, Saturation, Lightness) and HSV (Hue, Saturation, Value) are other useful models that represent colors based on human perceptions. Another important element of color in computer graphics is the color depth, also known as bit depth, which determines the number of colors that can be displayed at once.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pixar in a Box - Color",
|
||||
"url": "https://www.khanacademy.org/computing/pixar/animate/ball/v/intro-animation",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "In the realm of computer graphics, color plays an integral role. It can be defined in various color models such as RGB (Red, Green, Blue), CYMK (Cyan, Yellow, Magenta, Black), and others. RGB is a color model that combines the primary colors (red, green, blue) in different amounts to produce a spectrum of colors. This model is often used in digital displays. In contrast, CMYK is a color model used in color printing. It uses cyan, magyenta, yellow, and black as the primary colors. HSL (Hue, Saturation, Lightness) and HSV (Hue, Saturation, Value) are other useful models that represent colors based on human perceptions. Another important element of color in computer graphics is the color depth, also known as bit depth, which determines the number of colors that can be displayed at once.",
|
||||
"links": []
|
||||
},
|
||||
"1S1qPogijW2SQCiF7KLZe": {
|
||||
"title": "Visual Perception",
|
||||
@@ -706,14 +688,8 @@
|
||||
},
|
||||
"ztoW8fBY73Es624A_tjd7": {
|
||||
"title": "Behavior Tree",
|
||||
"description": "The **Behavior Tree** is a decision-making system used in game development, primarily for AI character behavior. These trees help define the actions an AI character will take, based on predefined tasks and conditions. The tree structure starts from a single root, branching out to nodes that represent these decisions or tasks. The tasks can be simple, such as moving from one point to another, or can be complex decisions like whether to attack or retreat. This kind of structure is advantageous because it is easy to add, remove, or modify tasks without breaking the tree or affecting other tasks. This makes it highly flexible and easy to manage, irrespective of the complexity of the tasks.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Unreal Engine 5 Tutorial - AI Part 2: Behavior Tree",
|
||||
"url": "https://www.youtube.com/watch?v=hbHqv9ov8IM&list=PL4G2bSPE_8uklDwraUCMKHRk2ZiW29R6e&index=3&t=16s",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "The **Behavior Tree** is a decision-making system used in game development, primarily for AI character behavior. These trees help define the actions an AI character will take, based on predefined tasks and conditions. The tree structure starts from a single root, branching out to nodes that represent these decisions or tasks. The tasks can be simple, such as moving from one point to another, or can be complex decisions like whether to attack or retreat. This kind of structure is advantageous because it is easy to add, remove, or modify tasks without breaking the tree or affecting other tasks. This makes it highly flexible and easy to manage, irrespective of the complexity of the tasks.",
|
||||
"links": []
|
||||
},
|
||||
"4ZCVUpYrCT14d_JULulLe": {
|
||||
"title": "Fuzzy Logic",
|
||||
@@ -772,25 +748,13 @@
|
||||
},
|
||||
"sz1047M8_kScjth84yPwU": {
|
||||
"title": "Decision Tree Learning",
|
||||
"description": "`Decision Tree Learning` is an important concept in game development, particularly in the development of artificial intelligence for game characters. It is a kind of machine learning method that is based on using decision tree models to predict or classify information. A decision tree is a flowchart-like model, where each internal node denotes a test on an attribute, each branch represents an outcome of that test, and each leaf node holds a class label (decision made after testing all attributes). By applying decision tree learning models, computer-controlled characters can make decisions based on different conditions or states. They play a key role in creating complex and interactive gameplay experiences, by enabling game characters to adapt to the player's actions and the ever-changing game environment.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Decision trees - A friendly introduction",
|
||||
"url": "https://www.youtube.com/watch?v=HkyWAhr9v8g",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "`Decision Tree Learning` is an important concept in game development, particularly in the development of artificial intelligence for game characters. It is a kind of machine learning method that is based on using decision tree models to predict or classify information. A decision tree is a flowchart-like model, where each internal node denotes a test on an attribute, each branch represents an outcome of that test, and each leaf node holds a class label (decision made after testing all attributes). By applying decision tree learning models, computer-controlled characters can make decisions based on different conditions or states. They play a key role in creating complex and interactive gameplay experiences, by enabling game characters to adapt to the player's actions and the ever-changing game environment.",
|
||||
"links": []
|
||||
},
|
||||
"ltkEyfuDxExs7knqs79ya": {
|
||||
"title": "Deep Learning",
|
||||
"description": "Deep Learning is a sub-field of machine learning, inspired by the structure and function of the human brain, specifically designed to process complex input/output transformations. It uses artificial neural networks with many layers (hence the term 'deep' learning) to model complex, non-linear hypotheses and discover hidden patterns within large datasets. Deep learning techniques are crucial in game development, primarily in creating intelligent behaviors and features in gaming agents, procedural content generation, and player profiling. You might have heard about the uses of deep learning technologies in popular, cutting-edge games like Google DeepMind's AlphaGo. Coding languages like Python, R, and frameworks like TensorFlow, Keras, and PyTorch are commonly used for deep learning tasks. Learning Deep Learning can be a prominent game-changer in your game development journey.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "But what is a neural network? | Chapter 1, Deep learning",
|
||||
"url": "https://www.youtube.com/watch?v=aircAruvnKk",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "Deep Learning is a sub-field of machine learning, inspired by the structure and function of the human brain, specifically designed to process complex input/output transformations. It uses artificial neural networks with many layers (hence the term 'deep' learning) to model complex, non-linear hypotheses and discover hidden patterns within large datasets. Deep learning techniques are crucial in game development, primarily in creating intelligent behaviors and features in gaming agents, procedural content generation, and player profiling. You might have heard about the uses of deep learning technologies in popular, cutting-edge games like Google DeepMind's AlphaGo. Coding languages like Python, R, and frameworks like TensorFlow, Keras, and PyTorch are commonly used for deep learning tasks. Learning Deep Learning can be a prominent game-changer in your game development journey.",
|
||||
"links": []
|
||||
},
|
||||
"AoH2r4EOHyZd8YaV24rBk": {
|
||||
"title": "Artificial Neural Network",
|
||||
@@ -845,14 +809,8 @@
|
||||
},
|
||||
"PuhXaRZ-Ql5PCqzMyz3en": {
|
||||
"title": "Translucency & Transparency",
|
||||
"description": "In the realm of physically-based rendering, **translucency** and **transparency** act as key aspects in creating visually authentic and compelling images. Transparency refers to the property of an object that allows light to pass through it unhindered, hence making the object clear or invisible. This is commonly seen in materials such as glass, clear plastic, and water. On the other hand, translucency describes how light interacts with a semi-transparent object. Instead of passing directly through, light enters the object, travels within for some distance and then exits at a different location. Common examples of such surfaces include human skin, marble, milk, or wax, which exhibit a soft, diffused lighting effect when light rays pass through them. The technique to achieve this effect in graphics involves subsurface scattering, where incoming light is scattered beneath the object's surface, illuminated it in a way that showcases the material's internal structure.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn OpenGL - Blending",
|
||||
"url": "https://learnopengl.com/Advanced-OpenGL/Blending",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "In the realm of physically-based rendering, **translucency** and **transparency** act as key aspects in creating visually authentic and compelling images. Transparency refers to the property of an object that allows light to pass through it unhindered, hence making the object clear or invisible. This is commonly seen in materials such as glass, clear plastic, and water. On the other hand, translucency describes how light interacts with a semi-transparent object. Instead of passing directly through, light enters the object, travels within for some distance and then exits at a different location. Common examples of such surfaces include human skin, marble, milk, or wax, which exhibit a soft, diffused lighting effect when light rays pass through them. The technique to achieve this effect in graphics involves subsurface scattering, where incoming light is scattered beneath the object's surface, illuminated it in a way that showcases the material's internal structure.",
|
||||
"links": []
|
||||
},
|
||||
"H3hkafXO9zqEnWuwHa38P": {
|
||||
"title": "Conservation of Energy",
|
||||
@@ -866,13 +824,7 @@
|
||||
},
|
||||
"YrQgfjsdLCIUxrwflpEHO": {
|
||||
"title": "Microsurface Scattering",
|
||||
"description": "Microsurface scattering, also known as sub-surface scattering, is an important phenomenon in Physically Based Rendering (PBR). This process involves the penetration of light into the surface of a material, where it is scattered by interacting with the material. In other words, when light strikes an object, rather than simply bouncing off the surface, some of it goes into the object and gets scattered around inside before getting re-emitted. It is key to achieving more realistic rendering of translucent materials like skin, marble, milk, and more. Consider it essential for replicating how light interacts with real-world materials in a convincing manner in your game.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "The 4 main types of subsurface scattering",
|
||||
"url": "https://www.youtube.com/watch?v=GkjvYSbGHg4",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "Microsurface scattering, also known as sub-surface scattering, is an important phenomenon in Physically Based Rendering (PBR). This process involves the penetration of light into the surface of a material, where it is scattered by interacting with the material. In other words, when light strikes an object, rather than simply bouncing off the surface, some of it goes into the object and gets scattered around inside before getting re-emitted. It is key to achieving more realistic rendering of translucent materials like skin, marble, milk, and more. Consider it essential for replicating how light interacts with real-world materials in a convincing manner in your game.",
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "About repositories",
|
||||
"url": "https://docs.github.com/en/repositories/creating-and-managing-repositories/about-repositories",
|
||||
"url": "hhttps://docs.github.com/en/repositories/creating-and-managing-repositories/about-repositories",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -1266,7 +1266,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "--soft documentation",
|
||||
"url": "https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---soft",
|
||||
"url": "https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---hard",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "--mixed documentation",
|
||||
"url": "https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---mixed",
|
||||
"url": "https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---hard",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1416,14 +1416,8 @@
|
||||
},
|
||||
"BKVA6Q7DXemAYjyQOA0nh": {
|
||||
"title": "git filter-branch",
|
||||
"description": "You can use `git filter-branch` to rewrite Git revision history by applying custom filters on each revision.\n\n* Filter types: You can modify trees (e.g., removing a file or running a Perl script) or information about each commit.\n* Preserving original data: The command preserves all original commit times, merge information, and other details unless specified otherwise.\n* Rewriting specific branches: Only the positive refs mentioned in the command line are rewritten; if no filters are specified, commits are recommitted without changes.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "git filter-branch",
|
||||
"url": "https://git-scm.com/docs/git-filter-branch",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "You can use `git filter-branch` to rewrite Git revision history by applying custom filters on each revision.",
|
||||
"links": []
|
||||
},
|
||||
"OQOmxg9mCfcjt80hpvXkA": {
|
||||
"title": "git push --force",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "JavaScript, often abbreviated JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS. It lets us add interactivity to pages e.g. you might have seen sliders, alerts, click interactions, popups, etc on different websites -- all of that is built using JavaScript. Apart from being used in the browser, it is also used in other non-browser environments as well such as Node.js for writing server-side code in JavaScript, Electron for writing desktop applications, React Native for mobile applications, and so on.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "You Don't Know JS Yet (book series)",
|
||||
"title": "You Dont Know JS Yet (book series)",
|
||||
"url": "https://github.com/getify/You-Dont-Know-JS",
|
||||
"type": "opensource"
|
||||
},
|
||||
@@ -200,7 +200,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Understanding Hoisting",
|
||||
"title": "Understanding hoisting ",
|
||||
"url": "https://www.digitalocean.com/community/tutorials/understanding-hoisting-in-javascript",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -307,7 +307,7 @@
|
||||
},
|
||||
"q85z6x1Lc-yLWepwtIT2_": {
|
||||
"title": "const",
|
||||
"description": "Constants are block-scoped, much like variables declared using the `let` keyword. The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be re-declared (i.e. through a variable declaration). However, if a constant is an object or array its properties or items can be updated or removed.\n\nVisit the following resources to learn more:",
|
||||
"description": "Constants are block-scoped, much like variables declared using the `let` keyword. The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be redeclared (i.e. through a variable declaration). However, if a constant is an object or array its properties or items can be updated or removed.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "JavaScript Constants - CodeGuage",
|
||||
@@ -360,7 +360,7 @@
|
||||
},
|
||||
"oC4o6GLEES_nUgCJu9Q6I": {
|
||||
"title": "Global",
|
||||
"description": "Variables declared Globally (outside any function) have Global Scope. Global variables can be accessed from anywhere in a JavaScript program. Variables declared with `var`, `let` and `const` are quite similar when declared outside a block.\n\nNote\n----\n\nIf you assign a value to a variable that has not been declared i.e `potato = true` it will automatically become a _GLOBAL_ variable.\n\nVisit the following resources to learn more:",
|
||||
"description": "Variables declared Globally (outside any function) have Global Scope. Global variables can be accessed from anywhere in a JavaScript program. Variables declared with `var`, `let` and `const` are quite similar when declared outside a block.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "JavaScript Scope",
|
||||
@@ -423,7 +423,7 @@
|
||||
},
|
||||
"1RcwBHU3jzx0YxxUGZic4": {
|
||||
"title": "string",
|
||||
"description": "String is a primitive type that holds a sequence of characters. String in Javascript is written within a pair of single quotation marks `''`, double quotation marks `\"\"`, or backticks ` `` ` (template literals). All types of quotes can be used to contain a string but only if the starting quote is the same as the end quote.\n\nVisit the following resources to learn more:",
|
||||
"description": "String is a primitive type that holds a sequence of characters. String in Javascript is written within a pair of single quotation marks `''` or double quotation marks `\"\"`. Both quotes can be used to contain a string but only if the starting quote is the same as the end quote.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "String",
|
||||
@@ -445,7 +445,7 @@
|
||||
},
|
||||
"GZ_SXsWmP7AsXRTc4WUMw": {
|
||||
"title": "number",
|
||||
"description": "The `Number` data type in JavaScript represents floating-point numbers, such as 37 or -9.25. The `Number` constructor provides constants and methods to work with numbers, and values of other types can be converted to numbers using the `Number()` function.\n\nExample\n-------\n\n let num1 = 255; // integer\n let num2 = 255.0; // floating-point number with no fractional part\n let num3 = 0xff; // hexadecimal notation\n let num4 = 0b11111111; // binary notation\n let num5 = 0.255e3; // exponential notation\n \n console.log(num1 === num2); // true\n console.log(num1 === num3); // true\n console.log(num1 === num4); // true\n console.log(num1 === num5); // true\n \n\nIn this example:\n\n* `255` and `255.0` are equivalent, as JavaScript treats both as the same number.\n* `0xff` represents `255` in hexadecimal notation.\n* `0b11111111` represents `255` in binary notation.\n* `0.255e3` is `255` in exponential notation.\n* All these different representations are equal to `255` in JavaScript.",
|
||||
"description": "The `Number` data type in JavaScript represents floating-point numbers, such as 37 or -9.25. The `Number` constructor provides constants and methods to work with numbers, and values of other types can be converted to numbers using the `Number()` function.\n\n### Example\n\n let num1 = 255; // integer\n let num2 = 255.0; // floating-point number with no fractional part\n let num3 = 0xff; // hexadecimal notation\n let num4 = 0b11111111; // binary notation\n let num5 = 0.255e3; // exponential notation\n \n console.log(num1 === num2); // true\n console.log(num1 === num3); // true\n console.log(num1 === num4); // true\n console.log(num1 === num5); // true\n \n\nIn this example:\n\n* `255` and `255.0` are equivalent, as JavaScript treats both as the same number.\n* `0xff` represents `255` in hexadecimal notation.\n* `0b11111111` represents `255` in binary notation.\n* `0.255e3` is `255` in exponential notation.\n* All these different representations are equal to `255` in JavaScript.",
|
||||
"links": []
|
||||
},
|
||||
"6lUF0neW1piiP1RsaVxEX": {
|
||||
@@ -580,12 +580,12 @@
|
||||
"description": "You can use the typeOf operator to find the data type of a JavaScript variable. It returns a string indicating the type of provided operand's value.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "typeof Reference",
|
||||
"title": "Typeof Reference",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "typeof Live Examples",
|
||||
"title": "Typeof Live Examples",
|
||||
"url": "https://www.w3schools.com/js/tryit.asp?filename=tryjs_typeof_all",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -695,7 +695,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What you need to know about JavaScript Implicit Coercion",
|
||||
"title": "What you need to know about Javascripts Implicit Coercion",
|
||||
"url": "https://dev.to/promisetochi/what-you-need-to-know-about-javascripts-implicit-coercion-e23",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1245,7 +1245,7 @@
|
||||
},
|
||||
"-z-4VTaC3tOThqChgyoMs": {
|
||||
"title": "Error Objects",
|
||||
"description": "When a runtime error occurs, a new `Error` object is created and thrown. With this `Error` object, we can determine the type of the Error and handle it according to its type.\n\nTypes of Errors\n---------------\n\nBesides error constructors, Javascript also has other core Error constructors. Like\n\n* AggregateError - A collection of errors thrown simultaneously.\n* EvalError - An error occurred during the evaluation of a JavaScript expression.\n* InternalError - An internal JavaScript error, often indicating a bug in the engine.\n* RangeError - A value is outside the allowed range for a given operation.\n* ReferenceError - A variable or object is referenced before it's declared or doesn't exist.\n* SyntaxError - The code contains incorrect syntax, preventing it from being parsed.\n\nExample\n-------\n\n try {\n willGiveErrorSometime();\n } catch (error) {\n if (error instanceof RangeError) {\n rangeErrorHandler(error);\n } else if (error instanceof ReferenceError) {\n referenceErrorHandle(error);\n } else {\n errorHandler(error);\n }\n }\n \n\nVisit the following resources to learn more:",
|
||||
"description": "When a runtime error occurs, a new `Error` object is created and thrown. With this `Error` object, we can determine the type of the Error and handle it according to its type.\n\nTypes of Errors:\n----------------\n\nBesides error constructors, Javascript also has other core Error constructors.\n\n* [@article@AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError)\n* [@article@EvalError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError)\n* [@article@InternalError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/InternalError)\n* [@article@RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError)\n* [@article@ReferenceError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError)\n* [@article@SyntaxError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError)\n\nExample\n-------\n\n try {\n willGiveErrorSometime();\n } catch (error) {\n if (error instanceof RangeError) {\n rangeErrorHandler(error);\n } else if (error instanceof ReferenceError) {\n referenceErrorHandle(error);\n } else {\n errorHandler(error);\n }\n }\n \n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Error Object - MDN",
|
||||
@@ -1256,36 +1256,6 @@
|
||||
"title": "Control flow & Error handling - MDN",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "AggregateError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "EvalError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "InternalError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/InternalError",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "RangeError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "ReferenceError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SyntaxError",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1445,7 +1415,7 @@
|
||||
]
|
||||
},
|
||||
"k9rSR-YQ8B_iRcXNm2btP": {
|
||||
"title": "Unary Operators",
|
||||
"title": "Unary Opeartors",
|
||||
"description": "JavaScript Unary Operators are the special operators that consider a single operand and perform all the types of operations on that single operand. These operators include unary plus, unary minus, prefix increments, postfix increments, prefix decrements, and postfix decrements.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
@@ -1510,7 +1480,7 @@
|
||||
},
|
||||
"fr0NChxMXLpJizyMhXcXS": {
|
||||
"title": "Arrow Functions",
|
||||
"description": "Arrow Function is a new way of creating functions with the '=>' operator with a shorter syntax.\n\nExample\n-------\n\n const sayHello = () => {\n console.log(`Hello from Arrow Function !`);\n }\n \n\nVisit the following resources to learn more:",
|
||||
"description": "Arrow Function is a new way of creating functions with the '=>' operator with a shorter syntax.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "MDN - Arrow Function Expressions",
|
||||
@@ -1526,7 +1496,7 @@
|
||||
},
|
||||
"YZlCoPvZuX5MmpLOTj5d4": {
|
||||
"title": "IIFEs",
|
||||
"description": "Immediately-Invoked Function Expression is a function that is executed immediately after it is created.\n\nExample\n-------\n\n // An Async IIFE\n ( async() => {\n \n const x = 1;\n const y = 9;\n \n console.log(`Hello, The Answer is ${x+y}`);\n \n })();\n \n\nVisit the following resources to learn more:",
|
||||
"description": "Immediately-Invoked Function Expression is a function that is executed immediately after it is created.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "IIFE — MDN Docs",
|
||||
@@ -1809,46 +1779,18 @@
|
||||
},
|
||||
"gsyY3Oa3Jf0W5K_lyqBYO": {
|
||||
"title": "call",
|
||||
"description": "The `call()` method allows you to invoke a function with a given `this` value, and arguments provided individually.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Call Method - MDN Docs",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"-BtF34cEzI6J8sZCDRlRE": {
|
||||
"title": "apply",
|
||||
"description": "The apply() method of Function instances calls this function with a given this value, and arguments provided as an array (or an array-like object).\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "apply() - MDN",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"dbercnxXVTJXMpYSDNGb2": {
|
||||
"title": "bind",
|
||||
"description": "The `bind()` method in JavaScript allows you to create a new function with a specific context and optionally preset arguments. Unlike `call()` or `apply()`, `bind()` does not immediately invoke the function. Instead, it returns a new function that can be called later, either as a regular function or with additional arguments. This is particularly useful when you want to ensure that a function retains a specific context, regardless of how or when it's invoked.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "bind()",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Function binding",
|
||||
"url": "https://javascript.info/bind",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Javascript Function Bind()",
|
||||
"url": "https://www.w3schools.com/js/js_function_bind.asp",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"sFOqx6_7poVIVuXhJVY0E": {
|
||||
"title": "Asynchronous JavaScript",
|
||||
@@ -1993,7 +1935,7 @@
|
||||
},
|
||||
"PJSdqvh5OBwPCNpn3q_S5": {
|
||||
"title": "Callback Hell",
|
||||
"description": "The callback hell is when we try to write asynchronous JavaScript in a way where execution happens visually from top to bottom, creating a code that has a pyramid shape with many **})** at the end.\n\nVisit the following resources to learn more:",
|
||||
"description": "The callback hell is when we try to write asynchronous JavaScript in a way where execution happens visually from top to bottom, creating a code that has a pyramid shape with many }) at the end.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Callbacks in Callbacks - Pyramid of Doom",
|
||||
@@ -2056,7 +1998,7 @@
|
||||
},
|
||||
"kL5rfWxXe4J44ENru1uJS": {
|
||||
"title": "Fetch",
|
||||
"description": "The `fetch()` method in JavaScript is used to request to the server and load the information on the webpages. The request can be of any APIs that return the data of the format JSON or XML. This method returns a promise.\n\nVisit the following resources to learn more:",
|
||||
"description": "The fetch() method in JavaScript is used to request to the server and load the information on the webpages. The request can be of any APIs that return the data of the format JSON or XML. This method returns a promise.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Fetch MDN Docs",
|
||||
@@ -2171,7 +2113,7 @@
|
||||
},
|
||||
"4EXeGkOpfAViB9Uo4zL6O": {
|
||||
"title": "CommonJS",
|
||||
"description": "CommonJS modules are the original way to package JavaScript code for Node.js. Node.js also supports the ESModules standard used by browsers and other JavaScript run-times, but CJS is still widely used in backend Node.js applications. Sometimes these modules will be written with a .cjs extension.\n\nVisit the following resources to learn more:",
|
||||
"description": "CommonJS modules are the original way to package JavaScript code for Node.js. Node.js also supports the ESModules standard used by browsers and other JavaScript runtimes, but CJS is still widely used in backend Node.js applications. Sometimes these modules will be written with a .cjs extension.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How the CJS Module System Works",
|
||||
@@ -2255,7 +2197,7 @@
|
||||
},
|
||||
"bhuGtcyqPFKu-900aESYz": {
|
||||
"title": "DOM APIs",
|
||||
"description": "With HTML DOM, JavaScript can access and change all the elements of an HTML document such as its attributes, CSS styles, remove elements, add and create new elements on the page. Web API means application programming interface for the web. All browsers have a set of built-in Web APIs to support complex operations, and to help accessing data. Like Geo-location API, Web Storage, Web History and others.\n\nVisit the following resources to learn more:",
|
||||
"description": "With HTML DOM, JavaScript can access and change all the elements of an HTML document such as its attributes, CSS styles, remove elements, add and create new elements on the page. Web API means application programming inteface for the web. All browsers have a set og built-in Web APIs to support complex operations, and to help accessing data. Like Geolocation API, Web Storage, Web History and others.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "DOM- MDN Docs",
|
||||
@@ -2287,16 +2229,11 @@
|
||||
},
|
||||
"rc5WzBBOm2cus-rQl8EOE": {
|
||||
"title": "Using Browser DevTools",
|
||||
"description": "These are a set of tools built into the browser to aid frontend developers diagnose and solve various issues in their applications — such as JavaScript and logical bugs, CSS styling issues or even just making quick temporary alterations to the DOM.\n\nTo enter the dev tools, right click and click **Inspect** (or press `ctrl+shift+c`/`cmd+opt+c`) to enter the Elements panel. Here you can debug CSS and HTML issues. If you want to see logged messages or interact with javascript, enter the **Console** tab from the tabs above (or press `ctrl+shift+j` or `F12` / `cmd+opt+j` to enter it directly). Another very useful feature in the Chrome dev tools is the Lighthouse (for checking performance).\n\nNOTE: This isn't a chrome-specific feature, and most browsers (Chromium based or otherwise) will have their own, largely-similar set of devtools.\n\nVisit the following resources to learn more:",
|
||||
"description": "These are a set of tools built into the browser to aid frontend developers diagnose and solve various issues in their applications — such as JavaScript and logical bugs, CSS styling issues or even just making quick temporary alterations to the DOM.\n\nTo enter the dev tools, right click and click **Inspect** (or press `ctrl+shift+c`/`cmd+opt+c`) to enter the Elements panel. Here you can debug CSS and HTML issues. If you want to see logged messages or interact with javascript, enter the **Console** tab from the tabs above (or press `ctrl+shift+j` or `F12` /`cmd+opt+j` to enter it directly). Another very useful feature in the Chrome dev tools is the Lighthouse (for checking performance).\n\nNOTE: This isn't a chrome-specific feature, and most browsers (Chromium based or otherwise) will have their own, largely-similar set of devtools.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Docs",
|
||||
"url": "https://developer.chrome.com/docs/devtools/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Debug JavaScript with Chrome Dev Tools",
|
||||
"url": "https://developer.chrome.com/docs/devtools/javascript/",
|
||||
"url": "https://developer.chrome.com/docs/devtools/overview/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -2327,7 +2264,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Effective Javascript Debugging",
|
||||
"title": "Effective Javascript Debugging ",
|
||||
"url": "https://medium.com/swlh/effective-javascript-debugging-memory-leaks-75059b2436f6",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2350,7 +2287,7 @@
|
||||
},
|
||||
"ECxISKUAU7js_JsfSHzud": {
|
||||
"title": "Debugging Performance",
|
||||
"description": "Enter the dev tools and check out the Lighthouse tab. This is essentially a series of tests which analyses the currently open website on a bunch of metrics related to performance, page speed, accessibility, etc. Feel free to run the tests by clicking the **Analyze Page Load** button (you might want to do this in an incognito tab to avoid errors arising from extensions you're using). Once you have the results, take your time and read through them (and do click through to the reference pages mentioned alongside each test result to know more about it!)\n\nVisit the following resources to learn more:",
|
||||
"description": "Enter the dev tools and check out the Lighthouse tab. This is essentially a series of tests which analyses the currently open website on a bunch of metrics related to performance, page speed, accessibility, etc. Feel free to run the tests by clicking the **Analyse Page Load** button (you might want to do this in an incognito tab to avoid errors arising from extensions you're using). Once you have the results, take your time and read through them (and do click through to the reference pages mentioned alongside each test result to know more about it!)\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Analyze runtime performance",
|
||||
|
||||
@@ -1616,11 +1616,6 @@
|
||||
"title": "Drizzle",
|
||||
"description": "Drizzle lets you build your project the way you want, without interfering with your project or structure. Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like or relational way, and take advantage of opt-in tools to make your developer experience amazing.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Drizzle Github",
|
||||
"url": "https://github.com/drizzle-team/drizzle-orm",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Drizzle Website",
|
||||
"url": "https://orm.drizzle.team/",
|
||||
@@ -1631,6 +1626,11 @@
|
||||
"url": "https://orm.drizzle.team/docs/overview",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Drizzle Github",
|
||||
"url": "https://github.com/drizzle-team/drizzle-orm",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Getting Started with Drizzle",
|
||||
"url": "https://dev.to/franciscomendes10866/getting-started-with-drizzle-orm-a-beginners-tutorial-4782",
|
||||
@@ -1942,11 +1942,6 @@
|
||||
"title": "Child Process Docs",
|
||||
"url": "https://nodejs.org/api/child_process.html#child-process",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Securing Node.js Against Command Injection",
|
||||
"url": "https://www.nodejs-security.com/blog/securing-your-nodejs-apps-by-analyzing-real-world-command-injection-examples",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -98,6 +98,11 @@
|
||||
"title": "Data Types",
|
||||
"description": "PostgreSQL offers a rich and diverse set of data types, catering to a wide range of applications and ensuring data integrity and performance. These include standard numeric types such as integers, floating-point numbers, and serial types for auto-incrementing fields. Character types like VARCHAR and TEXT handle varying lengths of text, while DATE, TIME, and TIMESTAMP support a variety of temporal data requirements. PostgreSQL also supports a comprehensive set of Boolean, enumerated (ENUM), and composite types, enabling more complex data structures. Additionally, it excels with its support for JSON and JSONB data types, allowing for efficient storage and querying of semi-structured data. The inclusion of array types, geometric data types, and the PostGIS extension for geographic data further extends PostgreSQL's versatility, making it a powerful tool for a broad spectrum of data management needs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "",
|
||||
"url": "https://www.instaclustr.com/blog/postgresql-data-types-mappings-to-sql-jdbc-and-java-data-types/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Data Types",
|
||||
"url": "https://www.postgresql.org/docs/current/datatype.html",
|
||||
@@ -107,11 +112,6 @@
|
||||
"title": "An introduction to PostgreSQL data types",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/introduction-to-data-types",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL® Data Types: Mappings to SQL, JDBC, and Java Data Types",
|
||||
"url": "https://www.instaclustr.com/blog/postgresql-data-types-mappings-to-sql-jdbc-and-java-data-types/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -95,17 +95,6 @@
|
||||
"title": "Type Conversion and Casting",
|
||||
"url": "https://www.programiz.com/python-programming/type-conversion-and-casting",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fNTb9y3zs1HPYclAmu_Wv": {
|
||||
"title": "Exceptions",
|
||||
"description": "Python exceptions are events that occur during the execution of a program and disrupt the normal flow of the program's instructions. When an exception is raised, it indicates that an error has occurred. Python provides a way to handle these exceptions using try-except blocks, allowing developers to manage errors gracefully and ensure the program can continue or exit smoothly.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Exceptions Documentation",
|
||||
"url": "https://docs.python.org/3/tutorial/errors.html#exceptions",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Python Exceptions: An Introduction",
|
||||
@@ -126,6 +115,17 @@
|
||||
"title": "Python Try Except",
|
||||
"url": "https://www.w3schools.com/python/python_try_except.asp",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fNTb9y3zs1HPYclAmu_Wv": {
|
||||
"title": "Exceptions",
|
||||
"description": "Python exceptions are events that occur during the execution of a program and disrupt the normal flow of the program's instructions. When an exception is raised, it indicates that an error has occurred. Python provides a way to handle these exceptions using try-except blocks, allowing developers to manage errors gracefully and ensure the program can continue or exit smoothly.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Exceptions Documentation",
|
||||
"url": "https://docs.python.org/3/tutorial/errors.html#exceptions",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Exception Handling in Python",
|
||||
@@ -227,16 +227,6 @@
|
||||
"title": "Loops in Python",
|
||||
"url": "https://www.geeksforgeeks.org/loops-in-python/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Python \"while\" Loops (Indefinite Iteration)",
|
||||
"url": "https://realpython.com/python-while-loop/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Python \"for\" Loops (Definite Iteration)",
|
||||
"url": "https://realpython.com/python-for-loop/#the-guts-of-the-python-for-loop",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1217,16 +1207,10 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"DS6nuAUhUYcqiJDmQisKM": {
|
||||
"black@DS6nuAUhUYcqiJDmQisKM.md": {
|
||||
"title": "black",
|
||||
"description": "black is a code formatter for Python. It is a tool that automatically formats Python code to adhere to the PEP 8 style guide. It is a great tool to use in your Python projects to ensure that your code is formatted consistently and correctly.",
|
||||
"links": [
|
||||
{
|
||||
"title": "black documentation",
|
||||
"url": "https://black.readthedocs.io/en/stable/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"tsh_vbhzKz1-H9Vh69tsK": {
|
||||
"title": "yapf",
|
||||
|
||||
@@ -220,18 +220,7 @@
|
||||
"0uiGsC5SWavNdlFqizkKe": {
|
||||
"title": "Rendering",
|
||||
"description": "React follows a declarative approach to rendering components, which means that developers specify what a component should look like, and React takes care of rendering the component to the screen. This is in contrast to an imperative approach, where developers would write code to manually manipulate the DOM (Document Object Model) to update the UI.\n\nThe virtual DOM (VDOM) is an important aspect of how React works. It is a lightweight in-memory representation of the DOM (Document Object Model), and it is used to optimize the rendering of components in a React application.\n\n* Components are written as JavaScript classes or functions that define a render method. The render method returns a description of what the component should look like, using JSX syntax.\n* When a component is rendered, React creates a virtual DOM (VDOM) representation of the component. The VDOM is a lightweight in-memory representation of the DOM, and it is used to optimize the rendering of components.\n* React compares the VDOM representation of the component with the previous VDOM representation (if it exists). If there are differences between the two VDOMs, React calculates the minimum number of DOM updates needed to bring the actual DOM into line with the new VDOM.\n* React updates the actual DOM with the minimum number of DOM updates needed to reflect the changes in the VDOM.\n\nThis process is known as reconciliation, and it is an important aspect of how React works. By using a declarative approach and a VDOM, React is able to optimize the rendering of components and improve the performance of web applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Rendering - Official Docs",
|
||||
"url": "https://legacy.reactjs.org/docs/rendering-elements.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Rendering in React - ui.dev",
|
||||
"url": "https://ui.dev/why-react-renders",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"links": []
|
||||
},
|
||||
"8OBlgDRUg-CTgDXY-QHyO": {
|
||||
"title": "Component Lifecycle",
|
||||
@@ -565,7 +554,7 @@
|
||||
},
|
||||
"t_laNdMmdLApYszqXRdWg": {
|
||||
"title": "useRef",
|
||||
"description": "`useRef` is a React hook that provides a way to create a mutable reference that persists across component re-renders. It stores a value that doesn't cause re-renders when it changes.\n\nVisit the following resources to learn more:",
|
||||
"description": "useRef is a React hook that provides a way to create a mutable reference that persists across component re-renders. It stores a value that doesn't cause re-renders when it changes.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "useRef",
|
||||
@@ -586,7 +575,7 @@
|
||||
},
|
||||
"w3bNp7OkehI1gjx8NzlC8": {
|
||||
"title": "useMemo",
|
||||
"description": "`useMemo` is a React hook that memoizes the result of a function. It is used to optimize performance by caching the result of a function and returning the cached result when the inputs to the function have not changed.\n\nLearn more from the following resources:",
|
||||
"description": "useMemo is a React hook that memorizes the result of a function. It is used to optimize performance by caching the result of a function and returning the cached result when the inputs to the function have not changed.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "useMemo Docs",
|
||||
@@ -602,7 +591,7 @@
|
||||
},
|
||||
"v48Mv0wQqjXbvy8x6gDjQ": {
|
||||
"title": "useReducer",
|
||||
"description": "`useReducer`: An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If you’re familiar with Redux, you already know how this works.)\n\nLearn more from the following resources:",
|
||||
"description": "useReducer: An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If you’re familiar with Redux, you already know how this works.)\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "useReducer Docs",
|
||||
@@ -686,23 +675,8 @@
|
||||
},
|
||||
"mkyU0ug8MXxV4biHuOity": {
|
||||
"title": "Hooks Best Practices",
|
||||
"description": "To fully leverage the capabilities of React Hooks, it is crucial to adopt best practices that not only enhance code readability but also optimize performance. By adhering to these practices, developers can create cleaner, more maintainable components that make the most of React's powerful features, leading to a more efficient and enjoyable development experience.\n\nLearn more from the following resources:",
|
||||
"description": "Learn the best practices for using React hooks from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Rules of Hooks",
|
||||
"url": "https://react.dev/reference/rules/rules-of-hooks/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "React Hooks Best Practices: Unlocking Efficiency and Elegance",
|
||||
"url": "https://medium.com/womenintechnology/react-hooks-best-practices-unlocking-efficiency-and-elegance-da23f7e1418a",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Mastering React Hooks: Best Practices and Common Pitfalls",
|
||||
"url": "https://dev.to/codesensei/mastering-react-hooks-best-practices-and-common-pitfalls-3d9i",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "React Hooks Cheat Sheet: Best Practices with Examples",
|
||||
"url": "https://blog.logrocket.com/react-hooks-cheat-sheet-solutions-common-problems/",
|
||||
@@ -720,12 +694,12 @@
|
||||
"description": "Routing is an essential concept in Single Page Applications (SPA). When your application is divided into separated logical sections, and all of them are under their own URL, your users can easily share links among each other.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to use Routing in React JS: A Comprehensive Guide.",
|
||||
"title": "How to use Routing in React JS: A Comprehensive Guide. ",
|
||||
"url": "https://blog.logrocket.com/react-router-v6-guide/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "React Router 6 – Tutorial for Beginners.",
|
||||
"title": "React Router 6 – Tutorial for Beginners. ",
|
||||
"url": "https://www.youtube.com/watch?v=59IXY5IDrBA",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -962,19 +936,8 @@
|
||||
},
|
||||
"thfnymb_UIiKxakKfiua5": {
|
||||
"title": "Component / Libraries",
|
||||
"description": "React component libraries are collections of pre-built, reusable components that can be used to speed up the development process. They can be styled using CSS in various ways, including traditional CSS files, CSS modules, and CSS-in-JS solutions like styled-components.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "MUI: React Component Library",
|
||||
"url": "https://mui.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NextUI.org",
|
||||
"url": "https://nextui.org/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "React component libraries are collections of pre-built, reusable components that can be used to speed up the development process. They can be styled using CSS in various ways, including traditional CSS files, CSS modules, and CSS-in-JS solutions like styled-components.",
|
||||
"links": []
|
||||
},
|
||||
"akVNUPOqaTXaSHoQFlkP_": {
|
||||
"title": "Panda CSS",
|
||||
@@ -1618,33 +1581,12 @@
|
||||
},
|
||||
"ElgRwv5LSVg5FXGx-2K2s": {
|
||||
"title": "TypeScript",
|
||||
"description": "TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"url": "https://www.typescriptlang.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The TypeScript Handbook",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/intro.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about TypeScript",
|
||||
"url": "https://app.daily.dev/tags/typescript?ref=roadmapsh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "TypeScript for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=BwuLxPH8IDs",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"K3RZ8ESxWCpLKHePF87Hy": {
|
||||
"title": "Zod",
|
||||
"description": "Zod is a TypeScript-first schema declaration and validation library. I'm using the term \"schema\" to broadly refer to any data type, from a simple string to a complex nested object.\n\nZod is designed to be as developer-friendly as possible. The goal is to eliminate duplicate type declarations. With Zod, you declare a validator once and Zod will automatically infer the static TypeScript type. It's easy to compose simpler types into complex data structures.\n\nVisit the following resources to learn more:",
|
||||
"description": "Zod is a TypeScript-first schema declaration and validation library. I'm using the term \"schema\" to broadly refer to any data type, from a simple string to a complex nested object.\n\nZod is designed to be as developer-friendly as possible. The goal is to eliminate duplicative type declarations. With Zod, you declare a validator once and Zod will automatically infer the static TypeScript type. It's easy to compose simpler types into complex data structures.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Zod Website",
|
||||
@@ -1729,24 +1671,8 @@
|
||||
},
|
||||
"y2dI1DVLWKAkv6VRpgaQa": {
|
||||
"title": "GSock",
|
||||
"description": "`GSAP` (GreenSock Animation Platform) is a framework-agnostic JavaScript animation library that turns developers into animation superheroes. Build high-performance animations that work in every major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths, generic objects...anything JavaScript can touch!\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GSAP: Homepage",
|
||||
"url": "https://gsap.com/docs/v3/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Beginner's Guide to the GreenSock Animation Platform",
|
||||
"url": "https://www.freecodecamp.org/news/the-beginners-guide-to-the-greensock-animation-platform-7dc9fd9eb826/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Intro to Greensock Web Animation",
|
||||
"url": "https://www.youtube.com/watch?v=EOa7ccPWvXg",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"_F3WMxhzaK9F8_-zHDDMF": {
|
||||
"title": "Suspense",
|
||||
|
||||
@@ -315,6 +315,11 @@
|
||||
"url": "https://www.tutorialspoint.com/typescript/index.htm",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Scrimba — TypeScript Basics",
|
||||
"url": "https://scrimba.com/learn/typescript",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about JavaScript",
|
||||
"url": "https://app.daily.dev/tags/javascript?ref=roadmapsh",
|
||||
@@ -1416,24 +1421,8 @@
|
||||
},
|
||||
"O7H6dt3Z7EKohxfJzwbPM": {
|
||||
"title": "Kanban",
|
||||
"description": "`Kanban` is a popular agile methodology that focuses on visualizing workflow and continuously improving that flow. It's a more flexible approach than Scrum, without the rigid framework.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What Is Kanban? A Simple Guide to Improve Efficiency.",
|
||||
"url": "https://businessmap.io/kanban-resources/getting-started/what-is-kanban",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Kanban Methodology: The Simplest Agile Framework ",
|
||||
"url": "https://kissflow.com/project/agile/kanban-methodology/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Kanban Methodology? The Ultimate Guide",
|
||||
"url": "https://www.wrike.com/kanban-guide/what-is-kanban/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"PKqwKvoffm0unwcFwpojk": {
|
||||
"title": "Scrum",
|
||||
@@ -1442,24 +1431,8 @@
|
||||
},
|
||||
"7fL9lSu4BD1wRjnZy9tM9": {
|
||||
"title": "XP",
|
||||
"description": "`Extreme Programming (XP)` is a popular agile software development framework that emphasizes speed, simplicity, and quality. It was developed by Kent Beck in the late 1990s and is based on five values:\n\n* **Communication**: Open and honest communication among team members and stakeholders is essential.\n* **Simplicity**: The simplest solution that works is always preferred.\n* **Feedback**: Continuous feedback from customers and team members is used to improve the product.\n* **Courage**: Team members must be willing to make changes and take risks.\n* **Respect**: Everyone on the team is treated with respect.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Extreme Programming (XP)?",
|
||||
"url": "https://www.agilealliance.org/glossary/xp/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "It's Values, Principles, And Practices",
|
||||
"url": "https://www.nimblework.com/agile/extreme-programming-xp/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Extreme Programming (XP)",
|
||||
"url": "https://scrum-master.org/en/extreme-programming-xp-a-beginners-guide-to-the-agile-method/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"cBWJ6Duw99tSKr7U6OW3A": {
|
||||
"title": "Networks",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -352,7 +352,7 @@
|
||||
"description": "The lifecycle meta-argument in Terraform customizes the behavior of resources during creation, update, and deletion. It includes settings such as create\\_before\\_destroy, which ensures a new resource is created before the old one is destroyed, preventing downtime. prevent\\_destroy protects resources from accidental deletion, and ignore\\_changes specifies attributes to ignore during updates, allowing external modifications without triggering Terraform changes. These options provide fine-grained control over resource management, ensuring that the desired state of infrastructure is maintained with minimal disruption and precise handling of resource lifecycles.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform Docs - lifecycle",
|
||||
"title": "Terraform Docs - for_each",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -535,7 +535,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Suppressing values in CLI output",
|
||||
"title": "Surpressing values in CLI output",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output",
|
||||
"type": "article"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "TypeScript Official Handbook",
|
||||
"title": "TypeScript Handbook",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -163,7 +163,7 @@
|
||||
"description": "The TypeScript Playground is a great tool to learn TypeScript. It allows you to write TypeScript code and see the JavaScript output. It also allows you to share your code with others.\n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TypeScript Official - Playground",
|
||||
"title": "TypeScript - Playground",
|
||||
"url": "https://www.typescriptlang.org/play",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -349,7 +349,7 @@
|
||||
"description": "The `never` type represents the type of values that never occur. For instance, `never` is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns. Variables also acquire the type never when narrowed by any type guards that can never be `true`.\n\nThe never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, `never` (except `never` itself). Even any isn’t assignable to `never`.\n\nExamples of functions returning never:\n\n // Function returning never must not have a reachable end point\n function error(message: string): never {\n throw new Error(message);\n }\n \n // Inferred return type is never\n function fail() {\n return error('Something failed');\n }\n \n // Function returning never must not have a reachable end point\n function infiniteLoop(): never {\n while (true) {}\n }\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Never Type",
|
||||
"title": "Never",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#the-never-type",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -379,14 +379,8 @@
|
||||
},
|
||||
"afTNr36VqeXoJpHxm2IoS": {
|
||||
"title": "as any",
|
||||
"description": "`any` is a special type in TypeScript that represents a value of any type. When a value is declared with the any type, the compiler will not perform any type checks or type inference on that value.\n\nFor example:\n\n let anyValue: any = 42;\n \n // we can assign any value to anyValue, regardless of its type\n anyValue = 'Hello, world!';\n anyValue = true;\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Arrays",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "`any` is a special type in TypeScript that represents a value of any type. When a value is declared with the any type, the compiler will not perform any type checks or type inference on that value.\n\nFor example:\n\n let anyValue: any = 42;\n \n // we can assign any value to anyValue, regardless of its type\n anyValue = 'Hello, world!';\n anyValue = true;",
|
||||
"links": []
|
||||
},
|
||||
"mjaL5ocLnM8VQlhUxW6KU": {
|
||||
"title": "Non-null Assertion",
|
||||
@@ -404,7 +398,7 @@
|
||||
"description": "TypeScript developers are often faced with a dilemma: we want to ensure that some expression matches some type, but also want to keep the most specific type of that expression for inference purposes.\n\nFor example:\n\n // Each property can be a string or an RGB tuple.\n const palette = {\n red: [255, 0, 0],\n green: '#00ff00',\n bleu: [0, 0, 255],\n // ^^^^ sacrebleu - we've made a typo!\n };\n \n // We want to be able to use array methods on 'red'...\n const redComponent = palette.red.at(0);\n \n // or string methods on 'green'...\n const greenNormalized = palette.green.toUpperCase();\n \n\nNotice that we’ve written `bleu`, whereas we probably should have written `blue`. We could try to catch that `bleu` typo by using a type annotation on palette, but we’d lose the information about each property.\n\n type Colors = 'red' | 'green' | 'blue';\n type RGB = [red: number, green: number, blue: number];\n \n const palette: Record<Colors, string | RGB> = {\n red: [255, 0, 0],\n green: '#00ff00',\n bleu: [0, 0, 255],\n // ~~~~ The typo is now correctly detected\n };\n // But we now have an undesirable error here - 'palette.red' \"could\" be a string.\n const redComponent = palette.red.at(0);\n \n\nThe `satisfies` operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression. As an example, we could use `satisfies` to validate that all the properties of palette are compatible with `string | number[]`:\n\n type Colors = 'red' | 'green' | 'blue';\n type RGB = [red: number, green: number, blue: number];\n \n const palette = {\n red: [255, 0, 0],\n green: '#00ff00',\n bleu: [0, 0, 255],\n // ~~~~ The typo is now caught!\n } satisfies Record<Colors, string | RGB>;\n \n // Both of these methods are still accessible!\n const redComponent = palette.red.at(0);\n const greenNormalized = palette.green.toUpperCase();\n \n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "satisfies Keyword",
|
||||
"title": "Satisfies Keyword",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -434,7 +428,7 @@
|
||||
},
|
||||
"qefnsugcveizVq2TORRgn": {
|
||||
"title": "Combining Types",
|
||||
"description": "In TypeScript, you can combine types using type union and type intersection.\n\nType Union\n----------\n\nThe union operator `|` is used to combine two or more types into a single type that represents all the possible types. For example:\n\n type stringOrNumber = string | number;\n let value: stringOrNumber = 'hello';\n \n value = 42;\n \n\nType Intersection\n-----------------\n\nThe intersection operator `&` is used to intersect two or more types into a single type that represents the properties of all the types. For example:\n\n interface A {\n a: string;\n }\n \n interface B {\n b: number;\n }\n \n type AB = A & B;\n let value: AB = { a: 'hello', b: 42 };\n \n\nLearn more from the following links:",
|
||||
"description": "In TypeScript, you can combine types using type union and type intersection.\n\n### Type Union:\n\nThe union operator `|` is used to combine two or more types into a single type that represents all the possible types. For example:\n\n type stringOrNumber = string | number;\n let value: stringOrNumber = 'hello';\n \n value = 42;\n \n\n### Type Intersection:\n\nThe intersection operator `&` is used to intersect two or more types into a single type that represents the properties of all the types. For example:\n\n interface A {\n a: string;\n }\n \n interface B {\n b: number;\n }\n \n type AB = A & B;\n let value: AB = { a: 'hello', b: 42 };\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Union Types in TypeScript",
|
||||
@@ -496,7 +490,7 @@
|
||||
"description": "The `keyof` operator in TypeScript is used to get the union of keys from an object type. Here's an example of how it can be used:\n\n interface User {\n name: string;\n age: number;\n location: string;\n }\n \n type UserKeys = keyof User; // \"name\" | \"age\" | \"location\"\n const key: UserKeys = 'name';\n \n\nIn this example, `UserKeys` is a type that represents the union of keys from the `User` interface, which is `\"name\"` | `\"age\"` | `\"location\"`. And a constant named `key` with the type `UserKeys` is declared with the value `\"name\"`.\n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "keyof Type Operator",
|
||||
"title": "Keyof Type Operator",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/2/keyof-types.html#handbook-content",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -652,14 +646,8 @@
|
||||
},
|
||||
"lvtTSHH9yBTCiLng8btnI": {
|
||||
"title": "Hybrid Types",
|
||||
"description": "In TypeScript, a hybrid type is a type that combines multiple types into a single type. The resulting type is considered a union of those types. This allows you to specify that a value can have multiple types, rather than just one.\n\nFor example, you can create a hybrid type that can accept either a string or a number:\n\n type StringOrNumber = string | number;\n \n\nYou can also use hybrid types to create more complex types that can represent a combination of several different types of values. For example:\n\n type Education = {\n degree: string;\n school: string;\n year: number;\n };\n \n type User = {\n name: string;\n age: number;\n email: string;\n education: Education;\n };\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Geeksforgeeks.org - Hybrid Types",
|
||||
"url": "https://www.geeksforgeeks.org/what-are-hybrid-types-in-typescript/#:~:text=Hybrid%20types%20are%20a%20combination,properties%20like%20a%20regular%20object.",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "In TypeScript, a hybrid type is a type that combines multiple types into a single type. The resulting type is considered a union of those types. This allows you to specify that a value can have multiple types, rather than just one.\n\nFor example, you can create a hybrid type that can accept either a string or a number:\n\n type StringOrNumber = string | number;\n \n\nYou can also use hybrid types to create more complex types that can represent a combination of several different types of values. For example:\n\n type Education = {\n degree: string;\n school: string;\n year: number;\n };\n \n type User = {\n name: string;\n age: number;\n email: string;\n education: Education;\n };",
|
||||
"links": []
|
||||
},
|
||||
"ib0jfZzukYOZ42AdJqt_W": {
|
||||
"title": "Classes",
|
||||
@@ -720,11 +708,6 @@
|
||||
"title": "Inheritance vs Polymorphism",
|
||||
"description": "Inheritance and polymorphism are two fundamental concepts in object-oriented programming, and they are supported in TypeScript as well.\n\nInheritance refers to a mechanism where a subclass inherits properties and methods from its parent class. This allows a subclass to reuse the code and behavior of its parent class while also adding or modifying its own behavior. In TypeScript, inheritance is achieved using the extends keyword.\n\nPolymorphism refers to the ability of an object to take on many forms. This allows objects of different classes to be treated as objects of a common class, as long as they share a common interface or inheritance hierarchy. In TypeScript, polymorphism is achieved through method overriding and method overloading.\n\n class Animal {\n makeSound(): void {\n console.log('Making animal sound');\n }\n }\n \n class Dog extends Animal {\n makeSound(): void {\n console.log('Bark');\n }\n }\n \n class Cat extends Animal {\n makeSound(): void {\n console.log('Meow');\n }\n }\n \n let animal: Animal;\n \n animal = new Dog();\n animal.makeSound(); // Output: Bark\n \n animal = new Cat();\n animal.makeSound(); // Output: Meow\n \n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Dev.to - Mastering OOP in TypeScript",
|
||||
"url": "https://dev.to/rajrathod/mastering-object-oriented-programming-with-typescript-encapsulation-abstraction-inheritance-and-polymorphism-explained-c6p",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Inheritance and Polymorphism In TypeScript",
|
||||
"url": "https://www.youtube.com/watch?v=Sn6K57YSuwU",
|
||||
@@ -810,7 +793,7 @@
|
||||
},
|
||||
"gBTem9Dp3IQLAkqGX4fOF": {
|
||||
"title": "Partial",
|
||||
"description": "The Partial type in TypeScript allows you to make all properties of a type optional. This is useful when you need to create an object with only a subset of the properties of an existing type.\n\nHere's an example of using the Partial type in TypeScript:\n\n interface User {\n name: string;\n age: number;\n email: string;\n }\n \n function createUser(user: Partial<User>): User {\n return {\n name: 'John Doe',\n age: 30,\n email: 'john.doe@example.com',\n ...user,\n };\n }\n \n const newUser = createUser({ name: 'Jane Doe' });\n \n console.log(newUser);\n // Output: { name: 'Jane Doe', age: 30, email: 'john.doe@example.com' }\n \n\nLearn more from the following links:\n\n@official@Partial",
|
||||
"description": "The Partial type in TypeScript allows you to make all properties of a type optional. This is useful when you need to create an object with only a subset of the properties of an existing type.\n\nHere's an example of using the Partial type in TypeScript:\n\n interface User {\n name: string;\n age: number;\n email: string;\n }\n \n function createUser(user: Partial<User>): User {\n return {\n name: 'John Doe',\n age: 30,\n email: 'john.doe@example.com',\n ...user,\n };\n }\n \n const newUser = createUser({ name: 'Jane Doe' });\n \n console.log(newUser);\n // Output: { name: 'Jane Doe', age: 30, email: 'john.doe@example.com' }\n \n\nLearn more from the following links:\n\n@article@Partial",
|
||||
"links": []
|
||||
},
|
||||
"E88tHQvARkHURZwGaO02l": {
|
||||
@@ -837,7 +820,7 @@
|
||||
},
|
||||
"IuO9-O_DQdDYuAbdGWdgb": {
|
||||
"title": "Readonly",
|
||||
"description": "Readonly constructs a type with all properties of Type set to readonly, meaning the properties of the constructed type cannot be reassigned.\n\n interface Todo {\n title: string;\n }\n \n const todo: Readonly<Todo> = {\n title: 'Delete inactive users',\n };\n \n // Cannot assign to 'title' because it is a read-only property.\n todo.title = 'Hello';\n \n\nLearn more from the following links:\n\n@official@Readonly",
|
||||
"description": "Readonly constructs a type with all properties of Type set to readonly, meaning the properties of the constructed type cannot be reassigned.\n\n interface Todo {\n title: string;\n }\n \n const todo: Readonly<Todo> = {\n title: 'Delete inactive users',\n };\n \n // Cannot assign to 'title' because it is a read-only property.\n todo.title = 'Hello';\n \n\nLearn more from the following links:\n\n@article@Readonly",
|
||||
"links": []
|
||||
},
|
||||
"DRdBmF5Dt_r09LoPOxOuq": {
|
||||
@@ -875,40 +858,28 @@
|
||||
},
|
||||
"_BAZlBEzE7ddr315OeHvl": {
|
||||
"title": "NonNullable",
|
||||
"description": "Non-Nullable constructs a type by excluding `null` and `undefined` from Type.\n\n type T0 = NonNullable<string | number | undefined>;\n // type T0 = string | number\n \n type T1 = NonNullable<string[] | null | undefined>;\n // type T1 = string[]\n \n\nLearn more from the following links:\n\n@official@NonNullable",
|
||||
"description": "Non-Nullable constructs a type by excluding `null` and `undefined` from Type.\n\n type T0 = NonNullable<string | number | undefined>;\n // type T0 = string | number\n \n type T1 = NonNullable<string[] | null | undefined>;\n // type T1 = string[]\n \n\nLearn more from the following links:\n\n@article@NonNullable",
|
||||
"links": []
|
||||
},
|
||||
"a7hl0iMZ-jcUACxqIYVqv": {
|
||||
"title": "Parameters",
|
||||
"description": "Parameters constructs a tuple type from the types used in the parameters of a function type Type.\n\n type T0 = Parameters<() => string>;\n // type T0 = []\n \n type T1 = Parameters<(s: string) => void>;\n // type T1 = [s: string]\n \n type T2 = Parameters<<T>(arg: T) => T>;\n // type T2 = [arg: unknown]\n \n declare function f1(arg: { a: number; b: string }): void;\n type T3 = Parameters<typeof f1>;\n // type T3 = [arg: {\n // a: number;\n // b: string;\n // }]\n \n type T4 = Parameters<any>;\n // type T4 = unknown[]\n \n type T5 = Parameters<never>;\n // type T5 = never\n \n type T6 = Parameters<string>;\n // ^ Type 'string' does not satisfy the constraint '(...args: any) => any'.\n \n type T7 = Parameters<Function>;\n // ^ Type 'Function' does not satisfy the constraint '(...args: any) => any'.\n \n\nLearn more from the following links:\n\n@official@Parameters",
|
||||
"description": "Parameters constructs a tuple type from the types used in the parameters of a function type Type.\n\n type T0 = Parameters<() => string>;\n // type T0 = []\n \n type T1 = Parameters<(s: string) => void>;\n // type T1 = [s: string]\n \n type T2 = Parameters<<T>(arg: T) => T>;\n // type T2 = [arg: unknown]\n \n declare function f1(arg: { a: number; b: string }): void;\n type T3 = Parameters<typeof f1>;\n // type T3 = [arg: {\n // a: number;\n // b: string;\n // }]\n \n type T4 = Parameters<any>;\n // type T4 = unknown[]\n \n type T5 = Parameters<never>;\n // type T5 = never\n \n type T6 = Parameters<string>;\n // ^ Type 'string' does not satisfy the constraint '(...args: any) => any'.\n \n type T7 = Parameters<Function>;\n // ^ Type 'Function' does not satisfy the constraint '(...args: any) => any'.\n \n\nLearn more from the following links:\n\n@article@Parameters",
|
||||
"links": []
|
||||
},
|
||||
"On75JR_UkiIlha0_qaSeu": {
|
||||
"title": "ReturnType",
|
||||
"description": "Return type constructs a type consisting of the return type of function Type.\n\n type T0 = ReturnType<() => string>;\n // type T0 = string\n \n type T1 = ReturnType<(s: string) => void>;\n // type T1 = void\n \n type T2 = ReturnType<<T>() => T>;\n // type T2 = unknown\n \n type T3 = ReturnType<<T extends U, U extends number[]>() => T>;\n // type T3 = number[]\n \n declare function f1(): { a: number; b: string };\n type T4 = ReturnType<typeof f1>;\n // type T4 = {\n // a: number;\n // b: string;\n // }\n \n type T5 = ReturnType<any>;\n // type T5 = any\n \n type T6 = ReturnType<never>;\n // type T6 = never\n \n type T7 = ReturnType<string>;\n // ^ Type 'string' does not satisfy the constraint '(...args: any) => any'.\n \n type T8 = ReturnType<Function>;\n // ^ Type 'Function' does not satisfy the constraint '(...args: any) => any'.\n \n\nLearn more from the following links:\n\n@official@ReturnType",
|
||||
"description": "Return type constructs a type consisting of the return type of function Type.\n\n type T0 = ReturnType<() => string>;\n // type T0 = string\n \n type T1 = ReturnType<(s: string) => void>;\n // type T1 = void\n \n type T2 = ReturnType<<T>() => T>;\n // type T2 = unknown\n \n type T3 = ReturnType<<T extends U, U extends number[]>() => T>;\n // type T3 = number[]\n \n declare function f1(): { a: number; b: string };\n type T4 = ReturnType<typeof f1>;\n // type T4 = {\n // a: number;\n // b: string;\n // }\n \n type T5 = ReturnType<any>;\n // type T5 = any\n \n type T6 = ReturnType<never>;\n // type T6 = never\n \n type T7 = ReturnType<string>;\n // ^ Type 'string' does not satisfy the constraint '(...args: any) => any'.\n \n type T8 = ReturnType<Function>;\n // ^ Type 'Function' does not satisfy the constraint '(...args: any) => any'.\n \n\nLearn more from the following links:\n\n@article@ReturnType",
|
||||
"links": []
|
||||
},
|
||||
"izGAjNtrh3BzQt3KiZX0W": {
|
||||
"title": "InstanceType",
|
||||
"description": "This type constructs a type consisting of the instance type of a constructor function in Type.\n\n class C {\n x = 0;\n y = 0;\n }\n \n type T0 = InstanceType<typeof C>;\n // type T0 = C\n \n type T1 = InstanceType<any>;\n // type T1 = any\n \n type T2 = InstanceType<never>;\n // type T2 = never\n \n type T3 = InstanceType<string>;\n // ^ Type 'string' does not satisfy the constraint 'abstract new (...args: any) => any'.\n \n type T4 = InstanceType<Function>;\n // ^ Type 'Function' does not satisfy the constraint 'abstract new (...args: any) => any'.\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "InstanceType<Type>",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "This type constructs a type consisting of the instance type of a constructor function in Type.\n\n class C {\n x = 0;\n y = 0;\n }\n \n type T0 = InstanceType<typeof C>;\n // type T0 = C\n \n type T1 = InstanceType<any>;\n // type T1 = any\n \n type T2 = InstanceType<never>;\n // type T2 = never\n \n type T3 = InstanceType<string>;\n // ^ Type 'string' does not satisfy the constraint 'abstract new (...args: any) => any'.\n \n type T4 = InstanceType<Function>;\n // ^ Type 'Function' does not satisfy the constraint 'abstract new (...args: any) => any'.\n \n\nLearn more from the following links:\n\n@article@InstanceType",
|
||||
"links": []
|
||||
},
|
||||
"aEhI_9mFWXRIZh1ZxTuzu": {
|
||||
"title": "Awaited",
|
||||
"description": "This type is meant to model operations like await in async functions, or the `.then()` method on Promises - specifically, the way that they recursively unwrap Promises.\n\n type A = Awaited<Promise<string>>;\n // type A = string\n \n type B = Awaited<Promise<Promise<number>>>;\n // type B = number\n \n type C = Awaited<boolean | Promise<number>>;\n // type C = number | boolean\n \n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Awaited<Type>",
|
||||
"url": "https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "This type is meant to model operations like await in async functions, or the `.then()` method on Promises - specifically, the way that they recursively unwrap Promises.\n\n type A = Awaited<Promise<string>>;\n // type A = string\n \n type B = Awaited<Promise<Promise<number>>>;\n // type B = number\n \n type C = Awaited<boolean | Promise<number>>;\n // type C = number | boolean\n \n\nLearn more from the following links:\n\n@article@Awaited",
|
||||
"links": []
|
||||
},
|
||||
"2F7vOL__v9dLBohA263aj": {
|
||||
"title": "Advanced Types",
|
||||
@@ -977,14 +948,8 @@
|
||||
},
|
||||
"N8xBTJ74xv1E5hSLYZtze": {
|
||||
"title": "Recursive Types",
|
||||
"description": "Recursive types in TypeScript are a way to define a type that references itself. Recursive types are used to define complex data structures, such as trees or linked lists, where a value can contain one or more values of the same type.\n\nFor example, the following is a recursive type that represents a linked list:\n\n type LinkedList<T> = {\n value: T;\n next: LinkedList<T> | null;\n };\n \n let list: LinkedList<number> = {\n value: 1,\n next: { value: 2, next: { value: 3, next: null } },\n };\n \n\nIn this example, the `LinkedList` type is defined as a type that extends `T` and contains a property `next` of the same type `LinkedList<T>`. This allows us to create a linked list where each node contains a value of type `T` and a reference to the next node in the list.\n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Recursive Types in TypeScript",
|
||||
"url": "https://www.typescriptlang.org/play/3-7/types-and-code-flow/recursive-type-references.ts.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"description": "Recursive types in TypeScript are a way to define a type that references itself. Recursive types are used to define complex data structures, such as trees or linked lists, where a value can contain one or more values of the same type.\n\nFor example, the following is a recursive type that represents a linked list:\n\n type LinkedList<T> = {\n value: T;\n next: LinkedList<T> | null;\n };\n \n let list: LinkedList<number> = {\n value: 1,\n next: { value: 2, next: { value: 3, next: null } },\n };\n \n\nIn this example, the `LinkedList` type is defined as a type that extends `T` and contains a property `next` of the same type `LinkedList<T>`. This allows us to create a linked list where each node contains a value of type `T` and a reference to the next node in the list.",
|
||||
"links": []
|
||||
},
|
||||
"sE9lqkkqwnsVJxTJv37YZ": {
|
||||
"title": "TypeScript Modules",
|
||||
|
||||
@@ -36,7 +36,7 @@ Here is the list of available roadmaps with more being actively worked upon.
|
||||
- [Backend Roadmap](https://roadmap.sh/backend) / [Backend Beginner Roadmap](https://roadmap.sh/backend?r=backend-beginner)
|
||||
- [DevOps Roadmap](https://roadmap.sh/devops) / [DevOps Beginner Roadmap](https://roadmap.sh/devops?r=devops-beginner)
|
||||
- [Full Stack Roadmap](https://roadmap.sh/full-stack)
|
||||
- [Git and GitHub](https://roadmap.sh/git-github)
|
||||
- [Git and GitHub Roadmap](https://roadmap.sh/git-github)
|
||||
- [API Design Roadmap](https://roadmap.sh/api-design)
|
||||
- [Computer Science Roadmap](https://roadmap.sh/computer-science)
|
||||
- [Data Structures and Algorithms Roadmap](https://roadmap.sh/datastructures-and-algorithms)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { type APIContext } from 'astro';
|
||||
import { api } from './api.ts';
|
||||
|
||||
export function projectApi(context: APIContext) {
|
||||
return {
|
||||
listProjectsUserCount: async function (projectIds: string[]) {
|
||||
return api(context).post<Record<string, number>>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-projects-user-count`,
|
||||
{
|
||||
projectIds,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { isLoggedIn } from '../../lib/jwt';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import {Flame, X, Zap, ZapOff} from 'lucide-react';
|
||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||
import { StreakDay } from './StreakDay';
|
||||
import {
|
||||
navigationDropdownOpen,
|
||||
roadmapsDropdownOpen,
|
||||
} from '../../stores/page.ts';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
type StreakResponse = {
|
||||
count: number;
|
||||
longestCount: number;
|
||||
previousCount?: number | null;
|
||||
firstVisitAt: Date;
|
||||
lastVisitAt: Date;
|
||||
};
|
||||
|
||||
type AccountStreakProps = {};
|
||||
|
||||
export function AccountStreak(props: AccountStreakProps) {
|
||||
const toast = useToast();
|
||||
const dropdownRef = useRef(null);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [accountStreak, setAccountStreak] = useState<StreakResponse>({
|
||||
count: 0,
|
||||
longestCount: 0,
|
||||
firstVisitAt: new Date(),
|
||||
lastVisitAt: new Date(),
|
||||
});
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
|
||||
const $roadmapsDropdownOpen = useStore(roadmapsDropdownOpen);
|
||||
const $navigationDropdownOpen = useStore(navigationDropdownOpen);
|
||||
|
||||
useEffect(() => {
|
||||
if ($roadmapsDropdownOpen || $navigationDropdownOpen) {
|
||||
setShowDropdown(false);
|
||||
}
|
||||
}, [$roadmapsDropdownOpen, $navigationDropdownOpen]);
|
||||
|
||||
const loadAccountStreak = async () => {
|
||||
if (!isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
const { response, error } = await httpGet<StreakResponse>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-streak`,
|
||||
);
|
||||
|
||||
if (error || !response) {
|
||||
toast.error(error?.message || 'Failed to load account streak');
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setAccountStreak(response);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
useOutsideClick(dropdownRef, () => {
|
||||
setShowDropdown(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadAccountStreak().finally(() => {});
|
||||
}, []);
|
||||
|
||||
if (!isLoggedIn() || isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let { count: currentCount } = accountStreak;
|
||||
const previousCount =
|
||||
accountStreak?.previousCount || accountStreak?.count || 0;
|
||||
|
||||
// Adding one to show the current day
|
||||
const currentCircleCount = Math.min(currentCount, 5) + 1;
|
||||
// Adding one day to show the streak they broke
|
||||
const leftCircleCount = Math.min(5 - currentCircleCount, previousCount) + 1;
|
||||
// In the maximum case, we will show 10 circles
|
||||
const remainingCount = Math.max(0, 10 - leftCircleCount - currentCircleCount);
|
||||
const totalCircles = leftCircleCount + currentCircleCount + remainingCount;
|
||||
|
||||
return (
|
||||
<div className="relative z-[90] animate-fade-in">
|
||||
<button
|
||||
className={cn(
|
||||
'flex items-center justify-center rounded-lg p-1.5 px-2 text-purple-400 hover:bg-purple-100/10 focus:outline-none',
|
||||
{
|
||||
'bg-purple-100/10': showDropdown,
|
||||
},
|
||||
)}
|
||||
onClick={() => setShowDropdown(true)}
|
||||
>
|
||||
<Zap strokeWidth={1} className="size-5 fill-current" />
|
||||
<span className="ml-1.5 text-sm font-semibold">
|
||||
{accountStreak?.count}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{showDropdown && (
|
||||
<div
|
||||
ref={dropdownRef}
|
||||
className="absolute right-0 top-full z-50 w-[335px] translate-y-1 rounded-lg bg-slate-800 shadow-xl"
|
||||
>
|
||||
<div className="pl-4 pr-5 py-3">
|
||||
<div className="flex items-center justify-between gap-2 text-sm text-slate-500">
|
||||
<p>
|
||||
Current Streak
|
||||
<span className="ml-2 font-medium text-white">
|
||||
{accountStreak?.count || 0}
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Longest Streak
|
||||
<span className="ml-2 font-medium text-white">
|
||||
{accountStreak?.longestCount || 0}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-5 mt-8">
|
||||
<div className="grid grid-cols-10 gap-1">
|
||||
{Array.from({ length: totalCircles }).map((_, index) => {
|
||||
let dayCount,
|
||||
icon,
|
||||
isPreviousStreakDay,
|
||||
isBrokenStreakDay,
|
||||
isCurrentStreakDay,
|
||||
isRemainingStreakDay,
|
||||
isToday;
|
||||
|
||||
if (index < leftCircleCount) {
|
||||
// Previous streak days
|
||||
dayCount = previousCount - leftCircleCount + index + 1 + 1;
|
||||
isPreviousStreakDay = true;
|
||||
isBrokenStreakDay = index === leftCircleCount - 1;
|
||||
|
||||
icon = isBrokenStreakDay ? (
|
||||
<ZapOff className="size-5 fill-current" />
|
||||
) : (
|
||||
<Zap className="size-5 fill-current" />
|
||||
);
|
||||
} else if (index < leftCircleCount + currentCircleCount) {
|
||||
// Current streak days
|
||||
const currentIndex = index - leftCircleCount;
|
||||
dayCount =
|
||||
currentCount - currentCircleCount + currentIndex + 1 + 1;
|
||||
isCurrentStreakDay = true;
|
||||
isToday = currentIndex === currentCircleCount - 1;
|
||||
icon = <Zap className="size-5 fill-current" />;
|
||||
} else {
|
||||
// Remaining streak days
|
||||
const remainingIndex =
|
||||
index - leftCircleCount - currentCircleCount;
|
||||
dayCount = currentCount + remainingIndex + 1 + 1;
|
||||
isRemainingStreakDay = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<StreakDay
|
||||
key={`streak-${index}`}
|
||||
dayCount={dayCount}
|
||||
icon={icon}
|
||||
isBrokenStreakDay={isBrokenStreakDay}
|
||||
isPreviousStreakDay={isPreviousStreakDay}
|
||||
isCurrentStreakDay={isCurrentStreakDay}
|
||||
isRemainingStreakDay={isRemainingStreakDay}
|
||||
isToday={isToday}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-center text-xs text-slate-600 tracking-wide mb-[1.75px] -mt-[0px]">
|
||||
Visit every day to keep your streak alive!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
.react-calendar-heatmap text {
|
||||
fill: rgb(148, 163, 184) !important;
|
||||
}
|
||||
|
||||
.react-calendar-heatmap rect:hover {
|
||||
stroke: rgb(148, 163, 184) !important;
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
import CalendarHeatmap from 'react-calendar-heatmap';
|
||||
import dayjs from 'dayjs';
|
||||
import { formatActivityDate } from '../../lib/date';
|
||||
import { Tooltip as ReactTooltip } from 'react-tooltip';
|
||||
import 'react-calendar-heatmap/dist/styles.css';
|
||||
import './AccountStreakHeatmap.css';
|
||||
|
||||
const legends = [
|
||||
{ count: 1, color: 'bg-slate-600' },
|
||||
{ count: 3, color: 'bg-slate-500' },
|
||||
{ count: 5, color: 'bg-slate-400' },
|
||||
{ count: 10, color: 'bg-slate-300' },
|
||||
{ count: 20, color: 'bg-slate-200' },
|
||||
];
|
||||
|
||||
type AccountStreakHeatmapProps = {};
|
||||
|
||||
export function AccountStreakHeatmap(props: AccountStreakHeatmapProps) {
|
||||
const startDate = dayjs().subtract(6, 'months').toDate();
|
||||
const endDate = dayjs().toDate();
|
||||
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<CalendarHeatmap
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
values={[
|
||||
{
|
||||
date: '2024-08-01',
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
date: '2024-08-02',
|
||||
count: 10,
|
||||
},
|
||||
{
|
||||
date: '2024-08-03',
|
||||
count: 5,
|
||||
},
|
||||
{
|
||||
date: '2024-08-04',
|
||||
count: 3,
|
||||
},
|
||||
{
|
||||
date: '2024-08-05',
|
||||
count: 7,
|
||||
},
|
||||
{
|
||||
date: '2024-08-06',
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
date: '2024-08-07',
|
||||
count: 6,
|
||||
},
|
||||
{
|
||||
date: '2024-08-08',
|
||||
count: 8,
|
||||
},
|
||||
{
|
||||
date: '2024-08-09',
|
||||
count: 9,
|
||||
},
|
||||
{
|
||||
date: '2024-08-10',
|
||||
count: 1,
|
||||
},
|
||||
{
|
||||
date: '2024-08-11',
|
||||
count: 3,
|
||||
},
|
||||
{
|
||||
date: '2024-08-12',
|
||||
count: 5,
|
||||
},
|
||||
{
|
||||
date: '2024-08-13',
|
||||
count: 7,
|
||||
},
|
||||
{
|
||||
date: '2024-08-14',
|
||||
count: 8,
|
||||
},
|
||||
{
|
||||
date: '2024-08-15',
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
date: '2024-08-16',
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
date: '2024-08-17',
|
||||
count: 6,
|
||||
},
|
||||
{
|
||||
date: '2024-08-18',
|
||||
count: 8,
|
||||
},
|
||||
{
|
||||
date: '2024-08-19',
|
||||
count: 10,
|
||||
},
|
||||
{
|
||||
date: '2024-08-20',
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
date: '2024-08-21',
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
date: '2024-08-22',
|
||||
count: 6,
|
||||
},
|
||||
{
|
||||
date: '2024-08-23',
|
||||
count: 8,
|
||||
},
|
||||
{
|
||||
date: '2024-08-24',
|
||||
count: 10,
|
||||
},
|
||||
{
|
||||
date: '2024-08-25',
|
||||
count: 30,
|
||||
},
|
||||
]}
|
||||
classForValue={(value) => {
|
||||
if (!value) {
|
||||
return 'fill-slate-700 rounded-md [rx:2px] focus:outline-none';
|
||||
}
|
||||
|
||||
const { count } = value;
|
||||
if (count >= 20) {
|
||||
return 'fill-slate-200 rounded-md [rx:2px] focus:outline-none';
|
||||
} else if (count >= 10) {
|
||||
return 'fill-slate-300 rounded-md [rx:2px] focus:outline-none';
|
||||
} else if (count >= 5) {
|
||||
return 'fill-slate-400 rounded-md [rx:2px] focus:outline-none';
|
||||
} else if (count >= 3) {
|
||||
return 'fill-slate-500 rounded-md [rx:2px] focus:outline-none';
|
||||
} else {
|
||||
return 'fill-slate-600 rounded-md [rx:2px] focus:outline-none';
|
||||
}
|
||||
}}
|
||||
tooltipDataAttrs={(value: any) => {
|
||||
if (!value || !value.date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const formattedDate = formatActivityDate(value.date);
|
||||
return {
|
||||
'data-tooltip-id': 'user-activity-tip',
|
||||
'data-tooltip-content': `${value.count} Updates - ${formattedDate}`,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
|
||||
<ReactTooltip
|
||||
id="user-activity-tip"
|
||||
className="!rounded-lg !bg-slate-900 !p-1 !px-2 !text-xs"
|
||||
/>
|
||||
|
||||
<div className="mt-2 flex items-center justify-end">
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 text-xs text-slate-500">Less</span>
|
||||
{legends.map((legend) => (
|
||||
<div
|
||||
key={legend.count}
|
||||
className="flex items-center"
|
||||
data-tooltip-id="user-activity-tip"
|
||||
data-tooltip-content={`${legend.count} Updates`}
|
||||
>
|
||||
<div
|
||||
className={`h-2.5 w-2.5 ${legend.color} mr-1 rounded-sm`}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
<span className="ml-2 text-xs text-slate-500">More</span>
|
||||
<ReactTooltip
|
||||
id="user-activity-tip"
|
||||
className="!rounded-lg !bg-slate-900 !p-1 !px-2 !text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
|
||||
type StreakDayProps = {
|
||||
isToday?: boolean;
|
||||
isCurrentStreakDay?: boolean;
|
||||
isPreviousStreakDay?: boolean;
|
||||
isBrokenStreakDay?: boolean;
|
||||
isRemainingStreakDay?: boolean;
|
||||
dayCount: number;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
export function StreakDay(props: StreakDayProps) {
|
||||
const {
|
||||
isCurrentStreakDay,
|
||||
isPreviousStreakDay,
|
||||
isBrokenStreakDay,
|
||||
isRemainingStreakDay,
|
||||
dayCount,
|
||||
icon,
|
||||
isToday = false,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative flex flex-col items-center justify-center gap-1.5',
|
||||
{
|
||||
'text-red-400 opacity-40': isPreviousStreakDay,
|
||||
'text-slate-600': isRemainingStreakDay,
|
||||
'text-yellow-300': isCurrentStreakDay,
|
||||
'text-slate-400': isToday,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn('flex size-6 items-center justify-center rounded-full', {
|
||||
'bg-slate-700': isRemainingStreakDay,
|
||||
'border border-dashed border-slate-500 striped-bg': isToday,
|
||||
})}
|
||||
>
|
||||
{isToday ? null : icon}
|
||||
</div>
|
||||
<span className={cn('text-xs')}>{dayCount}</span>
|
||||
{isToday && (
|
||||
<ChevronDown className="absolute bottom-full left-1/2 h-3.5 w-3.5 -translate-y-[0.75px] -translate-x-1/2 transform stroke-[2.5px] text-slate-400" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { CheckIcon } from './ReactIcons/CheckIcon.tsx';
|
||||
import { pageProgressMessage } from '../stores/page.ts';
|
||||
import { httpPost } from '../lib/http.ts';
|
||||
|
||||
type InputProps = {
|
||||
label: string;
|
||||
name: string;
|
||||
type: string;
|
||||
value: string;
|
||||
onChange: (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => void;
|
||||
required?: boolean;
|
||||
rows?: number;
|
||||
};
|
||||
|
||||
function Input(props: InputProps) {
|
||||
const { label, name, type, value, onChange, required, rows } = props;
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
|
||||
{label} {required && <span className="text-red-500">*</span>}
|
||||
</label>
|
||||
{type === 'textarea' ? (
|
||||
<textarea
|
||||
placeholder={label}
|
||||
id={name}
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
rows={rows}
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 p-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
autoComplete="off"
|
||||
data-1p-ignore=""
|
||||
data-form-type="other"
|
||||
data-lpignore="true"
|
||||
></textarea>
|
||||
) : (
|
||||
<input
|
||||
type={type}
|
||||
id={name}
|
||||
placeholder={label}
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
required={required}
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 p-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
autoComplete="off"
|
||||
data-1p-ignore=""
|
||||
data-form-type="other"
|
||||
data-lpignore="true"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AdvertiseForm() {
|
||||
const [status, setStatus] = useState<'submitting' | 'submitted'>();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
title: '',
|
||||
company: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
message: '',
|
||||
updates: false,
|
||||
});
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
const { name, value, type, checked } = e.target as any;
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]: type === 'checkbox' ? checked : value,
|
||||
});
|
||||
};
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
pageProgressMessage.set('Please wait');
|
||||
|
||||
// Placeholder function to send data
|
||||
console.log('Form data:', formData);
|
||||
|
||||
const { response, error } = await httpPost(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-advertise`,
|
||||
formData,
|
||||
);
|
||||
if (!response || error) {
|
||||
pageProgressMessage.set('');
|
||||
setError(error?.message || 'Something went wrong. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus('submitted');
|
||||
pageProgressMessage.set('');
|
||||
}
|
||||
|
||||
if (status === 'submitted') {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center rounded-md border bg-gray-50 p-12 text-center">
|
||||
<CheckIcon additionalClasses="h-12 w-12 text-green-500 mb-5" />
|
||||
<h2 className="text-balance text-xl font-semibold text-gray-900">
|
||||
Thank you for your interest in advertising with roadmap.sh
|
||||
</h2>
|
||||
<p className="mt-2 text-sm text-gray-500">
|
||||
We will get back to you soon.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-5 text-balance text-2xl font-bold">
|
||||
Ready to learn more? Fill out the form below to get started!
|
||||
</h2>
|
||||
{error && (
|
||||
<div className="relative mb-4 rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
<form className="mb-5" onSubmit={handleSubmit}>
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||
<Input
|
||||
label="First Name"
|
||||
name="firstName"
|
||||
type="text"
|
||||
value={formData.firstName}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
label="Last Name"
|
||||
name="lastName"
|
||||
type="text"
|
||||
value={formData.lastName}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||
<Input
|
||||
label="Title"
|
||||
name="title"
|
||||
type="text"
|
||||
value={formData.title}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Company"
|
||||
name="company"
|
||||
type="text"
|
||||
value={formData.company}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-4">
|
||||
<Input
|
||||
label="Email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Phone"
|
||||
name="phone"
|
||||
type="tel"
|
||||
value={formData.phone}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Message (Optional)"
|
||||
name="message"
|
||||
type="textarea"
|
||||
value={formData.message}
|
||||
onChange={handleInputChange}
|
||||
rows={4}
|
||||
/>
|
||||
<div className="mb-4 flex items-start">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
id="updates"
|
||||
name="updates"
|
||||
type="checkbox"
|
||||
checked={formData.updates}
|
||||
onChange={handleInputChange}
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 text-sm">
|
||||
<label htmlFor="updates" className="font-medium text-gray-700">
|
||||
I want to receive occasional updates about new products or
|
||||
advertising opportunities with roadmap.sh
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -59,7 +59,6 @@ export function EmailLoginForm(props: EmailLoginFormProps) {
|
||||
Email address
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
@@ -73,7 +72,6 @@ export function EmailLoginForm(props: EmailLoginFormProps) {
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
|
||||
@@ -122,7 +122,6 @@ export function CustomRoadmap(props: CustomRoadmapProps) {
|
||||
{!isEmbed && <RoadmapHeader />}
|
||||
<FlowRoadmapRenderer isEmbed={isEmbed} roadmap={roadmap!} />
|
||||
<TopicDetail
|
||||
resourceId={roadmap!._id}
|
||||
resourceTitle={roadmap!.title}
|
||||
resourceType="roadmap"
|
||||
isEmbed={isEmbed}
|
||||
|
||||
@@ -35,8 +35,8 @@ import Icon from './AstroIcon.astro';
|
||||
>
|
||||
</p>
|
||||
|
||||
<div class='flex flex-col justify-between gap-8 lg:gap-2 lg:flex-row'>
|
||||
<div class='max-w-[425px]'>
|
||||
<div class='flex flex-col justify-between gap-12 sm:flex-row'>
|
||||
<div class='max-w-[365px]'>
|
||||
<p class='text-md flex items-center'>
|
||||
<a
|
||||
class='inline-flex items-center text-lg font-medium text-white transition-colors hover:text-gray-400'
|
||||
@@ -56,7 +56,7 @@ import Icon from './AstroIcon.astro';
|
||||
</a>
|
||||
</p>
|
||||
<p class='my-4 text-slate-300/60'>
|
||||
Community created roadmaps, best practices, projects, articles, resources and journeys to help
|
||||
Community created roadmaps, articles, resources and journeys to help
|
||||
you choose your path and grow in your career.
|
||||
</p>
|
||||
<div class='text-sm text-gray-400'>
|
||||
@@ -67,8 +67,6 @@ import Icon from './AstroIcon.astro';
|
||||
<span class='mx-1.5'>·</span>
|
||||
<a href='/privacy' class='hover:text-white'>Privacy</a>
|
||||
<span class='mx-1.5'>·</span>
|
||||
<a href='/advertise' class='hover:text-white'>Advertise</a>
|
||||
<span class='mx-1.5'>·</span>
|
||||
<a
|
||||
aria-label='Write us an email'
|
||||
href='mailto:info@roadmap.sh'
|
||||
@@ -99,19 +97,20 @@ import Icon from './AstroIcon.astro';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='max-w-[340px] text-left lg:text-right'>
|
||||
<div class='max-w-[365px] text-left sm:text-right'>
|
||||
<a href='https://thenewstack.io' target='_blank'>
|
||||
<img
|
||||
src='/images/tns-sm.png'
|
||||
alt='ThewNewStack'
|
||||
class='my-1.5 mr-auto lg:ml-auto lg:mr-0'
|
||||
class='my-1.5 mr-auto sm:ml-auto sm:mr-0'
|
||||
width='200'
|
||||
height='24.8'
|
||||
loading="lazy"
|
||||
/>
|
||||
</a>
|
||||
<p class='my-4 text-slate-300/60'>
|
||||
The top DevOps resource for Kubernetes, cloud-native computing, and large-scale development and deployment.
|
||||
The leading DevOps resource for Kubernetes, cloud-native computing,
|
||||
and the latest in at-scale development, deployment, and management.
|
||||
</p>
|
||||
<div class='text-sm text-gray-400'>
|
||||
<p>
|
||||
|
||||
@@ -4,7 +4,6 @@ import Icon from '../AstroIcon.astro';
|
||||
import { NavigationDropdown } from '../NavigationDropdown';
|
||||
import { AccountDropdown } from './AccountDropdown';
|
||||
import NewIndicator from './NewIndicator.astro';
|
||||
import { AccountStreak } from '../AccountStreak/AccountStreak';
|
||||
import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu';
|
||||
---
|
||||
|
||||
@@ -43,7 +42,10 @@ import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu'
|
||||
Start Here
|
||||
</a>
|
||||
<RoadmapDropdownMenu client:load />
|
||||
<a href='/teams' class='group relative text-gray-400 hover:text-white'>
|
||||
<a
|
||||
href='/teams'
|
||||
class='group relative !mr-5 text-gray-400 hover:text-white'
|
||||
>
|
||||
Teams
|
||||
</a>
|
||||
</div>
|
||||
@@ -53,8 +55,7 @@ import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu'
|
||||
<li data-guest-required class='hidden'>
|
||||
<a href='/login' class='text-gray-400 hover:text-white'>Login</a>
|
||||
</li>
|
||||
<li class='flex items-center gap-2'>
|
||||
<AccountStreak client:only='react' />
|
||||
<li>
|
||||
<AccountDropdown client:only='react' />
|
||||
|
||||
<a
|
||||
|
||||
@@ -62,12 +62,6 @@ const links = [
|
||||
Icon: Shirt,
|
||||
isExternal: true,
|
||||
},
|
||||
{
|
||||
link: '/advertise',
|
||||
label: 'Advertise',
|
||||
description: 'Promote your product or service',
|
||||
Icon: Menu,
|
||||
},
|
||||
];
|
||||
|
||||
export function NavigationDropdown() {
|
||||
|
||||
@@ -8,7 +8,7 @@ export function EmptySolutions(props: EmptySolutionsProps) {
|
||||
const { projectId } = props;
|
||||
|
||||
return (
|
||||
<div className="flex min-h-[250px] flex-col items-center justify-center rounded-xl px-5 py-3 sm:px-0 sm:py-20 bg-white border mb-5">
|
||||
<div className="flex min-h-[250px] flex-col items-center justify-center rounded-xl px-5 py-3 sm:px-0 sm:py-20">
|
||||
<Blocks className="mb-4 opacity-10 h-14 w-14" />
|
||||
<h2 className="mb-1 text-lg font-semibold sm:text-xl">
|
||||
No solutions submitted yet
|
||||
|
||||
@@ -4,13 +4,13 @@ import { SubmissionRequirement } from './SubmissionRequirement.tsx';
|
||||
|
||||
type LeavingRoadmapWarningModalProps = {
|
||||
onClose: () => void;
|
||||
repositoryUrl: string;
|
||||
onContinue: () => void;
|
||||
};
|
||||
|
||||
export function LeavingRoadmapWarningModal(
|
||||
props: LeavingRoadmapWarningModalProps,
|
||||
) {
|
||||
const { onClose, repositoryUrl } = props;
|
||||
const { onClose, onContinue } = props;
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} bodyClassName="h-auto p-4">
|
||||
@@ -45,14 +45,13 @@ export function LeavingRoadmapWarningModal(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<a
|
||||
<button
|
||||
className="inline-flex w-full items-center gap-2 rounded-lg bg-black px-3 py-2.5 text-sm text-white"
|
||||
href={repositoryUrl}
|
||||
target="_blank"
|
||||
onClick={onContinue}
|
||||
>
|
||||
<ArrowUpRight className="h-5 w-5" />
|
||||
Continue to Solution
|
||||
</a>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="absolute right-2.5 top-2.5 text-gray-600 hover:text-black"
|
||||
|
||||
@@ -13,9 +13,7 @@ import { isLoggedIn } from '../../lib/jwt';
|
||||
import { showLoginPopup } from '../../lib/popup';
|
||||
import { VoteButton } from './VoteButton.tsx';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
import { SelectLanguages } from './SelectLanguages.tsx';
|
||||
import type { ProjectFrontmatter } from '../../lib/project.ts';
|
||||
import { ProjectSolutionModal } from './ProjectSolutionModal.tsx';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
export interface ProjectStatusDocument {
|
||||
_id?: string;
|
||||
@@ -26,7 +24,6 @@ export interface ProjectStatusDocument {
|
||||
startedAt?: Date;
|
||||
submittedAt?: Date;
|
||||
repositoryUrl?: string;
|
||||
languages?: string[];
|
||||
|
||||
upvotes: number;
|
||||
downvotes: number;
|
||||
@@ -56,20 +53,19 @@ type ListProjectSolutionsResponse = {
|
||||
|
||||
type QueryParams = {
|
||||
p?: string;
|
||||
l?: string;
|
||||
};
|
||||
|
||||
type PageState = {
|
||||
currentPage: number;
|
||||
language: string;
|
||||
};
|
||||
|
||||
const VISITED_SOLUTIONS_KEY = 'visited-project-solutions';
|
||||
|
||||
type ListProjectSolutionsProps = {
|
||||
project: ProjectFrontmatter;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const submittedAlternatives = [
|
||||
const submittedAlternatives = [
|
||||
'submitted their solution',
|
||||
'got it done',
|
||||
'submitted their take',
|
||||
@@ -94,26 +90,27 @@ export const submittedAlternatives = [
|
||||
];
|
||||
|
||||
export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
const { projectId, project: projectData } = props;
|
||||
const { projectId } = props;
|
||||
|
||||
const toast = useToast();
|
||||
const [pageState, setPageState] = useState<PageState>({
|
||||
currentPage: 0,
|
||||
language: '',
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [solutions, setSolutions] = useState<ListProjectSolutionsResponse>();
|
||||
const [alreadyVisitedSolutions, setAlreadyVisitedSolutions] = useState<
|
||||
Record<string, boolean>
|
||||
>({});
|
||||
const [showLeavingRoadmapModal, setShowLeavingRoadmapModal] = useState<
|
||||
ListProjectSolutionsResponse['data'][number] | null
|
||||
>(null);
|
||||
|
||||
const loadSolutions = async (page = 1, language: string = '') => {
|
||||
const loadSolutions = async (page = 1) => {
|
||||
const { response, error } = await httpGet<ListProjectSolutionsResponse>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-project-solutions/${projectId}`,
|
||||
{
|
||||
currPage: page,
|
||||
...(language ? { languages: language } : {}),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -135,7 +132,7 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageProgressMessage.set('Submitting vote');
|
||||
pageProgressMessage.set('Submitting vote...');
|
||||
const { response, error } = await httpPost(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-vote-project/${solutionId}`,
|
||||
{
|
||||
@@ -175,9 +172,13 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
|
||||
useEffect(() => {
|
||||
const queryParams = getUrlParams() as QueryParams;
|
||||
const alreadyVisitedSolutions = JSON.parse(
|
||||
localStorage.getItem(VISITED_SOLUTIONS_KEY) || '{}',
|
||||
);
|
||||
|
||||
setAlreadyVisitedSolutions(alreadyVisitedSolutions);
|
||||
setPageState({
|
||||
currentPage: +(queryParams.p || '1'),
|
||||
language: queryParams.l || '',
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -187,21 +188,23 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageState.currentPage !== 1 || pageState.language !== '') {
|
||||
if (pageState.currentPage !== 1) {
|
||||
setUrlParams({
|
||||
p: String(pageState.currentPage),
|
||||
l: pageState.language,
|
||||
});
|
||||
} else {
|
||||
deleteUrlParam('p');
|
||||
deleteUrlParam('l');
|
||||
}
|
||||
|
||||
loadSolutions(pageState.currentPage, pageState.language).finally(() => {
|
||||
loadSolutions(pageState.currentPage).finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, [pageState]);
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingSolutions />;
|
||||
}
|
||||
|
||||
const isEmpty = solutions?.data.length === 0;
|
||||
if (isEmpty) {
|
||||
return <EmptySolutions projectId={projectId} />;
|
||||
@@ -210,128 +213,116 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
const leavingRoadmapModal = showLeavingRoadmapModal ? (
|
||||
<LeavingRoadmapWarningModal
|
||||
onClose={() => setShowLeavingRoadmapModal(null)}
|
||||
repositoryUrl={showLeavingRoadmapModal?.repositoryUrl!}
|
||||
onContinue={() => {
|
||||
const visitedSolutions = {
|
||||
...alreadyVisitedSolutions,
|
||||
[showLeavingRoadmapModal._id!]: true,
|
||||
};
|
||||
localStorage.setItem(
|
||||
VISITED_SOLUTIONS_KEY,
|
||||
JSON.stringify(visitedSolutions),
|
||||
);
|
||||
|
||||
window.open(showLeavingRoadmapModal.repositoryUrl, '_blank');
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const selectedLanguage = pageState.language;
|
||||
|
||||
return (
|
||||
<div className="mb-4 overflow-hidden rounded-lg border bg-white p-3 sm:p-5">
|
||||
<section>
|
||||
{leavingRoadmapModal}
|
||||
<div className="relative mb-5 hidden items-center justify-between sm:flex">
|
||||
<div>
|
||||
<h1 className="mb-1 text-xl font-semibold">
|
||||
{projectData.title} Solutions
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">{projectData.description}</p>
|
||||
</div>
|
||||
{!isLoading && (
|
||||
<SelectLanguages
|
||||
projectId={projectId}
|
||||
selectedLanguage={selectedLanguage}
|
||||
onSelectLanguage={(language) => {
|
||||
setPageState((prev) => ({
|
||||
...prev,
|
||||
language: prev.language === language ? '' : language,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex min-h-[500px] flex-col divide-y divide-gray-100">
|
||||
{solutions?.data.map((solution, counter) => {
|
||||
const isVisited = alreadyVisitedSolutions[solution._id!];
|
||||
const avatar = solution.user.avatar || '';
|
||||
|
||||
return (
|
||||
<div
|
||||
key={solution._id}
|
||||
className={
|
||||
'flex flex-col justify-between gap-2 py-2 text-sm text-gray-500 sm:flex-row sm:items-center sm:gap-0'
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<img
|
||||
src={
|
||||
avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={solution.user.name}
|
||||
className="mr-0.5 h-7 w-7 rounded-full"
|
||||
/>
|
||||
<span className="font-medium text-black">
|
||||
{solution.user.name}
|
||||
</span>
|
||||
<span className="hidden sm:inline">
|
||||
{submittedAlternatives[
|
||||
counter % submittedAlternatives.length
|
||||
] || 'submitted their solution'}
|
||||
</span>{' '}
|
||||
<span className="flex-grow text-right text-gray-400 sm:flex-grow-0 sm:text-left sm:font-medium sm:text-black">
|
||||
{getRelativeTimeString(solution?.submittedAt!)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<span className="flex overflow-hidden rounded-full border">
|
||||
<VoteButton
|
||||
icon={ThumbsUp}
|
||||
isActive={solution?.voteType === 'upvote'}
|
||||
count={solution.upvotes || 0}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'upvote');
|
||||
}}
|
||||
/>
|
||||
|
||||
<VoteButton
|
||||
icon={ThumbsDown}
|
||||
isActive={solution?.voteType === 'downvote'}
|
||||
count={solution.downvotes || 0}
|
||||
hideCount={true}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'downvote');
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<a
|
||||
className="ml-1 flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setShowLeavingRoadmapModal(solution);
|
||||
}}
|
||||
target="_blank"
|
||||
href={solution.repositoryUrl}
|
||||
>
|
||||
<GitHubIcon className="h-4 w-4 text-current" />
|
||||
Visit Solution
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<LoadingSolutions />
|
||||
) : (
|
||||
<>
|
||||
<div className="flex min-h-[500px] flex-col divide-y divide-gray-100">
|
||||
{solutions?.data.map((solution, counter) => {
|
||||
const avatar = solution.user.avatar || '';
|
||||
return (
|
||||
<div
|
||||
key={solution._id}
|
||||
className="flex flex-col gap-2 py-2 text-sm text-gray-500"
|
||||
>
|
||||
<div className="flex flex-col justify-between gap-2 text-sm text-gray-500 sm:flex-row sm:items-center sm:gap-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<img
|
||||
src={
|
||||
avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={solution.user.name}
|
||||
className="mr-0.5 h-7 w-7 rounded-full"
|
||||
/>
|
||||
<span className="font-medium text-black">
|
||||
{solution.user.name}
|
||||
</span>
|
||||
<span className="hidden sm:inline">
|
||||
{submittedAlternatives[
|
||||
counter % submittedAlternatives.length
|
||||
] || 'submitted their solution'}
|
||||
</span>{' '}
|
||||
<span className="flex-grow text-right text-gray-400 sm:flex-grow-0 sm:text-left sm:font-medium sm:text-black">
|
||||
{getRelativeTimeString(solution?.submittedAt!)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<span className="flex shrink-0 overflow-hidden rounded-full border">
|
||||
<VoteButton
|
||||
icon={ThumbsUp}
|
||||
isActive={solution?.voteType === 'upvote'}
|
||||
count={solution.upvotes || 0}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'upvote');
|
||||
}}
|
||||
/>
|
||||
|
||||
<VoteButton
|
||||
icon={ThumbsDown}
|
||||
isActive={solution?.voteType === 'downvote'}
|
||||
count={solution.downvotes || 0}
|
||||
hideCount={true}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'downvote');
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<button
|
||||
className="ml-1 flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white"
|
||||
onClick={() => {
|
||||
setShowLeavingRoadmapModal(solution);
|
||||
}}
|
||||
>
|
||||
<GitHubIcon className="h-4 w-4 text-current" />
|
||||
Visit Solution
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{(solutions?.totalPages || 0) > 1 && (
|
||||
<div className="mt-4">
|
||||
<Pagination
|
||||
totalPages={solutions?.totalPages || 1}
|
||||
currPage={solutions?.currPage || 1}
|
||||
perPage={solutions?.perPage || 21}
|
||||
totalCount={solutions?.totalCount || 0}
|
||||
onPageChange={(page) => {
|
||||
setPageState({
|
||||
...pageState,
|
||||
currentPage: page,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{(solutions?.totalPages || 0) > 1 && (
|
||||
<div className="mt-4">
|
||||
<Pagination
|
||||
totalPages={solutions?.totalPages || 1}
|
||||
currPage={solutions?.currPage || 1}
|
||||
perPage={solutions?.perPage || 21}
|
||||
totalCount={solutions?.totalCount || 0}
|
||||
onPageChange={(page) => {
|
||||
setPageState({
|
||||
...pageState,
|
||||
currentPage: page,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,9 @@ import type {
|
||||
ProjectDifficultyType,
|
||||
ProjectFileType,
|
||||
} from '../../lib/project.ts';
|
||||
import { Users } from 'lucide-react';
|
||||
import { formatCommaNumber } from '../../lib/number.ts';
|
||||
|
||||
type ProjectCardProps = {
|
||||
project: ProjectFileType;
|
||||
userCount?: number;
|
||||
};
|
||||
|
||||
const badgeVariants: Record<ProjectDifficultyType, string> = {
|
||||
@@ -18,7 +15,7 @@ const badgeVariants: Record<ProjectDifficultyType, string> = {
|
||||
};
|
||||
|
||||
export function ProjectCard(props: ProjectCardProps) {
|
||||
const { project, userCount = 0 } = props;
|
||||
const { project } = props;
|
||||
|
||||
const { frontmatter, id } = project;
|
||||
|
||||
@@ -34,18 +31,8 @@ export function ProjectCard(props: ProjectCardProps) {
|
||||
/>
|
||||
<Badge variant={'grey'} text={frontmatter.nature} />
|
||||
</span>
|
||||
<span className="my-3 flex flex-col">
|
||||
<span className="mb-1 font-medium">{frontmatter.title}</span>
|
||||
<span className="text-sm text-gray-500">{frontmatter.description}</span>
|
||||
</span>
|
||||
<span className="flex items-center gap-2 text-xs text-gray-400">
|
||||
<Users className="inline-block size-3.5" />
|
||||
{userCount > 0 ? (
|
||||
<>{formatCommaNumber(userCount)} Started</>
|
||||
) : (
|
||||
<>Be the first to solve!</>
|
||||
)}
|
||||
</span>
|
||||
<span className="mb-1 mt-2.5 font-medium">{frontmatter.title}</span>
|
||||
<span className="text-sm text-gray-500">{frontmatter.description}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { deleteUrlParam, getUrlParams } from '../../lib/browser';
|
||||
import { ModalLoader } from '../UserProgress/ModalLoader';
|
||||
import { Modal } from '../Modal';
|
||||
import { httpGet, httpPost } from '../../lib/http';
|
||||
import {
|
||||
submittedAlternatives,
|
||||
type AllowedVoteType,
|
||||
} from './ListProjectSolutions';
|
||||
import { getRelativeTimeString } from '../../lib/date';
|
||||
import { ArrowUpRight, ThumbsDown, ThumbsUp, Trophy } from 'lucide-react';
|
||||
import { VoteButton } from './VoteButton';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon';
|
||||
import { isLoggedIn } from '../../lib/jwt';
|
||||
import { showLoginPopup } from '../../lib/popup';
|
||||
import { pageProgressMessage } from '../../stores/page';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
|
||||
type UserProjectSolutionResponse = {
|
||||
id?: string;
|
||||
|
||||
startedAt?: Date;
|
||||
submittedAt?: Date;
|
||||
repositoryUrl?: string;
|
||||
|
||||
upvotes?: number;
|
||||
downvotes?: number;
|
||||
|
||||
voteType?: AllowedVoteType | 'none';
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
};
|
||||
};
|
||||
|
||||
type ProjectSolutionModalProps = {
|
||||
projectId: string;
|
||||
projectTitle: string;
|
||||
projectDescription: string;
|
||||
};
|
||||
|
||||
export function ProjectSolutionModal(props: ProjectSolutionModalProps) {
|
||||
const { projectId, projectTitle, projectDescription } = props;
|
||||
|
||||
const { u: userId } = getUrlParams();
|
||||
if (!userId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toast = useToast();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
const [solution, setSolution] = useState<UserProjectSolutionResponse>();
|
||||
|
||||
const loadUserProjectSolution = async () => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
|
||||
const { response, error } = await httpGet<UserProjectSolutionResponse>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-project-solution/${projectId}/${userId}`,
|
||||
);
|
||||
|
||||
if (error || !response) {
|
||||
setError(error?.message || 'Something went wrong');
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setSolution(response);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleSubmitVote = async (
|
||||
solutionId: string,
|
||||
voteType: AllowedVoteType,
|
||||
) => {
|
||||
if (!isLoggedIn()) {
|
||||
showLoginPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
pageProgressMessage.set('Submitting vote');
|
||||
const { response, error } = await httpPost(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-vote-project/${solutionId}`,
|
||||
{
|
||||
voteType,
|
||||
},
|
||||
);
|
||||
|
||||
if (error || !response) {
|
||||
toast.error(error?.message || 'Failed to submit vote');
|
||||
pageProgressMessage.set('');
|
||||
return;
|
||||
}
|
||||
|
||||
pageProgressMessage.set('');
|
||||
setSolution((prev) => {
|
||||
if (!prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return {
|
||||
...prev,
|
||||
upvotes: response?.upvotes || 0,
|
||||
downvotes: response?.downvotes || 0,
|
||||
voteType,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadUserProjectSolution().finally();
|
||||
}, []);
|
||||
|
||||
if (isLoading || error) {
|
||||
return (
|
||||
<ModalLoader
|
||||
text="Loading project solution..."
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const avatar = solution?.user.avatar;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onClose={() => {
|
||||
deleteUrlParam('u');
|
||||
window.location.reload();
|
||||
}}
|
||||
wrapperClassName={'max-w-lg'}
|
||||
bodyClassName={'h-auto'}
|
||||
>
|
||||
<div className="relative p-6">
|
||||
<h1 className="text-2xl text-balance mb-1 font-bold text-gray-900">{projectTitle}</h1>
|
||||
<p className="text-sm text-balance text-gray-600">{projectDescription}</p>
|
||||
|
||||
<div className="my-5 rounded-lg bg-gray-100 p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<img
|
||||
src={
|
||||
avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={solution?.user?.name}
|
||||
className="h-12 w-12 rounded-full border-2 border-white shadow-md"
|
||||
/>
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900">{solution?.user.name}'s Solution</h2>
|
||||
<p className="text-sm text-gray-600">
|
||||
Submitted their solution{' '}
|
||||
{getRelativeTimeString(solution?.submittedAt!)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<a
|
||||
className="flex items-center gap-2 rounded-full bg-black px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-gray-800"
|
||||
href={solution?.repositoryUrl}
|
||||
target="_blank"
|
||||
>
|
||||
<GitHubIcon className="h-5 w-5 text-current" />
|
||||
View Solution on GitHub
|
||||
<ArrowUpRight className="h-4 w-4" />
|
||||
</a>
|
||||
|
||||
<div className="flex overflow-hidden rounded-full border">
|
||||
<VoteButton
|
||||
icon={ThumbsUp}
|
||||
isActive={solution?.voteType === 'upvote'}
|
||||
count={solution?.upvotes || 0}
|
||||
onClick={() => handleSubmitVote(solution?.id!, 'upvote')}
|
||||
/>
|
||||
<VoteButton
|
||||
icon={ThumbsDown}
|
||||
isActive={solution?.voteType === 'downvote'}
|
||||
count={solution?.downvotes || 0}
|
||||
hideCount={true}
|
||||
onClick={() => handleSubmitVote(solution?.id!, 'downvote')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { cn } from '../../lib/classname';
|
||||
import {
|
||||
ArrowLeft,
|
||||
Blocks,
|
||||
BoxSelect,
|
||||
type LucideIcon,
|
||||
StepBackIcon,
|
||||
StickyNote,
|
||||
Text,
|
||||
} from 'lucide-react';
|
||||
@@ -36,7 +34,7 @@ function TabButton(props: TabButtonProps) {
|
||||
{smText && <span className="sm:hidden">{smText}</span>}
|
||||
|
||||
{isActive && (
|
||||
<span className="absolute bottom-0 left-0 right-0 h-0.5 translate-y-1/2 rounded-t-md bg-black"></span>
|
||||
<span className="absolute bottom-0 left-0 right-0 h-0.5 translate-y-1/2 bg-black rounded-t-md"></span>
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
@@ -45,23 +43,13 @@ function TabButton(props: TabButtonProps) {
|
||||
type ProjectTabsProps = {
|
||||
activeTab: AllowedProjectTab;
|
||||
projectId: string;
|
||||
parentRoadmapId?: string;
|
||||
};
|
||||
|
||||
export function ProjectTabs(props: ProjectTabsProps) {
|
||||
const { activeTab, parentRoadmapId, projectId } = props;
|
||||
const { activeTab, projectId } = props;
|
||||
|
||||
return (
|
||||
<div className="my-3 flex flex-row flex-wrap items-center gap-1.5 overflow-hidden rounded-md border bg-white px-2.5 text-sm">
|
||||
<a
|
||||
href={`/${parentRoadmapId}/projects`}
|
||||
className={
|
||||
'-ml-1.5 flex items-center rounded-md bg-gray-300 px-2 py-1.5 text-xs tracking-wide text-black hover:bg-gray-400/60'
|
||||
}
|
||||
>
|
||||
<ArrowLeft className="mr-1 inline-block h-3.5 w-3.5" strokeWidth={2} />
|
||||
<span className="hidden sm:inline">Back to Projects</span>
|
||||
</a>
|
||||
<div className="my-3 flex flex-row flex-wrap items-center gap-1.5 rounded-md border bg-white px-2.5 text-sm">
|
||||
<TabButton
|
||||
text={'Project Detail'}
|
||||
icon={Text}
|
||||
|
||||
@@ -40,11 +40,10 @@ function DifficultyButton(props: DifficultyButtonProps) {
|
||||
|
||||
type ProjectsListProps = {
|
||||
projects: ProjectFileType[];
|
||||
userCounts: Record<string, number>;
|
||||
};
|
||||
|
||||
export function ProjectsList(props: ProjectsListProps) {
|
||||
const { projects, userCounts } = props;
|
||||
const { projects } = props;
|
||||
|
||||
const { difficulty: urlDifficulty } = getUrlParams();
|
||||
const [difficulty, setDifficulty] = useState<
|
||||
@@ -128,10 +127,9 @@ export function ProjectsList(props: ProjectsListProps) {
|
||||
.sort((a, b) => {
|
||||
return a.frontmatter.sort - b.frontmatter.sort;
|
||||
})
|
||||
.map((matchingProject) => {
|
||||
const count = userCounts[matchingProject?.id] || 0;
|
||||
return <ProjectCard project={matchingProject} userCount={count} />;
|
||||
})}
|
||||
.map((matchingProject) => (
|
||||
<ProjectCard project={matchingProject} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { ChevronDown, X } from 'lucide-react';
|
||||
|
||||
type SelectLanguagesProps = {
|
||||
projectId: string;
|
||||
selectedLanguage: string;
|
||||
onSelectLanguage: (language: string) => void;
|
||||
};
|
||||
|
||||
export function SelectLanguages(props: SelectLanguagesProps) {
|
||||
const { projectId, onSelectLanguage, selectedLanguage } = props;
|
||||
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const toast = useToast();
|
||||
|
||||
const [distinctLanguages, setDistinctLanguages] = useState<string[]>([]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const loadDistinctLanguages = async () => {
|
||||
const { response, error } = await httpGet<string[]>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-project-languages/${projectId}`,
|
||||
);
|
||||
|
||||
if (error || !response) {
|
||||
toast.error(error?.message || 'Failed to load project languages');
|
||||
return;
|
||||
}
|
||||
|
||||
setDistinctLanguages(response);
|
||||
};
|
||||
|
||||
useOutsideClick(dropdownRef, () => {
|
||||
setIsOpen(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadDistinctLanguages().finally(() => {});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative flex">
|
||||
<button
|
||||
className="flex items-center gap-1 rounded-md border border-gray-300 py-1.5 pl-3 pr-2 text-xs font-medium text-gray-900"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
{selectedLanguage || 'Select Language'}
|
||||
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</button>
|
||||
{selectedLanguage && (
|
||||
<button
|
||||
className="ml-1 text-red-500 text-xs border border-red-500 rounded-md px-2 py-1"
|
||||
onClick={() => onSelectLanguage('')}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
|
||||
{isOpen && (
|
||||
<div
|
||||
className="absolute right-0 top-full z-10 w-full min-w-[200px] max-w-[200px] translate-y-1.5 overflow-hidden rounded-md border border-gray-300 bg-white p-1 shadow-lg"
|
||||
ref={dropdownRef}
|
||||
>
|
||||
{distinctLanguages.map((language) => {
|
||||
const isSelected = selectedLanguage === language;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={language}
|
||||
className="flex w-full items-center rounded-md px-4 py-1.5 text-left text-sm text-gray-700 hover:bg-gray-100 aria-selected:bg-gray-100"
|
||||
onClick={() => {
|
||||
onSelectLanguage(language);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
{language}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Flag, Play, Send, Share } from 'lucide-react';
|
||||
import { Flag, Play, Send } from 'lucide-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { cn } from '../../../lib/classname.ts';
|
||||
import { useStickyStuck } from '../../../hooks/use-sticky-stuck.tsx';
|
||||
@@ -8,11 +8,9 @@ import { MilestoneStep } from './MilestoneStep.tsx';
|
||||
import { httpGet } from '../../../lib/http.ts';
|
||||
import { StartProjectModal } from '../StartProjectModal.tsx';
|
||||
import { getRelativeTimeString } from '../../../lib/date.ts';
|
||||
import { getUser, isLoggedIn } from '../../../lib/jwt.ts';
|
||||
import { isLoggedIn } from '../../../lib/jwt.ts';
|
||||
import { showLoginPopup } from '../../../lib/popup.ts';
|
||||
import { SubmitProjectModal } from '../SubmitProjectModal.tsx';
|
||||
import { useCopyText } from '../../../hooks/use-copy-text.ts';
|
||||
import { CheckIcon } from '../../ReactIcons/CheckIcon.tsx';
|
||||
|
||||
type ProjectStatusResponse = {
|
||||
id?: string;
|
||||
@@ -34,11 +32,9 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
|
||||
const stickyElRef = useRef<HTMLDivElement>(null);
|
||||
const isSticky = useStickyStuck(stickyElRef, 8);
|
||||
const currentUser = getUser();
|
||||
|
||||
const [isStartingProject, setIsStartingProject] = useState(false);
|
||||
const [isSubmittingProject, setIsSubmittingProject] = useState(false);
|
||||
const { copyText, isCopied } = useCopyText();
|
||||
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [activeStep, setActiveStep] = useState<number>(0);
|
||||
@@ -82,16 +78,13 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
loadProjectStatus().finally(() => {});
|
||||
}, []);
|
||||
|
||||
const projectSolutionUrl = `${import.meta.env.DEV ? 'http://localhost:3000' : 'https://roadmap.sh'}/projects/${projectId}/solutions?u=${currentUser?.id}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={stickyElRef}
|
||||
className={cn(
|
||||
'relative top-0 -mx-4 my-5 overflow-hidden rounded-none border border-x-0 bg-white transition-all sm:sticky sm:mx-0 sm:rounded-lg sm:border-x',
|
||||
'relative sm:sticky top-0 my-5 -mx-4 sm:mx-0 overflow-hidden rounded-none border-x-0 sm:border-x sm:rounded-lg border bg-white transition-all',
|
||||
{
|
||||
'sm:-mx-5 sm:rounded-none sm:border-x-0 sm:border-t-0 sm:bg-gray-50':
|
||||
isSticky,
|
||||
'sm:-mx-5 sm:rounded-none sm:border-x-0 sm:border-t-0 sm:bg-gray-50': isSticky,
|
||||
},
|
||||
)}
|
||||
>
|
||||
@@ -138,7 +131,7 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'bg-gray-100 px-4 py-2 text-sm text-gray-500 transition-colors sm:flex sm:items-center',
|
||||
'px-4 py-2 text-sm text-gray-500 transition-colors bg-gray-100',
|
||||
{
|
||||
'bg-purple-600 text-white': isSticky,
|
||||
},
|
||||
@@ -151,7 +144,7 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
)}
|
||||
{activeStep === 1 && (
|
||||
<>
|
||||
Started working
|
||||
Started working{' '}
|
||||
<span
|
||||
className={cn('font-medium text-gray-800', {
|
||||
'text-purple-200': isSticky,
|
||||
@@ -159,7 +152,7 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
>
|
||||
{getRelativeTimeString(projectStatus.startedAt!)}
|
||||
</span>
|
||||
. Follow
|
||||
. Follow{' '}
|
||||
<button
|
||||
className={cn('underline underline-offset-2 hover:text-black', {
|
||||
'text-purple-100 hover:text-white': isSticky,
|
||||
@@ -169,13 +162,13 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
}}
|
||||
>
|
||||
these tips
|
||||
</button>
|
||||
to get most out of it.
|
||||
</button>{' '}
|
||||
to get most out of it.
|
||||
</>
|
||||
)}
|
||||
{activeStep >= 2 && (
|
||||
<>
|
||||
Congrats on submitting your solution.
|
||||
Congrats on submitting your solution.{' '}
|
||||
<button
|
||||
className={cn('underline underline-offset-2 hover:text-black', {
|
||||
'text-purple-100 hover:text-white': isSticky,
|
||||
@@ -188,34 +181,9 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeStep >= 2 && (
|
||||
<button
|
||||
className={cn(
|
||||
'ml-auto hidden items-center gap-1 text-sm sm:flex',
|
||||
isCopied ? 'text-green-500' : '',
|
||||
)}
|
||||
onClick={() => {
|
||||
copyText(projectSolutionUrl);
|
||||
}}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
<CheckIcon additionalClasses="h-3 w-3" />
|
||||
Copied
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Share className="h-3 w-3 stroke-[2.5px]" />
|
||||
<span className="hidden md:inline">Share your Solution</span>
|
||||
<span className="md:hidden">Share</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-[60px] flex-col items-start justify-between gap-2 px-4 py-4 sm:flex-row sm:items-center sm:gap-3 sm:py-0">
|
||||
<div className="flex flex-col sm:flex-row min-h-[60px] items-start sm:items-center justify-between gap-2 sm:gap-3 px-4 py-4 sm:py-0">
|
||||
<StepperAction
|
||||
isActive={activeStep === 0}
|
||||
isCompleted={activeStep > 0}
|
||||
@@ -232,46 +200,21 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
}}
|
||||
/>
|
||||
<StepperStepSeparator isActive={activeStep > 0} />
|
||||
<div className="flex items-center gap-2">
|
||||
<StepperAction
|
||||
isActive={activeStep === 1}
|
||||
isCompleted={activeStep > 1}
|
||||
icon={Send}
|
||||
onClick={() => {
|
||||
if (!isLoggedIn()) {
|
||||
showLoginPopup();
|
||||
return;
|
||||
}
|
||||
<StepperAction
|
||||
isActive={activeStep === 1}
|
||||
isCompleted={activeStep > 1}
|
||||
icon={Send}
|
||||
onClick={() => {
|
||||
if (!isLoggedIn()) {
|
||||
showLoginPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmittingProject(true);
|
||||
}}
|
||||
text={activeStep > 1 ? 'Submitted' : 'Submit Solution'}
|
||||
number={2}
|
||||
/>
|
||||
|
||||
<span className="text-gray-600 sm:hidden">·</span>
|
||||
<button
|
||||
className={cn(
|
||||
'flex items-center gap-2 text-sm sm:hidden',
|
||||
isCopied ? 'text-green-500' : 'text-gray-600',
|
||||
)}
|
||||
onClick={() => {
|
||||
copyText(projectSolutionUrl);
|
||||
}}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
<CheckIcon additionalClasses="h-3 w-3" />
|
||||
URL Copied
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Share className="h-3 w-3 stroke-[2.5px]" />
|
||||
Share your Solution
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
setIsSubmittingProject(true);
|
||||
}}
|
||||
text={activeStep > 1 ? 'Submitted' : 'Submit Solution'}
|
||||
number={2}
|
||||
/>
|
||||
<StepperStepSeparator isActive={activeStep > 1} />
|
||||
<MilestoneStep
|
||||
isActive={activeStep === 2}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import { CheckIcon, CopyIcon, X } from 'lucide-react';
|
||||
import { CheckIcon as ReactCheckIcon } from '../ReactIcons/CheckIcon.tsx';
|
||||
import { Modal } from '../Modal';
|
||||
import { type FormEvent, useState } from 'react';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
import { SubmissionRequirement } from './SubmissionRequirement.tsx';
|
||||
import { useCopyText } from '../../hooks/use-copy-text.ts';
|
||||
import { getTopGitHubLanguages } from '../../lib/github.ts';
|
||||
import { SubmitSuccessModal } from './SubmitSuccessModal.tsx';
|
||||
|
||||
type SubmitProjectResponse = {
|
||||
repositoryUrl: string;
|
||||
submittedAt: Date;
|
||||
};
|
||||
|
||||
type GitHubApiLanguagesResponse = Record<string, number>;
|
||||
|
||||
type VerificationChecksType = {
|
||||
repositoryExists: 'pending' | 'success' | 'error';
|
||||
readmeExists: 'pending' | 'success' | 'error';
|
||||
@@ -39,7 +36,7 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
const { isCopied, copyText } = useCopyText();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
const [successMessage, setSuccessMessage] = useState('');
|
||||
const [repoUrl, setRepoUrl] = useState(defaultRepositoryUrl);
|
||||
const [verificationChecks, setVerificationChecks] =
|
||||
useState<VerificationChecksType>({
|
||||
@@ -61,7 +58,7 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
setIsSuccess(false);
|
||||
setSuccessMessage('');
|
||||
|
||||
if (!repoUrl) {
|
||||
setVerificationChecks({
|
||||
@@ -173,23 +170,10 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
projectUrlExists: 'success',
|
||||
});
|
||||
|
||||
const languagesResponse = await fetch(`${mainApiUrl}/languages`);
|
||||
let languages: string[] = [];
|
||||
if (languagesResponse.ok) {
|
||||
const languagesData =
|
||||
(await languagesResponse.json()) as GitHubApiLanguagesResponse;
|
||||
|
||||
languages = getTopGitHubLanguages(languagesData);
|
||||
if (languages?.length === 0) {
|
||||
languages = Object.keys(languagesData || {})?.slice(0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
const submitProjectUrl = `${import.meta.env.PUBLIC_API_URL}/v1-submit-project/${projectId}`;
|
||||
const { response: submitResponse, error } =
|
||||
await httpPost<SubmitProjectResponse>(submitProjectUrl, {
|
||||
repositoryUrl: repoUrl,
|
||||
languages,
|
||||
});
|
||||
|
||||
if (error || !submitResponse) {
|
||||
@@ -198,7 +182,7 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
);
|
||||
}
|
||||
|
||||
setIsSuccess(true);
|
||||
setSuccessMessage('Solution submitted successfully!');
|
||||
setIsLoading(false);
|
||||
|
||||
onSubmit(submitResponse);
|
||||
@@ -209,8 +193,15 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
}
|
||||
};
|
||||
|
||||
if (isSuccess) {
|
||||
return <SubmitSuccessModal projectId={projectId} onClose={onClose} />;
|
||||
if (successMessage) {
|
||||
return (
|
||||
<Modal onClose={onClose} bodyClassName="h-auto p-4">
|
||||
<div className="flex flex-col items-center justify-center gap-4 pb-10 pt-12">
|
||||
<ReactCheckIcon additionalClasses={'h-12 text-green-500 w-12'} />
|
||||
<p className="text-lg font-medium">{successMessage}</p>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -281,7 +272,7 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="mt-2 w-full rounded-lg bg-black p-2 text-sm font-medium text-white disabled:opacity-50"
|
||||
className="mt-2 w-full rounded-lg bg-black p-2 font-medium text-white disabled:opacity-50 text-sm"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Verifying...' : 'Verify and Submit'}
|
||||
@@ -289,6 +280,12 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) {
|
||||
{error && (
|
||||
<p className="mt-2 text-sm font-medium text-red-500">{error}</p>
|
||||
)}
|
||||
|
||||
{successMessage && (
|
||||
<p className="mt-2 text-sm font-medium text-green-500">
|
||||
{successMessage}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
|
||||
<button
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import { CheckCircle, CheckCircle2, Clipboard, Copy } from 'lucide-react';
|
||||
import { getUser } from '../../lib/jwt.ts';
|
||||
import { Modal } from '../Modal';
|
||||
import { CheckIcon as ReactCheckIcon } from '../ReactIcons/CheckIcon.tsx';
|
||||
import { useCopyText } from '../../hooks/use-copy-text.ts';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
type SubmitSuccessModalProps = {
|
||||
projectId: string;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export function SubmitSuccessModal(props: SubmitSuccessModalProps) {
|
||||
const { onClose, projectId } = props;
|
||||
|
||||
const user = getUser();
|
||||
|
||||
const projectSolutionUrl = `${import.meta.env.DEV ? 'http://localhost:3000' : 'https://roadmap.sh'}/projects/${projectId}/solutions?u=${user?.id}`;
|
||||
|
||||
const { isCopied, copyText } = useCopyText();
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} bodyClassName="h-auto p-4">
|
||||
<div className="flex flex-col items-center justify-center pb-3 pt-12">
|
||||
<ReactCheckIcon additionalClasses="h-12 text-green-500 w-12" />
|
||||
<p className="mt-4 text-lg font-medium">Solution Submitted</p>
|
||||
<p className="mt-0.5 text-center text-sm text-gray-500">
|
||||
Congrats! Your solution has been submitted.
|
||||
</p>
|
||||
|
||||
<div className="mt-4 w-full">
|
||||
<input
|
||||
type="text"
|
||||
readOnly={true}
|
||||
value={projectSolutionUrl}
|
||||
className="w-full rounded-md border bg-gray-50 px-2.5 py-2 text-sm text-gray-700 focus:outline-none"
|
||||
onClick={(e) => {
|
||||
e.currentTarget.select();
|
||||
}}
|
||||
/>
|
||||
|
||||
<button
|
||||
className={cn(
|
||||
'mt-2 flex w-full items-center justify-center gap-1 rounded-md px-2 py-2 text-sm font-medium transition-colors',
|
||||
isCopied
|
||||
? 'bg-green-600 text-white hover:bg-green-700'
|
||||
: 'bg-black text-white hover:bg-gray-800'
|
||||
)}
|
||||
onClick={() => {
|
||||
copyText(projectSolutionUrl);
|
||||
}}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
<CheckCircle className="size-4 stroke-[2.5px]" />
|
||||
URL Copied
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="size-4 stroke-[2.5px]" />
|
||||
Copy Shareable Link
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { decimalIfNeeded } from '../../lib/number.ts';
|
||||
|
||||
type RatingProps = {
|
||||
rating?: number;
|
||||
@@ -41,7 +40,7 @@ export function Rating(props: RatingProps) {
|
||||
if (readOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setStars(counter);
|
||||
onRatingChange?.(counter);
|
||||
}}
|
||||
@@ -50,14 +49,9 @@ export function Rating(props: RatingProps) {
|
||||
);
|
||||
})}
|
||||
{(props.total || 0) > 0 && (
|
||||
<>
|
||||
<span className="ml-1.5 text-xs font-medium text-gray-400">
|
||||
{decimalIfNeeded(Number(props.rating!))}
|
||||
</span>
|
||||
<span className="ml-1 text-xs text-gray-400">
|
||||
({Intl.NumberFormat('en-US').format(props.total!)})
|
||||
</span>
|
||||
</>
|
||||
<span className="ml-1.5 text-xs text-gray-400">
|
||||
({Intl.NumberFormat('en-US').format(props.total!)})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
interface FacebookIconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function FacebookIcon(props: FacebookIconProps) {
|
||||
const { className } = props;
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
fill="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +1,49 @@
|
||||
interface LinkedInIconProps {
|
||||
type LinkedInIconProps = {
|
||||
className?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export function LinkedInIcon(props: LinkedInIconProps) {
|
||||
const { className } = props;
|
||||
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0,0,256,256"
|
||||
>
|
||||
<g clipPath="url(#clip0_2344_20)">
|
||||
<path
|
||||
d="M0 0V24H24V0H0ZM8 19H5V8H8V19ZM6.5 6.732C5.534 6.732 4.75 5.942 4.75 4.968C4.75 3.994 5.534 3.204 6.5 3.204C7.466 3.204 8.25 3.994 8.25 4.968C8.25 5.942 7.467 6.732 6.5 6.732ZM20 19H17V13.396C17 10.028 13 10.283 13 13.396V19H10V8H13V9.765C14.397 7.179 20 6.988 20 12.241V19Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<g transform="translate(-26.66667,-26.66667) scale(1.20833,1.20833)">
|
||||
<g
|
||||
fill="none"
|
||||
fillRule="nonzero"
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
strokeLinecap="butt"
|
||||
strokeLinejoin="miter"
|
||||
strokeMiterlimit="10"
|
||||
strokeDasharray=""
|
||||
strokeDashoffset="0"
|
||||
fontFamily="none"
|
||||
fontWeight="none"
|
||||
fontSize="none"
|
||||
textAnchor="none"
|
||||
style={{ mixBlendMode: 'normal' }}
|
||||
>
|
||||
<g transform="scale(5.33333,5.33333)">
|
||||
<path
|
||||
d="M42,37c0,2.762 -2.238,5 -5,5h-26c-2.761,0 -5,-2.238 -5,-5v-26c0,-2.762 2.239,-5 5,-5h26c2.762,0 5,2.238 5,5z"
|
||||
fill="#0288d1"
|
||||
></path>
|
||||
<path
|
||||
d="M12,19h5v17h-5zM14.485,17h-0.028c-1.492,0 -2.457,-1.112 -2.457,-2.501c0,-1.419 0.995,-2.499 2.514,-2.499c1.521,0 2.458,1.08 2.486,2.499c0,1.388 -0.965,2.501 -2.515,2.501zM36,36h-5v-9.099c0,-2.198 -1.225,-3.698 -3.192,-3.698c-1.501,0 -2.313,1.012 -2.707,1.99c-0.144,0.35 -0.101,1.318 -0.101,1.807v9h-5v-17h5v2.616c0.721,-1.116 1.85,-2.616 4.738,-2.616c3.578,0 6.261,2.25 6.261,7.274l0.001,9.726z"
|
||||
fill="#ffffff"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2344_20">
|
||||
<rect width="24" height="24" rx="2" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SVGAttributes } from 'react';
|
||||
import type { JSX } from "preact/jsx-runtime";
|
||||
|
||||
type ShareIconProps = SVGAttributes<SVGSVGElement>;
|
||||
type ShareIconProps = JSX.SVGAttributes<SVGSVGElement>
|
||||
|
||||
export function ShareIcon(props: ShareIconProps) {
|
||||
return (
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
interface TwitterIconProps {
|
||||
type TwitterIconProps = {
|
||||
className?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export function TwitterIcon(props: TwitterIconProps) {
|
||||
const { className } = props;
|
||||
|
||||
return (
|
||||
<svg
|
||||
width="23"
|
||||
height="23"
|
||||
viewBox="0 0 23 23"
|
||||
width="15"
|
||||
height="15"
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<rect width="23" height="23" rx="3" fill="currentColor" />
|
||||
<path
|
||||
d="M12.9285 10.3522L18.5135 4H17.1905L12.339 9.5144L8.467 4H4L9.8565 12.3395L4 19H5.323L10.443 13.1754L14.533 19H19M5.8005 4.97619H7.833L17.1895 18.0718H15.1565"
|
||||
fill="#E5E5E5"
|
||||
d="M8.9285 6.35221L14.5135 0H13.1905L8.339 5.5144L4.467 0H0L5.8565 8.33955L0 15H1.323L6.443 9.17535L10.533 15H15M1.8005 0.976187H3.833L13.1895 14.0718H11.1565"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -91,7 +91,6 @@ export function TeamPricing() {
|
||||
{
|
||||
'top-full': !isCopied,
|
||||
'top-0': isCopied,
|
||||
'opacity-0': !isCopied,
|
||||
},
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { X } from 'lucide-react';
|
||||
|
||||
type PaidResourceDisclaimerProps = {
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export function PaidResourceDisclaimer(props: PaidResourceDisclaimerProps) {
|
||||
const { onClose } = props;
|
||||
|
||||
return (
|
||||
<div className="relative ml-3 mt-4 rounded-md bg-gray-100 p-3 px-3 text-xs text-gray-500">
|
||||
<button className="absolute right-1 top-1" onClick={onClose}>
|
||||
<X size={16} className="absolute right-2 top-2 cursor-pointer" />
|
||||
</button>
|
||||
|
||||
<p className="mb-1 font-medium text-gray-800">
|
||||
Note on Premium Resources
|
||||
</p>
|
||||
<p className="mb-1">
|
||||
These are optional paid resources vetted by the roadmap team.
|
||||
</p>
|
||||
<p>
|
||||
If you purchase a resource, we may receive a small commission at no
|
||||
extra cost to you. This helps us offset the costs of running this site
|
||||
and keep it free for everyone.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { type LucideIcon, Star } from 'lucide-react';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
type ResourceSeparatorProps = {
|
||||
text: string;
|
||||
className?: string;
|
||||
labelClassName?: string;
|
||||
icon?: LucideIcon;
|
||||
};
|
||||
|
||||
export function ResourceListSeparator(props: ResourceSeparatorProps) {
|
||||
const { text, icon: Icon, className = '', labelClassName = '' } = props;
|
||||
|
||||
return (
|
||||
<p
|
||||
className={cn(
|
||||
'relative mt-6 flex items-center justify-start text-purple-600',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'relative left-3 z-50 inline-flex items-center gap-1 rounded-md border border-current bg-white px-2 py-0.5 text-xs font-medium',
|
||||
labelClassName,
|
||||
)}
|
||||
>
|
||||
{Icon && <Icon className="inline-block h-3 w-3 fill-current" />}
|
||||
{text}
|
||||
</span>
|
||||
<hr className="absolute inset-x-0 flex-grow border-current" />
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -22,7 +22,8 @@ import type {
|
||||
RoadmapContentDocument,
|
||||
} from '../CustomRoadmap/CustomRoadmap';
|
||||
import { markdownToHtml, sanitizeMarkdown } from '../../lib/markdown';
|
||||
import { Ban, Coins, FileText, HeartHandshake, Star, X } from 'lucide-react';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { Ban, FileText, HeartHandshake, X } from 'lucide-react';
|
||||
import { getUrlParams, parseUrl } from '../../lib/browser';
|
||||
import { Spinner } from '../ReactIcons/Spinner';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
@@ -30,12 +31,20 @@ import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
|
||||
import { YouTubeIcon } from '../ReactIcons/YouTubeIcon.tsx';
|
||||
import { resourceTitleFromId } from '../../lib/roadmap.ts';
|
||||
import { lockBodyScroll } from '../../lib/dom.ts';
|
||||
import { TopicDetailLink } from './TopicDetailLink.tsx';
|
||||
import { ResourceListSeparator } from './ResourceListSeparator.tsx';
|
||||
import { PaidResourceDisclaimer } from './PaidResourceDisclaimer.tsx';
|
||||
|
||||
export const allowedRoadmapResourceTypes = ['course', 'book', 'other'] as const;
|
||||
export type AllowedRoadmapResourceType =
|
||||
(typeof allowedRoadmapResourceTypes)[number];
|
||||
|
||||
type TopicResource = {
|
||||
_id?: string;
|
||||
title: string;
|
||||
type: AllowedRoadmapResourceType;
|
||||
url: string;
|
||||
topicIds: string[];
|
||||
};
|
||||
|
||||
type TopicDetailProps = {
|
||||
resourceId?: string;
|
||||
resourceTitle?: string;
|
||||
resourceType?: ResourceType;
|
||||
|
||||
@@ -43,44 +52,21 @@ type TopicDetailProps = {
|
||||
canSubmitContribution: boolean;
|
||||
};
|
||||
|
||||
type PaidResourceType = {
|
||||
_id?: string;
|
||||
title: string;
|
||||
type: 'course' | 'book' | 'other';
|
||||
url: string;
|
||||
topicIds: string[];
|
||||
const linkTypes: Record<AllowedLinkTypes, string> = {
|
||||
article: 'bg-yellow-300',
|
||||
course: 'bg-green-400',
|
||||
opensource: 'bg-black text-white',
|
||||
'roadmap.sh': 'bg-black text-white',
|
||||
roadmap: 'bg-black text-white',
|
||||
podcast: 'bg-purple-300',
|
||||
video: 'bg-purple-300',
|
||||
website: 'bg-blue-300',
|
||||
official: 'bg-blue-600 text-white',
|
||||
feed: 'bg-[#ce3df3] text-white',
|
||||
};
|
||||
|
||||
const paidResourcesCache: Record<string, PaidResourceType[]> = {};
|
||||
|
||||
async function fetchRoadmapPaidResources(roadmapId: string) {
|
||||
if (paidResourcesCache[roadmapId]) {
|
||||
return paidResourcesCache[roadmapId];
|
||||
}
|
||||
|
||||
const { response, error } = await httpGet<PaidResourceType[]>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-roadmap-paid-resources/${roadmapId}`,
|
||||
);
|
||||
|
||||
if (!response || error) {
|
||||
console.error(error);
|
||||
return [];
|
||||
}
|
||||
|
||||
paidResourcesCache[roadmapId] = response;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
const PAID_RESOURCE_DISCLAIMER_HIDDEN = 'paid-resource-disclaimer-hidden';
|
||||
|
||||
export function TopicDetail(props: TopicDetailProps) {
|
||||
const {
|
||||
canSubmitContribution,
|
||||
resourceId: defaultResourceId,
|
||||
isEmbed = false,
|
||||
resourceTitle,
|
||||
} = props;
|
||||
const { canSubmitContribution, isEmbed = false, resourceTitle } = props;
|
||||
|
||||
const [hasEnoughLinks, setHasEnoughLinks] = useState(false);
|
||||
const [contributionUrl, setContributionUrl] = useState('');
|
||||
@@ -95,8 +81,7 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
const [links, setLinks] = useState<RoadmapContentDocument['links']>([]);
|
||||
const toast = useToast();
|
||||
|
||||
const [showPaidResourceDisclaimer, setShowPaidResourceDisclaimer] =
|
||||
useState(false);
|
||||
const [topicResources, setTopicResources] = useState<TopicResource[]>([]);
|
||||
|
||||
const { secret } = getUrlParams() as { secret: string };
|
||||
const isGuest = useMemo(() => !isLoggedIn(), []);
|
||||
@@ -106,7 +91,6 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
const [topicId, setTopicId] = useState('');
|
||||
const [resourceId, setResourceId] = useState('');
|
||||
const [resourceType, setResourceType] = useState<ResourceType>('roadmap');
|
||||
const [paidResources, setPaidResources] = useState<PaidResourceType[]>([]);
|
||||
|
||||
// Close the topic detail when user clicks outside the topic detail
|
||||
useOutsideClick(topicRef, () => {
|
||||
@@ -117,19 +101,19 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
setIsActive(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (resourceType !== 'roadmap' || !defaultResourceId) {
|
||||
const loadTopicResources = async (roadmapId: string, topicId: string) => {
|
||||
const sanitizedTopicId = topicId.split('@')?.[1] || topicId;
|
||||
const { response, error } = await httpGet<TopicResource[]>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-topic-resources/${roadmapId}?t=${sanitizedTopicId}`,
|
||||
);
|
||||
|
||||
if (error) {
|
||||
toast.error(error?.message || 'Failed to load topic resources');
|
||||
return;
|
||||
}
|
||||
|
||||
setShowPaidResourceDisclaimer(
|
||||
localStorage.getItem(PAID_RESOURCE_DISCLAIMER_HIDDEN) !== 'true',
|
||||
);
|
||||
|
||||
fetchRoadmapPaidResources(defaultResourceId).then((resources) => {
|
||||
setPaidResources(resources);
|
||||
});
|
||||
}, [defaultResourceId]);
|
||||
setTopicResources(response || []);
|
||||
};
|
||||
|
||||
// Toggle topic is available even if the component UI is not active
|
||||
// This is used on the best practice screen where we have the checkboxes
|
||||
@@ -195,120 +179,125 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
}`;
|
||||
}
|
||||
|
||||
httpGet<string | RoadmapContentDocument>(
|
||||
topicUrl,
|
||||
{},
|
||||
{
|
||||
...(!isCustomResource && {
|
||||
headers: {
|
||||
Accept: 'text/html',
|
||||
},
|
||||
}),
|
||||
},
|
||||
)
|
||||
.then(({ response }) => {
|
||||
if (!response) {
|
||||
setError('Topic not found.');
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
let topicHtml = '';
|
||||
if (!isCustomResource) {
|
||||
const topicDom = new DOMParser().parseFromString(
|
||||
response as string,
|
||||
'text/html',
|
||||
);
|
||||
Promise.all([
|
||||
httpGet<string | RoadmapContentDocument>(
|
||||
topicUrl,
|
||||
{},
|
||||
{
|
||||
...(!isCustomResource && {
|
||||
headers: {
|
||||
Accept: 'text/html',
|
||||
},
|
||||
}),
|
||||
},
|
||||
)
|
||||
.then(({ response }) => {
|
||||
if (!response) {
|
||||
setError('Topic not found.');
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
let topicHtml = '';
|
||||
if (!isCustomResource) {
|
||||
const topicDom = new DOMParser().parseFromString(
|
||||
response as string,
|
||||
'text/html',
|
||||
);
|
||||
|
||||
const links = topicDom.querySelectorAll('a');
|
||||
const urlElem: HTMLElement =
|
||||
topicDom.querySelector('[data-github-url]')!;
|
||||
const contributionUrl = urlElem?.dataset?.githubUrl || '';
|
||||
const links = topicDom.querySelectorAll('a');
|
||||
const urlElem: HTMLElement =
|
||||
topicDom.querySelector('[data-github-url]')!;
|
||||
const contributionUrl = urlElem?.dataset?.githubUrl || '';
|
||||
|
||||
const titleElem: HTMLElement = topicDom.querySelector('h1')!;
|
||||
const otherElems = topicDom.querySelectorAll('body > *:not(h1, div)');
|
||||
const titleElem: HTMLElement = topicDom.querySelector('h1')!;
|
||||
const otherElems = topicDom.querySelectorAll(
|
||||
'body > *:not(h1, div)',
|
||||
);
|
||||
|
||||
let ulWithLinks: HTMLUListElement = document.createElement('ul');
|
||||
let ulWithLinks: HTMLUListElement = document.createElement('ul');
|
||||
|
||||
// we need to remove the `ul` with just links (i.e. resource links)
|
||||
// and show them separately.
|
||||
topicDom.querySelectorAll('ul').forEach((ul) => {
|
||||
const lisWithJustLinks = Array.from(
|
||||
ul.querySelectorAll('li'),
|
||||
).filter((li) => {
|
||||
return (
|
||||
li.children.length === 1 &&
|
||||
li.children[0].tagName === 'A' &&
|
||||
li.children[0].textContent === li.textContent
|
||||
);
|
||||
// we need to remove the `ul` with just links (i.e. resource links)
|
||||
// and show them separately.
|
||||
topicDom.querySelectorAll('ul').forEach((ul) => {
|
||||
const lisWithJustLinks = Array.from(
|
||||
ul.querySelectorAll('li'),
|
||||
).filter((li) => {
|
||||
return (
|
||||
li.children.length === 1 &&
|
||||
li.children[0].tagName === 'A' &&
|
||||
li.children[0].textContent === li.textContent
|
||||
);
|
||||
});
|
||||
|
||||
if (lisWithJustLinks.length > 0) {
|
||||
ulWithLinks = ul;
|
||||
}
|
||||
});
|
||||
|
||||
if (lisWithJustLinks.length > 0) {
|
||||
ulWithLinks = ul;
|
||||
const listLinks = Array.from(ulWithLinks.querySelectorAll('li > a'))
|
||||
.map((link, counter) => {
|
||||
const typePattern = /@([a-z.]+)@/;
|
||||
let linkText = link.textContent || '';
|
||||
const linkHref = link.getAttribute('href') || '';
|
||||
const linkType = linkText.match(typePattern)?.[1] || 'article';
|
||||
|
||||
linkText = linkText.replace(typePattern, '');
|
||||
|
||||
return {
|
||||
id: `link-${linkHref}-${counter}`,
|
||||
title: linkText,
|
||||
url: linkHref,
|
||||
type: linkType as AllowedLinkTypes,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// official at the top
|
||||
// opensource at second
|
||||
// article at third
|
||||
// videos at fourth
|
||||
// rest at last
|
||||
const order = [
|
||||
'official',
|
||||
'opensource',
|
||||
'article',
|
||||
'video',
|
||||
'feed',
|
||||
];
|
||||
return order.indexOf(a.type) - order.indexOf(b.type);
|
||||
});
|
||||
|
||||
if (ulWithLinks) {
|
||||
ulWithLinks.remove();
|
||||
}
|
||||
});
|
||||
|
||||
const listLinks = Array.from(ulWithLinks.querySelectorAll('li > a'))
|
||||
.map((link, counter) => {
|
||||
const typePattern = /@([a-z.]+)@/;
|
||||
let linkText = link.textContent || '';
|
||||
const linkHref = link.getAttribute('href') || '';
|
||||
const linkType = linkText.match(typePattern)?.[1] || 'article';
|
||||
topicHtml = topicDom.body.innerHTML;
|
||||
|
||||
linkText = linkText.replace(typePattern, '');
|
||||
setLinks(listLinks);
|
||||
setHasContent(otherElems.length > 0);
|
||||
setContributionUrl(contributionUrl);
|
||||
setHasEnoughLinks(links.length >= 3);
|
||||
setTopicHtmlTitle(titleElem?.textContent || '');
|
||||
} else {
|
||||
setLinks((response as RoadmapContentDocument)?.links || []);
|
||||
setTopicTitle((response as RoadmapContentDocument)?.title || '');
|
||||
|
||||
return {
|
||||
id: `link-${linkHref}-${counter}`,
|
||||
title: linkText,
|
||||
url: linkHref,
|
||||
type: linkType as AllowedLinkTypes,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// official at the top
|
||||
// opensource at second
|
||||
// article at third
|
||||
// videos at fourth
|
||||
// rest at last
|
||||
const order = [
|
||||
'official',
|
||||
'opensource',
|
||||
'article',
|
||||
'video',
|
||||
'feed',
|
||||
];
|
||||
return order.indexOf(a.type) - order.indexOf(b.type);
|
||||
});
|
||||
const sanitizedMarkdown = sanitizeMarkdown(
|
||||
(response as RoadmapContentDocument).description || '',
|
||||
);
|
||||
|
||||
if (ulWithLinks) {
|
||||
ulWithLinks.remove();
|
||||
setHasContent(sanitizedMarkdown?.length > 0);
|
||||
topicHtml = markdownToHtml(sanitizedMarkdown, false);
|
||||
}
|
||||
|
||||
topicHtml = topicDom.body.innerHTML;
|
||||
|
||||
setLinks(listLinks);
|
||||
setHasContent(otherElems.length > 0);
|
||||
setContributionUrl(contributionUrl);
|
||||
setHasEnoughLinks(links.length >= 3);
|
||||
setTopicHtmlTitle(titleElem?.textContent || '');
|
||||
} else {
|
||||
setLinks((response as RoadmapContentDocument)?.links || []);
|
||||
setTopicTitle((response as RoadmapContentDocument)?.title || '');
|
||||
|
||||
const sanitizedMarkdown = sanitizeMarkdown(
|
||||
(response as RoadmapContentDocument).description || '',
|
||||
);
|
||||
|
||||
setHasContent(sanitizedMarkdown?.length > 0);
|
||||
topicHtml = markdownToHtml(sanitizedMarkdown, false);
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
setTopicHtml(topicHtml);
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
});
|
||||
setIsLoading(false);
|
||||
setTopicHtml(topicHtml);
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
}),
|
||||
loadTopicResources(resourceId, topicId),
|
||||
]);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -330,12 +319,6 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
const tnsLink =
|
||||
'https://thenewstack.io/devops/?utm_source=roadmap.sh&utm_medium=Referral&utm_campaign=Topic';
|
||||
|
||||
const paidResourcesForTopic = paidResources.filter((resource) => {
|
||||
const normalizedTopicId =
|
||||
topicId.indexOf('@') !== -1 ? topicId.split('@')[1] : topicId;
|
||||
return resource.topicIds.includes(normalizedTopicId);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={'relative z-[90]'}>
|
||||
<div
|
||||
@@ -433,71 +416,50 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
)}
|
||||
|
||||
{links.length > 0 && (
|
||||
<>
|
||||
<ResourceListSeparator
|
||||
text="Free Resources"
|
||||
className="text-green-600"
|
||||
icon={HeartHandshake}
|
||||
/>
|
||||
<ul className="ml-3 mt-4 space-y-1">
|
||||
{links.map((link) => {
|
||||
return (
|
||||
<li key={link.id}>
|
||||
<TopicDetailLink
|
||||
url={link.url}
|
||||
type={link.type}
|
||||
title={link.title}
|
||||
onClick={() => {
|
||||
// if it is one of our roadmaps, we want to track the click
|
||||
if (canSubmitContribution) {
|
||||
const parsedUrl = parseUrl(link.url);
|
||||
<ul className="mt-6 space-y-1">
|
||||
{links.map((link) => {
|
||||
return (
|
||||
<li key={link.id}>
|
||||
<a
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
className="group font-medium text-gray-800 underline underline-offset-1 hover:text-black"
|
||||
onClick={() => {
|
||||
// if it is one of our roadmaps, we want to track the click
|
||||
if (canSubmitContribution) {
|
||||
const parsedUrl = parseUrl(link.url);
|
||||
|
||||
window.fireEvent({
|
||||
category: 'TopicResourceClick',
|
||||
action: `Click: ${parsedUrl.hostname}`,
|
||||
label: `${resourceType} / ${resourceId} / ${topicId} / ${link.url}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
{paidResourcesForTopic.length > 0 && (
|
||||
<>
|
||||
<ResourceListSeparator text="Premium Resources" icon={Star} />
|
||||
|
||||
<ul className="ml-3 mt-3 space-y-1">
|
||||
{paidResourcesForTopic.map((resource) => {
|
||||
return (
|
||||
<li key={resource._id}>
|
||||
<TopicDetailLink
|
||||
url={resource.url}
|
||||
type={resource.type as any}
|
||||
title={resource.title}
|
||||
isPaid={true}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
{showPaidResourceDisclaimer && (
|
||||
<PaidResourceDisclaimer
|
||||
onClose={() => {
|
||||
localStorage.setItem(
|
||||
PAID_RESOURCE_DISCLAIMER_HIDDEN,
|
||||
'true',
|
||||
);
|
||||
setShowPaidResourceDisclaimer(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
window.fireEvent({
|
||||
category: 'TopicResourceClick',
|
||||
action: `Click: ${parsedUrl.hostname}`,
|
||||
label: `${resourceType} / ${resourceId} / ${topicId} / ${link.url}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'mr-2 inline-block rounded px-1.5 py-0.5 text-xs uppercase no-underline',
|
||||
link.type in linkTypes
|
||||
? linkTypes[link.type]
|
||||
: 'bg-gray-200',
|
||||
)}
|
||||
>
|
||||
{link.type === 'opensource' ? (
|
||||
<>
|
||||
{link.url.includes('github') && 'GitHub'}
|
||||
{link.url.includes('gitlab') && 'GitLab'}
|
||||
</>
|
||||
) : (
|
||||
link.type
|
||||
)}
|
||||
</span>
|
||||
{link.title}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{/* Contribution */}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
import type { AllowedLinkTypes } from '../CustomRoadmap/CustomRoadmap.tsx';
|
||||
|
||||
const linkTypes: Record<AllowedLinkTypes, string> = {
|
||||
article: 'bg-yellow-300',
|
||||
course: 'bg-green-400',
|
||||
opensource: 'bg-black text-white',
|
||||
'roadmap.sh': 'bg-black text-white',
|
||||
roadmap: 'bg-black text-white',
|
||||
podcast: 'bg-purple-300',
|
||||
video: 'bg-purple-300',
|
||||
website: 'bg-blue-300',
|
||||
official: 'bg-blue-600 text-white',
|
||||
feed: 'bg-[#ce3df3] text-white',
|
||||
};
|
||||
|
||||
const paidLinkTypes: Record<string, string> = {
|
||||
course: 'bg-yellow-300',
|
||||
};
|
||||
|
||||
type TopicDetailLinkProps = {
|
||||
url: string;
|
||||
onClick?: () => void;
|
||||
type: AllowedLinkTypes;
|
||||
title: string;
|
||||
isPaid?: boolean;
|
||||
};
|
||||
|
||||
export function TopicDetailLink(props: TopicDetailLinkProps) {
|
||||
const { url, onClick, type, title, isPaid = false } = props;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
className="group font-medium text-gray-800 underline underline-offset-1 hover:text-black"
|
||||
onClick={onClick}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'mr-2 inline-block rounded px-1.5 py-0.5 text-xs uppercase no-underline',
|
||||
(isPaid ? paidLinkTypes[type] : linkTypes[type]) || 'bg-gray-200',
|
||||
)}
|
||||
>
|
||||
{type === 'opensource' ? (
|
||||
<>
|
||||
{url.includes('github') && 'GitHub'}
|
||||
{url.includes('gitlab') && 'GitLab'}
|
||||
</>
|
||||
) : (
|
||||
type
|
||||
)}
|
||||
</span>
|
||||
{title}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={name}
|
||||
className="h-32 w-32 object-cover rounded-full"
|
||||
className="h-32 w-32 rounded-full"
|
||||
/>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -385,7 +385,7 @@ As a recommendation for technology implementing this project, [Socket.io](http:/
|
||||
|
||||

|
||||
|
||||
For this particular backend project, we’re not going to focus on coding, but rather on backend tools and their configuration. A [CDN](https://aws.amazon.com/what-is/cdn/) (or Content Delivery Network) is a platform that allows you to serve static content (like text files, images, audio, etc) safely and reliably.
|
||||
For this particular backend project, we’re not going to focus on coding, but rather on backend tools and their configuration. A [CDN](https://aws.amazon.com/es/what-is/cdn/) (or Content Delivery Network) is a platform that allows you to serve static content (like text files, images, audio, etc) safely and reliably.
|
||||
|
||||
Instead of having all files inside the same server, the content is replicated and distributed across a network of servers that can provide you with the files at any given point in time.
|
||||
|
||||
@@ -459,4 +459,4 @@ Feel free to add extra commands to make the navigation even more interactive.
|
||||
|
||||
With the last of our backend project ideas, you’ve covered all the major areas involved in backend development and you’re more than ready to apply for a backend development job if you haven’t already.
|
||||
|
||||
If you find a piece of technology that wasn’t covered here, you’ll have the skills required to pick it up in no time.
|
||||
If you find a piece of technology that wasn’t covered here, you’ll have the skills required to pick it up in no time.
|
||||
@@ -1,452 +0,0 @@
|
||||
---
|
||||
title: 'Top 10+ Backend Technologies to Use in @currentYear@: Expert Advice'
|
||||
description: 'Looking for the best backend technologies in @currentYear@? Check out our expert list of top tools for developers.'
|
||||
authorId: fernando
|
||||
excludedBySlug: '/backend/technologies'
|
||||
seo:
|
||||
title: 'Top 10+ Backend Technologies to Use in @currentYear@: Expert Advice'
|
||||
description: 'Looking for the best backend technologies in @currentYear@? Check out our expert list of top tools for developers.'
|
||||
ogImageUrl: 'https://assets.roadmap.sh/guest/backend-technologies-pnof4.jpg'
|
||||
isNew: true
|
||||
type: 'textual'
|
||||
date: 2024-08-27
|
||||
sitemap:
|
||||
priority: 0.7
|
||||
changefreq: 'weekly'
|
||||
tags:
|
||||
- 'guide'
|
||||
- 'textual-guide'
|
||||
- 'guide-sitemap'
|
||||
---
|
||||
|
||||

|
||||
|
||||
Backend technologies are the key to building robust and scalable applications. They power all platforms and products on the web without even being visible to the users.
|
||||
|
||||
While backend programming languages form the foundation of backend development, they aren't enough on their own. Understanding and leveraging the right backend technologies can significantly enhance your development workflow and application performance.
|
||||
|
||||
As a [backend developer](https://roadmap.sh/backend), you’ll be faced with too many options while trying to define your backend technology stack, and that can feel overwhelming.
|
||||
|
||||
So, in this article, we’re going to cover the best backend technologies in the following categories:
|
||||
|
||||
- Databases
|
||||
- Version control systems
|
||||
- Containerization and orchestration
|
||||
- Cloud platforms
|
||||
- APIs & Web Services
|
||||
- Caching systems
|
||||
- Message brokers
|
||||
- Authentication and Authorization systems
|
||||
- CI/CD
|
||||
- Monitoring & Logging
|
||||
|
||||
These should help you stay up-to-date or reach the required level to succeed as a backend developer.
|
||||
|
||||
## Databases
|
||||
|
||||

|
||||
|
||||
We can’t have a list of backend technologies to learn without covering databases. After all, databases are a core piece of the best backend technologies in use today and the backbone of any application, providing the necessary storage and retrieval of data. Choosing the right type of database depends on your application's requirements, such as data consistency, scalability, and complexity.
|
||||
|
||||
### SQL Databases
|
||||
|
||||
SQL databases (or relational databases as they’re also called) bring structure to your data and a standard querying language known as SQL.
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
PostgreSQL is an advanced open-source relational database known for its reliability and extensive feature set. It supports a wide range of data types and complex queries, making it ideal for applications that require ACID compliance and advanced data handling capabilities. PostgreSQL is commonly used in financial systems, data warehousing, and applications needing strong data integrity and complex reporting.
|
||||
|
||||
PostgreSQL also offers robust support for JSON and JSONB data types, enabling seamless integration of relational and NoSQL capabilities within a single database system. Its powerful indexing mechanisms ensure efficient query performance even with large datasets.
|
||||
|
||||
Additionally, PostgreSQL provides advanced security features like row-level security and multi-factor authentication, making it a secure choice for handling sensitive data.
|
||||
|
||||
#### MySQL
|
||||
|
||||
MySQL is a widely used open-source SQL database praised for its speed, reliability, and ease of use. It is particularly popular backend technology for web applications and online transaction processing (OLTP) due to its performance and robust community support. MySQL is often the database of choice for content management systems, e-commerce platforms, and logging applications.
|
||||
|
||||
MySQL also supports a variety of storage engines, including InnoDB, which provides ACID compliance, foreign key support, and transaction-safe operations, making it suitable for a wide range of applications.
|
||||
|
||||
Its replication capabilities, including master-slave and group replication, ensure high availability and scalability for large-scale deployments. Additionally, MySQL offers advanced security features such as data encryption, user authentication, and role-based access control, enhancing its suitability for handling sensitive data.
|
||||
|
||||
#### Microsoft SQL Server
|
||||
|
||||
SQL Server is a relational database management system from Microsoft that offers great performance, scalability, and deep integration with other Microsoft products. It provides comprehensive tools for database management, including advanced analytics and business intelligence features. SQL Server is ideal for enterprise-level applications, data warehousing, and environments where integration with Microsoft services, such as Azure, is beneficial.
|
||||
|
||||
MSSQL Server also includes robust security features, such as transparent data encryption, dynamic data masking, and advanced threat protection, making it a trusted choice for handling sensitive data. It supports a wide range of data types, including spatial and XML data, and offers powerful indexing and query optimization techniques to ensure efficient data retrieval and processing.
|
||||
|
||||
SQL Server's integration with Visual Studio and other Microsoft development tools helps to streamline the development process.
|
||||
|
||||
#### SQLite
|
||||
|
||||
SQLite is a self-contained, serverless, and zero-configuration database engine known for its simplicity and ease of use. It is lightweight and efficient, making it perfect for small to medium-sized applications, mobile apps, desktop applications, and prototyping. SQLite is embedded within the application, eliminating the need for a separate database server, which simplifies deployment and maintenance.
|
||||
Its single-disk file format makes it highly portable across various operating systems and platforms.
|
||||
SQLite's efficient memory and disk usage allow it to perform well even on devices with limited resources, such as IoT devices and embedded systems.
|
||||
|
||||
This makes SQLite an excellent choice for applications where simplicity, reliability, and low overhead are essential.
|
||||
|
||||
### NoSQL Databases
|
||||
|
||||
On the other hand, NoSQL databases allow for more flexibility by removing the need for a fixed schema and structure to your data. Each solution presented here covers a different type of unstructured database, and it’s up to you to decide if that focus actually makes sense for your business logic or not.
|
||||
|
||||
#### MongoDB
|
||||
|
||||
MongoDB is a document-oriented database that offers flexibility and scalability. It handles unstructured data with ease, making it ideal for applications with large-scale data and real-time analytics. MongoDB is commonly used in content management systems, e-commerce platforms, and applications that require a dynamic schema. Its ability to store data in JSON-like documents allows for easy data retrieval and manipulation.
|
||||
|
||||
#### DynamoDB
|
||||
|
||||
DynamoDB is a fully managed NoSQL database service provided by AWS. It is designed for high-performance applications requiring seamless scalability and high availability. DynamoDB is best suited for high-traffic web applications, gaming, and IoT applications. Its serverless nature means it can automatically scale up or down based on demand, ensuring consistent performance and cost-efficiency.
|
||||
|
||||
#### Cassandra
|
||||
|
||||
Cassandra is an open-source distributed NoSQL database known for its high availability and fault tolerance without compromising performance. It is ideal for large-scale applications and real-time big data analytics. Cassandra's distributed architecture makes it perfect for environments requiring continuous availability and the ability to handle large amounts of data across multiple nodes. It is commonly used in social media platforms, recommendation engines, and other data-intensive applications.
|
||||
|
||||
## Version Control Systems
|
||||
|
||||

|
||||
|
||||
Version control systems are essential for managing changes to source code over time, allowing multiple developers to collaborate effectively and maintain a history of changes.
|
||||
|
||||
### Git
|
||||
|
||||
When it comes to picking the right version control tool, Git is the most widely used one. It provides a powerful, flexible, and distributed model for tracking changes. Git’s architecture supports nonlinear development, allowing multiple branches to be created, merged, and managed independently. This makes Git essential for code collaboration and version tracking, making it a foundational tool for any developer.
|
||||
|
||||
Let’s go through some of the key benefits that make Git one of the leading backend technologies in web development.
|
||||
|
||||
#### Distributed Version Control
|
||||
|
||||
Unlike centralized version control systems (CVCS) where a single central repository holds the entire project history, Git allows each developer to have a complete copy of the repository, including its history. This decentralized approach enhances collaboration and ensures that work can continue even if the central server is down.
|
||||
|
||||
#### Branching and Merging
|
||||
|
||||
**Branching**: Git’s lightweight branching model allows developers to create, delete, and switch between branches effortlessly. This facilitates isolated development of features, bug fixes, or experiments without impacting the main codebase.
|
||||
|
||||
**Merging**: Git provides powerful merging capabilities to integrate changes from different branches. Tools like merge commits and rebasing help manage and resolve conflicts, ensuring a smooth integration process.
|
||||
|
||||
#### Performance
|
||||
|
||||
Git is designed to handle everything from small to very large projects with speed and efficiency. Its performance for both local operations (like committing and branching) and remote operations (like fetching and pushing changes) is optimized, making it suitable for high-performance needs.
|
||||
|
||||
#### Commit History and Tracking
|
||||
|
||||
Commit Granularity: Git encourages frequent commits, each with a descriptive message, making it easier to track changes, understand the project history, and identify when and why a change was made.
|
||||
|
||||
**History Viewing**: Commands like git log, git blame, and git bisect allow developers to explore the project’s history, pinpoint the introduction of bugs, and understand the evolution of the codebase.
|
||||
|
||||
#### Collaboration
|
||||
|
||||
While strictly not part of Git’s feature set, these functionalities enhance the basic set of features provided by the version control system.
|
||||
|
||||
**Pull Requests**: Platforms like GitHub, GitLab, and Bitbucket build on Git’s capabilities, offering features like pull requests to facilitate code reviews and discussions before integrating changes into the main branch.
|
||||
|
||||
**Code Reviews**: Integrating with continuous integration (CI) systems, Git platforms enable automated testing and code quality checks, ensuring that changes meet project standards before merging.
|
||||
|
||||
#### Staging Area
|
||||
|
||||
Git’s staging area (or index) provides an intermediate area where changes can be formatted and reviewed before committing. This allows for more granular control over what changes are included in a commit.
|
||||
|
||||
### GitHub
|
||||
|
||||
GitHub is a web-based platform that leverages Git for version control. It provides an extensive list of collaborative features, including (as already mentioned) pull requests, code reviews, and project management tools.
|
||||
|
||||
#### Key Features and Benefits
|
||||
|
||||
**Pull Requests and Code Reviews**: Facilitate discussions around proposed changes before integrating them into the main codebase. Developers can review code, leave comments, and suggest improvements. Built-in tools for reviewing code changes ensure collaborations are following coding standards and catch potential issues early.
|
||||
|
||||
**Project Management**: GitHub Issues allow tracking of bugs, enhancements, and tasks. Milestones help in organizing issues into targeted releases or sprints. Kanban-style boards provide a visual way to manage tasks, track progress, and organize workflows.
|
||||
|
||||
**Continuous Integration and Deployment**: Automate workflows for CI/CD, testing, deployment, and more. GitHub Actions supports custom scripts and pre-built actions to streamline DevOps processes.
|
||||
|
||||
**Community and Collaboration**: Developers can host static websites directly from a GitHub repository with Github Pages, they’re ideal for project documentation or personal websites. Integrated wikis can be used for detailed project documentation. And through forking, starring, and following repositories the platform encourages collaboration and knowledge sharing.
|
||||
|
||||
GitHub’s extensive features and strong community support make it the de facto choice for many companies and developers, both for open-source and private projects.
|
||||
|
||||
### GitLab
|
||||
GitLab is a web-based platform for version control using Git, known for its robust CI/CD pipeline integration. It offers a comprehensive set of tools for the entire DevOps lifecycle, making it suitable for continuous integration, deployment, and monitoring.
|
||||
|
||||
#### Key Features and Benefits
|
||||
|
||||
**Integrated CI/CD**: Built-in continuous integration and continuous deployment pipelines allow backend developers to automate building, testing, and deploying code changes. With Gitlabs they can even automatically configure CI/CD pipelines, deploy applications, and monitor performance, all through the same platform.
|
||||
|
||||
**Security and Compliance**: Gitlabs provides key security capabilities for backend development: built-in static and dynamic application security testing (SAST/DAST).
|
||||
|
||||
**Collaboration and Communication**: Instead of Pull Requests like Github, Gitlabs provides the concept of “Merge Requests”: a simplified code review process with inline comments and suggestions.
|
||||
|
||||
GitLab’s all-in-one platform makes it an excellent choice for teams looking to streamline their DevOps processes and improve collaboration and productivity.
|
||||
|
||||
### Bitbucket
|
||||
|
||||
Bitbucket is a Git-based source code repository hosting service that provides both commercial plans and free accounts for small teams. It integrates seamlessly with Atlassian products like Jira and Trello, making it a great choice for teams already using these tools.
|
||||
|
||||
**Repository Hosting**: Bitbucket supports both Git and Mercurial version control systems. And it offers unlimited private repositories for teams.
|
||||
|
||||
**Integration with Atlassian Products**: Seamlessly integrates with Jira for issue tracking and project management. It can create branches from Jira issues and view development progress which is a fantastic integration for big teams using both tools. If, on the other hand, you’re using Trello, it can connect to Trello’s boards for visual task management and tracking.
|
||||
|
||||
**Continuous Integration and Deployment**: Integrated CI/CD service for automating builds, tests, and deployments. It can be configured with a YAML file for custom workflows.
|
||||
|
||||
**Security and Permissions**: Control who accesses specific branches to enforce workflows and protect critical branches. You can even enhance security with two-factor authentication.
|
||||
|
||||
Bitbucket’s integration with Atlassian’s suite of products, along with its robust CI/CD capabilities, make it an attractive option for teams seeking a tightly integrated development and project management environment.
|
||||
|
||||
## Containerization and Orchestration
|
||||
|
||||

|
||||
|
||||
While backend developers aren’t always directly involved in the deployment process, understanding the basics of containerization and orchestration can help them work and interact with the team in charge of devops (who usually set up these CI/CD pipelines).
|
||||
|
||||
While this is not an exhaustive list of backend technologies, the two main ones to learn about are:
|
||||
|
||||
### Docker
|
||||
|
||||
Docker is a platform for developing, shipping, and running applications in containers. Containers package software and its dependencies, ensuring it runs consistently across different environments. Docker simplifies application deployment and testing, making it ideal for microservices architectures and continuous integration/continuous deployment (CI/CD) pipelines.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Kubernetes is an open-source system for automating the deployment, scaling, and management of containerized applications. It orchestrates containers across clusters of machines, providing high availability, scalability, and efficient resource utilization. Kubernetes is perfect for complex, large-scale applications requiring robust infrastructure management and automated scaling.
|
||||
|
||||
## Cloud Platforms
|
||||
|
||||

|
||||
|
||||
Cloud platforms provide a range of services and infrastructure that allow developers to deploy, manage, and scale applications without maintaining physical servers. Mind you, the “cloud” is nothing else than someone else’s servers that you don’t have to manage.
|
||||
|
||||
These platforms all offer very similar types of managed services (each with its own flavor) that allow you to set up powerful and scalable infrastructures with a few clicks.
|
||||
|
||||
### Amazon Web Services (AWS)
|
||||
|
||||
Amazon Web Services (AWS) is a very complete cloud computing platform offered by Amazon. It provides a broad range of services, including computing power, storage solutions, and databases, catering to various needs and applications.
|
||||
|
||||
#### Key Characteristics of AWS
|
||||
|
||||
**Scalability**: AWS provides scalable solutions that allow businesses to easily adjust resources based on demand.
|
||||
Global Reach: With data centers located worldwide, AWS offers high availability and low latency for global applications.
|
||||
|
||||
**Diverse Service Offerings**: AWS offers a wide range of services, including EC2 for computing, S3 for storage, and RDS for databases.
|
||||
|
||||
**Security and Compliance**: AWS provides robust security features and complies with numerous industry standards and regulations.
|
||||
|
||||
**Cost Management**: Flexible pricing models and cost management tools help businesses optimize their cloud spending.
|
||||
|
||||
### Google Cloud Platform (GCP)
|
||||
|
||||
Google Cloud Platform (GCP) is a suite of cloud computing services provided by Google. Like AWS and Microsoft Azure, GCP offers a variety of services, including computing power, storage, machine learning, and data analytics.
|
||||
|
||||
#### Key Characteristics of GCP
|
||||
|
||||
**AI and Machine Learning**: GCP excels in providing advanced AI and machine learning tools, leveraging Google's expertise.
|
||||
|
||||
**Big Data and Analytics**: GCP offers powerful analytics tools, including BigQuery, for handling large-scale data processing.
|
||||
|
||||
**Networking**: GCP provides a robust and secure global network infrastructure.
|
||||
|
||||
**Integration with Google Services**: Seamless integration with Google Workspace and other Google services enhances productivity and collaboration.
|
||||
|
||||
**Open Source Support**: GCP supports various open-source technologies, promoting flexibility and innovation.
|
||||
|
||||
### Microsoft Azure
|
||||
|
||||
Microsoft Azure is a cloud computing service created by Microsoft, offering a wide range of cloud services, including those for computing, analytics, storage, and networking.
|
||||
|
||||
#### Key Characteristics of Microsoft Azure
|
||||
|
||||
**Integration with Microsoft Products**: Azure offers seamless integration with popular Microsoft software and services.
|
||||
|
||||
**Hybrid Cloud Capabilities**: Azure supports hybrid cloud environments, enabling smooth integration between on-premises and cloud resources.
|
||||
|
||||
**Comprehensive Service Range**: Azure provides a broad spectrum of services, including Azure Virtual Machines, Azure SQL Database, and Azure DevOps.
|
||||
|
||||
**Enterprise-Grade Security**: Azure emphasizes security with advanced features and compliance with industry standards.
|
||||
|
||||
**Developer and IT Pro Tools**: Azure offers a wide range of tools for developers and IT professionals, including Visual Studio and Azure DevOps.
|
||||
|
||||
At a high level, all of these providers are very similar to each other, to the point where backend developers experienced in one of them, can extrapolate their understanding of the environment into others with minimum ramp-up time.
|
||||
|
||||
## APIs and Web Services
|
||||
|
||||

|
||||
|
||||
APIs (or Application Programming Interfaces) and web services are another mandatory incorporation to the list of top backend technologies any developer should keep in mind. They enable communication between different software systems.
|
||||
|
||||
The three most common types of APIs right now, are REST, GraphQL and gPRC, let’s take a closer look at each one of them.
|
||||
|
||||
### REST
|
||||
|
||||
REST is a standard architecture for web services, known for its simplicity and scalability. It operates on stateless principles and uses standard HTTP methods (GET, POST, PUT, DELETE) to perform CRUD (Create, Read, Update, Delete) operations. RESTful APIs are typically used to access and manipulate web resources using URLs.
|
||||
|
||||
REST is ideal for web applications and services due to its ease of implementation and broad compatibility with various web technologies. It is commonly used for developing APIs for web and mobile applications, providing endpoints that clients can interact with to perform various operations. RESTful APIs are also ideal for integrating with third-party services, enabling data exchange and interaction between different systems.
|
||||
|
||||
#### Key Characteristics of REST
|
||||
|
||||
**Statelessness**: Each request from a client contains all the information needed to process the request, without relying on stored context on the server.
|
||||
|
||||
**Uniform Interface**: REST APIs follow standard conventions, making them easy to understand and use. This includes using standard HTTP methods and status codes.
|
||||
|
||||
**Client-Server Architecture**: Separates the client and server concerns, improving scalability and flexibility. Clients handle the user interface and user experience, while servers handle data storage and business logic.
|
||||
|
||||
**Cacheability**: Responses from REST APIs can be cached to improve performance, reducing the need for repeated requests.
|
||||
|
||||
**Layered System**: REST allows for a layered system architecture, enabling intermediaries like load balancers and proxy servers to enhance security, performance, and scalability.
|
||||
|
||||
If you’d like to know more about REST, you can read the full definition directly from [its source here](https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm).
|
||||
|
||||
### GraphQL
|
||||
|
||||
GraphQL is a query language for APIs and a runtime for executing those queries by using a type system you define for your data. Unlike REST, where multiple endpoints return fixed data structures, GraphQL allows clients to request exactly the data they need. This flexibility reduces the amount of data transferred over the network and can significantly improve performance.
|
||||
|
||||
GraphQL is ideal for applications with complex and dynamic data requirements.
|
||||
|
||||
#### Key Characteristics of GraphQL
|
||||
|
||||
**Declarative Data Fetching**: Clients specify the structure of the response, ensuring they receive only the data they need.
|
||||
|
||||
**Strongly Typed Schema**: The API schema is strongly typed, providing clear and detailed documentation of available data and operations.
|
||||
|
||||
**Single Endpoint**: Unlike REST, GraphQL uses a single endpoint to serve all requests, simplifying the API architecture.
|
||||
|
||||
**Real-time Data**: Supports real-time updates through subscriptions, enabling clients to receive live data changes.
|
||||
|
||||
### gRPC
|
||||
|
||||
gRPC is a high-performance, open-source RPC (Remote Procedure Call) framework developed by Google. gRPC is designed for low-latency, high-throughput communication, making it suitable for microservices architectures and real-time communication systems.
|
||||
|
||||
gRPC is ideal for applications that require efficient, reliable, and bi-directional communication.
|
||||
|
||||
#### Key Characteristics of gRPC
|
||||
|
||||
**Protocol Buffers**: Uses Protocol Buffers for compact, efficient, and platform-neutral serialization of structured data.
|
||||
|
||||
**HTTP/2**: Utilizes HTTP/2 for multiplexing, flow control, header compression, and efficient binary transport.
|
||||
|
||||
**Bi-directional Streaming**: Supports multiple types of streaming, including client-side, server-side, and bi-directional streaming.
|
||||
|
||||
**Cross-Language Compatibility**: Provides support for multiple backend programming languages, enabling interoperability between different systems.
|
||||
|
||||
## Caching Systems
|
||||
|
||||

|
||||
|
||||
Caching systems store copies of frequently accessed data to reduce latency and improve application performance. They are essential for speeding up data retrieval and reducing the load on primary data stores.
|
||||
|
||||
Implementing a successful caching strategy is not trivial, and one key aspect of it is the backend technology used for the implementation. While there might be multiple options out there, the industry currently recognizes only one de facto choice: Redis.
|
||||
|
||||
### Redis: a fast in-memory storage solution
|
||||
|
||||
Redis is an in-memory data structure store that can function as a database, cache, and message broker. It supports various data structures such as strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, and with the right add-ons, even vectors. Redis uses a key-value storage mechanism, which makes it simple yet powerful for a wide range of use cases.
|
||||
|
||||
Let’s quickly review some of the characteristics of Redis that make it such a fantastic option.
|
||||
|
||||
#### High Availability and Scalability
|
||||
|
||||
- **Redis Sentinel**: Provides high availability and monitoring, automatically promoting a slave to master in case of failure, ensuring minimal downtime.
|
||||
|
||||
- **Redis Cluster**: Supports automatic sharding, allowing Redis to scale horizontally. It partitions data across multiple nodes, ensuring that the system can handle large datasets and high throughput.
|
||||
|
||||
#### Performance and Use Cases
|
||||
|
||||
Redis's in-memory architecture gives it unmatched I/O speed, making it ideal for real-time applications such as:
|
||||
|
||||
- **Gaming**: Managing leaderboards, player sessions, and real-time statistics.
|
||||
- **Chat Applications**: Storing messages, user presence information, and delivering real-time notifications.
|
||||
- **Analytics**: Real-time data processing and analytics, where rapid data access and manipulation are crucial.
|
||||
- **Caching**: Reducing database load by caching frequently accessed data, improving application response times.
|
||||
|
||||
#### Persistence and Durability
|
||||
|
||||
- **RDB (Redis Database)**: Creates snapshots of the dataset at specified intervals, allowing data to be restored from the last snapshot.
|
||||
- **AOF (Append Only File)**: Logs every write operation received by the server, providing a more durable solution that can replay the log to reconstruct the dataset.
|
||||
- **Hybrid Approach**: Combining RDB and AOF to leverage the benefits of both methods, balancing performance and data durability.
|
||||
|
||||
#### Advanced Features
|
||||
|
||||
On top of all of that, Redis even provides some very powerful out-of-the-box features:
|
||||
|
||||
- **Lua Scripting**: Supports server-side scripting with Lua, enabling complex operations to be executed atomically.
|
||||
- **Pub/Sub Messaging**: Allows for message broadcasting to multiple clients, supporting real-time messaging and notifications. You can create whole event-based architectures around Redis.
|
||||
- **Modules**: Extend Redis functionality with custom modules, such as RedisGraph for graph database capabilities and RedisJSON for JSON document storage.
|
||||
|
||||
Redis's robust feature set, combined with its high performance and flexibility, makes it a versatile tool for developers looking to build scalable and responsive applications.
|
||||
|
||||
## Message Brokers and Streaming Platforms
|
||||
|
||||

|
||||
|
||||
Message brokers and streaming platforms facilitate communication between different parts of a system, enabling efficient data exchange and processing. They are crucial for building scalable and resilient applications and they are the core of reactive architectures (also known as event-based architectures).
|
||||
|
||||
### RabbitMQ
|
||||
|
||||
RabbitMQ is an open-source message broker that implements the Advanced Message Queuing Protocol (AMQP). It supports multiple messaging protocols and can be deployed in distributed and federated configurations. RabbitMQ is ideal for use cases that require reliable message delivery, complex routing, and interoperability with other messaging systems. It is commonly used in financial systems, order processing, and other applications that need robust messaging capabilities.
|
||||
|
||||
### Apache Kafka
|
||||
|
||||
Apache Kafka is a distributed streaming platform designed for high-throughput, low-latency data processing. It excels at handling real-time data feeds, making it suitable for applications that require continuous data integration and processing. Kafka’s publish-subscribe messaging system is fault-tolerant and scalable, making it ideal for big data applications, real-time analytics, event sourcing, and log aggregation. Its ability to store streams of records in a fault-tolerant manner also makes it useful for building event-driven architectures and microservices.
|
||||
|
||||
As backend developers, understanding how to take advantage of these message queues is critical to the development of scalable and resilient platforms. It is definitely a must-have skill and you need to master it.
|
||||
|
||||
## Authentication and Authorization
|
||||
|
||||

|
||||
|
||||
Authentication and authorization technologies are essential for securing applications, ensuring that users are who they claim to be and have the appropriate permissions to access resources.
|
||||
|
||||
This space is filled with solutions and methodologies, so it’s not easy to pick one option here, however, these two are very common solutions used to implement both, authZ (authorization) and authN (authentication).
|
||||
|
||||
### OAuth
|
||||
|
||||
OAuth is an open standard for access delegation commonly used to grant websites or applications limited access to a user’s information without exposing their passwords. It is widely used in single sign-on (SSO) systems, enabling users to log in to multiple applications with a single set of credentials. OAuth is ideal for third-party applications that need access to user data, such as social media integrations and API access management.
|
||||
|
||||
### JWT (JSON Web Tokens)
|
||||
|
||||
JWT is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object, which is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure. JWTs are commonly used for authentication and authorization in web applications, providing a secure way to transmit information between parties. They are particularly useful in stateless authentication systems, where user state is not stored on the server (like when dealing with RESTful APIs).
|
||||
|
||||
## CI/CD Pipelines
|
||||
|
||||

|
||||
|
||||
CI/CD (Continuous Integration/Continuous Deployment) pipelines automate the process of code integration, testing, and deployment, enabling faster and more reliable software delivery. This is one of the key areas backend developers need to understand to avoid creating code that simply gets in the way of the deployment process.
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
GitHub Actions is an integrated CI/CD service within GitHub repositories, allowing developers to automate build, test, and deployment workflows. It supports a wide range of actions and integrations, making it highly customizable and versatile for various development workflows.
|
||||
|
||||
### CircleCI
|
||||
|
||||
CircleCI is a continuous integration and delivery platform that automates the building, testing, and deployment of applications. It supports multiple backend languages and integrates with various version control systems, making it a popular choice for diverse development environments. CircleCI is known for its speed and ease of setup, providing robust tools for optimizing and monitoring CI/CD pipelines.
|
||||
|
||||
### GitLab CI/CD
|
||||
|
||||
GitLab CI/CD is an integrated part of the GitLab platform (similar to how GitHub actions are a part of GitHub), offering continuous integration, delivery, and deployment features within the GitLab ecosystem. It allows developers to manage their entire DevOps lifecycle in a single application, from planning and coding to monitoring and security. GitLab CI/CD is particularly useful for teams seeking a seamless and comprehensive CI/CD solution.
|
||||
|
||||
### Jenkins
|
||||
|
||||
If instead of a SaaS, you’re looking for a solution that you can potentially self-host, then you might want to look into Jenkins. Jenkins is an open-source automation server that provides hundreds of plugins to support building, deploying, and automating your software development process. It is highly extensible and can be integrated with a wide array of tools and technologies. Jenkins is ideal for complex, large-scale projects requiring a customizable and powerful CI/CD environment.
|
||||
|
||||
## Monitoring and Logging
|
||||
|
||||

|
||||
|
||||
Understanding how the systems that you develop behave and perform on a daily basis is crucial to launching a successful product. Here’s where monitoring and logging come into play. Monitoring and logging are crucial pieces of backend technology used for maintaining the health, performance, and security of applications. These tools help detect issues, analyze performance, and ensure system reliability.
|
||||
|
||||
### ELK Stack (Elasticsearch, Logstash, Kibana)
|
||||
|
||||
The ELK Stack is a set of tools for searching, analyzing, and visualizing log data in real time. Elasticsearch is a search and analytics engine, Logstash is a server-side data processing pipeline, and Kibana is a visualization tool. Together, they provide a powerful platform for centralized logging and monitoring, making them ideal for applications requiring detailed log analysis and real-time insights.
|
||||
|
||||
### Grafana
|
||||
|
||||
Grafana is an open-source platform for monitoring and observability that integrates with various data sources. It provides powerful visualizations, dashboards, and alerting capabilities, making it a popular choice for monitoring infrastructure and application performance. Grafana is particularly useful for teams needing a flexible and customizable monitoring solution.
|
||||
|
||||
### Loki
|
||||
|
||||
Loki is a log aggregation system designed to work with Grafana. It is optimized for cost-effective and scalable logging, making it suitable for applications with high log volumes. Loki simplifies log management by allowing developers to query logs using the same language as Grafana, providing seamless integration for comprehensive observability.
|
||||
|
||||
### Prometheus
|
||||
|
||||
Prometheus is an open-source monitoring and alerting toolkit designed for reliability and scalability. It collects and stores metrics as time series data, providing powerful querying language and alerting capabilities. Prometheus is ideal for monitoring applications and infrastructure, particularly in cloud-native and microservices environments, where dynamic and ephemeral resources are common.
|
||||
|
||||
In the end, you might want to go with one or several of these options, the point is that you, as a developer, should be aware of them and what type of value they add to the project.
|
||||
|
||||
## Conclusion
|
||||
|
||||
As backend developers, focusing on a backend programming language and a backend framework is not going to be enough. The backend ecosystem is very rich, and there are many areas that are either directly or indirectly related to the daily tasks that a backend dev needs to work on.
|
||||
|
||||
This is why you need to stay up-to-date and look at the trends that develop within each area to make sure you’re still working with and focusing on the right solutions.
|
||||
|
||||
If you'd like more details on the type of backend development technologies you should be focusing on to excel at your role as a backend developer, check out our [Backend Developer roadmap](https://roadmap.sh/backend).
|
||||
@@ -132,7 +132,7 @@ As a DevOps professional, you can decide to go for any of these following DevOps
|
||||
- Automation expert
|
||||
- General DevOps engineer
|
||||
- System engineer
|
||||
- DevOps architect
|
||||
- DevOps erchitect
|
||||
- DevOps release manager
|
||||
- DevSecOps engineer
|
||||
- DevOps test engineer
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: 'Accessible Form UI'
|
||||
description: 'Create an accessible form UI using HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 7
|
||||
difficulty: 'beginner'
|
||||
nature: 'Accessibility'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'Layouts'
|
||||
- 'Positioning'
|
||||
- 'Accessibility'
|
||||
seo:
|
||||
title: 'Create an Accessible Form UI for a Website Using HTML and CSS'
|
||||
description: 'Learn how to create an accessible form component using HTML and CSS.'
|
||||
keywords:
|
||||
- 'accessible forms'
|
||||
- 'css project idea'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
In this project, you are required to create a form UI using only HTML and CSS. The form will include fields for a full name, email, password, and confirm password, along with a button to toggle the visibility of the password text. Additionally, the form will feature a completeness progress bar and a checklist of requirements that must be met for the form to reach 100% completeness. While this version of the form won’t be functional, it will be a static UI component that can be enhanced with JavaScript in the future.
|
||||
|
||||
The goal of this project is to not only help you practice your HTML and CSS but also to focus on creating an accessible form that is easy to use for all users, including those with disabilities. Given below is the rough mockup of the form UI that you need to create:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/form-components-7t4b3.png)
|
||||
|
||||
## Accessibility Guidelines
|
||||
|
||||
You should read up on accessibility guidelines and best practices before starting this project. However, here are some key points to keep in mind while creating an accessible form UI:
|
||||
|
||||
- **Labeling**: Ensure that each form field has a corresponding `<label>` element that is clearly associated with the field using the `for` attribute.
|
||||
- **Focus State**: Style the focus state of each input field so that users navigating with a keyboard can easily see which field is currently active.
|
||||
- **Error Messaging**: Consider adding space for error messages that can be displayed when a user inputs invalid data. These messages should be clearly associated with the relevant input field.
|
||||
- **ARIA Attributes**: Use ARIA (Accessible Rich Internet Applications) attributes where necessary, such as `aria-required` for required fields and `aria-invalid` for fields with errors.
|
||||
- **Color Contrast**: Ensure that the color contrast between text and background is sufficient to meet WCAG (Web Content Accessibility Guidelines) standards, making the form readable for users with visual impairments.
|
||||
- **Interactive Elements**: Make sure that the button to show/hide the password is accessible via keyboard and screen readers, providing clear feedback on the current state (e.g., "Password is hidden" or "Password is visible").
|
||||
|
||||
Once done, you can test the form UI using a screen reader or browser extensions like Axe or Lighthouse to check for accessibility issues and make necessary adjustments.
|
||||
|
||||
---
|
||||
|
||||
After completing this project, you will have a solid foundation in creating accessible and well-structured forms using HTML and CSS. You can later enhance this form by adding JavaScript to make it fully functional and dynamic in future projects.
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
title: 'Accordion'
|
||||
description: 'Create an accordion component using HTML, CSS, and JavaScript.'
|
||||
isNew: false
|
||||
sort: 18
|
||||
difficulty: 'beginner'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Build an Accordion Component with JavaScript'
|
||||
description: 'Learn how to create a responsive accordion component that allows users to toggle between different sections of content.'
|
||||
keywords:
|
||||
- 'accordion'
|
||||
- 'javascript accordion'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
You are required to create an accordion component that displays a list of questions or headings. When a user clicks on a question, its corresponding answer or content section will expand while collapsing any previously opened section. This allows only one section to be open at a time, keeping the UI clean and organized.
|
||||
|
||||
Given below is the mockup showing the accordion in its default and expanded states:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/accordion-rbvpo.png)
|
||||
|
||||
This project will help you practice DOM manipulation, event handling, and implementing responsive design patterns using JavaScript.
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: 'Github Actions Workflow'
|
||||
description: 'Write GitHub Actions workflow to deploy a simple GitHub Pages site.'
|
||||
isNew: true
|
||||
sort: 3
|
||||
difficulty: 'beginner'
|
||||
nature: 'CI/CD'
|
||||
skills:
|
||||
- 'devops'
|
||||
- 'github actions'
|
||||
- 'ci/cd'
|
||||
seo:
|
||||
title: 'Github Actions Workflow'
|
||||
description: 'Write GitHub Actions workflow to deploy a simple GitHub Pages site.'
|
||||
keywords:
|
||||
- 'basic ci/cd'
|
||||
- 'devops'
|
||||
- 'devops projects'
|
||||
roadmapIds:
|
||||
- 'git-github'
|
||||
- 'devops'
|
||||
---
|
||||
|
||||
In this project, you will write a basic HTML file and setup a GitHub Actions workflow to test, build & deploy it to GitHub Pages.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Create a simple HTML file (the content is up to you)
|
||||
- Create a GitHub Actions workflow that will test, build & deploy the website to [GitHub Pages](https://pages.github.com/).
|
||||
- Failures in the workflow should be clearly indicated and failures will halt the workflow
|
||||
- The workflow should be in the `.github/workflows` directory
|
||||
- The workflow file should be named `main.yml`
|
||||
|
||||
<hr />
|
||||
|
||||
If you are looking to build a more advanced version of this project, you can either create a more advanced Astro website or you can build a more advanced GitHub Actions workflow.
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: 'Basic HTML Website'
|
||||
description: 'Create simple HTML only website with multiple pages.'
|
||||
isNew: false
|
||||
sort: 2
|
||||
difficulty: 'beginner'
|
||||
nature: 'HTML'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'Layouts'
|
||||
- 'semantic HTML'
|
||||
seo:
|
||||
title: 'Basic HTML Website Project'
|
||||
description: 'Create a simple HTML only website with multiple pages.'
|
||||
keywords:
|
||||
- 'basic html'
|
||||
- 'html project idea'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
> Goal of this project is to teach you how to structure a website using HTML i.e. different sections of a website like header, footer, navigation, main content, sidebars etc. Do not style the website, only focus on the structure. Styling will be done in separate projects.
|
||||
|
||||
In this project, you are required to create a simple HTML only website with multiple pages. The website should have following pages:
|
||||
|
||||
- Homepage
|
||||
- Projects
|
||||
- Articles
|
||||
- Contact
|
||||
|
||||
The website should have a navigation bar that should be present on all pages and link to all the pages.
|
||||
|
||||
You are not required to style the website, you are only required to create the structure of the website using HTML. Goals of this project are:
|
||||
|
||||
- Learn how to create multiple pages in a website.
|
||||
- Structure a website using HTML in a semantic way.
|
||||
- Structure in a way that you can easily add styles later.
|
||||
- Add SEO meta tags to the website.
|
||||
|
||||
You can use the following mockup example to create the structure of the website (remember, you are not required to style the website, only focus on the structure that you can style later):
|
||||
|
||||

|
||||
|
||||
Again, make sure that your submission includes the following:
|
||||
|
||||
- Semantically correct HTML structure.
|
||||
- Multiple pages with a navigation bar.
|
||||
- SEO meta tags in the head of each page.
|
||||
- Contact page should have a form with fields like name, email, message etc.
|
||||
|
||||
<hr />
|
||||
|
||||
After completing this project, you will have a good understanding of how to structure a website using HTML, basic SEO meta tags, HTML tags, forms etc. You can now move on to the next project where you will learn how to style this website using CSS.
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: 'Basic Infrastructure as Code with Terraform'
|
||||
description: 'Provision a simple cloud infrastructure using Terraform'
|
||||
isNew: false
|
||||
sort: 4
|
||||
difficulty: 'beginner'
|
||||
nature: 'CLI'
|
||||
skills:
|
||||
- 'terraform'
|
||||
- 'devops'
|
||||
- 'iac'
|
||||
- 'cloud'
|
||||
seo:
|
||||
title: 'Basic Infrastructure as Code with Terraform'
|
||||
description: 'Learn to provision cloud resources using Terraform'
|
||||
keywords:
|
||||
- 'terraform'
|
||||
- 'infrastructure as code'
|
||||
- 'cloud provisioning'
|
||||
- 'devops'
|
||||
roadmapIds:
|
||||
- 'devops'
|
||||
- 'terraform'
|
||||
- 'aws'
|
||||
---
|
||||
|
||||
In this project, you will use Terraform to provision a virtual machine in AWS.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Install Terraform on your local machine.
|
||||
- Set up an account with a AWS and obtain necessary credentials.
|
||||
- Create a `main.tf` file in the root directory of your project.
|
||||
- Write Terraform configuration to provision a basic resource (e.g., an EC2 instance on AWS or a VM on Azure).
|
||||
- Use Terraform commands to initialize, plan, apply, and destroy your infrastructure.
|
||||
- The provisioned resource should be accessible and verifiable in your cloud provider's console.
|
||||
|
||||
You can learn more about Terraform basics [here](https://learn.hashicorp.com/terraform).
|
||||
|
||||
<hr />
|
||||
|
||||
For a more advanced version of this project, consider adding multiple resources, using variables and outputs, or implementing a modular structure for your Terraform configuration.
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
title: 'Changelog Component'
|
||||
description: 'Create a changelog component for a website using HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 4
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'Layouts'
|
||||
- 'CSS'
|
||||
- 'Flexbox'
|
||||
seo:
|
||||
title: 'Create a Changelog Component Website Using HTML and CSS'
|
||||
description: 'Learn how to create a changelog component for a website using HTML and CSS.'
|
||||
keywords:
|
||||
- 'basic css'
|
||||
- 'css project idea'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
In this project you are required to create a simple component for a website that displays a changelog. A changelog is a log or record of all notable changes made to a project or software. It is often used to keep users informed about the latest updates and improvements.
|
||||
|
||||
The goal of this project is to teach you about positioning and layout in CSS. You will create a simple HTML structure and use CSS to style it into a visually appealing and responsive changelog component. Given below is a rough mockup of the changelog component you need to create.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/changelog-component-1m86j.png)
|
||||
|
||||
Feel free to customize the design and layout of the component as you see fit. The focus should be on creating a well-structured and responsive component that can be easily integrated into a website.
|
||||
|
||||
---
|
||||
|
||||
After completing this project, you will have a good understanding of how to create simple layouts using HTML and CSS. You can further enhance your skills by exploring more complex layouts, such as grids and flexbox, in future projects.
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
title: 'Cookie Consent'
|
||||
description: 'Create a simple cookie consent banner using JavaScript.'
|
||||
isNew: false
|
||||
sort: 12
|
||||
difficulty: 'beginner'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Create a Cookie Consent Popup Using HTML, CSS, and JavaScript'
|
||||
description: 'Learn how to build a cookie consent popup with basic JavaScript for managing user consent.'
|
||||
keywords:
|
||||
- 'cookie consent'
|
||||
- 'javascript popup'
|
||||
- 'html and css'
|
||||
- 'javascript project'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
This project is designed to introduce you to basic DOM manipulation and event handling in JavaScript.
|
||||
|
||||
Many websites display a cookie consent popup to inform users about the use of cookies and to obtain their consent. In this project, you will create a simple cookie consent popup that appears when the user visits the page. The popup will include a message and a button to accept the consent. Once accepted, the popup will disappear. Given below is an example of how the popup might look:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/cookie-consent-banner-07etz.png)
|
||||
|
||||
Bonus points if you persist the user's consent using cookies or local storage and prevent the popup from appearing on subsequent visits.
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
title: 'Custom Dropdown'
|
||||
description: 'Create a custom dropdown using HTML, CSS, and JavaScript.'
|
||||
isNew: false
|
||||
sort: 19
|
||||
difficulty: 'intermediate'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Build a Custom Dropdown Menu with JavaScript'
|
||||
description: 'Learn how to create a fully customizable dropdown menu that allows users to select an item and see the selection reflected in the dropdown.'
|
||||
keywords:
|
||||
- 'custom dropdown'
|
||||
- 'javascript dropdown'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
You will create a custom dropdown menu that lets users select an item from a list. The dropdown should have a default state showing a placeholder text, an open state revealing all options, and a selected state where the chosen item is displayed. When an item is selected, the dropdown closes, and the selected item is highlighted.
|
||||
|
||||
Given below is the mockup showing the dropdown in its default, open, and selected states:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/dropdown-1f4b3.png)
|
||||
|
||||
This project will help you practice DOM manipulation, event handling, and creating responsive and interactive elements with JavaScript.
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: 'Datepicker UI'
|
||||
description: 'Create a simple datepicker UI using HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 6
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'Layouts'
|
||||
- 'Positioning'
|
||||
seo:
|
||||
title: 'Create a Datepicker UI for a Website Using HTML and CSS'
|
||||
description: 'Learn how to create a datepicker component using HTML and CSS.'
|
||||
keywords:
|
||||
- 'basic css'
|
||||
- 'css project idea'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
In this project, you are required to create a simple datepicker UI using only HTML and CSS. It will not be a functional datepicker, but a static UI component that you can later enhance with JavaScript.
|
||||
|
||||
The goal of this project is to help you practice positioning, layout, and styling techniques in CSS. Below is a rough mockup showing the datepicker UI you need to create.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/datepicker-ui-7l480.png)
|
||||
|
||||
Feel free to customize the colors, fonts, and overall design to match your style.
|
||||
|
||||
---
|
||||
|
||||
While this version won't be functional, it will provide a solid foundation for creating an interactive datepicker in a future project.
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: 'Docker Web Server'
|
||||
description: 'Create a Web Server using Docker & NGINX'
|
||||
isNew: false
|
||||
sort: 3
|
||||
difficulty: 'beginner'
|
||||
nature: 'CLI'
|
||||
skills:
|
||||
- 'docker'
|
||||
- 'devops'
|
||||
- 'nginx'
|
||||
- 'web'
|
||||
seo:
|
||||
title: 'Docker Web Server'
|
||||
description: 'Create a Web Server using Docker & NGINX'
|
||||
keywords:
|
||||
- 'docker web server'
|
||||
- 'docker'
|
||||
- 'system administration'
|
||||
- 'web server'
|
||||
roadmapIds:
|
||||
- 'devops'
|
||||
- 'docker'
|
||||
---
|
||||
|
||||
In this project, you will create an NGINX web server that will serve a simple HTML page using Docker.
|
||||
|
||||
## Requirements
|
||||
|
||||
- The Dockerfile should be named `Dockerfile`.
|
||||
- The Dockerfile should be in the root directory of the project.
|
||||
- The build process will add a local HTML file to the container, which will be accessible to NGINX.
|
||||
- The simple HTML page will be accessible to you from `localhost:8080`
|
||||
|
||||
You can learn more about writing a Dockerfile [here](https://docs.docker.com/engine/reference/builder/).
|
||||
|
||||
<hr />
|
||||
|
||||
If you are looking to build a more advanced version of this project, you can consider using the `alpine:latest` image and setting up NGINX yourself rather than using the official NGINX image.
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: 'GitHub Random Repository'
|
||||
description: 'Create a GitHub random repository finder using GitHub API.'
|
||||
isNew: false
|
||||
sort: 25
|
||||
difficulty: 'intermediate'
|
||||
nature: 'API Integration'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'API Integration'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Build a GitHub Repository Finder with JavaScript and GitHub API'
|
||||
description: 'Learn how to create a dynamic application that fetches random GitHub repositories based on a chosen language and displays key information like stars, forks, and issues.'
|
||||
keywords:
|
||||
- 'github api'
|
||||
- 'repository finder'
|
||||
- 'javascript project'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
This project is designed to introduce you to working with external APIs, handling asynchronous requests, and managing different UI states with JavaScript.
|
||||
|
||||
You will create a GitHub repository finder that allows users to select a programming language from a dropdown menu. The app will then use the GitHub Repository Search API to fetch and display a random repository that matches the selected language. The displayed information should include the repository name, description, number of stars, forks, and open issues. Users can fetch another random repository with a button click.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/github-repo-finder-n2qz4.png)
|
||||
|
||||
The application should handle loading, empty, and error states effectively. After successfully fetching a repository, a "Refresh" button should appear to allow users to get another random repository.
|
||||
|
||||
Here are the links to the resources you will need for this project:
|
||||
|
||||
- [GitHub Repository Search API](https://docs.github.com/en/rest/reference/search#search-repositories)
|
||||
- [Programming Language Data](https://raw.githubusercontent.com/kamranahmedse/githunt/master/src/components/filters/language-filter/languages.json)
|
||||
|
||||
This project will help you practice API integration, managing asynchronous data, and enhancing user experience with responsive UI states.
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: 'Image Grid Layout'
|
||||
description: 'Create a grid layout of images using HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 8
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'Grid Layout'
|
||||
- 'Responsive Design'
|
||||
seo:
|
||||
title: 'Create an Image Grid Layout for a Website Using HTML and CSS'
|
||||
description: 'Learn how to create a responsive grid layout of images using HTML and CSS.'
|
||||
keywords:
|
||||
- 'css grid'
|
||||
- 'image layout'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
In this project, you are required to create a grid layout using HTML and CSS. You will be provided with six images that need to be arranged in a grid pattern based on the provided mockup. The primary focus of this project is to help you learn and practice the CSS Grid layout technique, which is essential for creating responsive and flexible web layouts.
|
||||
|
||||
The goal of this project is to give you hands-on experience with CSS Grid, allowing you to create complex layouts with ease. Below is a rough mockup showing the grid layout you need to create along with the six images that you should use.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/image-grid.jpg)
|
||||
|
||||
You can use the same images provided in the mockup or replace them with your own images. The grid layout should be responsive, meaning it should adapt to different screen sizes and maintain a visually appealing design.
|
||||
|
||||
- [A foggy beach with a large rock formation in the foreground](https://unsplash.com/photos/a-foggy-beach-with-a-large-rock-formation-in-the-foreground-TTExgxV06KA)
|
||||
- [A living room with a white couch and a round window](https://unsplash.com/photos/a-living-room-with-a-white-couch-and-a-round-window-Wuu6H3mI7UA)
|
||||
- [A table topped with plates and bowls of food](https://unsplash.com/photos/a-table-topped-with-plates-and-bowls-of-food-zx8_8jwZ5m8)
|
||||
- [A building with a red door and a tree in front of it](https://unsplash.com/photos/a-building-with-a-red-door-and-a-tree-in-front-of-it-uTd-kylh7bE)
|
||||
- [A row of white apartment buildings next to a street](https://unsplash.com/photos/a-row-of-white-apartment-buildings-next-to-a-street-f1PzRPbqt0M)
|
||||
- [A view of a beach from the top of a hill](https://unsplash.com/photos/a-view-of-a-beach-from-the-top-of-a-hill-SAyIShcE5rs)
|
||||
|
||||
Key learning objectives of this project include:
|
||||
|
||||
- **Grid Structure**: Understand the fundamentals of CSS Grid, including defining grid containers, rows, columns, and how to place items within the grid.
|
||||
|
||||
- **Responsive Design**: Learn how to make the grid layout responsive so that it adapts to different screen sizes. This might involve changing the number of columns or the layout of the images based on the viewport width.
|
||||
|
||||
- **Alignment and Spacing**: Explore how to align grid items and manage spacing between them to achieve a clean and visually appealing layout.
|
||||
|
||||
---
|
||||
|
||||
By completing this project, you will gain confidence in using CSS Grid to create flexible and responsive layouts. You can further apply these skills to more complex projects as you continue learning web design and development.
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: 'Local Monitoring System with Docker'
|
||||
description: 'Set up a local monitoring system using Docker with Grafana and Prometheus'
|
||||
isNew: false
|
||||
sort: 1
|
||||
difficulty: 'intermediate'
|
||||
nature: 'CLI'
|
||||
skills:
|
||||
- 'docker'
|
||||
- 'devops'
|
||||
- 'monitoring'
|
||||
- 'grafana'
|
||||
- 'prometheus'
|
||||
seo:
|
||||
title: 'Local Monitoring System with Docker, Grafana, and Prometheus'
|
||||
description: 'Learn to set up a local monitoring system using Docker with Grafana and Prometheus'
|
||||
keywords:
|
||||
- 'docker'
|
||||
- 'monitoring'
|
||||
- 'grafana'
|
||||
- 'prometheus'
|
||||
- 'devops'
|
||||
roadmapIds:
|
||||
- 'devops'
|
||||
- 'docker'
|
||||
---
|
||||
|
||||
In this project, you will set up a local monitoring system using Docker, Grafana, and Prometheus. This setup will allow you to collect metrics and visualize them in a dashboard.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker and Docker Compose installed on your local machine.
|
||||
- Create a `docker-compose.yml` file in the root directory of your project.
|
||||
- Set up Prometheus as the metrics collection system.
|
||||
- Configure Grafana as the visualization tool.
|
||||
- Create a simple dashboard in Grafana to display system metrics.
|
||||
- Add a sample application to monitor, such as a simple web server.
|
||||
|
||||
Your `docker-compose.yml` file should define services for:
|
||||
1. Prometheus
|
||||
2. Grafana
|
||||
3. A sample application to monitor
|
||||
|
||||
## Steps
|
||||
|
||||
1. Create the `docker-compose.yml` file with services for Prometheus and Grafana.
|
||||
2. Configure Prometheus to scrape metrics (you'll need a `prometheus.yml` configuration file).
|
||||
3. Set up Grafana to use Prometheus as a data source.
|
||||
4. Create a simple dashboard in Grafana to display metrics.
|
||||
5. Use `docker-compose up` to start your monitoring stack.
|
||||
6. Access Grafana through your web browser and verify that metrics are being collected and displayed.
|
||||
|
||||
You can learn more about Prometheus [here](https://prometheus.io/docs/introduction/overview/) and Grafana [here](https://grafana.com/docs/grafana/latest/).
|
||||
|
||||
<hr />
|
||||
|
||||
For a more advanced version of this project, consider adding alerting rules in Prometheus, setting up additional exporters to collect more diverse metrics, or monitoring a multi-container application.
|
||||
@@ -1,54 +0,0 @@
|
||||
---
|
||||
title: 'Personal Portfolio'
|
||||
description: 'Convert the previous simple HTML website into a personal portfolio.'
|
||||
isNew: false
|
||||
sort: 3
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'CSS'
|
||||
- 'Responsive Design'
|
||||
- 'Box Model'
|
||||
- 'Typography'
|
||||
- 'Flexbox'
|
||||
seo:
|
||||
title: 'Create a Personal Portfolio Website Using HTML and CSS'
|
||||
description: 'Learn how to style a website using CSS by converting a simple HTML website into a personal portfolio.'
|
||||
keywords:
|
||||
- 'basic css'
|
||||
- 'css project idea'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
> The goal of this project is to teach you how to style a website using CSS. You will take the structure from the [previous HTML-only project](/projects/basic-html-website) and apply various CSS techniques to enhance its appearance and responsiveness.
|
||||
|
||||
In this project, you will style the HTML website structure you created previously [in a different project](/projects/basic-html-website). The focus will be on learning how to use CSS to create responsive layouts, apply color and typography, and enhance the overall design of your website.
|
||||
|
||||
Rough mockups of the website structure for mobile and desctop devices are given below. Do not worry about the design details i.e. colors backgrounds etc at this stage; we are not looking for a beautiful design, but a well-structured and responsive website. Just focus on making the layout same as the mockup and ensuring it looks good on different screen sizes.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/portfolio-template-xdhki.png)
|
||||
|
||||
## Submission Requirements
|
||||
|
||||
Your submission should include:
|
||||
|
||||
- A fully styled, responsive website with the same structure as the previous project.
|
||||
- Consistent use of a chosen color scheme and typography.
|
||||
- Proper use of CSS techniques like Flexbox, media queries, and the box model.
|
||||
- A responsive navigation bar and well-styled contact form.
|
||||
|
||||
## Bonus Points
|
||||
|
||||
For bonus points, you can:
|
||||
|
||||
- Use [Google Fonts](https://fonts.google.com/) to enhance the typography of your website.
|
||||
- Look into [GitHub Pages](https://pages.github.com/) or [Cloudflare Pages](https://pages.cloudflare.com/) to host your website for free.
|
||||
- Add support for dark mode using CSS variables.
|
||||
|
||||
---
|
||||
|
||||
After completing this project, you will have a solid understanding of how to style a basic HTML website using CSS. You can move on to more advanced topics, such as CSS animations, transitions, and grid layouts, in future projects.
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: 'Reddit Client'
|
||||
description: 'Create a Reddit client with customizable subreddit lanes.'
|
||||
isNew: false
|
||||
sort: 26
|
||||
difficulty: 'intermediate'
|
||||
nature: 'API Integration'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'API Integration'
|
||||
- 'DOM Manipulation'
|
||||
- 'Asynchronous Programming'
|
||||
seo:
|
||||
title: 'Build a Multi-Lane Reddit Client with JavaScript and Reddit API'
|
||||
description: 'Learn how to create a dynamic browser-based Reddit client that allows users to add and view multiple subreddits in customizable lanes.'
|
||||
keywords:
|
||||
- 'reddit api'
|
||||
- 'subreddit viewer'
|
||||
- 'javascript project'
|
||||
- 'multi-lane client'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
You are required to create a browser-based Reddit client that displays multiple subreddits in separate, customizable lanes. You'll work with the Reddit JSON feed to fetch posts from different subreddits and display them in a dynamic, responsive layout.
|
||||
|
||||
The application will allow users to add new subreddit lanes by entering a subreddit name. It will verify the existence of the subreddit, fetch its posts, and display them in a new lane. Each lane will show the subreddit's posts, including titles, authors, and vote counts.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/reddit-client-o876k.png)
|
||||
|
||||
To fetch data from reddit, you can use the JSON feed available at the following URL. You can also use the Reddit API to fetch more details about the posts, such as comments, upvotes, and more.
|
||||
|
||||
```plaintext
|
||||
https://www.reddit.com/r/{subreddit}.json
|
||||
```
|
||||
|
||||
The application should handle loading states while fetching data, display error messages for invalid subreddits or API issues, and provide a smooth user experience when adding or removing lanes. You can use local storage to save the user's custom lanes and restore them when the application is reloaded.
|
||||
|
||||
This project will help you practice API integration, state management, asynchronous programming, and creating a responsive, dynamic user interface. It's an excellent opportunity to enhance your skills in frontend development and working with real-time data.
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
title: 'Restricted Textarea'
|
||||
description: 'Create a textarea with live character count and a max character limit.'
|
||||
isNew: false
|
||||
sort: 15
|
||||
difficulty: 'beginner'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Build a Restricted Textarea with JavaScript'
|
||||
description: 'Learn how to create a textarea with live character count and a maximum limit, with visual feedback as the limit is reached.'
|
||||
keywords:
|
||||
- 'character count'
|
||||
- 'textarea limit'
|
||||
- 'javascript input'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
You are required to create a textarea that tracks and displays the number of characters typed by the user, along with a maximum character limit. As the user types, the character count will update dynamically. Once the limit is reached, the textarea will prevent further input and the border will turn red to visually indicate the limit has been hit.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/textarea-input-vdclr.png)
|
||||
|
||||
This project will help you practice manipulating input elements with JavaScript, handling user input events, and providing real-time feedback to enhance user experience.
|
||||
@@ -31,34 +31,84 @@ Build a scalable e-commerce platform using microservices architecture and Docker
|
||||
|
||||
Here are the sample core microservices that you can implement for your e-commerce platform:
|
||||
|
||||
- **User Service:** Handles user registration, authentication, and profile management.
|
||||
- **Product Catalog Service:** Manages product listings, categories, and inventory.
|
||||
- **Shopping Cart Service:** Manages users' shopping carts, including adding/removing items and updating quantities.
|
||||
- **Order Service:** Processes orders, including placing orders, tracking order status, and managing order history.
|
||||
- **Payment Service:** Handles payment processing, integrating with external payment gateways (e.g., Stripe, PayPal).
|
||||
- **Notification Service:** Sends email and SMS notifications for various events (e.g., order confirmation, shipping updates). You can use third-party services like Twilio or SendGrid for this purpose.
|
||||
1. **User Service:**
|
||||
- **Functionality:** Handles user registration, authentication, and profile management.
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Database:** Any database e.g. PostgreSQL
|
||||
|
||||
2. **Product Catalog Service:**
|
||||
- **Functionality:** Manages product listings, categories, and inventory.
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Database:** Any database e.g. MongoDB or MySQL
|
||||
|
||||
3. **Shopping Cart Service:**
|
||||
- **Functionality:** Manages users' shopping carts, including adding/removing items and updating quantities.
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Database:** Redis (for quick access)
|
||||
|
||||
4. **Order Service:**
|
||||
- **Functionality:** Processes orders, including placing orders, tracking order status, and managing order history.
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Database:** MySQL
|
||||
|
||||
5. **Payment Service:**
|
||||
- **Functionality:** Handles payment processing, integrating with external payment gateways.
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Third-Party Integration:** Stripe, PayPal, etc.
|
||||
|
||||
6. **Notification Service:**
|
||||
- **Functionality:** Sends email and SMS notifications for various events (e.g., order confirmation, shipping updates).
|
||||
- **Tech Stack:** Any backend language e.g. Node.js (Express), Go, Python (Flask/Django)
|
||||
- **Third-Party Integration:** Twilio, SendGrid, etc.
|
||||
|
||||
## **Additional Components:**
|
||||
|
||||
In addition to the core microservices, you can include the following components to enhance the scalability, reliability, and manageability of your e-commerce platform:
|
||||
- **API Gateway:**
|
||||
- **Functionality:** Serves as the entry point for all client requests, routing them to the appropriate microservice.
|
||||
- **Tech Stack:** NGINX, Kong, or Traefik
|
||||
|
||||
- **API Gateway:** Serves as the entry point for all client requests, routing them to the appropriate microservice. It might be worth looking into Kong, Traefik, or NGINX for this purpose.
|
||||
- **Service Discovery:** Automatically detects and manages service instances. You can use Consul or Eureka for service discovery.
|
||||
- **Centralized Logging:** Aggregates logs from all microservices for easy monitoring and debugging. You can use the ELK stack (Elasticsearch, Logstash, Kibana) for this purpose.
|
||||
- **Docker & Docker Compose:** Containerize each microservice and manages their orchestration, networking, and scaling. Docker Compose can be used to define and manage multi-container applications.
|
||||
- **CI/CD Pipeline:** Automates the build, test, and deployment process of each microservice. You can use Jenkins, GitLab CI, or GitHub Actions for this purpose.
|
||||
- **Service Discovery:**
|
||||
- **Functionality:** Automatically detects and manages service instances.
|
||||
- **Tech Stack:** Consul or Eureka
|
||||
|
||||
- **Centralized Logging:**
|
||||
- **Functionality:** Aggregates logs from all microservices for easy monitoring and debugging.
|
||||
- **Tech Stack:** ELK Stack (Elasticsearch, Logstash, Kibana)
|
||||
|
||||
- **Docker & Docker Compose:**
|
||||
- **Functionality:** Containerizes each microservice and manages their orchestration, networking, and scaling.
|
||||
- **Docker Compose:** Defines and runs multi-container Docker applications for development and testing.
|
||||
|
||||
- **CI/CD Pipeline:**
|
||||
- **Functionality:** Automates the build, test, and deployment process of each microservice.
|
||||
- **Tech Stack:** Jenkins, GitLab CI, or GitHub Actions
|
||||
|
||||
## Steps to Get Started:
|
||||
|
||||
Here's a high-level roadmap to guide you through the development of your scalable e-commerce platform:
|
||||
1. **Set up Docker and Docker Compose:**
|
||||
- Create Dockerfiles for each microservice.
|
||||
- Use Docker Compose to define and manage multi-container applications.
|
||||
|
||||
- **Set up Docker and Docker Compose:** Create Dockerfiles for each microservice. Use Docker Compose to define and manage multi-container applications.
|
||||
- **Develop Microservices:** Start with a simple MVP (Minimum Viable Product) for each service, then iterate by adding more features.
|
||||
- **Integrate Services:** Use REST APIs or gRPC for communication between microservices. Implement an API Gateway to handle external requests and route them to the appropriate services.
|
||||
- **Implement Service Discovery:** Use Consul or Eureka to enable dynamic service discovery.
|
||||
- **Set up Monitoring and Logging:** Use tools like Prometheus and Grafana for monitoring. Set up the ELK stack for centralized logging.
|
||||
- **Deploy the Platform:** Use Docker Swarm or Kubernetes for production deployment. Implement auto-scaling and load balancing.
|
||||
- **CI/CD Integration:** Automate testing and deployment using Jenkins or GitLab CI.
|
||||
2. **Develop Microservices:**
|
||||
- Start with a simple MVP (Minimum Viable Product) for each service, then iterate by adding more features.
|
||||
|
||||
3. **Integrate Services:**
|
||||
- Use REST APIs or gRPC for communication between microservices.
|
||||
- Implement an API Gateway to handle external requests and route them to the appropriate services.
|
||||
|
||||
4. **Implement Service Discovery:**
|
||||
- Use Consul or Eureka to enable dynamic service discovery.
|
||||
|
||||
5. **Set up Monitoring and Logging:**
|
||||
- Use tools like Prometheus and Grafana for monitoring.
|
||||
- Set up the ELK stack for centralized logging.
|
||||
|
||||
6. **Deploy the Platform:**
|
||||
- Use Docker Swarm or Kubernetes for production deployment.
|
||||
- Implement auto-scaling and load balancing.
|
||||
|
||||
7. **CI/CD Integration:**
|
||||
- Automate testing and deployment using Jenkins or GitLab CI.
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
title: 'Tabs'
|
||||
description: 'Create a simple tabs component using HTML, CSS, and JavaScript.'
|
||||
isNew: false
|
||||
sort: 10
|
||||
difficulty: 'beginner'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Create a Tabs Functionality Using HTML, CSS, and JavaScript'
|
||||
description: 'Learn how to build a tabs component with basic JavaScript for switching between content sections.'
|
||||
keywords:
|
||||
- 'javascript tabs'
|
||||
- 'dynamic content'
|
||||
- 'html and css'
|
||||
- 'javascript project'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
This project is designed to introduce you to basic DOM manipulation and event handling in JavaScript.
|
||||
|
||||
You are required to create a simple tabs functionality using HTML, CSS, and basic JavaScript. The page will have four tabs, with the first tab being active by default. When the user clicks on another tab, the content of the current tab will be hidden, and the content of the selected tab will be displayed.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/simple-tabs-8e6gy.png)
|
||||
|
||||
This project will help you practice selecting elements with JavaScript, listen for click events, and manipulate the dom to show or hide relevant tab content.
|
||||
@@ -1,49 +0,0 @@
|
||||
---
|
||||
title: 'Single-Page CV'
|
||||
description: 'Create a single-page HTML CV to showcase your career history'
|
||||
isNew: false
|
||||
sort: 1
|
||||
difficulty: 'beginner'
|
||||
nature: 'HTML'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'Semantic HTML'
|
||||
- 'Layout'
|
||||
- 'SEO'
|
||||
seo:
|
||||
title: 'Single-Page HTML CV Project'
|
||||
description: 'Create a simple single-page HTML CV that displays your education, skills, and career history.'
|
||||
keywords:
|
||||
- 'html cv'
|
||||
- 'single-page cv'
|
||||
- 'html resume'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
> The goal of this project is to teach you how to create a structured, single-page CV using only HTML. You will focus on laying out your education, skills, and career history in a clean, semantic manner. Styling will be addressed in a later project.
|
||||
|
||||
In this project, you are required to create a single-page CV (Curriculum Vitae) using only HTML. Your webpage should look like the following image:
|
||||
|
||||

|
||||
|
||||
Key requirements for this project:
|
||||
|
||||
- **Semantic HTML**: Use appropriate HTML tags to structure your CV.
|
||||
- **SEO Meta Tags**: Include essential meta tags for SEO.
|
||||
- **Open Graph (OG) Tags**: Add OG tags for better social media sharing.
|
||||
- **Favicon**: Add a favicon for your CV page.
|
||||
|
||||
The structure of your CV should be easily understandable and ready for styling in a future project.
|
||||
|
||||
### Submission Checklist:
|
||||
|
||||
- Semantically correct HTML structure.
|
||||
- Single-page layout with sections for education, skills, and career history.
|
||||
- SEO meta tags in the head section.
|
||||
- OG tags for better social media sharing.
|
||||
- A favicon linked in the head section.
|
||||
|
||||
<hr />
|
||||
|
||||
By completing this project, you'll gain a solid understanding of how to create a single-page CV using HTML, apply basic SEO principles, and prepare your webpage for future styling. This foundation will enable you to move on to styling the CV using CSS in subsequent projects.
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
title: 'Task Tracker'
|
||||
description: 'Create a task tracker with a to-do list using JavaScript.'
|
||||
isNew: false
|
||||
sort: 22
|
||||
difficulty: 'intermediate'
|
||||
nature: 'JavaScript'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'JavaScript'
|
||||
- 'DOM Manipulation'
|
||||
seo:
|
||||
title: 'Build a Task Tracker with JavaScript'
|
||||
description: 'Learn how to create a dynamic task tracker that allows users to add, complete, and delete tasks with real-time updates.'
|
||||
keywords:
|
||||
- 'task tracker'
|
||||
- 'to-do list'
|
||||
- 'javascript project'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
You are required to create a task tracker that lets users add new tasks, mark them as complete, or delete them. Completed tasks will be moved to the end of the list and will have strikethrough, and users can unmark tasks to return them to the pending list.
|
||||
|
||||
Here is the mockup of the task tracker:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/task-tracker-2diba.png)
|
||||
|
||||
## Hint
|
||||
|
||||
Store your tasks in an array of objects, where each object represents a task with properties like description and status (completed or not). Whenever a new task is added, updated, deleted, or marked as complete/uncomplete, update the tasks array. Write a function `renderTasks` which will remove all tasks from the DOM and re-render them based on the updated tasks array.
|
||||
|
||||
This project will help you practice array manipulation, event handling, and dynamic DOM updates using JavaScript.
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
title: Temperature Converter
|
||||
description: Build a temperature converter that converts between different units.
|
||||
isNew: false
|
||||
sort: 27
|
||||
difficulty: intermediate
|
||||
nature: JavaScript
|
||||
skills:
|
||||
- HTML
|
||||
- CSS
|
||||
- JavaScript
|
||||
- DOM Manipulation
|
||||
seo:
|
||||
- title: Build a Temperature Converter with JavaScript
|
||||
- description: Learn how to create an interactive temperature converter that converts between Celsius, Fahrenheit, and Kelvin using JavaScript.
|
||||
- keywords:
|
||||
- 'temperature converter'
|
||||
- 'javascript project'
|
||||
- 'unit conversion'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
---
|
||||
|
||||
This project is designed to help you practice DOM manipulation, form handling, and basic calculations in JavaScript.
|
||||
|
||||
You will create a temperature converter that allows users to enter a temperature value, select the unit they want to convert from, and select the unit they want to convert to. The "Convert" button should only be enabled when all three fields are filled in. Once the user clicks "Convert," the tool will display the converted temperature below the form.
|
||||
|
||||
Here is a mockup of what the temperature converter might look like:
|
||||
|
||||
[](https://assets.roadmap.sh/guest/temperature-converter-8omel.png)
|
||||
|
||||
This project will help you gain experience with handling user input, conditionally enabling form elements, and performing simple calculations using JavaScript.
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: 'Testimonial Cards'
|
||||
description: 'Create testimonial cards for a website using HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 5
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'Layouts'
|
||||
- 'Flexbox'
|
||||
- 'Positioning'
|
||||
seo:
|
||||
title: 'Create Testimonial Cards for a Website Using HTML and CSS'
|
||||
description: 'Learn how to create testimonial components using HTML and CSS.'
|
||||
keywords:
|
||||
- 'basic css'
|
||||
- 'css project idea'
|
||||
- 'responsive design'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
In this project, you are required to create a bunch of testimonial cards. Testimonials are quotes or statements from satisfied customers or users, often used on websites to build credibility and trust.
|
||||
|
||||
The goal of this project is to teach you about positioning and layout in CSS. Below is a rough mockup showing some testimonial cards. Each card is designed to help you understand different layout and positioning techniques.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/testimonials-min-3j2j4.png)
|
||||
|
||||
Feel free to use any content and images you like for the testimonials.
|
||||
|
||||
---
|
||||
|
||||
After completing this project, you will have a good understanding of how to create layouts using HTML and CSS. You can further enhance your skills by exploring more complex projects as you progress.
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
title: 'Tooltip UI'
|
||||
description: 'Create a tooltip for navigation items using only HTML and CSS.'
|
||||
isNew: false
|
||||
sort: 9
|
||||
difficulty: 'beginner'
|
||||
nature: 'CSS'
|
||||
skills:
|
||||
- 'HTML'
|
||||
- 'CSS'
|
||||
- 'Positioning'
|
||||
- 'Hover Effects'
|
||||
seo:
|
||||
title: 'Create a CSS Tooltip for Navigation Items'
|
||||
description: 'Learn how to create a tooltip that appears above navigation items on hover using only HTML and CSS.'
|
||||
keywords:
|
||||
- 'css tooltip'
|
||||
- 'hover effects'
|
||||
- 'navigation menu'
|
||||
- 'html and css'
|
||||
roadmapIds:
|
||||
- 'frontend'
|
||||
|
||||
---
|
||||
|
||||
In this project, you are required to create a tooltip that appears above navigation items when hovered, using only HTML and CSS. A tooltip is a small pop-up box that provides additional information about a navigation item when a user hovers over it. This project will focus on mastering CSS positioning, hover effects, and creating visually appealing tooltips without relying on JavaScript.
|
||||
|
||||
The goal of this project is to help you understand how to use CSS for dynamic UI effects. You will learn how to position elements relative to each other, create smooth transitions, and make your navigation more interactive and user-friendly. Below is a rough mockup showing the tooltip appearing above a navigation item.
|
||||
|
||||
[](https://assets.roadmap.sh/guest/tooltip-zh8gm.png)
|
||||
|
||||
Bonus points for different animations for the tooltip, such as fade-in, slide-in, or scale-in effects.
|
||||
|
||||
After completing this project, you will have a better understanding of CSS positioning, hover effects, and creating interactive UI elements without JavaScript.
|
||||
@@ -1,8 +0,0 @@
|
||||
# Animations
|
||||
|
||||
`Animations` can add visual cues that notify users about what's going on in your app. They are especially useful when the UI changes state, such as when new content loads or new actions become available. Animations also add a polished look to your app, which gives it a higher quality look and feel.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [@official@Google developers: Animations](https://developer.android.com/develop/ui/views/animations/overview)
|
||||
- [@video@Google developers: Animations](https://www.youtube.com/watch?v=N_x7SV3I3P0)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# ConstraintLayout
|
||||
|
||||
Lets you create large, complex layouts with a flat view hierarchy—no nested view groups. It's similar to `RelativeLayout` in that all views are laid out according to relationships between sibling views and the parent layout, but it's more flexible than RelativeLayout and easier to use. Its available on xml and jetpack compose.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [@official@Android developers: ConstraintLayout in xml](https://developer.android.com/develop/ui/views/layout/constraint-layout)
|
||||
- [@official@Android developers: ContraintLayout in compose](https://developer.android.com/develop/ui/compose/layouts/constraintlayout)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# Drawer
|
||||
|
||||
The **Navigation Drawer** in Android is a sliding menu from the left that simplifies navigation between important app links. It opens by sliding or via an icon in the `ActionBar`. It’s an overlay panel that replaces a screen dedicated to displaying options.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [@official@Android developers: DrawerLayout](https://developer.android.com/reference/androidx/drawerlayout/widget/DrawerLayout)
|
||||
- [@article@Navigate Drawer Tutorial](https://www.digitalocean.com/community/tutorials/android-navigation-drawer-example-tutorial)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# EditText
|
||||
|
||||
`EditText` is a fundamental UI element in Android Studio, used for allowing users to input and edit text within an application. It is a subclass of `TextView` that provides additional features to handle user input.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [@official@Android developers: EditText](https://developer.android.com/reference/android/widget/EditText)
|
||||
@@ -1,9 +0,0 @@
|
||||
# ListView
|
||||
|
||||
Displays a vertically-scrollable collection of views, where each view is positioned immediatelybelow the previous view in the list.
|
||||
|
||||
For a more modern, flexible, and performant approach to displaying lists, use `RecyclerView`.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [@official@Android developers: ListView](https://developer.android.com/reference/android/widget/ListView)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user