Compare commits

..

85 Commits

Author SHA1 Message Date
Arik Chakma
3179c95e4e feat: migrate changelogs 2024-09-23 20:16:55 +06:00
Arik Chakma
f75579806b Merge branch 'master' into feat/content-migration 2024-09-23 20:11:39 +06:00
Kamran Ahmed
086c790837 Update alert text 2024-09-23 13:54:50 +01:00
Arik Chakma
9948e89b84 feat: implement changelog page (#7099)
* feat: implement leaderboard page

* feat: sample changelog files

* Update UI for changelog page

* Make changelog page noindex

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-09-23 13:52:42 +01:00
Arik Chakma
3166a02f23 feat: implement roadmap alert (#7116)
* feat: implement roadmap alert

* fix: floating icon position
2024-09-23 13:46:37 +01:00
Kamran Ahmed
e9fdde087f Add redis roadmap 2024-09-23 13:32:25 +01:00
Kamran Ahmed
fdfc8e6c6b Add redis links to roadmaps and get-staretd pages 2024-09-23 13:30:59 +01:00
Arik Chakma
7642493369 feat: update public profile (#7170)
* feat: update public profile

* Update arp@M52V7hmG4ORf4TIVw3W3J.md (#7171)

* Update arp@M52V7hmG4ORf4TIVw3W3J.md

A little changes made to the Topic

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>

* chore: update roadmap content json (#7164)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Add redis roadmap

* Add redis roadmap

* Add redis roadmap

* Improved Docker Roadmap. 🌨️  (#7029)

* Introduction.

* Namespaces.

* Installation & Setup

* Data Persistence.

* Databases.

* Building Container Images.

* Container Registries.

* Running Containers.

* Container Security

* Docker CLI. (Goated)

* Developer Experience.

* Deploying Containers + Extras.

* Few Refractors.

* Trim Content As Requested.

* Undo / Remove Refractors.

* Update 100-dockerhub.md

* Update 101-dockerhub-alt.md

* Update index.md

* Apply Requested Changes.

* Update what-is-hosting@aqMaEY8gkKMikiqleV5EP.md (#7174)

Add new article for 'Web Hosting', it has clearly explained all the details for the beginners. And it will be more reasonable to have not only videos but also article

* replaced broken link (#7176)

* 7165 roadmap title typo (#7177)

* corrected the node title

* corrected file name

* Fix SEO title

* chore: update roadmap content json (#7173)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Complete spell-check for "Prespective Analytics" (#7179)

Corrected "Prespective Analytics" into _Prescriptive Analytics_ 


References:
Issue #7165 
PR #7177

* Fix typo in article title (#7180)

* Update 101-memory-management.md (#7181)

* Update 101-memory-management.md

* Update src/data/roadmaps/java/content/101-java-advanced-topics/101-memory-management.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Add cybersecurity content (#7136)

* add 80+ topics

* 7 topics

* 19 topics

* complete cyber roadmap

* expanded internal links into full urls

* Update DevOps roadmap resources (#7081)

* 6 topics

* 6 topics

* 37 topics

* 25 topics

* 53 topics

* finalised the updated content

* Apply suggestions from code review

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* reverted the removal of go link

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* chore: update roadmap content json (#7188)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Update Rendering link to the new React docs (#7205)

* Fix typo (#7202)

* Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md (#7198)

* Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

* Update src/data/roadmaps/devrel/content/technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md (#7195)

* Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md

* Update src/data/roadmaps/devrel/content/vs-code@j5nNSYI8s-cH8EA6G1EWY.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md (#7193)

* Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

* Update src/data/roadmaps/devrel/content/basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* [Update] Software architect: ITIL (#7191)

* [Update] Software architect: ITIL

* [Update] Android roadmap: Firebase docs (#7190)

* [Update] Android roadmap: Firebase docs

* [Update] Android roadmap: Firebase docs

* Chibuike 19/add redis contents (#7186)

* added content to 10 redis topics

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* Update links type to official (#7209)

* add link for an article about rendering ,by kentcdodds.com (#7208)

* add link for an article about rendering ,by kentcdodds.com

* Update src/data/roadmaps/react/content/rendering@0uiGsC5SWavNdlFqizkKe.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Fix: Change "virutalenv" to "virtualenv" (#7184)

* Update 102-control-flow.md (#7182)

* feat: update dashboard layout (#7155)

* Update button design for cards

* Default visiblity to all

* Fix qa roadmap issue and public projects

* Update button design for profile

---------

Co-authored-by: Vipul Patil <70363133+1VIP1786@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: Vedansh <superuser.ntsystems@outlook.com>
Co-authored-by: Jiayou Zhu <43867657+ZlatanCN@users.noreply.github.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Sarkis Kovlekjian <83559262+kenshanta@users.noreply.github.com>
Co-authored-by: Mark <mac21macky@gmail.com>
Co-authored-by: Rahul <rahulrp3031@gmail.com>
Co-authored-by: tal bendet <68239430+t-bendet@users.noreply.github.com>
Co-authored-by: Philip B. Krogh <71797726+phibkro@users.noreply.github.com>
Co-authored-by: Brian Rodriguez <rzknairb@gmail.com>
Co-authored-by: Obiechina Emmanuel <94564639+chibuike-19@users.noreply.github.com>
Co-authored-by: Inkyung Huh <inkyung.huh@metric-studio.com>
Co-authored-by: Ahmad Asaad <ahmadasaadh@gmail.com>
2024-09-23 13:23:28 +01:00
Kamran Ahmed
3355b91aa0 Update button design for cards 2024-09-23 12:00:23 +01:00
Arik Chakma
9b865678b2 feat: update dashboard layout (#7155) 2024-09-23 11:51:27 +01:00
Ahmad Asaad
9b3ec7cc19 Update 102-control-flow.md (#7182) 2024-09-23 10:49:42 +01:00
Inkyung Huh
e78a7da1a9 Fix: Change "virutalenv" to "virtualenv" (#7184) 2024-09-23 10:40:45 +01:00
tal bendet
8c99cb6ea8 add link for an article about rendering ,by kentcdodds.com (#7208)
* add link for an article about rendering ,by kentcdodds.com

* Update src/data/roadmaps/react/content/rendering@0uiGsC5SWavNdlFqizkKe.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-23 10:32:11 +01:00
tal bendet
bd4e3edf76 Update links type to official (#7209) 2024-09-23 10:29:15 +01:00
Obiechina Emmanuel
af132495d5 Chibuike 19/add redis contents (#7186)
* added content to 10 redis topics

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-09-23 10:28:42 +01:00
Brian Rodriguez
c77465aa8a [Update] Android roadmap: Firebase docs (#7190)
* [Update] Android roadmap: Firebase docs

* [Update] Android roadmap: Firebase docs
2024-09-23 10:20:37 +01:00
Brian Rodriguez
4e02f2fe43 [Update] Software architect: ITIL (#7191)
* [Update] Software architect: ITIL
2024-09-23 10:07:33 +01:00
Vedansh
363fb3cbf5 Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md (#7193)
* Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

* Update src/data/roadmaps/devrel/content/basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-23 10:06:44 +01:00
Vedansh
8f92c34e2e Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md (#7195)
* Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md

* Update src/data/roadmaps/devrel/content/vs-code@j5nNSYI8s-cH8EA6G1EWY.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-23 10:03:18 +01:00
Vedansh
abb4b6ff97 Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md (#7198)
* Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

* Update src/data/roadmaps/devrel/content/technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-23 10:00:01 +01:00
Philip B. Krogh
ba75bc3336 Fix typo (#7202) 2024-09-23 09:56:11 +01:00
tal bendet
ba135d9f0b Update Rendering link to the new React docs (#7205) 2024-09-23 09:53:56 +01:00
github-actions[bot]
47bfa7724e chore: update roadmap content json (#7188)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-21 19:22:26 +06:00
Arik Chakma
33b617ef85 fix: migrate videos 2024-09-21 04:56:29 +06:00
Arik Chakma
2333694e2c feat: migrate projects 2024-09-21 04:26:30 +06:00
Arik Chakma
0aca915e21 fix: remove authors data 2024-09-21 03:13:27 +06:00
Arik Chakma
904ba51b7b fix: migrate content 2024-09-21 03:12:10 +06:00
Arik Chakma
8ccc8aa17d fix: remove .astro 2024-09-21 03:02:11 +06:00
Arik Chakma
ab759671d8 feat: migrate questions 2024-09-21 03:01:34 +06:00
Arik Chakma
cd453e5ad0 wip: migrate authors 2024-09-21 02:23:15 +06:00
dsh
f344571ce4 Update DevOps roadmap resources (#7081)
* 6 topics

* 6 topics

* 37 topics

* 25 topics

* 53 topics

* finalised the updated content

* Apply suggestions from code review

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* reverted the removal of go link

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-09-20 17:16:42 +01:00
dsh
89bea259f9 Add cybersecurity content (#7136)
* add 80+ topics

* 7 topics

* 19 topics

* complete cyber roadmap

* expanded internal links into full urls
2024-09-20 16:37:50 +01:00
Rahul
06489391f5 Update 101-memory-management.md (#7181)
* Update 101-memory-management.md

* Update src/data/roadmaps/java/content/101-java-advanced-topics/101-memory-management.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-20 14:59:17 +01:00
Mark
f08566a24c Fix typo in article title (#7180) 2024-09-20 14:58:30 +01:00
Sarkis Kovlekjian
acfa8c343a Complete spell-check for "Prespective Analytics" (#7179)
Corrected "Prespective Analytics" into _Prescriptive Analytics_ 


References:
Issue #7165 
PR #7177
2024-09-20 14:58:09 +01:00
github-actions[bot]
9f6de412c3 chore: update roadmap content json (#7173)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-20 19:29:22 +06:00
Kamran Ahmed
0998196593 Fix SEO title 2024-09-20 11:18:38 +01:00
dsh
9fdb9be863 7165 roadmap title typo (#7177)
* corrected the node title

* corrected file name
2024-09-20 09:48:46 +01:00
dsh
ca1abffc36 replaced broken link (#7176) 2024-09-20 09:36:24 +01:00
Jiayou Zhu
8b73387f03 Update what-is-hosting@aqMaEY8gkKMikiqleV5EP.md (#7174)
Add new article for 'Web Hosting', it has clearly explained all the details for the beginners. And it will be more reasonable to have not only videos but also article
2024-09-20 09:05:46 +01:00
Vedansh
2eac27b03b Improved Docker Roadmap. 🌨️ (#7029)
* Introduction.

* Namespaces.

* Installation & Setup

* Data Persistence.

* Databases.

* Building Container Images.

* Container Registries.

* Running Containers.

* Container Security

* Docker CLI. (Goated)

* Developer Experience.

* Deploying Containers + Extras.

* Few Refractors.

* Trim Content As Requested.

* Undo / Remove Refractors.

* Update 100-dockerhub.md

* Update 101-dockerhub-alt.md

* Update index.md

* Apply Requested Changes.
2024-09-20 09:04:40 +01:00
Kamran Ahmed
03d92f893c Add redis roadmap 2024-09-20 00:08:57 +01:00
Kamran Ahmed
8918940aa6 Add redis roadmap 2024-09-19 23:57:01 +01:00
Kamran Ahmed
e620c1a686 Add redis roadmap 2024-09-19 23:48:00 +01:00
github-actions[bot]
4162a4aedd chore: update roadmap content json (#7164)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-20 01:30:44 +06:00
Vipul Patil
13a1c6e085 Update arp@M52V7hmG4ORf4TIVw3W3J.md (#7171)
* Update arp@M52V7hmG4ORf4TIVw3W3J.md

A little changes made to the Topic

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-09-20 01:22:00 +06:00
teykamp
4183871a75 Added v-cloak and v-slot content on Vue roadmap (#7161)
* Add v-cloak description

Added v-cloak content in Vue roadmap

* Add v-slot description

Added v-slot content in Vue roadmap
2024-09-19 09:45:02 +01:00
Cody
61c4d566c2 Add new resource to symbol, refine documentation for clarity and flow. (#7163) 2024-09-19 09:43:09 +01:00
mori yuta
c49563ba16 Update 102-bitrise.md 404 link (#7167) 2024-09-19 09:41:44 +01:00
Arik Chakma
77c47e8f03 feat: add mark favourite button (#7156)
* feat: add mark favourite button

* fix: update favourite
2024-09-19 00:32:53 +01:00
Mark
597efd07ca Add new article links for triggers section in postgresql roadmap (#7152) 2024-09-18 15:41:10 +01:00
眼圈发黑
9577f4d615 Update optimizing-renders@RRPhAxIqvAcjZIcLe_N8-.md (#7154)
* Update optimizing-renders@RRPhAxIqvAcjZIcLe_N8-.md

* Update src/data/roadmaps/vue/content/optimizing-renders@RRPhAxIqvAcjZIcLe_N8-.md

cleaned up the styling

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-09-18 15:39:38 +01:00
stuartrace
4f01c51232 Add formatting so the HTML elements don't get rendered (#7157)
The <input> <textarea> and <select> elements are attempted to be rendered by the browser so they aren't visible as text
2024-09-18 15:37:28 +01:00
Hang
84184724c4 Updates to the Linux Roadmap (#7149)
* add Practice Linux Commands with Hands-on Labs

* Update public/roadmap-content/devops.json

Co-authored-by: Arik Chakma <arikchangma@gmail.com>

* Update public/roadmap-content/devops.json

* add linux free tutorials

---------

Co-authored-by: huhuhang <huhuhang@github.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: huhuhang <no-reply@huhuhang.com>
2024-09-18 15:30:42 +01:00
github-actions[bot]
024c7cbda1 chore: update roadmap content json (#7148)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-18 19:02:01 +06:00
dsh
951f97d5f0 fix: expand all internal roadmap urls (#7151) 2024-09-18 13:18:29 +01:00
Kamran Ahmed
c3118daa57 Fix typo in homepage 2024-09-18 13:17:47 +01:00
Mark
358402e20f Fix no article title in postgres roadmap (#7153) 2024-09-18 12:39:24 +01:00
Arik Chakma
6c914d1b47 fix: update copy roadmap alert (#7110)
* fix: update copy roadmap alert

* fix: update text
2024-09-18 12:24:36 +01:00
Nicholas Zingleman
3598db798c Update 104-selection-sort.md (#7147)
Dollar Signs were being rendered on the website. Removed for visual clarity.
2024-09-18 10:48:39 +01:00
Arik Chakma
ffaba806c9 feat: add projects in homepage (#7118) 2024-09-17 18:16:02 +01:00
Ed Lan
caf39819da Small content update (#7145) 2024-09-17 18:15:31 +01:00
dsh
1a98f62b38 Update Frontend FAQs (#7146) 2024-09-17 18:15:09 +01:00
J. Degand
b2e2e2c3ad docs(angular): update angular architecture content (#7103)
* docs(angular): update angular architecture content

* docs(angular): change list to paragraph
2024-09-17 10:30:53 +01:00
Saumya Shah
387d5218b2 Improve structured data content for rookies (#7137)
Improve the content in `src/data/roadmaps/prompt-engineering/content/103-real-world/100-structured-data.md` to be more concise and understandable for rookies.
2024-09-17 10:04:31 +01:00
Krishna Chaiatanya
fa0452e9c9 Update oauth-apps@qrdOARfqGPF9xhF6snbAn.md (#7138)
* Update oauth-apps@qrdOARfqGPF9xhF6snbAn.md

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-09-17 10:02:17 +01:00
Mark
915373f16d Add offical links for for nodejs core modules (#7140) 2024-09-17 09:59:10 +01:00
Carl Walsh
12077bb8f2 devops networking fix ping typo (#7142)
Changed URL with hostname
2024-09-17 09:54:03 +01:00
github-actions[bot]
ade4b279e4 chore: update roadmap content json (#7141)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-17 06:10:43 +06:00
VotreX Tan
c5eaf08f6e Update content relevance (#7106)
Updated the explanation to include the key thesis of the framework and the components of the CREATE acronym.
2024-09-16 14:20:19 +01:00
VotreX Tan
50b342bdbf Update content (#7108)
Previous content did not refer to the correct framework by Stephen Wendel. See: https://www.oreilly.com/library/view/designing-for-behavior/9781449367947/ch01.html#in_familiar_situations_our_minds_can_use
2024-09-16 14:19:27 +01:00
moonzn
cf1e2b4d5c Update devops-engineer.md (#7111)
Typo in line 2: "Responsbilities" -> "Responsibilities"
2024-09-16 14:18:22 +01:00
Sparsh
ce6fc83ad9 Added new course link of 100 days of SwiftUI | Hacking with SwiftUI (#7112)
* Update swiftui@kAIKsDcDzwI1E0wSnC_uo.md

Added new course link of 100 days of SwiftUI | Hacking with SwiftUI

* Added new course link of 100 days of SwiftUI | Hacking with SwiftUI

Added new course link of 100 days of SwiftUI | Hacking with SwiftUI
2024-09-16 14:17:03 +01:00
Krishna Chaiatanya
d2a44fbe75 Update flink@o6GQ3-8DgDtHzdX6yeg1w.md (#7115)
* Update spark@UljuqA89_SlCSDWWMD_C_.md

* Update src/data/roadmaps/mlops/content/spark@UljuqA89_SlCSDWWMD_C_.md

* Update flink@o6GQ3-8DgDtHzdX6yeg1w.md

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-09-16 14:15:20 +01:00
Mark
1d772af10a Add realtime data links in Backend roadmap (#7121) 2024-09-16 14:13:26 +01:00
Hang
4cb4c057aa add "Practice Linux Commands with Hands-on Labs" to "Ubuntu / Debian" node (#7122)
* add Practice Linux Commands with Hands-on Labs

* Update public/roadmap-content/devops.json

Co-authored-by: Arik Chakma <arikchangma@gmail.com>

* Update public/roadmap-content/devops.json

---------

Co-authored-by: huhuhang <huhuhang@github.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-09-16 14:11:56 +01:00
sickpoitew
8dd03f0272 Added content to some Vue topics. (#7127)
* Added v-bind description

* Added v-for description

* Added v-text description

* Added v-html description

* Added v-once description

* Added v-pre description

* Added v-else-if description
2024-09-16 14:08:19 +01:00
Brian Rodriguez
6130f16b23 [Update] Fcm docs (#7130) 2024-09-16 14:07:00 +01:00
Stavros Siamantas
30edae3e6e add git filter-repo as an alternative to git filter-branch (#7135) 2024-09-16 14:05:39 +01:00
dsh
ce48c7b594 added and removed the requested links (#7134) 2024-09-16 13:06:39 +01:00
Kamran Ahmed
3a24ff7f24 Update homepage link 2024-09-16 12:33:09 +01:00
Arik Chakma
111c7f23ab fix: progress nudge count (#7133) 2024-09-16 17:22:22 +06:00
Nicholas Zingleman
6ccbde99fe feat: content line break (#7131)
Updating formatting. Placed summary on a new line.
2024-09-16 02:29:05 +06:00
Mark
7754f7a576 fix: SQL query pattern title section in backend roadmap (#7129) 2024-09-15 15:11:57 +06:00
github-actions[bot]
2fc86bc400 chore: update roadmap content json (#7120)
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
2024-09-14 20:23:54 +06:00
884 changed files with 7516 additions and 14235 deletions

View File

@@ -1,8 +0,0 @@
{
"devToolbar": {
"enabled": false
},
"_variables": {
"lastUpdateCheck": 1725962974592
}
}

1
.astro/types.d.ts vendored
View File

@@ -1 +0,0 @@
/// <reference types="astro/client" />

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ tests-examples
!/editor/readonly-editor.tsx
!/editor/renderer/renderer.ts
!/editor/renderer/index.tsx
/.astro

View File

@@ -50,11 +50,12 @@
"jose": "^5.6.3",
"js-cookie": "^3.0.5",
"lucide-react": "^0.419.0",
"luxon": "^3.5.0",
"nanoid": "^5.0.7",
"nanostores": "^0.10.3",
"node-html-parser": "^6.1.13",
"npm-check-updates": "^17.0.0",
"playwright": "^1.45.3",
"playwright": "^1.47.1",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-calendar-heatmap": "^1.9.0",
@@ -80,6 +81,7 @@
"@tailwindcss/typography": "^0.5.13",
"@types/dom-to-image": "^2.6.7",
"@types/js-cookie": "^3.0.6",
"@types/luxon": "^3.4.2",
"@types/prismjs": "^1.26.4",
"@types/react-calendar-heatmap": "^1.6.7",
"@types/turndown": "^5.0.5",

1610
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -620,8 +620,19 @@
},
"e3vHFaFFMV7kI9q6yf5e9": {
"title": "Cloud Messaging",
"description": "Firebase Cloud Messaging (FCM) is a powerful, battery-efficient messaging service that enables you to send messages reliably and securely to your Android applications. It enables you to send two types of messages: \"notification messages\" and \"data messages\". Notification messages are primarily meant for user notifications and will only be delivered when the application is in the foreground. On the other hand, data messages can handle even when the app is in the background or killed and can be used to send custom key-value pairs. FCM also supports various additional features, such as topic messaging to send messages to multiple devices subscribed to a common topic, device group messaging for sending messages to groups of user devices, and upstream messaging for sending messages from the client application to the FCM server.",
"links": []
"description": "Firebase Cloud Messaging (FCM) is a powerful, battery-efficient messaging service that enables you to send messages reliably and securely to your Android applications. It enables you to send two types of messages: \"notification messages\" and \"data messages\". Notification messages are primarily meant for user notifications and will only be delivered when the application is in the foreground. On the other hand, data messages can handle even when the app is in the background or killed and can be used to send custom key-value pairs. FCM also supports various additional features, such as topic messaging to send messages to multiple devices subscribed to a common topic, device group messaging for sending messages to groups of user devices, and upstream messaging for sending messages from the client application to the FCM server.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Documentation",
"url": "https://firebase.google.com/docs/cloud-messaging/android/client",
"type": "article"
},
{
"title": "Firebase Cloud Messaging",
"url": "https://www.youtube.com/watch?v=sioEY4tWmLI&list=PLl-K7zZEsYLkuHRCtHTpi6JYHka8oHLft",
"type": "video"
}
]
},
"3EEfKAd-ppIQpdQSEhbA1": {
"title": "FireStore",

View File

@@ -12,12 +12,42 @@
},
"DE3cMpeRYuUPw2ADtfS-3": {
"title": "Angular Architecture",
"description": "Visit the following resources to learn more:",
"description": "Angular follows a modular architecture pattern, dividing the application into distinct modules, components, services, and other elements, which enhances code organization and maintainability. The key building blocks include modules, which are containers grouping related components, services, directives, and other elements to ensure proper encapsulation and reusability. Components are the building blocks of Angular applications, representing parts of the user interface with associated logic, consisting of templates, styles, and a class defining behavior. Services encapsulate reusable business logic, data manipulation, and API communication, enabling data and functionality sharing across components. Directives are HTML attributes or elements that extend HTML functionality, allowing reusable behaviors across the application. Lastly, pipes transform data before displaying it in templates, providing convenient ways to format, filter, and sort data.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Angular coding style guide",
"url": "https://angular.dev/style-guide",
"type": "article"
},
{
"title": "The Ultimate Guide to Angular Architecture: Best Practices for efficient coding with Angular Framework",
"url": "https://angulardive.com/blog/the-ultimate-guide-to-angular-architecture-best-practices-for-efficient-coding-with-angular-framework/",
"type": "article"
},
{
"title": "Modern Architectures with Angular Part 1: Strategic design with Sheriff and Standalone Components",
"url": "https://www.angulararchitects.io/en/blog/modern-architectures-with-angular-part-1-strategic-design-with-sheriff-and-standalone-components/",
"type": "article"
},
{
"title": "Optimizing the architecture of large web applications with Angular",
"url": "https://albertobasalo.medium.com/optimizing-the-architecture-of-large-web-applications-with-angular-79d03b01a92b",
"type": "article"
},
{
"title": "Angular Architecture Concepts and Patterns",
"url": "https://www.bigscal.com/blogs/frontend/angular-architecture-concepts-and-patterns/",
"type": "article"
},
{
"title": "Top 10 Angular Architecture Mistakes",
"url": "https://angularexperts.io/blog/top-10-angular-architecture-mistakes",
"type": "article"
},
{
"title": "Architecting Angular: A Guide to effective project structure",
"url": "https://medium.com/@nile.bits/architecting-angular-a-guide-to-effective-project-structure-9756bae92262",
"type": "article"
}
]
},

View File

@@ -134,7 +134,7 @@
"links": [
{
"title": "Visit Dedicated Go Roadmap",
"url": "/golang",
"url": "https://roadmap.sh/golang",
"type": "article"
},
{
@@ -170,7 +170,7 @@
"links": [
{
"title": "Visit Dedicated JavaScript Roadmap",
"url": "/javascript",
"url": "https://roadmap.sh/javascript",
"type": "article"
},
{
@@ -201,7 +201,7 @@
"links": [
{
"title": "Visit Dedicated Java Roadmap",
"url": "/java",
"url": "https://roadmap.sh/java",
"type": "article"
},
{
@@ -237,7 +237,7 @@
},
{
"title": "Visit Dedicated Python Roadmap",
"url": "/python",
"url": "https://roadmap.sh/python",
"type": "article"
},
{
@@ -330,7 +330,7 @@
"links": [
{
"title": "Learn Git & GitHub",
"url": "/git-github",
"url": "https://roadmap.sh/git-github",
"type": "article"
},
{
@@ -366,7 +366,7 @@
"links": [
{
"title": "Learn Git & GitHub",
"url": "/git-github",
"url": "https://roadmap.sh/git-github",
"type": "article"
},
{
@@ -392,7 +392,7 @@
"links": [
{
"title": "Learn Git & GitHub",
"url": "/git-github",
"url": "https://roadmap.sh/git-github",
"type": "article"
},
{
@@ -506,7 +506,7 @@
"links": [
{
"title": "Visit Dedicated PostgreSQL DBA Roadmap",
"url": "/postgresql-dba",
"url": "https://roadmap.sh/postgresql-dba",
"type": "article"
},
{
@@ -542,7 +542,7 @@
"links": [
{
"title": "SQL Roadmap",
"url": "/sql",
"url": "https://roadmap.sh/sql",
"type": "article"
},
{
@@ -1105,7 +1105,7 @@
"links": [
{
"title": "GraphQL Roadmap",
"url": "/graphql",
"url": "https://roadmap.sh/graphql",
"type": "article"
},
{
@@ -1967,7 +1967,7 @@
"links": [
{
"title": "Visit Dedicated MongoDB Roadmap",
"url": "/mongodb",
"url": "https://roadmap.sh/mongodb",
"type": "article"
},
{
@@ -2907,8 +2907,19 @@
},
"5XGvep2qoti31bsyqNzrU": {
"title": "Real-Time Data",
"description": "Real-time data refers to information that is processed and made available immediately or with minimal delay, allowing users or systems to react promptly to current conditions. This type of data is essential in applications requiring immediate updates and responses, such as financial trading platforms, online gaming, real-time analytics, and monitoring systems. Real-time data processing involves capturing, analyzing, and delivering information as it is generated, often using technologies like stream processing frameworks (e.g., Apache Kafka, Apache Flink) and low-latency databases. Effective real-time data systems can handle high-speed data flows, ensuring timely and accurate decision-making.",
"links": []
"description": "Real-time data refers to information that is processed and made available immediately or with minimal delay, allowing users or systems to react promptly to current conditions. This type of data is essential in applications requiring immediate updates and responses, such as financial trading platforms, online gaming, real-time analytics, and monitoring systems. Real-time data processing involves capturing, analyzing, and delivering information as it is generated, often using technologies like stream processing frameworks (e.g., Apache Kafka, Apache Flink) and low-latency databases. Effective real-time data systems can handle high-speed data flows, ensuring timely and accurate decision-making.\n\nLearn more from the following resources:",
"links": [
{
"title": "Real-time data - Wiki",
"url": "https://en.wikipedia.org/wiki/Real-time_data",
"type": "article"
},
{
"title": "What is Real-time Data?",
"url": "https://www.qlik.com/us/streaming-data/real-time-data",
"type": "article"
}
]
},
"osvajAJlwGI3XnX0fE-kA": {
"title": "Long Polling",

View File

@@ -1953,7 +1953,7 @@
"links": [
{
"title": "Visit Dedicated Python Roadmap",
"url": "/python",
"url": "https://roadmap.sh/python",
"type": "article"
},
{
@@ -1994,7 +1994,7 @@
"links": [
{
"title": "Visit Dedicated Go Roadmap",
"url": "/golang",
"url": "https://roadmap.sh/golang",
"type": "article"
},
{
@@ -2056,7 +2056,7 @@
"links": [
{
"title": "Visit Dedicated React Roadmap",
"url": "/react",
"url": "https://roadmap.sh/react",
"type": "article"
},
{
@@ -2097,7 +2097,7 @@
"links": [
{
"title": "Visit Dedicated Angular Roadmap",
"url": "/angular",
"url": "https://roadmap.sh/angular",
"type": "article"
},
{
@@ -2118,7 +2118,7 @@
"links": [
{
"title": "Visit Dedicated Vue Roadmap",
"url": "/vue",
"url": "https://roadmap.sh/vue",
"type": "article"
},
{

View File

@@ -51,7 +51,7 @@
"links": [
{
"title": "Visit Dedicated Python Roadmap",
"url": "/python",
"url": "https://roadmap.sh/python",
"type": "article"
},
{
@@ -107,7 +107,7 @@
"links": [
{
"title": "Visit Dedicated Go Roadmap",
"url": "/golang",
"url": "https://roadmap.sh/golang",
"type": "article"
},
{
@@ -292,7 +292,7 @@
"links": [
{
"title": "Visit Dedicated Java Roadmap",
"url": "/java",
"url": "https://roadmap.sh/java",
"type": "article"
},
{

File diff suppressed because it is too large Load Diff

View File

@@ -84,7 +84,7 @@
]
},
"DFMR-0MbmVCCrJu0I9JWG": {
"title": "Prespective Analytics",
"title": "Prescriptive Analytics",
"description": "Prescriptive analytics, a crucial type of data analytics, is essential for making data-driven decisions in business and organizational contexts. As a data analyst, the goal of prescriptive analytics is to recommend various actions using predictions on the basis of known parameters to help decision makers understand likely outcomes. Prescriptive analytics employs a blend of techniques and tools such as algorithms, machine learning, computational modelling procedures, and decision-tree structures to enable automated decision making. Therefore, prescriptive analytics not only anticipates what will happen and when it will happen, but also explains why it will happen, contributing to the significance of a data analysts role in an organization.\n\nLearn more from the following resources:",
"links": [
{

File diff suppressed because one or more lines are too long

View File

@@ -137,6 +137,11 @@
"title": "What is hosting?",
"description": "Web hosting is an online service that allows you to publish your website files onto the internet. So, anyone who has access to the internet has access to your website.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Web Hosting Explained for Beginners",
"url": "https://www.hostinger.com/tutorials/what-is-web-hosting/",
"type": "article"
},
{
"title": "What Is Web Hosting? Explained",
"url": "https://www.youtube.com/watch?v=htbY9-yggB0",
@@ -542,7 +547,7 @@
"links": [
{
"title": "Visit Dedicated JavaScript Roadmap",
"url": "/javascript",
"url": "https://roadmap.sh/javascript",
"type": "article"
},
{
@@ -972,7 +977,7 @@
"links": [
{
"title": "Visit Dedicated Angular Roadmap",
"url": "/angular",
"url": "https://roadmap.sh/angular",
"type": "article"
},
{
@@ -998,7 +1003,7 @@
"links": [
{
"title": "Visit Dedicated Vue Roadmap",
"url": "/vue",
"url": "https://roadmap.sh/vue",
"type": "article"
},
{
@@ -1039,7 +1044,7 @@
"links": [
{
"title": "Visit Dedicated React Roadmap",
"url": "/react",
"url": "https://roadmap.sh/react",
"type": "article"
},
{
@@ -2063,7 +2068,7 @@
"links": [
{
"title": "Visit Dedicated React Roadmap",
"url": "/react",
"url": "https://roadmap.sh/react",
"type": "article"
},
{
@@ -2545,7 +2550,7 @@
"links": [
{
"title": "Visit Dedicated Flutter Roadmap",
"url": "/flutter",
"url": "https://roadmap.sh/flutter",
"type": "article"
},
{
@@ -2680,7 +2685,7 @@
"links": [
{
"title": "Visit Dedicated Flutter Roadmap",
"url": "/flutter",
"url": "https://roadmap.sh/flutter",
"type": "article"
},
{

View File

@@ -62,7 +62,7 @@
"links": [
{
"title": "Visit Dedicated JavaScript Roadmap",
"url": "/javascript",
"url": "https://roadmap.sh/javascript",
"type": "article"
},
{
@@ -257,7 +257,7 @@
"links": [
{
"title": "Visit Dedicated React Roadmap",
"url": "/react",
"url": "https://roadmap.sh/react",
"type": "article"
},
{
@@ -650,7 +650,7 @@
"links": [
{
"title": "Visit Dedicated PostgreSQL DBA Roadmap",
"url": "/postgresql-dba",
"url": "https://roadmap.sh/postgresql-dba",
"type": "article"
},
{

View File

@@ -13,6 +13,11 @@
"url": "https://www.datacamp.com/blog/all-about-git",
"type": "article"
},
{
"title": "Version Control (Git) - The Missing Semester of Your CS Education",
"url": "https://missing.csail.mit.edu/2020/version-control/",
"type": "article"
},
{
"title": "GUI Clients",
"url": "https://git-scm.com/downloads/guis",
@@ -215,6 +220,11 @@
"title": ".gitignore",
"description": "Ignored files are tracked in a special file named `.gitignore` that is checked in at the root of your repository. There is no explicit git ignore command: instead the `.gitignore` file must be edited and committed by hand when you have new files that you wish to ignore. `.gitignore` files contain patterns that are matched against file names in your repository to determine whether or not they should be ignored.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "gitignore - A collection of useful .gitignore templates",
"url": "https://github.com/github/gitignore",
"type": "opensource"
},
{
"title": "gitignore Documentation",
"url": "https://git-scm.com/docs/gitignore/en",
@@ -1427,12 +1437,22 @@
},
"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:",
"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\nNotably, there exists a simpler, safer, and more powerful alternative: `git filter-repo`. This tool is actively promoted by Git and offers a streamlined approach to filtering revisions, making it a preferred choice for rewriting your Git history, especially when managing large repositories.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "git filter-branch",
"url": "https://git-scm.com/docs/git-filter-branch",
"type": "article"
},
{
"title": "git filter-repo",
"url": "https://github.com/newren/git-filter-repo",
"type": "article"
},
{
"title": "Removing sensitive data from a repository",
"url": "https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository",
"type": "article"
}
]
},
@@ -2199,7 +2219,7 @@
},
"qrdOARfqGPF9xhF6snbAn": {
"title": "OAuth Apps",
"description": "GitHub OAuth Apps are a way to integrate with the GitHub platform using OAuth authentication. They allow developers to create custom integrations that can automate tasks, provide real-time notifications, and build custom workflows.\n\nVisit the following resources to learn more:",
"description": "GitHub OAuth Apps allow developers to integrate with GitHub using OAuth 2.0 authentication. They enable secure, token-based access to specific GitHub resources like repositories, issues, and pull requests. OAuth Apps can automate tasks, personalize interactions, and provide real-time notifications through webhooks, all while allowing users to approve only the necessary permissions without sharing their credentials.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Creating an OAuth app",

View File

@@ -965,6 +965,11 @@
"title": "SwiftUI",
"description": "SwiftUI is Apple's modern declarative framework for building user interfaces across all Apple platforms. Introduced in 2019, it allows developers to create UIs using Swift code, describing the desired layout and behavior rather than implementing them imperatively. SwiftUI offers a more concise and intuitive approach to UI development, with features like automatic support for Dark Mode, dynamic type, and localization. It uses a state-driven approach, automatically updating the UI when underlying data changes. While newer than UIKit, SwiftUI is rapidly evolving and gaining adoption, offering seamless integration with UIKit when needed.\n\nLearn more from the following resources:",
"links": [
{
"title": "HackingWithSwift - 100 Days of SwiftUI",
"url": "https://www.hackingwithswift.com/100/swiftui",
"type": "course"
},
{
"title": "SwiftUI Documentation",
"url": "https://developer.apple.com/xcode/swiftui/",

View File

@@ -503,7 +503,7 @@
},
"R6ICrk6vjoBxx5nRGo4Jg": {
"title": "Symbol",
"description": "Symbols are a unique and immutable primitive data type in JavaScript, introduced in ECMAScript 6 (ES6). They are often used to create unique property keys for objects, ensuring that no property key collisions occur. Each Symbol value is unique, even if created with the same description. Symbols can be created using the Symbol() function, and their primary use case is to add hidden or special properties to objects that wont interfere with other properties or methods.\n\nLearn more from the following resources:",
"description": "Symbols are a unique and immutable primitive data type in JavaScript, introduced in ECMAScript 6 (ES6). They are often used to create unique property keys for objects, ensuring no property key collisions occur. Each Symbol value is distinct, even when multiple are created with the same description. Symbols can be created using the Symbol() function, and their primary use case is to add hidden or special properties to objects that wont interfere with other properties or methods.\n\nLearn more from the following resources:",
"links": [
{
"title": "Symbol data type in JavaScript",
@@ -514,6 +514,16 @@
"title": "Symbol type",
"url": "https://javascript.info/symbol",
"type": "article"
},
{
"title": "Symbol",
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol",
"type": "article"
},
{
"title": "Symbols in Javascript",
"url": "https://www.youtube.com/watch?v=E5Bblr-SFbA",
"type": "video"
}
]
},

View File

@@ -36,7 +36,7 @@
"links": [
{
"title": "Visit Dedicated Go Roadmap",
"url": "/golang",
"url": "https://roadmap.sh/golang",
"type": "article"
},
{
@@ -351,8 +351,13 @@
},
"UljuqA89_SlCSDWWMD_C_": {
"title": "Spark",
"description": "Apache Spark is an open-source distributed computing system used for big data processing and analytics. It provides an interface for programming entire clusters with implicit data parallelism and fault tolerance.\n\nVisit the following resources to learn more:",
"description": "Apache Spark is an open-source distributed computing system designed for big data processing and analytics. It offers a unified interface for programming entire clusters, enabling efficient handling of large-scale data with built-in support for data parallelism and fault tolerance. Spark excels in processing tasks like batch processing, real-time data streaming, machine learning, and graph processing. Its known for its speed, ease of use, and ability to process data in-memory, significantly outperforming traditional MapReduce systems. Spark is widely used in big data ecosystems for its scalability and versatility across various data processing tasks.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "ApacheSpark",
"url": "https://spark.apache.org/documentation.html",
"type": "article"
},
{
"title": "Spark By Examples",
"url": "https://sparkbyexamples.com",
@@ -388,7 +393,7 @@
},
"o6GQ3-8DgDtHzdX6yeg1w": {
"title": "Flink",
"description": "Apache Flink is a distributed stream processing framework that is used to process large amounts of data in real-time. It is designed to be highly scalable and fault-tolerant. Flink is built on top of the Apache Kafka messaging system and is used to process data streams in real-time.\n\nVisit the following resources to learn more:",
"description": "Apache Flink is an open-source stream processing framework designed for real-time and batch data processing with low latency and high throughput. It supports event time processing, fault tolerance, and stateful operations, making it ideal for applications like real-time analytics, fraud detection, and event-driven systems. Flink is highly scalable, integrates with various data systems, and is widely used in industries for large-scale, real-time data processing tasks.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Apache Flink Documentation",
@@ -399,6 +404,11 @@
"title": "Explore top posts about Apache Flink",
"url": "https://app.daily.dev/tags/apache-flink?ref=roadmapsh",
"type": "article"
},
{
"title": "Apache Flink Tutorialpoint",
"url": "https://www.tutorialspoint.com/apache_flink/apache_flink_introduction.htm",
"type": "article"
}
]
},

View File

@@ -2085,7 +2085,58 @@
},
"M62lAWBOrTe99TfpFOQ-Y": {
"title": "Common Built-in Modules",
"description": "These are the common modules that come with `Node.js` out of the box. This module provides tools or APIs for performing out certain standard `Node.js` operations. like interacting with the file system, url parsing, or logging information to the console.",
"links": []
"description": "These are the core modules that come with `Node.js` out of the box. This module provides tools or APIs for performing out certain standard `Node.js` operations. like interacting with the file system, url parsing, or logging information to the console.\n\nLearn more from the following resources:",
"links": [
{
"title": "Nodejs fs module",
"url": "https://nodejs.org/api/fs.html",
"type": "article"
},
{
"title": "Nodejs url module",
"url": "https://nodejs.org/api/url.html",
"type": "article"
},
{
"title": "Nodejs console module",
"url": "https://nodejs.org/api/console.html",
"type": "article"
},
{
"title": "Nodejs util module",
"url": "https://nodejs.org/api/util.html",
"type": "article"
},
{
"title": "Nodejs events module",
"url": "https://nodejs.org/api/events.html",
"type": "article"
},
{
"title": "Nodejs os module",
"url": "https://nodejs.org/api/os.html",
"type": "article"
},
{
"title": "Nodejs worker threads module",
"url": "https://nodejs.org/api/worker_threads.html",
"type": "article"
},
{
"title": "Nodejs child process module",
"url": "https://nodejs.org/api/child_process.html",
"type": "article"
},
{
"title": "Nodejs process object",
"url": "https://nodejs.org/api/process.html",
"type": "article"
},
{
"title": "Nodejs crypto module",
"url": "https://nodejs.org/api/crypto.html",
"type": "article"
}
]
}
}

View File

@@ -550,7 +550,7 @@
"description": "PostgreSQL offers a comprehensive set of data types to cater to diverse data needs, including numeric types like `INTEGER`, `FLOAT`, and `SERIAL` for auto-incrementing fields; character types such as `VARCHAR` and `TEXT` for variable-length text; and temporal types like `DATE`, `TIME`, and `TIMESTAMP` for handling date and time data. Additionally, PostgreSQL supports `BOOLEAN` for true/false values, `ENUM` for enumerated lists, and composite types for complex structures. It also excels with `JSON` and `JSONB` for storing and querying semi-structured data, arrays for storing multiple values in a single field, and geometric types for spatial data. These data types ensure flexibility and robust data management for various applications.\n\nLearn more from the following resources:",
"links": [
{
"title": "",
"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"
},
@@ -866,7 +866,7 @@
"type": "article"
},
{
"title": "Query Planning@",
"title": "Query Planning",
"url": "https://www.postgresql.org/docs/current/runtime-config-query.html",
"type": "article"
}
@@ -2091,6 +2091,16 @@
"url": "https://www.postgresql.org/docs/8.1/triggers.html",
"type": "article"
},
{
"title": "PostgreSQL Triggers",
"url": "https://www.postgresqltutorial.com/postgresql-triggers/",
"type": "article"
},
{
"title": "Understanding PostgreSQL Triggers",
"url": "https://hevodata.com/learn/postgresql-triggers/",
"type": "article"
},
{
"title": "Using PostgreSQL triggers to automate processes with Supabase",
"url": "https://www.youtube.com/watch?v=0N6M5BBe9AE",

View File

@@ -1120,7 +1120,7 @@
]
},
"_IXXTSwQOgYzYIUuKVWNE": {
"title": "virutalenv",
"title": "virtualenv",
"description": "`virtualenv` is a tool to create isolated Python environments. It creates a folder which contains all the necessary executables to use the packages that a Python project would need.\n\nLearn more about `virtualenv` by visiting the following resources:",
"links": [
{

View File

@@ -0,0 +1,812 @@
{
"-3pADOHMDQ0H6ZKNjURyn": {
"title": "What is Redis?",
"description": "",
"links": []
},
"M-EXrTDeAEMz_IkEi-ab4": {
"title": "In-memory Data Structure Store",
"description": "",
"links": []
},
"l2aXyO3STnhbFjvUXPpm2": {
"title": "Key-value Database",
"description": "",
"links": []
},
"eHuBz_zSZK3rubn7nkd7g": {
"title": "Cache",
"description": "",
"links": []
},
"mgGJTBU8ofvOzl9gYWhnG": {
"title": "Message Broker",
"description": "",
"links": []
},
"-TjnSOY8txYrhhxRV1OIl": {
"title": "Caching",
"description": "",
"links": []
},
"bVJASI7bfSYqYnNhX83ng": {
"title": "Real-time Analytics",
"description": "",
"links": []
},
"URxGmhZHr0Y8nyrYj0gJl": {
"title": "Session Management",
"description": "",
"links": []
},
"ZCyId3aIoLv3duxoJdk2P": {
"title": "Pub/Sub Messaging",
"description": "",
"links": []
},
"Fv1iGX22sApIEifM2IpJz": {
"title": "Leaderboards and Counters",
"description": "",
"links": []
},
"8uRpPJ0iD4XnQPKruQc8P": {
"title": "Data Persistence Options",
"description": "",
"links": []
},
"uVewcyaFi1Pt2Gs0KrkfA": {
"title": "Rich Data Structures",
"description": "",
"links": []
},
"5-3pd4rLDqRzMzSRVLdXh": {
"title": "High Performance and Scalability",
"description": "",
"links": []
},
"EvWiEx_AoxAht6sKxzW2l": {
"title": "Redis vs SQL/NoSQL DBs",
"description": "",
"links": []
},
"1Af5H0BgdAsRdBCNdHz5v": {
"title": "When to choose Redis?",
"description": "",
"links": []
},
"Bf_kLfmy7_uflqC9N0-jt": {
"title": "Using Package Managers",
"description": "",
"links": []
},
"yBZ79s6mzGdj5AnX2H_Hy": {
"title": "Pre-compiled Binaries",
"description": "",
"links": []
},
"TDxv0q7jlZ26uZYYlneem": {
"title": "Using Docker",
"description": "",
"links": []
},
"43LvShQhmoWQ8Nye7fLkz": {
"title": "Starting the Server",
"description": "",
"links": []
},
"BOGXTjmCLo6WI6mYDsqRu": {
"title": "Connecting using Redis CLI",
"description": "",
"links": []
},
"NhcZM4nUQoSBBf_1qXi6l": {
"title": "Basic Commands / SET, GET",
"description": "",
"links": []
},
"DOdNkTY1yIMipWA2CD9xH": {
"title": "Settings and Getting Keys",
"description": "",
"links": []
},
"lV_MnUNTB2h925idX0YWk": {
"title": "DEL",
"description": "",
"links": []
},
"U84XgBFPyIbY0W5afH4cx": {
"title": "Overview of Data Types",
"description": "",
"links": []
},
"ltF4vCT9ZA2XuUuHnuGnN": {
"title": "SET",
"description": "",
"links": []
},
"mQc4H2ZMMSVjh33LJY8mK": {
"title": "GET",
"description": "",
"links": []
},
"5K9qyC4mrhXYWOC8WSq8C": {
"title": "INCR",
"description": "",
"links": []
},
"t4BXPofF8OCqH5KHwdYVh": {
"title": "DECR",
"description": "",
"links": []
},
"cPWd53BO6tm-uy4gqLdtZ": {
"title": "APPEND",
"description": "",
"links": []
},
"eJQW986HM4Wf1o1i2FnXs": {
"title": "STRLEN",
"description": "",
"links": []
},
"0v8uLWRCbAqEmKKdYaRQW": {
"title": "More Commands",
"description": "",
"links": []
},
"2_E2VwbjTgk4xxTFWfHuV": {
"title": "Usecases",
"description": "",
"links": []
},
"nS0DHhfy4wxHItgOFhulA": {
"title": "EXPR",
"description": "",
"links": []
},
"Vll7VMmGWSI5XGZ9JpHyl": {
"title": "TTL",
"description": "",
"links": []
},
"Kq7G89KaZZMFkrH-9WZoS": {
"title": "LPUSH",
"description": "",
"links": []
},
"jC8G1o7yFj7D_PGmOIgcD": {
"title": "RPUSH",
"description": "",
"links": []
},
"voa61RTWMJD3Sk8DNJoVQ": {
"title": "LPOP",
"description": "",
"links": []
},
"brUGqWZ287EWtvl9uUbNt": {
"title": "RPOP",
"description": "",
"links": []
},
"8JTtBy6oD2wFYDizVkcVa": {
"title": "LRANGE",
"description": "",
"links": []
},
"hBFEUXtuzUTzWZKp2qWaZ": {
"title": "LINDEX",
"description": "",
"links": []
},
"4oCcP9FxDJSDMHCEVBCNa": {
"title": "LLEN",
"description": "",
"links": []
},
"9KvHcS5F4Jj5ZXgIAdOQY": {
"title": "LMOVE",
"description": "",
"links": []
},
"eBeEUYY-IL_CMkcm31lUL": {
"title": "More Commands",
"description": "",
"links": []
},
"XTwNCCtzXvZMdaex4gZEh": {
"title": "Usecases",
"description": "",
"links": []
},
"Qgkpr9vf9d6-vUg1o8XFj": {
"title": "Sets",
"description": "",
"links": []
},
"xUKoQps69FFQrJeuhD1pz": {
"title": "SADD",
"description": "",
"links": []
},
"mQ0ILns53n1By0Tq6xSZI": {
"title": "SMEMBERS",
"description": "",
"links": []
},
"WQWVL5GT_scHdgfCtI7WT": {
"title": "SREM",
"description": "",
"links": []
},
"Ji5ghlcGJtlmErHFqVf3d": {
"title": "SISMEMBER",
"description": "",
"links": []
},
"5aLfNBewK4Dx017qVNO3T": {
"title": "SINTER",
"description": "",
"links": []
},
"2gZL4a9aWGKWLa89iyHTc": {
"title": "SCARD",
"description": "",
"links": []
},
"6QoYa-N2BKNBaRtvNeVNm": {
"title": "SUNION",
"description": "",
"links": []
},
"JX5ajmcUmkshTO-mLF8lH": {
"title": "SDIFF",
"description": "",
"links": []
},
"2SG4Hr9Tuv6cxmGkrKjYZ": {
"title": "More Commands",
"description": "",
"links": []
},
"3hayYoSZepw7pppBubotg": {
"title": "Usecases",
"description": "",
"links": []
},
"b48EUyFGUeSjtT5fOa_m6": {
"title": "More Commands",
"description": "",
"links": []
},
"Wl23Jh-ASJOQ850yjaTIU": {
"title": "Strings",
"description": "",
"links": []
},
"4-C4XqACUp4nvcMIj6djF": {
"title": "Lists",
"description": "",
"links": []
},
"wY46Qj5Inw_ClBNI9PB_2": {
"title": "Hashes",
"description": "",
"links": []
},
"BOJzn9SWad9oRRdY_ub01": {
"title": "HSET",
"description": "",
"links": []
},
"MsKg9m5jFwHM2Bzjf-vdu": {
"title": "HGET",
"description": "",
"links": []
},
"TpR33sJ-tAjeG3jpGTvYR": {
"title": "HGETALL",
"description": "",
"links": []
},
"E7xFZkqqbzokD5KGTn9zJ": {
"title": "HDEL",
"description": "",
"links": []
},
"adhLMuSmfYMRyWTwIgnyE": {
"title": "HEXISTS",
"description": "",
"links": []
},
"jtVnUD-na-WffMaS8qYfu": {
"title": "Usecases",
"description": "",
"links": []
},
"QTbkWZ7BpqYmBhUivccPu": {
"title": "Sorted Sets",
"description": "",
"links": []
},
"0swsBD0sOY-o5lzibT999": {
"title": "ZADD",
"description": "",
"links": []
},
"3pFChX6YIItrBz9lxu4XM": {
"title": "ZRANGE",
"description": "",
"links": []
},
"OlbixGa5RmdqEt7snY04j": {
"title": "ZRANGEBYSCORE",
"description": "",
"links": []
},
"m0FZDPwNE71zcwM_gUwz0": {
"title": "ZREM",
"description": "",
"links": []
},
"W4v7FIQr2k-Vbm-HdfKog": {
"title": "ZINCRBY",
"description": "",
"links": []
},
"AF_kWM4V8n5Ux06IgEVTl": {
"title": "ZRANK",
"description": "",
"links": []
},
"O-fZM_U-tW0pYtNzN_8Ax": {
"title": "ZCOUNT",
"description": "",
"links": []
},
"P6TDUCroLlEI7qePBFHIH": {
"title": "More Commands",
"description": "",
"links": []
},
"lxevY15ZyP43s_JrEqMX7": {
"title": "Usecases",
"description": "",
"links": []
},
"o6e_CwxfPoU6qkfWkwKwj": {
"title": "More Commands",
"description": "",
"links": []
},
"jCaVx5wvsvuyqtwh6m8si": {
"title": "Naming Conventions",
"description": "",
"links": []
},
"UlQHqw1dbxZnAKbsWsOgU": {
"title": "Retrieval by Pattern",
"description": "",
"links": []
},
"OSIYDYPGz8Vgo9SU9GGH9": {
"title": "Expiration",
"description": "",
"links": []
},
"jrgaoDnt_RxTu79hk4hCD": {
"title": "Atomicity in Redis",
"description": "",
"links": []
},
"LHlwjN3WHYUBUafzzwsWQ": {
"title": "Pipelining",
"description": "",
"links": []
},
"7JzeyTrkZ_1_yxMVrqvZU": {
"title": "Batch Operations",
"description": "",
"links": []
},
"0Q3AkE8leWAyYsww3-BHX": {
"title": "Bitmaps",
"description": "",
"links": []
},
"B-YUFhPQNdr1KZNupmR5N": {
"title": "SETBIT",
"description": "",
"links": []
},
"0HFLJfcrcSnAVTecG3P8W": {
"title": "GETBIT",
"description": "",
"links": []
},
"jpcyXSSib7q4WBPmpgnXA": {
"title": "BITCOUNT",
"description": "",
"links": []
},
"tkrxArg_oYH0aQfM8NkD2": {
"title": "BITOP",
"description": "",
"links": []
},
"Df1Eu7CuA-ARYii9JVvnm": {
"title": "BITPOS",
"description": "",
"links": []
},
"s7PEr-5TAm5EGJm0RSjPJ": {
"title": "Usecases",
"description": "",
"links": []
},
"cszjT3YK8oyhGpqLTQzwX": {
"title": "HyperLogLog",
"description": "",
"links": []
},
"8a4DmPZrX2xGZ7zdWxS63": {
"title": "PFADD",
"description": "",
"links": []
},
"JWT30KIJQHVw0MXI5sGR6": {
"title": "PFCOUNT",
"description": "",
"links": []
},
"s50jr_XOUcxh65-tGCKf5": {
"title": "PFMERGE",
"description": "",
"links": []
},
"XPeCvikPuu6EJ8UcOLGPh": {
"title": "Usecases",
"description": "",
"links": []
},
"zXs_9n2yEb_eVi0WuOQKH": {
"title": "Streams",
"description": "",
"links": []
},
"7isWhgrUA6M5IGM2U2tm4": {
"title": "XADD",
"description": "",
"links": []
},
"4sKiAtX5aIL4NDsQkilNC": {
"title": "XREAD",
"description": "",
"links": []
},
"CiYFuYE8XudZkR6AW2NQ7": {
"title": "XRANGE",
"description": "",
"links": []
},
"DQJCMEw13lELcw_AwLfrT": {
"title": "XLEN",
"description": "",
"links": []
},
"zXlSBfa-Gi9_GhSYEzre3": {
"title": "Usecases",
"description": "",
"links": []
},
"4-z4hDKm86qQatYnmE21R": {
"title": "More Commands",
"description": "",
"links": []
},
"_NiUdVQ85qnvryI38k_vQ": {
"title": "Geospatial Indexes",
"description": "",
"links": []
},
"U3N1EgHFs1-YUaB_VrJfw": {
"title": "GEOADD",
"description": "",
"links": []
},
"OWWDLuGTbdNwME7v2jxVP": {
"title": "GEOSEARCH",
"description": "",
"links": []
},
"GNMjrLPkpTphneoQ0GoZF": {
"title": "Usecases",
"description": "",
"links": []
},
"FCbdKnkI1ZHGekT6yiGua": {
"title": "More Commands",
"description": "",
"links": []
},
"9W_jaK1DSEZHRKdPcUM7h": {
"title": "Pub/Sub",
"description": "",
"links": []
},
"55BCntuWlaQiLPqNtb-2i": {
"title": "SUBSCRIBE",
"description": "",
"links": []
},
"5gkZzm2F4vu6IxUoJLYbK": {
"title": "UNSUBSCRIBE",
"description": "",
"links": []
},
"gIPo-2CNqE1BsOaDzmkCU": {
"title": "PUBLISH",
"description": "",
"links": []
},
"V-d6q-3Sf0dl5v8xiCQwl": {
"title": "More Commands",
"description": "",
"links": []
},
"MvyE_JUJej0UB9xe8Anfj": {
"title": "Usecases",
"description": "",
"links": []
},
"YHbWlKrQqptUDbaQVy0_A": {
"title": "Transactions",
"description": "",
"links": []
},
"c-y5Eck8VtSyIf8RAW9p7": {
"title": "WATCH",
"description": "",
"links": []
},
"Ljy-Mc0EBBX4_vXfYZ5-4": {
"title": "EXEC",
"description": "",
"links": []
},
"U6hST1MkS16T2CHV3-Ise": {
"title": "MULTI",
"description": "",
"links": []
},
"msW0Wd2H-6FFNDnjC64t-": {
"title": "Optimistic Locking",
"description": "",
"links": []
},
"Veb30QrPYNjUn13dtGbUr": {
"title": "Lua Scripting",
"description": "",
"links": []
},
"rjeq3i9oX8IGyQzo--L3c": {
"title": "EVAL",
"description": "",
"links": []
},
"3X0x_PcJGWBVPL-LSVAln": {
"title": "EVALSHA",
"description": "",
"links": []
},
"kF_nGo845XDwLkwcQt008": {
"title": "Usecases",
"description": "",
"links": []
},
"bQaek7f3dAaZfSUhwovm1": {
"title": "Persistence Options",
"description": "",
"links": []
},
"D3pZdAjwPFMRxX1-iyu5-": {
"title": "How RDB Works?",
"description": "",
"links": []
},
"_pb2DPrFUUZabKxWsuFUo": {
"title": "Configuring Save Interval",
"description": "",
"links": []
},
"Z6yJwUkcDX08HoMyf1LwX": {
"title": "Usecases / Best Practices",
"description": "",
"links": []
},
"PTj6oxvpw8vP295WvAI80": {
"title": "How AOF Works?",
"description": "",
"links": []
},
"ibaZ34-laQtUyxAsERi7o": {
"title": "AOF rewrite & compaction",
"description": "",
"links": []
},
"9ToKTUqbi-NV5Wcwb21PT": {
"title": "Truncation / Corruption",
"description": "",
"links": []
},
"VvOQUO22ZF8VvDSqHENNU": {
"title": "Usecases",
"description": "",
"links": []
},
"vzp7DUpjklzIA0E9WxJQA": {
"title": "Usecases / Best Practices",
"description": "",
"links": []
},
"80035BzcB-fKCvD_3N8zE": {
"title": "No Persistence Option",
"description": "",
"links": []
},
"3S-qqOlfr60HR4VvDr4He": {
"title": "RDB vs AOF Tradeoffs",
"description": "",
"links": []
},
"S5Y26m1oHCQpB-oLCdtac": {
"title": "Hybrid Persistence",
"description": "",
"links": []
},
"rSD8nJ-uNpHJVe5Hn66h7": {
"title": "Replication Basics",
"description": "",
"links": []
},
"nci3OB1NE1zJHUPfZCOpT": {
"title": "Redis Sentinel",
"description": "",
"links": []
},
"AQiCcHS6dBAAAPloxiXub": {
"title": "Clustering",
"description": "",
"links": []
},
"Qy42paiTUsO8HIwbWTMui": {
"title": "Authentication",
"description": "",
"links": []
},
"wsuKH7YwGDV6GYQbdhA4o": {
"title": "Network Security",
"description": "",
"links": []
},
"gdiWwTQg6A-BFHdQBmgmH": {
"title": "SSL/TLS Encryption",
"description": "",
"links": []
},
"q2Jw49QUWCUGIfcEC1bZI": {
"title": "INFO",
"description": "",
"links": []
},
"jBtEiylcedtaE6E20Uk4V": {
"title": "MONITOR",
"description": "",
"links": []
},
"XBPwHgIsXupMsyoOFkJZ0": {
"title": "RedisInsight",
"description": "",
"links": []
},
"y5FPSAi6T-5X9SUfR58_-": {
"title": "RedisCommander",
"description": "",
"links": []
},
"xF0wQYmtwXYkrzvWg5gOO": {
"title": "Memory Management",
"description": "",
"links": []
},
"Sd1ENOXSFCz1YqccXjr2A": {
"title": "Max Memory Policy",
"description": "",
"links": []
},
"yaCWw2KjX58SaPajUAb0d": {
"title": "Slow Log Analysis",
"description": "",
"links": []
},
"kgHwK4N-sfh6dHjd_D_me": {
"title": "redis-benchmark",
"description": "",
"links": []
},
"2p5RF4lVYfRvYTo1Ofm-a": {
"title": "Monitoring",
"description": "",
"links": []
},
"hLIT00Iz7rV56ZBIUhWYn": {
"title": "Redis Modules",
"description": "",
"links": []
},
"jicsfYw56VrbRUt7M8c85": {
"title": "RedisJSON",
"description": "",
"links": []
},
"_GdTXcJO8uJlhPdfrmeXG": {
"title": "Search",
"description": "",
"links": []
},
"RBr8opWSh2TKXC8Fmdg0j": {
"title": "RedisTimeSeries",
"description": "",
"links": []
},
"GwVL5CvbnHsiWb1hVh7lK": {
"title": "RedisBloom",
"description": "",
"links": []
},
"giyKPtQ-pziA064P8OQD-": {
"title": "redis.conf",
"description": "",
"links": []
},
"wXRDsNGFckXV_CSiit5sN": {
"title": "Backup and Recovery",
"description": "",
"links": []
},
"Cb-KazR4PuR86VX5oT0zi": {
"title": "Upgrading Redis",
"description": "",
"links": []
},
"nUIfTkgm3PlSiqgun1BS7": {
"title": "Disaster Recovery",
"description": "",
"links": []
},
"8lyXDuZJ-KHl4v2_8Ew1h": {
"title": "Redis Enterprise",
"description": "",
"links": []
},
"cybF72wlJyJbHLUjitLvn": {
"title": "Active-Active geo Distribution",
"description": "",
"links": []
},
"sWOFnbh2EyaHRzquz1UeF": {
"title": "Redis on Flash",
"description": "",
"links": []
},
"ujs77bV8g8-FOm5hBtZFd": {
"title": "Security and Compliance",
"description": "",
"links": []
},
"JlLwy69eQ1bPHAOOJNqjo": {
"title": "When to consider enterprise?",
"description": "",
"links": []
}
}

View File

@@ -148,7 +148,7 @@
"links": [
{
"title": "Visit Dedicated Java Roadmap",
"url": "/java",
"url": "https://roadmap.sh/java",
"type": "article"
},
{
@@ -184,7 +184,7 @@
"links": [
{
"title": "Visit Dedicated Python Roadmap",
"url": "/python",
"url": "https://roadmap.sh/python",
"type": "article"
},
{
@@ -246,7 +246,7 @@
"links": [
{
"title": "Visit Dedicated Go Roadmap",
"url": "/golang",
"url": "https://roadmap.sh/golang",
"type": "article"
},
{
@@ -282,7 +282,7 @@
"links": [
{
"title": "Visit Dedicated JavaScript Roadmap",
"url": "/javascript",
"url": "https://roadmap.sh/javascript",
"type": "article"
},
{
@@ -1177,7 +1177,7 @@
"links": [
{
"title": "Visit Dedicated React Roadmap",
"url": "/react",
"url": "https://roadmap.sh/react",
"type": "article"
},
{

View File

@@ -1258,7 +1258,7 @@
"links": [
{
"title": "SQL Server Indexes",
"url": "https://www.sqlservercentral.com/articles/sql-server-indexes",
"url": "https://www.sqlservercentral.com/articles/introduction-to-indexes",
"type": "article"
},
{

View File

@@ -64,7 +64,7 @@
},
"kcG4IpneJzA6di0uqTiwb": {
"title": "CREATE Action Funnel",
"description": "Stephen Wendell's Create Action Funnel is a UX design framework focused on converting website visitors into active customers through a systematic and engaging process. The approach emphasizes on understanding user behavior, catering to their needs, and directing them towards specific actions. The Action Funnel consists of four major steps:\n\n* **Establish the Objectives:** Before diving into the design, clearly define the goals you want to achieve through the website or app. Determine what actions you want the users to take (e.g., sign up, make a purchase, share content) and what constitutes a successful conversion.\n \n* **Understand User Mindsets:** Identify your target audience and recognize their needs, preferences, emotions, and pain points. Accomplishing this requires user research, creating personas, storyboarding, and empathy mapping, among other methods.\n \n* **Design the Optimal User Flow:** Craft a seamless and intuitive user journey by designing a clear path from the landing page to the desired action. Prioritize simplicity, usability, and efficiency. Make sure to include meaningful touchpoints and interactions to engage the users and make it easy for them to complete the intended action.\n \n* **Refine and Test the Experience:** Use wireframes and prototypes to test and iteratively refine the user experience. Employ user testing, A/B testing, and analytics to gather insight on user behavior, preferences, and engagement. Continuously use feedback to make improvements, ensuring that the design effectively leads visitors down the action funnel.\n \n\nBy implementing Stephen Wendell's `Create Action Funnel`, you can effectively guide users through an engaging journey that motivates them to become active customers, ultimately increasing conversion rates and overall satisfaction.",
"description": "Stephen Wendel's CREATE Action Funnel is a behavioral design framework aimed at helping individuals or organizations encourage specific behaviors in others, especially in the context of product design. It breaks down the process of motivating action into six key stages. Each stage helps identify where users might drop off or face barriers, allowing designers or strategists to address these pain points effectively. These stages are:\n\n* **CUE:** The user must notice a cue or prompt that tells them to act. This could be a notification, a visual element, or any kind of reminder.\n \n* **REACTION:** The user must react positively to the cue. This stage involves emotional and cognitive processing, where the individual decides if the action is relevant or attractive.\n \n* **EVALUATION:** The user evaluates whether the action is worth their time, energy, or resources. They assess the benefits versus the effort required.\n \n* **ABILITY:** The user must feel capable of taking the action. This involves ensuring that the action is easy enough to do and aligns with their skills and resources.\n \n* **TIMING:** The action needs to happen at the right time. Users need to have the opportunity and be in the right context to act.\n \n* **EXECUTION:** Finally, the action must be carried out successfully. This is the stage where the behavior is completed.\n \n\nThe CREATE Action Funnel is helpful for product designers, marketers, or behavior change professionals, as it provides a structured way to understand user actions and design interventions to improve completion rates. It identifies and solves the gaps that occur between intention and action.",
"links": [
{
"title": "Behavioral Science Crash Course: Steve Wendel's CREATE Action Funnel",
@@ -75,7 +75,7 @@
},
"0Df110GZcDw5wbAe1eKoA": {
"title": "Spectrum of Thinking Interventions",
"description": "The _Spectrum of Thinking Interventions_ provides a structure to guide your UX design process, helping you identify the types and range of thinking interventions that the user may require. This spectrum encompasses four primary categories: guidance, explanation, exploration, and creation.\n\nGuidance\n--------\n\nGuidance-based interventions are designed to help users navigate through a digital product or service with minimal effort. They may be aimed at full-fledged beginners, casual users, or experts in their respective domains. Such interventions may include signposts, tooltips, and clearly articulated labels.\n\n_Examples:_\n\n* Visual cues (e.g., icons, colors)\n* Signposting (e.g., breadcrumbs)\n* In-context information (e.g., tool tips, hints)\n\nExplanation\n-----------\n\nExplanation-based interventions provide users with detailed narratives, overviews, or background information that helps them make informed decisions. This may include tutorials, articles, videos, or any other mediums that help explain complex concepts or instructions.\n\n_Examples:_\n\n* Multimedia tutorials\n* Articles or blog posts\n* Infographics or diagrams\n\nExploration\n-----------\n\nExploration-based interventions encourage users to understand and interact with the product by investigating, asking questions, or searching for solutions on their own. This can be done by providing interactive elements, multiple pathways, and opportunities for discovery.\n\n_Examples:_\n\n* Interactive simulations or models\n* Advanced search capabilities\n* Multiple UI paths for task completion\n\nCreation\n--------\n\nCreation-based interventions engage users by offering them the tools and resources to co-create or customize their experience. This type of intervention often involves a more extensive level of input and involvement from the user as they become active participants in the design process.\n\n_Examples:_\n\n* Customizable user interfaces\n* Allowing users to create their content\n* Enabling users to manage their preferences, settings, and configurations\n\nWith this spectrum in mind, it is essential as a UX designer to analyze which types of thinking interventions are most relevant to your target users and design the most accessible and effective solutions. Always consider how these interventions will influence users' decision-making processes and their overall satisfaction with your digital product or service.",
"description": "The _Spectrum of Thinking Interventions_ provides a structure for understanding the different types of decision-making processes by illustrating how our minds would respond in a _default, lowest energy way_, if we didn't consciously do something different. This spectrum ranges from situations requiring minimal thought to those demanding intensive thinking, and includes the mechanisms (\"interventions\") that our minds will likely use.\n\n* **Habits:** Triggering a learned routine based on familiar cues\n* **Other intuitive responses:** Used in familiar or semi-familiar situations, with responses based on past experiences\n* **Active mindset or self-concept:** Used in ambiguous scenarios with multiple possible interpretations\n* **Heuristics:** Used in situations requiring conscious attention, but where decisions can be made more easily\n* **Focused, conscious calculation:** Used in unfamiliar scenarios or crucial decisions where deliberate focus is needed\n\nWith this spectrum in mind, it is essential as a UX designer to leverage on the mind's decision-making process, analyze which mechanisms are most applicable to your target users and design the most accessible and effective solutions.",
"links": []
},
"kWA8CvocP1pkom2N7O4gb": {

View File

@@ -242,13 +242,25 @@
},
"NCIzs3jbQTv1xXhAaGfZN": {
"title": "v-text",
"description": "",
"links": []
"description": "The `v-text` directive is used to set the textContent property of an element. It's important to note that when using this directive it will overwrite the HTML content inside the element. The expected input is a string, so it's important to wrap any text in single quotes.\n\nExample:\n\n <template>\n <p v-text=\"'I am some text'\"></p>\n </template>\n \n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-text documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-text",
"type": "article"
}
]
},
"bZxtIBeIfeUcR32LZWrPW": {
"title": "v-html",
"description": "",
"links": []
"description": "The `v-thml` directive is similar to the `v-text` directive, but the difference is that `v-html` renders its content as HTML. This means that if you pass an HTML element it will be rendered as an element and not plain text. Since the content is render as HTMl, it can pose a security risk if the content contains malicius JavaScript code. For this reason you should never use this directive in combination with user input, unless the input is first properly sanitized.\n\nExample:\n\n <template>\n <p v-html=\"'<h1>Text</h1>'\"></p>\n </template>\n \n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-html documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-html",
"type": "article"
}
]
},
"_TlbGTKFCMO0wdLbC6xHX": {
"title": "v-show",
@@ -285,13 +297,25 @@
},
"a9caVhderJaVo0v14w8WB": {
"title": "v-else-if",
"description": "",
"links": []
"description": "This directive is used to add additional conditions to a v-if and v-else block.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-else-if Documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-else-if",
"type": "article"
}
]
},
"3ftwRjQ9e1-qDT9BV53zr": {
"title": "v-for",
"description": "",
"links": []
"description": "The `v-for` directive is used to render an HTML element, a block of elements, or even a component based on an array, an object, or a set number of times. When using this directive it is important to assign a unique key to each item to avoid issues and improve perfomance. This directive follows the `item in items` syntax.\n\nExample:\n\n <script setup>\n import { ref } from 'vue';\n const foods = ref([\n {id: 1, name: \"apple\"},\n {id: 2, name: \"pear\"},\n {id: 3, name: \"pizza\"}\n ]);\n </script>\n \n <template>\n <p v-for=\"food in foods\" :key=\"food.id\">{{ food.name }}</p>\n </template>\n \n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-for documentation",
"url": "https://vuejs.org/guide/essentials/list#v-for",
"type": "article"
}
]
},
"hVuRmhXVP65IPtuHTORjJ": {
"title": "v-on",
@@ -300,12 +324,18 @@
},
"cuM9q9vYy8JpZPGeBffd1": {
"title": "v-bind",
"description": "",
"links": []
"description": "The `v-bind` directive dynamically binds an HTML attribute to data.\n\nThe shorthand for this directive is `:`\n\nExample:\n\n <script setup>\n import { ref } from 'vue';\n const image_url = ref(\"path/to/image.png\")\n </script>\n \n <template>\n <img :src=\"image_url\" />\n </template>\n \n\nVisit the following resources for more information:",
"links": [
{
"title": "v-bind documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-bind",
"type": "article"
}
]
},
"cxu2Wbt306SxM4JKQQqnL": {
"title": "v-model",
"description": "The v-model directive in Vue.js is used for creating two-way data bindings on form input elements, such as , , and . This means that the data can be updated in the component when the user inputs something, and the UI will update if the data in the component changes.",
"description": "The v-model directive in Vue.js is used for creating two-way data bindings on form input elements, such as `<input>`, `<textarea>`, and `<select>`. This means that the data can be updated in the component when the user inputs something, and the UI will update if the data in the component changes.",
"links": [
{
"title": "Form Input Bindings",
@@ -316,28 +346,58 @@
},
"m9pQ3daR3KiwRATcQysHA": {
"title": "v-slot",
"description": "",
"links": []
"description": "The v-slot directive to define slots in components, allowing you to pass and render content dynamically inside a component.\n\nFor named slots, you use v-slot with a specific slot name. This lets you pass different content to different parts of a component:\n\n <template>\n <custom-component>\n <template v-slot:header>\n <h1>Header Content</h1>\n </template>\n <template v-slot:footer>\n <p>Footer Content</p>\n </template>\n </custom-component>\n </template>\n \n\nThe shorthand for `v-slot` is `#`, for example `v-slot:header` becomes `#header`.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-slot documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-slot",
"type": "article"
}
]
},
"5k9CrbzhNy9iiS6ez2UE6": {
"title": "v-once",
"description": "",
"links": []
"description": "The `v-once` directive makes an HTML element render only once, skipping every future update.\n\nExample:\n\n <script setup>\n import { ref } from 'vue';\n const input = ref(\"Some Text\");\n </script>\n \n <template>\n <input v-model=\"input\">\n <p v-once>{{ input }}</p>\n </template>\n \n\nIn this example the **p** element will not change its text even if the input variable is changed through the **input** element.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-once documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-once",
"type": "article"
}
]
},
"mlsrhioiEkqnRIL6O3hNa": {
"title": "v-pre",
"description": "",
"links": []
"description": "The `v-pre` directive makes an element render its content as-is, skipping its compilation. The most common use case is when displaying raw mustache syntax.\n\nExample:\n\n <script setup>\n import { ref } from 'vue';\n const text = ref(\"Some Text\")\n </script>\n \n <template>\n <p v-pre >{{ text }}</p>\n </template>\n \n\nThe **p** element will display: `{{ text }}` and not `Some Text` because the compilation is skipped.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-pre Documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-pre",
"type": "article"
}
]
},
"RrSekP8Ub01coegMwLP6a": {
"title": "v-cloak",
"description": "",
"links": []
"description": "The v-cloak directive is used to prevent the uncompiled Vue template from being visible while the Vue instance is still loading. It temporarily hides the content until Vue has finished compiling the template\n\nThe v-cloak directive remains until the component instance is mounted.\n\n <div v-cloak>\n {{ message }}\n </div>\n \n\nCombined with CSS, you can hide elements with v-cloak until they are ready.\n\n [v-cloak] {\n display: none;\n }\n \n\nThe `<div>` will not be visible until the compilation is done.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "v-cloak documentation",
"url": "https://vuejs.org/api/built-in-directives.html#v-cloak",
"type": "article"
}
]
},
"RRPhAxIqvAcjZIcLe_N8-": {
"title": "Optimizing Renders",
"description": "",
"links": []
"description": "Optimizing rendering is crucial for ensuring a smooth and efficient user experience across all your frontend projects. Sluggish webpages can lead to frustration for users, and potentially cause them to entirely abandon your web application. This issue comes up most often in single-page applications (SPAs), where the entirety of your application is loaded within a single webpage, and updates to it are handled dynamically without needing a full reload of the webpage.\n\nLearn more from the following resources:",
"links": [
{
"title": "Optimizing rendering in Vue",
"url": "https://blog.logrocket.com/optimizing-rendering-vue/",
"type": "article"
}
]
},
"dxwKfBxd5KYVkfEPMdHp-": {
"title": "Debugging",

BIN
public/roadmaps/redis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

View File

@@ -71,6 +71,7 @@ Here is the list of available roadmaps with more being actively worked upon.
- [Design System Roadmap](https://roadmap.sh/design-system)
- [PostgreSQL Roadmap](https://roadmap.sh/postgresql-dba)
- [SQL Roadmap](https://roadmap.sh/sql)
- [Redis Roadmap](https://roadmap.sh/redis)
- [Blockchain Roadmap](https://roadmap.sh/blockchain)
- [ASP.NET Core Roadmap](https://roadmap.sh/aspnet-core)
- [System Design Roadmap](https://roadmap.sh/system-design)

View File

@@ -12,8 +12,8 @@ const ALL_BEST_PRACTICE_DIR = path.join(
process.cwd(),
'/src/data/best-practices',
);
const ALL_GUIDE_DIR = path.join(process.cwd(), '/src/data/guides');
const ALl_AUTHOR_DIR = path.join(process.cwd(), '/src/data/authors');
const ALL_GUIDE_DIR = path.join(process.cwd(), '/src/content/guides');
const ALl_AUTHOR_DIR = path.join(process.cwd(), '/src/content/authors');
const ALL_ROADMAP_IMAGE_DIR = path.join(process.cwd(), '/public/roadmaps');
const ALL_BEST_PRACTICE_IMAGE_DIR = path.join(
process.cwd(),

View File

@@ -1,6 +1,6 @@
import Cookies from 'js-cookie';
import type { FormEvent } from 'react';
import { useState } from 'react';
import { useId, useState } from 'react';
import { httpPost } from '../../lib/http';
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
@@ -53,13 +53,16 @@ export function EmailLoginForm(props: EmailLoginFormProps) {
setError(error?.message || 'Something went wrong. Please try again later.');
};
const emailFieldId = `form:${useId()}`;
const passwordFieldId = `form:${useId()}`;
return (
<form className="w-full" onSubmit={handleFormSubmit}>
<label htmlFor="email" className="sr-only">
<label htmlFor={emailFieldId} className="sr-only">
Email address
</label>
<input
id="email"
id={emailFieldId}
name="email"
type="email"
autoComplete="email"
@@ -69,11 +72,11 @@ export function EmailLoginForm(props: EmailLoginFormProps) {
value={email}
onInput={(e) => setEmail(String((e.target as any).value))}
/>
<label htmlFor="password" className="sr-only">
<label htmlFor={passwordFieldId} className="sr-only">
Password
</label>
<input
id="password"
id={passwordFieldId}
name="password"
type="password"
autoComplete="current-password"

View File

@@ -0,0 +1,39 @@
---
import type { ChangelogFileType } from '../../lib/changelog';
import { DateTime } from 'luxon';
interface Props {
changelog: ChangelogFileType;
}
const { changelog } = Astro.props;
const { data: frontmatter } = changelog;
const { Content } = await changelog.render();
const formattedDate = DateTime.fromJSDate(frontmatter.date).toFormat(
'dd LLL, yyyy',
);
---
<div class='relative'>
<span
class='absolute -left-6 top-2 h-2 w-2 flex-shrink-0 rounded-full bg-gray-300'
></span>
<div class='mb-3 flex items-center gap-2'>
<span class='flex-shrink-0 text-xs tracking-wide text-gray-400'>
{formattedDate}
</span>
<span class='truncate text-base font-medium'>
{frontmatter.title}
</span>
</div>
<div class='rounded-xl border bg-white p-6'>
<div
class='prose prose-sm prose-h2:mt-3 prose-h2:text-lg prose-h2:font-medium prose-p:mb-0 prose-blockquote:font-normal prose-blockquote:text-gray-500 prose-ul:my-0 prose-ul:rounded-lg prose-ul:bg-gray-100 prose-ul:px-4 prose-ul:py-4 prose-ul:pl-7 prose-img:mt-0 prose-img:rounded-lg [&>blockquote>p]:mt-0 [&>ul>li]:my-0 [&>ul>li]:mb-1 [&>ul]:mt-3'
>
<Content />
</div>
</div>
</div>

View File

@@ -9,28 +9,31 @@ export function ContentConfirmationModal(props: ContentConfirmationModalProps) {
const { onClose, onClick } = props;
return (
<Modal onClose={onClose}>
<Modal onClose={onClose} wrapperClassName="max-w-lg">
<div className="p-4">
<h2 className="text-lg font-semibold">Roadmap Content</h2>
<h2 className="text-lg font-semibold">
Copy Node Details and Resources?
</h2>
<p className="balanc text-gray-600">
Do you want to copy the content of this roadmap?
This will just copy the roadmap in your team. Would you like to copy
the resource links and node details as well?
</p>
<div className="mt-4 grid grid-cols-2 gap-2">
<button
className="rounded-lg border p-2.5 font-medium"
className="rounded-lg border p-2.5 font-normal"
onClick={() => {
onClick(false);
}}
>
No
No, copy roadmap only
</button>
<button
className="rounded-lg border bg-black p-2.5 font-medium text-white hover:opacity-80"
className="rounded-lg border bg-black p-2.5 font-normal text-white hover:opacity-80"
onClick={() => {
onClick(true);
}}
>
Yes
Yes, also copy resources
</button>
</div>
</div>

View File

@@ -10,6 +10,7 @@ import { showLoginPopup } from '../../lib/popup.ts';
import { isLoggedIn } from '../../lib/jwt.ts';
import { useState } from 'react';
import { CreateRoadmapModal } from './CreateRoadmap/CreateRoadmapModal.tsx';
import { RoadmapAlert } from '../RoadmapAlert.tsx';
export function CustomRoadmapAlert() {
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
@@ -23,33 +24,18 @@ export function CustomRoadmapAlert() {
}}
/>
)}
<div className="relative mb-5 mt-0 rounded-md border border-yellow-500 bg-yellow-100 p-2 sm:-mt-6 sm:mb-7 sm:p-2.5">
<p className="mb-2.5 mt-2 text-sm text-yellow-800 sm:mb-1.5 sm:mt-1 sm:text-base">
This is a custom roadmap made by a community member and is not
verified by <span className="font-semibold">roadmap.sh</span>
</p>
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
<a
href="/roadmaps"
className="inline-flex items-center gap-1.5 text-sm font-semibold text-yellow-700 underline-offset-2 hover:underline"
>
<BadgeCheck className="h-4 w-4 stroke-[2.5]" />
Visit Official Roadmaps
</a>
<span className="hidden font-black text-yellow-700 sm:block">
&middot;
</span>
<a
href="/community"
className="inline-flex items-center gap-1.5 text-sm font-semibold text-yellow-700 underline-offset-2 hover:underline"
>
<HeartHandshake className="h-4 w-4 stroke-[2.5]" />
More Community Roadmaps
</a>
</div>
<MessageCircleHeart className="absolute bottom-2 right-2 hidden h-12 w-12 text-yellow-500 opacity-50 sm:block" />
</div>
<RoadmapAlert
title="Community Roadmaps"
description={
<>
This is a custom roadmap made by a community member and is not
verified by <span className="font-semibold">roadmap.sh</span>
</>
}
floatingIcon={MessageCircleHeart}
className="mb-5 mt-0 sm:-mt-6 sm:mb-7"
/>
</>
);
}

View File

@@ -159,7 +159,8 @@ export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
{hideRenderer && (
<EmptyRoadmap
roadmapId={roadmapId}
canManage={roadmap.canManage}
// @ts-ignore
canManage={roadmap?.canManage}
className="grow"
/>
)}

View File

@@ -4,7 +4,13 @@ import { DashboardCardLink } from './DashboardCardLink';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { Simulate } from 'react-dom/test-utils';
import { Bot, BrainCircuit, Map, PencilRuler } from 'lucide-react';
import {
ArrowUpRight,
Bot,
BrainCircuit,
Map,
PencilRuler,
} from 'lucide-react';
type DashboardAiRoadmapsProps = {
roadmaps: {
@@ -20,9 +26,18 @@ export function DashboardAiRoadmaps(props: DashboardAiRoadmapsProps) {
return (
<>
<h2 className="mb-2 mt-6 text-xs uppercase text-gray-400">
AI Generated Roadmaps
</h2>
<div className="mb-2 mt-6 flex items-center justify-between gap-2">
<h2 className="text-xs uppercase text-gray-400">
My AI Roadmaps
</h2>
<a
href="/ai/explore"
className="rounded-full bg-gray-200 px-2.5 py-0.5 text-xs font-medium text-gray-700 hover:bg-gray-300 hover:text-black"
>
AI Generated Roadmaps
</a>
</div>
{!isLoading && roadmaps.length === 0 && (
<DashboardCardLink
@@ -48,7 +63,7 @@ export function DashboardAiRoadmaps(props: DashboardAiRoadmapsProps) {
{roadmaps.map((roadmap) => (
<a
href={`/ai/${roadmap.slug}`}
className="relative rounded-md border bg-white p-2.5 text-left text-sm shadow-sm truncate hover:border-gray-400 hover:bg-gray-50"
className="relative truncate rounded-md border bg-white p-2.5 text-left text-sm shadow-sm hover:border-gray-400 hover:bg-gray-50"
>
{roadmap.title}
</a>
@@ -69,9 +84,7 @@ export function DashboardAiRoadmaps(props: DashboardAiRoadmapsProps) {
type CustomProgressCardSkeletonProps = {};
function RoadmapCardSkeleton(
props: CustomProgressCardSkeletonProps,
) {
function RoadmapCardSkeleton(props: CustomProgressCardSkeletonProps) {
return (
<div className="h-[42px] w-full animate-pulse rounded-md bg-gray-200" />
);

View File

@@ -19,7 +19,6 @@ export function DashboardCardLink(props: DashboardCardLinkProps) {
className,
)}
href={href}
target="_blank"
>
<Icon className="mb-4 size-10 text-gray-300" strokeWidth={1.25} />
<h4 className="text-xl font-semibold tracking-wide">{title}</h4>

View File

@@ -54,13 +54,14 @@ export function DashboardPage(props: DashboardPageProps) {
return (
<div className="min-h-screen bg-gray-50 pb-20 pt-8">
<div className="container">
<div className="mb-6 sm:mb-8 flex flex-wrap items-center gap-1.5">
<div className="mb-6 flex flex-wrap items-center gap-1.5 sm:mb-8">
<DashboardTab
label="Personal"
isActive={!selectedTeamId}
onClick={() => setSelectedTeamId(undefined)}
avatar={userAvatar}
/>
{isLoading && (
<>
<DashboardTabSkeleton />

View File

@@ -1,17 +1,26 @@
import { cn } from '../../lib/classname';
type EmptyStackMessageProps = {
number: number;
number: number | string;
title: string;
description: string;
buttonText: string;
buttonLink: string;
bodyClassName?: string;
};
export function EmptyStackMessage(props: EmptyStackMessageProps) {
const { number, title, description, buttonText, buttonLink } = props;
const { number, title, description, buttonText, buttonLink, bodyClassName } =
props;
return (
<div className="absolute inset-0 flex items-center justify-center rounded-md bg-black/50">
<div className="flex max-w-[200px] flex-col items-center justify-center rounded-md bg-white p-4 shadow-sm">
<div
className={cn(
'flex max-w-[200px] flex-col items-center justify-center rounded-md bg-white p-4 shadow-sm',
bodyClassName,
)}
>
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-gray-300 text-white">
{number}
</span>

View File

@@ -4,7 +4,13 @@ import { DashboardCardLink } from './DashboardCardLink';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { Simulate } from 'react-dom/test-utils';
import {Bot, BrainCircuit, Map, PencilRuler} from 'lucide-react';
import {
ArrowUpRight,
Bot,
BrainCircuit,
Map,
PencilRuler,
} from 'lucide-react';
type ListDashboardCustomProgressProps = {
progresses: UserProgress[];
@@ -40,9 +46,18 @@ export function ListDashboardCustomProgress(
<>
{customRoadmapModal}
<h2 className="mb-2 mt-6 text-xs uppercase text-gray-400">
{isAIGeneratedRoadmaps ? 'AI Generated Roadmaps' : 'Custom Roadmaps'}
</h2>
<div className="mb-2 mt-6 flex items-center justify-between gap-2">
<h2 className="text-xs uppercase text-gray-400">
{isAIGeneratedRoadmaps ? 'My AI Roadmaps' : 'My Custom Roadmaps'}
</h2>
<a
href="/community"
className="rounded-full bg-gray-200 px-2.5 py-0.5 text-xs font-medium text-gray-700 hover:bg-gray-300 hover:text-black"
>
Community Roadmaps
</a>
</div>
{!isLoading && progresses.length === 0 && isAIGeneratedRoadmaps && (
<DashboardCardLink

View File

@@ -14,6 +14,9 @@ import { CheckEmoji } from '../ReactIcons/CheckEmoji.tsx';
import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx';
import { BookEmoji } from '../ReactIcons/BookEmoji.tsx';
import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx';
import type { AllowedProfileVisibility } from '../../api/user.ts';
import { PencilIcon, type LucideIcon } from 'lucide-react';
import { cn } from '../../lib/classname.ts';
type UserDashboardResponse = {
name: string;
@@ -21,6 +24,7 @@ type UserDashboardResponse = {
avatar: string;
headline: string;
username: string;
profileVisibility: AllowedProfileVisibility;
progresses: UserProgress[];
projects: ProjectStatusDocument[];
aiRoadmaps: {
@@ -222,20 +226,22 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return 0;
});
const { username } = personalDashboardDetails || {};
return (
<section>
{isLoading ? (
<div className="h-7 w-1/4 animate-pulse rounded-lg bg-gray-200"></div>
) : (
<div className="flex items-start sm:items-center justify-between flex-col sm:flex-row gap-1">
<div className="flex flex-col items-start justify-between gap-1 sm:flex-row sm:items-center">
<h2 className="text-lg font-medium">
Hi {name}, good {getCurrentPeriod()}!
</h2>
<a
href="/home"
className="text-xs text-purple-600 underline underline-offset-2 hover:text-purple-700"
className="rounded-full bg-gray-200 px-2.5 py-1 text-xs font-medium text-gray-700 hover:bg-gray-300 hover:text-black"
>
Looking for old homepage? Click here
Visit Homepage
</a>
</div>
)}
@@ -253,8 +259,20 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<DashboardCard
imgUrl={avatarLink}
title={name!}
description="Setup your profile"
href="/account/update-profile"
description={
username ? 'View your profile' : 'Setup your profile'
}
href={username ? `/u/${username}` : '/account/update-profile'}
{...(username && {
externalLinkIcon: PencilIcon,
externalLinkHref: '/account/update-profile',
externalLinkText: 'Edit',
})}
className={
!username
? 'border-dashed border-gray-500 bg-gray-100 hover:border-gray-500 hover:bg-gray-200'
: ''
}
/>
<DashboardCard
@@ -273,7 +291,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<DashboardCard
icon={CheckEmoji}
title="Best Practices"
description="Do things right way"
description="Do things the right way"
href="/best-practices"
/>
</>
@@ -312,34 +330,61 @@ type DashboardCardProps = {
title: string;
description: string;
href: string;
externalLinkIcon?: LucideIcon;
externalLinkText?: string;
externalLinkHref?: string;
className?: string;
};
function DashboardCard(props: DashboardCardProps) {
const { icon: Icon, imgUrl, title, description, href } = props;
const {
icon: Icon,
imgUrl,
title,
description,
href,
externalLinkHref,
externalLinkIcon: ExternalLinkIcon,
externalLinkText,
className,
} = props;
return (
<a
href={href}
target="_blank"
className="flex flex-col overflow-hidden rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50"
<div
className={cn(
'relative overflow-hidden',
className,
)}
>
{Icon && (
<div className="px-4 pb-3 pt-4">
<Icon className="size-6" />
</div>
)}
<a href={href} className="flex flex-col rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50">
{Icon && (
<div className="px-4 pb-3 pt-4">
<Icon className="size-6" />
</div>
)}
{imgUrl && (
<div className="px-4 pb-1.5 pt-3.5">
<img src={imgUrl} alt={title} className="size-8 rounded-full" />
</div>
)}
{imgUrl && (
<div className="px-4 pb-1.5 pt-3.5">
<img src={imgUrl} alt={title} className="size-8 rounded-full" />
</div>
)}
<div className="flex grow flex-col justify-center gap-0.5 p-4">
<h3 className="truncate font-medium text-black">{title}</h3>
<p className="text-xs text-black">{description}</p>
</div>
</a>
<div className="flex grow flex-col justify-center gap-0.5 p-4">
<h3 className="truncate font-medium text-black">{title}</h3>
<p className="text-xs text-black">{description}</p>
</div>
</a>
{externalLinkHref && (
<a
href={externalLinkHref}
className="absolute right-1 top-1 flex items-center gap-1.5 rounded-md bg-gray-200 p-1 px-2 text-xs text-gray-600 hover:bg-gray-300 hover:text-black"
>
{ExternalLinkIcon && <ExternalLinkIcon className="size-3" />}
{externalLinkText}
</a>
)}
</div>
);
}

View File

@@ -26,8 +26,7 @@ type ProgressStackProps = {
topicDoneToday: number;
};
const MAX_PROGRESS_TO_SHOW = 5;
const MAX_BOOKMARKS_TO_SHOW = 5;
const MAX_PROGRESS_TO_SHOW = 11;
const MAX_PROJECTS_TO_SHOW = 8;
type ProgressLaneProps = {
@@ -36,6 +35,7 @@ type ProgressLaneProps = {
linkHref?: string;
isLoading?: boolean;
isEmpty?: boolean;
loadingWrapperClassName?: string;
loadingSkeletonCount?: number;
loadingSkeletonClassName?: string;
children: React.ReactNode;
@@ -43,6 +43,7 @@ type ProgressLaneProps = {
emptyIcon?: LucideIcon;
emptyLinkText?: string;
emptyLinkHref?: string;
className?: string;
};
function ProgressLane(props: ProgressLaneProps) {
@@ -51,6 +52,7 @@ function ProgressLane(props: ProgressLaneProps) {
linkText,
linkHref,
isLoading = false,
loadingWrapperClassName = '',
loadingSkeletonCount = 4,
loadingSkeletonClassName = '',
children,
@@ -59,10 +61,16 @@ function ProgressLane(props: ProgressLaneProps) {
emptyMessage = `No ${title.toLowerCase()} to show`,
emptyLinkHref = '/roadmaps',
emptyLinkText = 'Explore',
className,
} = props;
return (
<div className="flex h-full flex-col rounded-md border bg-white px-4 py-3 shadow-sm">
<div
className={cn(
'flex h-full flex-col rounded-md border bg-white px-4 py-3 shadow-sm',
className,
)}
>
{isLoading && (
<div className={'flex flex-row justify-between'}>
<div className="h-[16px] w-[75px] animate-pulse rounded-md bg-gray-100"></div>
@@ -86,11 +94,13 @@ function ProgressLane(props: ProgressLaneProps) {
<div className="mt-4 flex flex-grow flex-col gap-1.5">
{isLoading && (
<>
<div
className={cn('grid grid-cols-2 gap-2', loadingWrapperClassName)}
>
{Array.from({ length: loadingSkeletonCount }).map((_, index) => (
<CardSkeleton key={index} className={loadingSkeletonClassName} />
))}
</>
</div>
)}
{!isLoading && children}
@@ -119,29 +129,27 @@ export function ProgressStack(props: ProgressStackProps) {
const { progresses, projects, isLoading, accountStreak, topicDoneToday } =
props;
const bookmarkedProgresses = progresses.filter(
(progress) => progress?.isFavorite,
);
const userProgresses = progresses.filter(
(progress) => !progress?.isFavorite || progress?.done > 0,
);
const [showAllProgresses, setShowAllProgresses] = useState(false);
const sortedProgresses = progresses.sort((a, b) => {
if (a.isFavorite && !b.isFavorite) {
return 1;
}
if (!a.isFavorite && b.isFavorite) {
return -1;
}
return 0;
});
const userProgressesToShow = showAllProgresses
? userProgresses
: userProgresses.slice(0, MAX_PROGRESS_TO_SHOW);
? sortedProgresses
: sortedProgresses.slice(0, MAX_PROGRESS_TO_SHOW);
const [showAllProjects, setShowAllProjects] = useState(false);
const projectsToShow = showAllProjects
? projects
: projects.slice(0, MAX_PROJECTS_TO_SHOW);
const [showAllBookmarks, setShowAllBookmarks] = useState(false);
const bookmarksToShow = showAllBookmarks
? bookmarkedProgresses
: bookmarkedProgresses.slice(0, MAX_BOOKMARKS_TO_SHOW);
const totalProjectFinished = projects.filter(
(project) => project.repositoryUrl,
).length;
@@ -167,92 +175,70 @@ export function ProgressStack(props: ProgressStackProps) {
</div>
<div className="mt-2 grid min-h-[330px] grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
<div className="relative">
{!isLoading && bookmarksToShow.length === 0 && (
<div className="relative col-span-2">
{!isLoading && userProgressesToShow.length === 0 && (
<EmptyStackMessage
number={1}
title={'Bookmark Roadmaps'}
description={'Bookmark some roadmaps to access them quickly'}
title={'Bookmark some Roadmaps'}
description={
'Bookmark some roadmaps to access them quickly and start updating your progress'
}
buttonText={'Explore Roadmaps'}
buttonLink={'/roadmaps'}
bodyClassName="max-w-[280px]"
/>
)}
<ProgressLane
title={'Bookmarks'}
title="Progress & Bookmarks"
isLoading={isLoading}
loadingSkeletonCount={5}
linkHref={'/roadmaps'}
linkText={'Roadmaps'}
isEmpty={bookmarksToShow.length === 0}
loadingSkeletonCount={MAX_PROGRESS_TO_SHOW}
linkHref="/roadmaps"
linkText="Roadmaps"
isEmpty={userProgressesToShow.length === 0}
emptyIcon={Bookmark}
emptyMessage={'No bookmarks to show'}
emptyLinkHref={'/roadmaps'}
emptyLinkText={'Explore Roadmaps'}
>
{bookmarksToShow.map((progress) => {
return (
<DashboardBookmarkCard
key={progress.resourceId}
bookmark={progress}
<div className="grid grid-cols-2 gap-2">
{userProgressesToShow.length > 0 && (
<>
{userProgressesToShow.map((progress) => {
const isFavorite =
progress.isFavorite &&
!progress.done &&
!progress.skipped;
if (isFavorite) {
return (
<DashboardBookmarkCard
key={progress.resourceId}
bookmark={progress}
/>
);
}
return (
<DashboardProgressCard
key={progress.resourceId}
progress={progress}
/>
);
})}
</>
)}
{sortedProgresses.length > MAX_PROGRESS_TO_SHOW && (
<ShowAllButton
showAll={showAllProgresses}
setShowAll={setShowAllProgresses}
count={sortedProgresses.length}
maxCount={MAX_PROGRESS_TO_SHOW}
className="min-h-[38px] rounded-md border border-dashed leading-none"
/>
);
})}
{bookmarkedProgresses.length > MAX_BOOKMARKS_TO_SHOW && (
<ShowAllButton
showAll={showAllBookmarks}
setShowAll={setShowAllBookmarks}
count={bookmarkedProgresses.length}
maxCount={MAX_BOOKMARKS_TO_SHOW}
className="mb-0.5 mt-3"
/>
)}
</ProgressLane>
</div>
<div className="relative">
{!isLoading && userProgressesToShow.length === 0 && (
<EmptyStackMessage
number={2}
title={'Track Progress'}
description={'Pick your first roadmap and start learning'}
buttonText={'Explore roadmaps'}
buttonLink={'/roadmaps'}
/>
)}
<ProgressLane
title={'Progress'}
linkHref={'/roadmaps'}
linkText={'Roadmaps'}
isLoading={isLoading}
loadingSkeletonCount={5}
isEmpty={userProgressesToShow.length === 0}
emptyMessage={'Update your Progress'}
emptyIcon={Map}
emptyLinkText={'Explore Roadmaps'}
>
{userProgressesToShow.length > 0 && (
<>
{userProgressesToShow.map((progress) => {
return (
<DashboardProgressCard
key={progress.resourceId}
progress={progress}
/>
);
})}
</>
)}
{userProgresses.length > MAX_PROGRESS_TO_SHOW && (
<ShowAllButton
showAll={showAllProgresses}
setShowAll={setShowAllProgresses}
count={userProgresses.length}
maxCount={MAX_PROGRESS_TO_SHOW}
className="mb-0.5 mt-3"
/>
)}
)}
</div>
</ProgressLane>
</div>
@@ -262,6 +248,7 @@ export function ProgressStack(props: ProgressStackProps) {
linkHref={'/projects'}
linkText={'Projects'}
isLoading={isLoading}
loadingWrapperClassName="grid-cols-1"
loadingSkeletonClassName={'h-5'}
loadingSkeletonCount={8}
isEmpty={projectsToShow.length === 0}
@@ -272,7 +259,7 @@ export function ProgressStack(props: ProgressStackProps) {
>
{!isLoading && projectsToShow.length === 0 && (
<EmptyStackMessage
number={3}
number={2}
title={'Build your first project'}
description={'Pick a project to practice and start building'}
buttonText={'Explore Projects'}
@@ -317,17 +304,15 @@ function ShowAllButton(props: ShowAllButtonProps) {
const { showAll, setShowAll, count, maxCount, className } = props;
return (
<span className="flex flex-grow items-end">
<button
className={cn(
'flex w-full items-center justify-center text-sm text-gray-500 hover:text-gray-700',
className,
)}
onClick={() => setShowAll(!showAll)}
>
{!showAll ? <>+ show {count - maxCount} more</> : <>- show less</>}
</button>
</span>
<button
className={cn(
'flex w-full items-center justify-center text-sm text-gray-500 hover:text-gray-700',
className,
)}
onClick={() => setShowAll(!showAll)}
>
{!showAll ? <>+ show {count - maxCount} more</> : <>- show less</>}
</button>
);
}
@@ -341,7 +326,7 @@ function CardSkeleton(props: CardSkeletonProps) {
return (
<div
className={cn(
'h-10 w-full animate-pulse rounded-md bg-gray-100',
'h-[38px] w-full animate-pulse rounded-md bg-gray-100',
className,
)}
/>

View File

@@ -1,7 +1,7 @@
---
import type { GuideFileType } from '../lib/guide';
import GuideListItem from './GuideListItem.astro';
import { QuestionGroupType } from '../lib/question-group';
import type { QuestionGroupType } from '../lib/question-group';
export interface Props {
heading: string;
@@ -15,8 +15,8 @@ const sortedGuides: (QuestionGroupType | GuideFileType)[] = [
...guides,
...questions,
].sort((a, b) => {
const aDate = new Date(a.frontmatter.date);
const bDate = new Date(b.frontmatter.date);
const aDate = new Date(a.data.date!);
const bDate = new Date(b.data.date!);
return bDate.getTime() - aDate.getTime();
});

View File

@@ -11,7 +11,9 @@ export function ProgressNudge(props: ProgressNudgeProps) {
const $totalRoadmapNodes = useStore(totalRoadmapNodes);
const $roadmapProgress = useStore(roadmapProgress);
const done = $roadmapProgress?.done?.length || 0;
const done =
($roadmapProgress?.done?.length || 0) +
($roadmapProgress?.skipped?.length || 0);
const hasProgress = done > 0;
@@ -51,7 +53,8 @@ export function ProgressNudge(props: ProgressNudgeProps) {
<span className="relative -top-[0.45px] mr-2 text-xs font-medium uppercase text-yellow-400">
Progress
</span>
<span>{done > $totalRoadmapNodes ? $totalRoadmapNodes : done}</span> of <span>{$totalRoadmapNodes}</span> Done
<span>{done > $totalRoadmapNodes ? $totalRoadmapNodes : done}</span> of{' '}
<span>{$totalRoadmapNodes}</span> Done
</span>
<span

View File

@@ -1,4 +1,5 @@
import { BadgeCheck, Telescope, Wand } from 'lucide-react';
import { BadgeCheck, Bot, Telescope, Wand } from 'lucide-react';
import { RoadmapAlert } from '../RoadmapAlert';
type AIRoadmapAlertProps = {
isListing?: boolean;
@@ -8,46 +9,20 @@ export function AIRoadmapAlert(props: AIRoadmapAlertProps) {
const { isListing = false } = props;
return (
<div className="mb-3 w-full rounded-xl bg-yellow-100 px-4 py-3 text-yellow-800">
<h2 className="flex items-center text-base font-semibold text-yellow-800 sm:text-lg">
AI Generated Roadmap{isListing ? 's' : ''}{' '}
<span className="ml-1.5 rounded-md border border-yellow-500 bg-yellow-200 px-1.5 text-xs uppercase tracking-wide text-yellow-800">
Beta
</span>
</h2>
<p className="mb-2 mt-1">
{isListing
? 'These are AI generated roadmaps and are not verified by'
: 'This is an AI generated roadmap and is not verified by'}{' '}
<span className={'font-semibold'}>roadmap.sh</span>. We are currently in
beta and working hard to improve the quality of the generated roadmaps.
</p>
<p className="mb-1.5 mt-2 flex flex-col gap-2 text-sm sm:flex-row">
{isListing ? (
<a
href="/ai"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 px-2 py-1 text-yellow-700 transition-colors hover:bg-yellow-300 hover:text-yellow-800"
>
<Wand size={15} />
Create your own Roadmap with AI
</a>
) : (
<a
href="/ai/explore"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 px-2 py-1 text-yellow-700 transition-colors hover:bg-yellow-300 hover:text-yellow-800"
>
<Telescope size={15} />
Explore other AI Roadmaps
</a>
)}
<a
href="/roadmaps"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 bg-yellow-200 px-2 py-1 text-yellow-800 transition-colors hover:bg-yellow-300"
>
<BadgeCheck size={15} />
Visit Official Roadmaps
</a>
</p>
</div>
<RoadmapAlert
title={`AI Generated Roadmap${isListing ? 's' : ''}`}
badgeText="Beta"
description={
<>
{isListing
? 'These are AI generated roadmaps and are not verified by'
: 'This is an AI generated roadmap and is not verified by'}{' '}
<span className={'font-semibold'}>roadmap.sh</span>. We are currently
in beta and working hard to improve the quality of the generated
roadmaps.
</>
}
floatingIcon={Bot}
/>
);
}

View File

@@ -10,11 +10,11 @@ interface Props {
const { guide } = Astro.props;
const allHeadings = guide.getHeadings();
const { headings: allHeadings, Content } = await guide.render();
const tableOfContent = getGuideTableOfContent(allHeadings);
const showTableOfContent = tableOfContent.length > 0;
const { frontmatter: guideFrontmatter, author } = guide;
const { data: guideFrontmatter, author } = guide;
---
<article class='lg:grid lg:max-w-full lg:grid-cols-[1fr_minmax(0,700px)_1fr]'>
@@ -40,26 +40,26 @@ const { frontmatter: guideFrontmatter, author } = guide;
</h1>
<p class='my-0 flex items-center justify-start text-sm text-gray-400'>
<a
href={`/authors/${author.id}`}
href={`/authors/${author.slug}`}
class='inline-flex items-center font-medium underline-offset-2 hover:text-gray-600 hover:underline'
>
<img
alt={author.frontmatter.name}
src={author.frontmatter.imageUrl}
alt={author.data.name}
src={author.data.imageUrl}
class='mb-0 mr-2 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.name}
{author.data.name}
</a>
<span class='mx-2 hidden sm:inline'>&middot;</span>
<a
class='hidden underline-offset-2 hover:text-gray-600 sm:inline'
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/guides/${guide.id}.md`}
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/guides/${guide.slug}.md`}
target='_blank'
>
Improve this Guide
</a>
</p>
<guide.Content />
<Content />
</MarkdownFile>
</div>
</article>

View File

@@ -7,7 +7,7 @@ export interface Props {
}
const { guide } = Astro.props;
const { frontmatter, author } = guide;
const { data: frontmatter, author } = guide;
return undefined;
---
@@ -18,18 +18,18 @@ return undefined;
class='hidden items-center justify-start text-gray-400 sm:flex sm:justify-center'
>
{
author?.frontmatter && (
author?.data && (
<>
<a
href={`/authors/${author.id}`}
href={`/authors/${author.slug}`}
class='inline-flex items-center font-medium hover:text-gray-600 hover:underline'
>
<img
alt={author.frontmatter.name}
src={author.frontmatter.imageUrl}
alt={author.data.name}
src={author.data.imageUrl}
class='mr-2 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.name}
{author.data.name}
</a>
<span class='mx-1.5'>&middot;</span>
</>
@@ -39,7 +39,7 @@ return undefined;
<span class='mx-1.5'>&middot;</span>
<a
class='text-blue-400 hover:text-blue-500 hover:underline'
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/guides/${guide.id}.md`}
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/guides/${guide.slug}.md`}
target='_blank'>Improve this Guide</a
>
</p>

View File

@@ -1,7 +1,7 @@
---
import type { GuideFileType, GuideFrontmatter } from '../lib/guide';
import type { GuideFileType } from '../lib/guide';
import { replaceVariables } from '../lib/markdown';
import { QuestionGroupType } from '../lib/question-group';
import type { QuestionGroupType } from '../lib/question-group';
export interface Props {
guide: GuideFileType | QuestionGroupType;
@@ -14,7 +14,7 @@ function isQuestionGroupType(
}
const { guide } = Astro.props;
const { frontmatter, id } = guide;
const { data: frontmatter, slug: id } = guide;
let pageUrl = '';
let guideType = '';
@@ -23,9 +23,9 @@ if (isQuestionGroupType(guide)) {
pageUrl = `/questions/${id}`;
guideType = 'Questions';
} else {
const excludedBySlug = (frontmatter as GuideFrontmatter).excludedBySlug;
const excludedBySlug = (frontmatter as GuideFileType['data']).excludedBySlug;
pageUrl = excludedBySlug ? excludedBySlug : `/guides/${id}`;
guideType = (frontmatter as GuideFrontmatter).type;
guideType = (frontmatter as GuideFileType['data']).type;
}
---
@@ -46,7 +46,7 @@ if (isQuestionGroupType(guide)) {
New
<span class='hidden sm:inline'>
&middot;
{new Date(frontmatter.date).toLocaleString('default', {
{new Date(frontmatter.date!).toLocaleString('default', {
month: 'long',
})}
</span>

View File

@@ -1,5 +1,16 @@
---
interface Props {
class?: string;
}
const { class: className } = Astro.props;
---
<div
class='container prose-h2:text-balance prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-3xl prose-h3:mt-2 prose-h3:scroll-mt-5 prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10'
class:list={[
'container prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-balance prose-h2:text-3xl prose-h3:mt-2 prose-h3:scroll-mt-5 prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10',
className,
]}
>
<slot />
</div>

View File

@@ -14,8 +14,7 @@ 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 type { ProjectFileType } from '../../lib/project.ts';
export interface ProjectStatusDocument {
_id?: string;
@@ -65,7 +64,7 @@ type PageState = {
};
type ListProjectSolutionsProps = {
project: ProjectFrontmatter;
project: ProjectFileType['data'];
projectId: string;
};

View File

@@ -1,10 +1,8 @@
import { Badge } from '../Badge.tsx';
import type {
ProjectDifficultyType,
ProjectFileType,
} from '../../lib/project.ts';
import type { ProjectFileType } from '../../lib/project.ts';
import { Users } from 'lucide-react';
import { formatCommaNumber } from '../../lib/number.ts';
import type { ProjectDifficultyType } from '../../content/project.ts';
type ProjectCardProps = {
project: ProjectFileType;
@@ -20,7 +18,7 @@ const badgeVariants: Record<ProjectDifficultyType, string> = {
export function ProjectCard(props: ProjectCardProps) {
const { project, userCount = 0 } = props;
const { frontmatter, id } = project;
const { data: frontmatter, slug: id } = project;
return (
<a

View File

@@ -2,16 +2,16 @@ import { ProjectCard } from './ProjectCard.tsx';
import { HeartHandshake, Trash2 } from 'lucide-react';
import { cn } from '../../lib/classname.ts';
import { useMemo, useState } from 'react';
import {
projectDifficulties,
type ProjectDifficultyType,
type ProjectFileType,
} from '../../lib/project.ts';
import { type ProjectFileType } from '../../lib/project.ts';
import {
deleteUrlParam,
getUrlParams,
setUrlParams,
} from '../../lib/browser.ts';
import {
projectDifficulties,
type ProjectDifficultyType,
} from '../../content/project.ts';
type DifficultyButtonProps = {
difficulty: ProjectDifficultyType;
@@ -56,7 +56,7 @@ export function ProjectsList(props: ProjectsListProps) {
const result = new Map<ProjectDifficultyType, ProjectFileType[]>();
for (const project of projects) {
const difficulty = project.frontmatter.difficulty;
const difficulty = project.data.difficulty;
if (!result.has(difficulty)) {
result.set(difficulty, []);
@@ -78,6 +78,7 @@ export function ProjectsList(props: ProjectsListProps) {
<div className="flex flex-wrap gap-1">
{projectDifficulties.map((projectDifficulty) => (
<DifficultyButton
key={projectDifficulty}
onClick={() => {
setDifficulty(projectDifficulty);
setUrlParams({ difficulty: projectDifficulty });
@@ -119,18 +120,24 @@ export function ProjectsList(props: ProjectsListProps) {
{matchingProjects
.sort((project) => {
return project.frontmatter.difficulty === 'beginner'
return project.data.difficulty === 'beginner'
? -1
: project.frontmatter.difficulty === 'intermediate'
: project.data.difficulty === 'intermediate'
? 0
: 1;
})
.sort((a, b) => {
return a.frontmatter.sort - b.frontmatter.sort;
return a.data.sort - b.data.sort;
})
.map((matchingProject) => {
const count = userCounts[matchingProject?.id] || 0;
return <ProjectCard project={matchingProject} userCount={count} />;
const count = userCounts[matchingProject?.slug] || 0;
return (
<ProjectCard
key={matchingProject.slug}
project={matchingProject}
userCount={count}
/>
);
})}
</div>
</div>

View File

@@ -7,11 +7,9 @@ import {
setUrlParams,
} from '../../lib/browser.ts';
import { CategoryFilterButton } from '../Roadmaps/CategoryFilterButton.tsx';
import {
projectDifficulties,
type ProjectFileType,
} from '../../lib/project.ts';
import { type ProjectFileType } from '../../lib/project.ts';
import { ProjectCard } from './ProjectCard.tsx';
import { projectDifficulties } from '../../content/project.ts';
type ProjectGroup = {
id: string;
@@ -28,7 +26,7 @@ export function ProjectsPage(props: ProjectsPageProps) {
const { roadmapsProjects, userCounts } = props;
const allUniqueProjectIds = new Set<string>(
roadmapsProjects.flatMap((group) =>
group.projects.map((project) => project.id),
group.projects.map((project) => project.slug),
),
);
const allUniqueProjects = useMemo(
@@ -37,7 +35,7 @@ export function ProjectsPage(props: ProjectsPageProps) {
.map((id) =>
roadmapsProjects
.flatMap((group) => group.projects)
.find((project) => project.id === id),
.find((project) => project.slug === id),
)
.filter(Boolean) as ProjectFileType[],
[allUniqueProjectIds],
@@ -67,8 +65,8 @@ export function ProjectsPage(props: ProjectsPageProps) {
const sortedVisibleProjects = useMemo(
() =>
visibleProjects.sort((a, b) => {
const projectADifficulty = a?.frontmatter.difficulty || 'beginner';
const projectBDifficulty = b?.frontmatter.difficulty || 'beginner';
const projectADifficulty = a?.data.difficulty || 'beginner';
const projectBDifficulty = b?.data.difficulty || 'beginner';
return (
projectDifficulties.indexOf(projectADifficulty) -
projectDifficulties.indexOf(projectBDifficulty)
@@ -189,7 +187,7 @@ export function ProjectsPage(props: ProjectsPageProps) {
<ProjectCard
key={project.id}
project={project}
userCount={userCounts[project.id] || 0}
userCount={userCounts[project.slug] || 0}
/>
))}
</div>

View File

@@ -1,13 +1,9 @@
---
import {
getGuideTableOfContent,
type GuideFileType,
HeadingGroupType,
} from '../../lib/guide';
import { getGuideTableOfContent, type HeadingGroupType } from '../../lib/guide';
import MarkdownFile from '../MarkdownFile.astro';
import { TableOfContent } from '../TableOfContent/TableOfContent';
import { markdownToHtml, replaceVariables } from '../../lib/markdown';
import { QuestionGroupType } from '../../lib/question-group';
import type { QuestionGroupType } from '../../lib/question-group';
import { QuestionsList } from './QuestionsList';
interface Props {
@@ -16,19 +12,17 @@ interface Props {
const { questionGroup } = Astro.props;
const allHeadings = questionGroup.getHeadings();
const { headings: allHeadings, Content } = await questionGroup.render();
const tableOfContent: HeadingGroupType[] = [
...getGuideTableOfContent(allHeadings),
{
depth: 2,
title: 'Test with Flashcards',
text: 'Test yourself with Flashcards',
children: [],
slug: 'test-with-flashcards',
text: 'Test yourself with Flashcards',
},
{
depth: 2,
title: 'Questions List',
children: [
{
depth: 2,
@@ -58,7 +52,7 @@ const tableOfContent: HeadingGroupType[] = [
];
const showTableOfContent = tableOfContent.length > 0;
const { frontmatter: guideFrontmatter, author } = questionGroup;
const { data: guideFrontmatter, author } = questionGroup;
---
<article class='lg:grid lg:max-w-full lg:grid-cols-[1fr_minmax(0,700px)_1fr]'>
@@ -86,20 +80,20 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
author && (
<p class='my-0 flex items-center justify-start text-sm text-gray-400'>
<a
href={`/authors/${author?.id}`}
href={`/authors/${author?.slug}`}
class='inline-flex items-center font-medium underline-offset-2 hover:text-gray-600 hover:underline'
>
<img
alt={author.frontmatter.name}
src={author.frontmatter.imageUrl}
alt={author.data.name}
src={author.data.imageUrl}
class='mb-0 mr-2 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.name}
{author.data.name}
</a>
<span class='mx-2 hidden sm:inline'>&middot;</span>
<a
class='hidden underline-offset-2 hover:text-gray-600 sm:inline'
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/question-groups/${questionGroup.id}`}
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/question-groups/${questionGroup.slug}`}
target='_blank'
>
Improve this Guide
@@ -107,7 +101,7 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
</p>
)
}
<questionGroup.Content />
<Content />
<h2 id='test-with-flashcards'>Test yourself with Flashcards</h2>
<p>
@@ -116,7 +110,7 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
</p>
<div class='mx-0 sm:-mb-32'>
<QuestionsList
groupId={questionGroup.id}
groupId={questionGroup.slug}
questions={questionGroup.questions}
client:load
/>
@@ -136,8 +130,8 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
</h3>
{questionGroup.questions
.filter((q) => {
return q.topics
.map((t) => t.toLowerCase())
return q?.topics
?.map((t) => t.toLowerCase())
.includes(questionLevel);
})
.map((q) => (

View File

@@ -0,0 +1,70 @@
import {
BadgeCheck,
HeartHandshake,
Telescope,
type LucideIcon,
} from 'lucide-react';
import type { ReactNode } from 'react';
import { cn } from '../lib/classname';
type RoadmapAlertProps = {
title: string;
badgeText?: string;
description: string | ReactNode;
floatingIcon: LucideIcon;
className?: string;
};
export function RoadmapAlert(props: RoadmapAlertProps) {
const {
title,
badgeText,
description,
floatingIcon: FloatingIcon,
className,
} = props;
return (
<div
className={cn(
'relative mb-3 w-full rounded-xl bg-yellow-100 px-4 py-3 text-yellow-800',
className,
)}
>
<h2 className="flex items-center text-base font-semibold text-yellow-800 sm:text-lg">
{title}{' '}
{badgeText && (
<span className="ml-1.5 rounded-md border border-yellow-500 bg-yellow-200 px-1.5 text-xs uppercase tracking-wide text-yellow-800">
{badgeText}
</span>
)}
</h2>
<p className="mb-2 mt-1 text-balance">{description}</p>
<p className="mb-1.5 mt-2 flex flex-col gap-2 text-sm md:flex-row">
<a
href="/roadmaps"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 bg-yellow-200 px-2 py-1 text-yellow-800 transition-colors hover:bg-yellow-300"
>
<BadgeCheck size={15} />
Visit Official Roadmaps
</a>
<a
href="/community"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 px-2 py-1 text-yellow-700 transition-colors hover:bg-yellow-300 hover:text-yellow-800"
>
<HeartHandshake size={15} />
Community Roadmaps
</a>
<a
href="/ai/explore"
className="flex items-center gap-1.5 rounded-md border border-yellow-600 px-2 py-1 text-yellow-700 transition-colors hover:bg-yellow-300 hover:text-yellow-800"
>
<Telescope size={15} />
AI Generated Roadmaps
</a>
</p>
<FloatingIcon className="pointer-events-none absolute right-2 top-2 hidden h-12 w-12 text-yellow-500 opacity-50 sm:block md:bottom-2 md:top-auto" />
</div>
);
}

View File

@@ -0,0 +1,31 @@
import { useIsMounted } from '../../hooks/use-is-mounted';
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
import type { GroupType } from './RoadmapsPage';
type RoadmapCardProps = {
roadmap: GroupType['roadmaps'][number];
};
export function RoadmapCard(props: RoadmapCardProps) {
const { roadmap } = props;
const isMounted = useIsMounted();
return (
<a
key={roadmap.link}
className="relative rounded-md border bg-white px-3 py-2 text-left text-sm shadow-sm transition-all hover:border-gray-300 hover:bg-gray-50"
href={roadmap.link}
>
{roadmap.title}
{isMounted && (
<MarkFavorite
resourceId={roadmap.link.split('/').pop()!}
resourceType="roadmap"
className="data-[is-favorite=true]:opacity-35"
/>
)}
</a>
);
}

View File

@@ -8,6 +8,10 @@ import {
getUrlParams,
setUrlParams,
} from '../../lib/browser.ts';
import { RoadmapCard } from './RoadmapCard.tsx';
import { httpGet } from '../../lib/http.ts';
import type { UserProgressResponse } from '../HeroSection/FavoriteRoadmaps.tsx';
import { isLoggedIn } from '../../lib/jwt.ts';
const groupNames = [
'Absolute Beginners',
@@ -27,7 +31,7 @@ const groupNames = [
type AllowGroupNames = (typeof groupNames)[number];
type GroupType = {
export type GroupType = {
group: AllowGroupNames;
roadmaps: {
title: string;
@@ -281,6 +285,12 @@ const groups: GroupType[] = [
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Redis',
link: '/redis',
type: 'skill',
otherGroups: ['Web Development'],
},
],
},
{
@@ -473,6 +483,37 @@ export function RoadmapsPage() {
]);
}, [activeGroup]);
async function loadProgress() {
const { response: progressList, error } =
await httpGet<UserProgressResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-hero-roadmaps`,
);
if (error || !progressList) {
return;
}
progressList?.forEach((progress) => {
window.dispatchEvent(
new CustomEvent('mark-favorite', {
detail: {
resourceId: progress.resourceId,
resourceType: progress.resourceType,
isFavorite: progress.isFavorite,
},
}),
);
});
}
useEffect(() => {
if (!isLoggedIn()) {
return;
}
loadProgress().finally(() => {});
}, []);
useEffect(() => {
const { g } = getUrlParams() as { g: AllowGroupNames };
if (!g) {
@@ -547,13 +588,7 @@ export function RoadmapsPage() {
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 md:grid-cols-3">
{group.roadmaps.map((roadmap) => (
<a
key={roadmap.link}
className="rounded-md border bg-white px-3 py-2 text-left text-sm shadow-sm transition-all hover:border-gray-300 hover:bg-gray-50"
href={roadmap.link}
>
{roadmap.title}
</a>
<RoadmapCard roadmap={roadmap} key={roadmap.link} />
))}
</div>
</div>

View File

@@ -87,15 +87,13 @@ export function ProfileUsername(props: ProfileUsernameProps) {
{currentUsername !== username && username && isUnique && (
<span className="text-xs text-green-600">
URL after update{' '}
<a
href={`${import.meta.env.DEV ? 'http://localhost:3000' : 'https://roadmap.sh'}/u/${username}`}
target="_blank"
<span
className={
'ml-0.5 rounded-md border border-purple-500 px-1.5 py-0.5 text-xs font-medium text-purple-700 transition-colors hover:bg-purple-500 hover:text-white'
'ml-0.5 rounded-md border border-purple-500 px-1.5 py-0.5 text-xs font-medium text-purple-700 transition-colors'
}
>
roadmap.sh/u/{username}
</a>
</span>
</span>
)}
</span>

View File

@@ -71,6 +71,7 @@ export function UpdatePublicProfileForm() {
const [profileRoadmaps, setProfileRoadmaps] = useState<RoadmapType[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isProfileUpdated, setIsProfileUpdated] = useState(false);
const { isCopied, copyText } = useCopyText();
@@ -109,6 +110,7 @@ export function UpdatePublicProfileForm() {
await loadProfileSettings();
toast.success('Profile updated successfully');
setIsProfileUpdated(true);
};
const loadProfileSettings = async () => {
@@ -593,6 +595,42 @@ export function UpdatePublicProfileForm() {
>
{isLoading ? 'Please wait..' : 'Save Profile'}
</button>
{isProfileUpdated && publicProfileUrl && (
<div className="flex items-center gap-2">
<button
type="button"
className={cn(
'flex shrink-0 flex-row items-center gap-1 rounded-lg border border-black py-1.5 pl-2.5 pr-3.5 text-xs uppercase text-black transition-colors hover:bg-black hover:text-white',
isCopied
? 'border-green-600 bg-green-600 text-white hover:bg-green-600 hover:text-white'
: '',
)}
onClick={() => {
copyText(`${window.location.origin}${publicProfileUrl}`);
}}
>
{isCopied ? (
<>
<CheckCircle className="size-4" />
Copied Profile URL
</>
) : (
<>
<Copy className="size-4" />
Copy Profile URL
</>
)}
</button>
<a
className='flex shrink-0 flex-row items-center gap-1 rounded-lg border border-black py-1.5 pl-2.5 pr-3.5 text-xs uppercase text-black transition-colors hover:bg-black hover:text-white'
href={publicProfileUrl}
target="_blank"
>
<ArrowUpRight className="size-4" />
View Profile
</a>
</div>
)}
</form>
</div>
);

View File

@@ -3,6 +3,7 @@ import {
Globe,
LinkedinIcon,
Mail,
Pencil,
Twitter,
} from 'lucide-react';
import type { GetPublicProfileResponse } from '../../api/user';
@@ -15,11 +16,12 @@ type UserPublicProfileHeaderProps = {
export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
const { userDetails } = props;
const { name, links, publicConfig, avatar, email } = userDetails;
const { name, links, publicConfig, avatar, email, isOwnProfile } =
userDetails;
const { headline, isAvailableForHire, isEmailVisible } = publicConfig!;
return (
<div className="container flex items-center gap-6 rounded-xl border bg-white p-8">
<div className="container relative flex items-center gap-6 rounded-xl border bg-white p-8">
<img
src={
avatar
@@ -27,7 +29,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 object-cover"
/>
<div>
@@ -51,6 +53,16 @@ export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
{isEmailVisible && <UserLink href={`mailto:${email}`} icon={Mail} />}
</div>
</div>
{isOwnProfile && (
<a
href="/account/update-profile"
className="absolute right-4 top-4 flex items-center gap-1.5 text-sm text-gray-500 hover:text-black"
>
<Pencil className="h-3 w-3 stroke-2" />
Edit Profile
</a>
)}
</div>
);
}

View File

@@ -38,6 +38,10 @@ export function UserPublicProjects(props: UserPublicProjectsProps) {
return 0;
}) || [];
if (!enrichedProjects.length) {
return null;
}
return (
<div className="mt-5">
<h2 className="mb-2 text-xs uppercase tracking-wide text-gray-400">

View File

@@ -1,13 +1,12 @@
---
import type { VideoFileType } from '../lib/video';
import YouTubeAlert from './YouTubeAlert.astro';
export interface Props {
video: VideoFileType;
}
const { video } = Astro.props;
const { frontmatter, author } = video;
const { data: frontmatter, author } = video;
---
<div class='border-b bg-white py-5 sm:py-12'>
@@ -16,15 +15,15 @@ const { frontmatter, author } = video;
class='hidden items-center justify-start text-gray-400 sm:flex sm:justify-center'
>
<a
href={`/authors/${author.id}`}
href={`/authors/${author.slug}`}
class='inline-flex items-center font-medium hover:text-gray-600 hover:underline'
>
<img
alt={author.frontmatter.name}
src={author.frontmatter.imageUrl}
alt={author.data.name}
src={author.data.imageUrl}
class='mr-2 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.name}
{author.data.name}
</a>
<span class='mx-1.5'>&middot;</span>
<span class='capitalize'>Illustrated Video</span>

View File

@@ -6,21 +6,21 @@ export interface Props {
}
const { video } = Astro.props;
const { frontmatter, id } = video;
const { data: frontmatter, slug: id } = video;
---
<a
class:list={[
'block no-underline py-2 group text-md items-center text-gray-600 hover:text-blue-600 flex justify-between border-b',
'text-md group block flex items-center justify-between border-b py-2 text-gray-600 no-underline hover:text-blue-600',
]}
href={`/videos/${id}`}
>
<span class='group-hover:translate-x-2 transition-transform'>
<span class='transition-transform group-hover:translate-x-2'>
{frontmatter.title}
{
frontmatter.isNew && (
<span class='bg-green-300 text-green-900 text-xs font-medium px-1.5 py-0.5 rounded-sm uppercase ml-1.5'>
<span class='ml-1.5 rounded-sm bg-green-300 px-1.5 py-0.5 text-xs font-medium uppercase text-green-900'>
New
<span class='hidden sm:inline'>
&middot;
@@ -32,9 +32,9 @@ const { frontmatter, id } = video;
)
}
</span>
<span class='capitalize text-gray-500 text-xs hidden sm:block'>
<span class='hidden text-xs capitalize text-gray-500 sm:block'>
{frontmatter.duration}
</span>
<span class='text-gray-400 text-xs block sm:hidden'> &raquo;</span>
<span class='block text-xs text-gray-400 sm:hidden'> &raquo;</span>
</a>

23
src/content/author.ts Normal file
View File

@@ -0,0 +1,23 @@
import { defineCollection, z } from 'astro:content';
export const authorCollection = defineCollection({
type: 'content',
schema: z.object({
name: z.string(),
imageUrl: z.string(),
employment: z
.object({
title: z.string(),
company: z.string(),
})
.optional(),
social: z
.object({
linkedin: z.string().optional(),
twitter: z.string().optional(),
github: z.string().optional(),
website: z.string().optional(),
})
.optional(),
}),
});

16
src/content/changelog.ts Normal file
View File

@@ -0,0 +1,16 @@
import { defineCollection, z } from 'astro:content';
export const changelogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
seo: z
.object({
title: z.string(),
description: z.string().optional(),
})
.optional(),
date: z.date(),
}),
});

View File

@@ -0,0 +1,25 @@
---
title: 'New Dashboard, Leaderboards and Projects'
description: 'New leaderboard page showing the most active users'
seo:
title: 'Leaderboard Page - roadmap.sh'
description: ''
date: 2024-09-13
---
TL;DR: new dashboard, leaderboard page and projects page.
- New dashboard for logged-in users
- New leaderboard page
- Projects page listing all projects
- Ability to stop a started project
- Frontend and backend content improvements
- Bug fixes
![Leaderboard Page](https://assets.roadmap.sh/guest/personal-dashboard.png)
We just launched a dedicated dashboard for logged-in users to showing progress, projects, bookmarks and more. You can still access the old homepage by visiting [this page](https://roadmap.sh/home).
We also launched a new [leaderboard page](/leaderboard) showing the most active users, users who completed most projects and more.
There is also a [new projects page](/projects) where you can see all the projects you have been working on. You can also now stop a started project.

View File

@@ -0,0 +1,12 @@
---
title: 'New Dashboard Page'
description: 'We have added a new dashboard page to help you track your progress'
seo:
title: 'New Dashboard Page - roadmap.sh'
description: 'We have added a new dashboard page to help you track your progress'
date: 2024-09-12
---
We have revamped the dashboard page for logged-in users. The new dashboard page will help you track your progress and see your overall progress in a single view. We have also added a new progress bar to help you visualize your progress.
If you want to access the guest homepage, you check check it out [here](/home).

15
src/content/config.ts Normal file
View File

@@ -0,0 +1,15 @@
import { authorCollection } from './author';
import { changelogCollection } from './changelog';
import { guideCollection } from './guide';
import { projectCollection } from './project';
import { questionGroupCollection } from './question-group';
import { videoCollection } from './video';
export const collections = {
authors: authorCollection,
guides: guideCollection,
'question-groups': questionGroupCollection,
projects: projectCollection,
videos: videoCollection,
changelogs: changelogCollection,
};

25
src/content/guide.ts Normal file
View File

@@ -0,0 +1,25 @@
import { defineCollection, z } from 'astro:content';
export const guideCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
authorId: z.string(),
canonicalUrl: z.string().optional(),
excludedBySlug: z.string().optional(),
seo: z.object({
title: z.string(),
description: z.string(),
ogImageUrl: z.string().optional(),
}),
isNew: z.boolean(),
type: z.enum(['visual', 'textual']),
date: z.date(),
sitemap: z.object({
priority: z.number(),
changefreq: z.enum(['daily', 'weekly', 'monthly', 'yearly']),
}),
tags: z.array(z.string()).optional(),
}),
});

View File

@@ -1,5 +1,5 @@
---
title: 'What is a DevOps Engineer? Responsbilities & Roles in @currentYear@'
title: 'What is a DevOps Engineer? Responsibilities & Roles in @currentYear@'
description: 'Explore the responsibilities and roles of a DevOps Engineer in @currentYear@. Gain insights into the evolving field of DevOps and what it takes to succeed.'
authorId: ekene
excludedBySlug: '/devops/devops-engineer'
@@ -21,13 +21,13 @@ tags:
![What is a DevOps engineer and what are their responsibilities?](https://assets.roadmap.sh/guest/what-is-devops-engineer-jort4.jpg)
Are you a developer monitoring recent changes in the ecosystem, looking to change careers or pick up new skills in 2024? If your choice is DevOps, you might be wondering what it entails, what it will take to become one in 2024, and how it is affected by the recent changes in the tech ecosystem.
Are you a developer monitoring recent changes in the ecosystem, looking to change careers or pick up new skills in 2024? If your choice is [DevOps](https://roadmap.sh/devops), you might be wondering what it entails, what it will take to become one in 2024, and how it is affected by the recent changes in the tech ecosystem.
In recent years, the technology ecosystem has experienced a constant shift in the way hiring managers reach out, companies hire, and the roles and responsibilities described in job postings. Particularly, 2023 proved to be a challenging year as layoffs in the technology sector grew significantly, with more than [262,000 employees laid off across 1,180 firms](https://www.statista.com/statistics/199999/worldwide-tech-layoffs-covid-19/).
Despite this change, DevOps, a field within the same ecosystem, has experienced continuous growth. In fact, the DevOps market size is expected to grow to [25.5 billion USD by 2028](https://www.marketsandmarkets.com/Market-Reports/devops-market-824.html#:~:text=The%20global%20DevOps%20market%20size,USD%2010.4%20billion%20in%202023.). This indicates that the roles and responsibilities of a DevOps engineer in the modern technology environment will evolve alongside this increasing demand.
In this guide, we'll discuss the roles and responsibilities of a [DevOps engineer](https://roadmap.sh/devops), the importance of DevOps in teams, common roles within a DevOps team, and best practices for DevOps teams. Finally, the guide will offer roadmaps for your DevOps journey.
In this guide, we'll discuss the roles and responsibilities of a DevOps engineer, the importance of DevOps in teams, common roles within a DevOps team, and best practices for DevOps teams. Finally, the guide will offer roadmaps for your DevOps journey.
A DevOps engineer's roles and responsibilities include:

Some files were not shown because too many files have changed in this diff Show More