Compare commits

...

712 Commits

Author SHA1 Message Date
Arik Chakma
68c944f777 fix: showcase roadmap index 2024-07-30 17:07:32 +06:00
Kamran Ahmed
bff7c4203a Fix community page URL 2024-07-30 11:39:18 +01:00
Kamran Ahmed
55b5639541 Fix community page URL 2024-07-30 11:36:10 +01:00
Arik Chakma
9c3539eb3a feat: implement discover custom roadmaps (#6162)
* feat: implement discover custom roadmaps

* feat: add error page

* wip: roadmap ratings

* wip

* feat: implement rating

* refactor: roadmap discover page

* Update UI

* fix: search

* fix: search query

* Update UI for the discover page

* Refactor rating logic

* Button changes on the custom roadmap page

* Refactor feedback modal

* Hide rating from custom roadmaps which are not discoverable

* feat: rating feedback pagination

* fix: remove per page

* Update ratings

* fix: button height

* Update UI for the discover page

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-30 11:26:19 +01:00
dsh
283a88e719 Update all PostgreSQL roadmap content (#6241)
* update all postgresql roadmap content

* added half the links

* complete all link adding

* Update src/data/roadmaps/postgresql-dba/content/awk@HJCRntic0aGVvdmCN45aP.md
2024-07-29 22:12:48 +01:00
Pranjal Pratap Singh
3f4a256e94 Update JavaScript Datatype -- Number (#6275)
Added Definition and Easy to Understand Examples for DataType Number.
2024-07-30 00:04:40 +06:00
fellalli
1019addbcd Fix links in roadmaps (#6270) 2024-07-29 15:21:55 +01:00
Samaila Chatto Bashir
dcb8df908d added description and resources for null in javascript (#6242) 2024-07-29 10:06:04 +01:00
JesusG16
8da3fb7220 Update 109-event-sourcing.md (#6250)
The youtube video for event sourcing is no longer available, I added an alternative.
2024-07-29 10:03:21 +01:00
André Oliveira
b4111cefca Update dnssec.md (#6251)
Update various topics with new links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-29 10:02:38 +01:00
Ganesh Hegde
e46f24e4e2 add resource for hono (#6253) 2024-07-29 09:57:45 +01:00
Satyam Vyas
5b723198be Improved usecontext@D5_O-uElftYGQr_bTU_se.md (#6257)
* Improved usecontext@D5_O-uElftYGQr_bTU_se.md

- Rectified bullet point structure (earlier erroneous)
- Added a video tutorial for the same

* Update src/data/roadmaps/react/content/usecontext@D5_O-uElftYGQr_bTU_se.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-29 09:55:03 +01:00
Satyam Vyas
a1996b6fb8 Update shadcn-ui@njKsYNkwTXPQ1NjlGKXab.md (#6258)
`Added resources for Shadcn`
- Added links to the website and official documentation
- Added video tutorial 
- Added a guide explaining the use cases of the framework
2024-07-29 09:54:13 +01:00
Beryl Atieno
24533cc887 update Go types and type assertions (#6260)
* update Go types and type assertions

* Update src/data/roadmaps/golang/content/101-go-advanced/102-types-and-type-assertions.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-29 09:53:04 +01:00
André Oliveira
82ba5898a7 Update comptia resources(#6249)
* Update dns.md - Fix the YouTube video link error and update the video title.

* Update understand-cia-triad.md

* Update comptia-security.md

- Fix all broken links.
- Update Exam Details.
- Add new links.
- Remove outdated links.

* Update comptia-network.md

- Update Exam Details.
- Preparation Resources.
- New links.
2024-07-27 01:11:47 +01:00
nufuk
7dd8dfc70f Fix invalid links in blockchain roadmap (#6246)
Fixed broken links for "Visit the following relevant roadmaps". Backend redirected to javascript and Rust redirected to python.
2024-07-26 22:02:13 +01:00
Kamran Ahmed
c186289cde Update link in Node.js roadmap 2024-07-26 21:58:35 +01:00
Enguang Cai
81aa63c098 Adding resource links to SwiftUI (#6240)
* adding contents to swiftui data binding

* adding contents to swiftui - views and modifiers

* adding contents to swiftui - state management

* adding contents to swiftui - navigation

* correcting typo in state management
2024-07-26 21:51:25 +01:00
Kamran Ahmed
4dc4bfb9ee Redraw nodejs roadmap using our editor 2024-07-26 21:42:09 +01:00
Jim Bennett
a0c49edc80 Update introduction-to-angular@KDd40JOAvZ8O1mfhTYB3K.md (#6245)
Adding a description to the angular introduction with a link to the core angular website. This was generated live on a stream using Pieces for developers!
2024-07-26 18:18:35 +01:00
Kamran Ahmed
8206a3594a Update resource content 2024-07-26 12:53:19 +01:00
Satyam Vyas
49472a20c9 Updated useref@t_laNdMmdLApYszqXRdWg.md (#6239)
* Update useref@t_laNdMmdLApYszqXRdWg.md

Added useRef documentation for React Developer Roadmap on roadmap.sh

* Update src/data/roadmaps/react/content/useref@t_laNdMmdLApYszqXRdWg.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-26 09:11:14 +01:00
Benny Neugebauer
62598ec5cd Describe how TypeScript checks JavaScript files (#6238) 2024-07-26 09:10:02 +01:00
Glen Miracle
068a896caf Update Detailed Explanation for useCallback Hook in React Documentation usecallback@2zrN65JZhCyNimi33g78f.md (#6237)
* Update usecallback@2zrN65JZhCyNimi33g78f.md

this is an update for the useCallback explanation on roadmap.sh

* Update src/data/roadmaps/react/content/usecallback@2zrN65JZhCyNimi33g78f.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-26 09:07:59 +01:00
André Oliveira
331c45446c Update cybersecurity roadmap links (#6236)
* Update dns.md - Fix the YouTube video link error and update the video title.

* Update understand-cia-triad.md

* Update comptia-security.md

- Fix all broken links.
- Update Exam Details.
- Add new links.
- Remove outdated links.
2024-07-25 22:41:26 +01:00
Darlin Daniel Arias M.
5df2572f02 Update react releated roadmaps Frontend Roadmap data-link (#6233) 2024-07-25 18:08:53 +01:00
dsh
91be286f8e Update devops vs sre guide (#6232) 2024-07-25 17:12:12 +01:00
Kamran Ahmed
e114c2f246 Update related roadmaps 2024-07-25 16:58:39 +01:00
magjogui
4821f9ff6d Fix typo (#6230)
It just a letter, but whenever you are learning, one letter can make the difference... I hope I will start contributing more and more to the project.

The typo was proxmax and not proxmox...

src: src/data/roadmaps/cyber-security/content/proxmax@jqX1A5hFF3Qznqup4lfiF.md
2024-07-25 16:35:29 +01:00
Kamran Ahmed
5f9c3f2813 Fix file name 2024-07-25 16:35:16 +01:00
dsh
2787620c5a update fs-vs-swe guide (#6228) 2024-07-25 16:31:40 +01:00
Kamran Ahmed
714263c184 Redraw angular roadmap using our editor 2024-07-25 16:22:47 +01:00
dsh
34423f4e83 update how to become a devops engineer guide (#6229) 2024-07-25 14:53:12 +01:00
ㅅㅡㅇㅇㅕㅂ
8e4baa02b1 Update 103-queues.md (#6224)
This is a tutorial about queues, but it was referencing a video link about stacks.
2024-07-25 09:15:06 +01:00
André Oliveira
adfdd1eabe Update dns.md (#6223)
* Update dns.md - Fix the YouTube video link error and update the video title.

* Update understand-cia-triad.md
2024-07-25 09:13:43 +01:00
fleurien
2ab437077c Fix typo data-analyst.json (#6222) 2024-07-25 09:12:39 +01:00
Gabriel Barbosa
16056db603 Update usecontext@D5_O-uElftYGQr_bTU_se.md (#6221)
* Update usecontext@D5_O-uElftYGQr_bTU_se.md

* Update usecontext@D5_O-uElftYGQr_bTU_se.md

* Update src/data/roadmaps/react/content/usecontext@D5_O-uElftYGQr_bTU_se.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-25 09:12:18 +01:00
G30RG35
0f276bf03a Update Js Roadmap Strict Equality Operator === (#6220)
* Update Js Roadmap Strict Equality Operator ===

Update @lJwcc6JoUIQoiQ6FkV2KW.md

* Update src/data/roadmaps/javascript/content/@lJwcc6JoUIQoiQ6FkV2KW.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-25 09:11:36 +01:00
Boja Sri Manu Koti Naidu
8bc81b6381 Update 100-metrics.md (#6217)
* Update 100-metrics.md

Added some extra points to the metrics, which will give a bit more knowledge on the go.

* Update src/data/roadmaps/aws/content/108-cloudwatch/100-metrics.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-25 09:08:46 +01:00
Kamran Ahmed
a8dcdf60dd Redraw JavaScript roadmap using our editor 2024-07-24 15:59:22 +01:00
Natan Yellin
539e9e1a60 Update 104-observability-engines.md (#6215) 2024-07-23 10:40:50 +01:00
dsh
380a3cd3e6 Add wadcoms, gtfobins (#6214) 2024-07-23 09:57:39 +01:00
zyadfallatah
30b60181d6 useReducer typo error fixed in the new roadmap (#6212) 2024-07-23 09:26:41 +01:00
dsh
b02a284e49 Update frontend languages guide (#6208)
* update guide and replace images

* remove whitespace
2024-07-22 21:10:33 +01:00
dsh
dd86b912c9 Update java/developer-skills guide (#6185)
* updated java/developer-skills guide

* remove whitespace
2024-07-22 21:09:47 +01:00
Kamran Ahmed
f207fdc48c Redraw Vue roadmap using our editor 2024-07-22 21:01:10 +01:00
Kamran Ahmed
5859bf5c63 Redraw react roadmap using our editor 2024-07-22 14:48:24 +01:00
Abdul Samad
f4870885cc Fix persistant search result (#6199) 2024-07-22 11:45:16 +01:00
Lilith
1cb49fc18e Minor grammar fixes to what-is-technical-writing@jl1FsQ5-WGKeFyaILNt_p.md (#6200) 2024-07-22 10:05:54 +01:00
EverSinceWWI
3a7f7a2355 Update blue-ocean-strategy@gjdCSm_jZmG_q6YjG_8Qu.md (#6206)
Added video resource
2024-07-22 09:52:47 +01:00
dsh
b4d34ba65d removed dead link (#6197) 2024-07-20 09:47:31 +01:00
Juan Gerardo Eulufi Salazar
d9c509f1eb Update 102-conditionals.md (#6196)
* Changes in copy testing pipes angular

* Add article if statements
2024-07-20 09:42:47 +01:00
dsh
8f4710d8f7 Complete iOS content (#6168)
* completed xcode, data persistence, callbacks and others

* add copy for remaining topics

* complete ios content, correct platform names
2024-07-19 20:10:25 +01:00
Eduardo Pires
4b00f300af Add content to programming languages in data analyst roadmap (#6188)
* Update learn-a-programming-lang@i2uEcaO4bJhcZ5ayRs2CQ.md

add description.

* Update src/data/roadmaps/data-analyst/content/learn-a-programming-lang@i2uEcaO4bJhcZ5ayRs2CQ.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-19 20:09:41 +01:00
Rahul Kumar
b0b01e7b83 Update content of Linux fundamentals (#6190) 2024-07-19 20:07:19 +01:00
Kamran Ahmed
c3972382af Fix duplicated content for dual process theory 2024-07-19 20:05:42 +01:00
Kamran Ahmed
9f7d902e5c Redraw computer science roadmap using our editor 2024-07-19 19:47:42 +01:00
Louis
0ac616d18e Update 101-docker-engine.md - Improving wording (#6177)
Changed wording of sentence to make more sense.
2024-07-19 09:54:37 +01:00
Kamran Ahmed
77ed07eafd Fix broken build 2024-07-18 23:27:48 +01:00
Kamran Ahmed
ba04fe112e Redraw MLOps roadmap usin gour editor 2024-07-18 23:21:17 +01:00
da-im
5a2cb3ee8d Update product-identification@fmpJB_14CYn7PVuoGZdoz.md (#6178)
Grammatical correction
2024-07-18 16:48:08 +01:00
Renan
2db553ca32 Update 103-components.md (#6179)
Update of reference links to articles. One of them was no longer working (http://makble.com/spring-mvc-components)
2024-07-18 16:47:27 +01:00
spanwalla
8f60bb58f6 Update 110-scheduler.md (#6173)
fix typo
2024-07-18 09:25:43 +01:00
Juan Gerardo Eulufi Salazar
cde6990d21 Changes in copy testing pipes angular (#6171) 2024-07-18 00:51:07 +01:00
Kamran Ahmed
45e75af774 Redraw technical writer roadmap using our editor 2024-07-18 00:30:37 +01:00
Kamran Ahmed
f05c0a36c0 Redraw technical writer roadmap using our editor 2024-07-18 00:29:39 +01:00
Kamran Ahmed
23d40e2df7 Fix missing topic on backend roadmap 2024-07-17 23:34:53 +01:00
Kiko Castro
361cc0bd4f Improve "Update writing-skills" section and add additional resources (#6170)
* Improve "Update writing-skills" section and add additional resources

* Enhanced the explanation of the importance of good writing skills for software developers
* Added three resources for further reading on effective communication and documentation

* Update src/data/roadmaps/devrel/content/writing-skills@0ntOE6PSdMl_EXB9gdgIv.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-17 23:32:54 +01:00
Martijn ten Caat
ae7bff26cc Added Hyperskill as course in Java Fundamentals (#6167)
* Added video URL on Product Management Discovery content page

* Added Hyperskill as course in Java Fundamentals
2024-07-17 14:34:47 +01:00
Martijn ten Caat
36815aa8ea Added video URL on Product Management Discovery content page (#6165) 2024-07-17 12:16:01 +01:00
Shubham Karmveer
e07a829638 Updating 100-prototype.md (#6164)
Adding a video fro understanding concept of prototype in javascript and Object prototype and Prototype Inheritance
2024-07-17 09:12:14 +01:00
Eduardo Pires
0a506b3ead Add learning resource for excel (#6163)
w3schools tutorial.
2024-07-17 00:33:49 +01:00
Eduardo Pires
fb2d007831 fix: content of trim function (#6161)
This Microsoft article talks about the features of the 'Trim' function. The function only removes the spaces: 

https://support.microsoft.com/en-us/office/trim-function-410388fa-c5df-49c6-b16c-9e5630b479f9
2024-07-17 00:32:19 +01:00
Kamran Ahmed
5cb5db0f16 Redraw server side game developer roadmap using our editor 2024-07-17 00:30:33 +01:00
Kamran Ahmed
3302c9ab3f Redraw game developer using our editor 2024-07-16 18:52:45 +01:00
Alexey Nikitchenko
e406d4121d Fix grammar in sorting algorithms articles (#6158)
* Fix grammar in 100-bubble-sort.md

* Fix grammar in 101-merge-sort.md

* Fix grammar in 103-quick-sort.md
2024-07-16 16:25:08 +01:00
dsantosmerino-wkl
918eb1dc9c Fix typo (#6157) 2024-07-16 11:08:02 +01:00
Praise Emmanuel
8809354837 Fix typo (#6155)
changed typo from Rerords -> Records
2024-07-15 23:40:53 +01:00
Kamran Ahmed
df64c0de51 Add migration for ux-design roadmap 2024-07-15 23:35:58 +01:00
Kamran Ahmed
334b17beef Redraw UX design roadmap using our editor 2024-07-15 23:35:19 +01:00
Kamran Ahmed
3e75feda6a Redraw cyber security roadmap using our editor 2024-07-15 18:10:46 +01:00
Kamran Ahmed
358a80c457 Update AI Data Scientist roadmap 2024-07-15 17:13:36 +01:00
Kamran Ahmed
37db7ebd5b Resolve merge conflicts 2024-07-15 17:09:50 +01:00
dsh
c3ca762799 Complete tf content (#6154)
* finalise tf roadmap content

* add HCP use-case content
2024-07-15 16:24:23 +01:00
alloky
bab8739405 Add ssl/tls explanation video (#6147)
* Update ssltls@0v3OsaghJEGHeXX0c5kqn.md

Very simple and newbie friendly explanation of TLS handshake

* Update src/data/roadmaps/backend/content/ssltls@0v3OsaghJEGHeXX0c5kqn.md

removed time param from link

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-15 09:59:37 +01:00
dsh
504fcd8126 correct styling of content i.e. links to the bottom (#6152) 2024-07-15 09:58:13 +01:00
dsh
3cb0d45764 fix topic not found on prometheus (#6151) 2024-07-15 09:54:59 +01:00
DMGK
75bd422ef4 Update recycleview@xIvplWfe-uDr9iHjPT1Mx.md (#6148)
* Update recycleview@xIvplWfe-uDr9iHjPT1Mx.md

* Update src/data/roadmaps/android/content/recycleview@xIvplWfe-uDr9iHjPT1Mx.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-15 09:47:46 +01:00
Kamran Ahmed
76a9d67018 Migrate progress for software architect roadmap 2024-07-14 14:08:32 +01:00
Kamran Ahmed
2fccb646b6 Migrate content for software architect roadmap 2024-07-14 14:08:04 +01:00
Kamran Ahmed
568a357b97 Redraw software architect roadmap 2024-07-14 10:56:00 +01:00
dsh
e69c53b49d updated images, added alt tags, adding client facing images. (#6140) 2024-07-13 01:48:02 +01:00
Kamran Ahmed
9a758bc069 Migrate QA roadmap to use our editor 2024-07-12 20:51:35 +01:00
Kaylum Snape
26fad32246 Update punctuation in TriggerVerifyEmail.tsx (#6138)
- Removed a duplicate full stop from text displayed to the user during verifying email flow.
2024-07-12 15:50:51 +01:00
Arik Chakma
c7ed1bd59f fix: username input (#6141) 2024-07-12 15:50:30 +01:00
dsh
f618ef0bf6 Add content and links to multiple TF topics (#6142)
* add content to modules, provisioners and workspaces

* fix style on module best practices
2024-07-12 15:25:38 +01:00
Howie Z
48b636b145 Update 101-tester-mindset.md (#6136)
Updated markdown with up to date resources
2024-07-12 09:35:42 +01:00
Torben
c8e968949e Fix small typo in devops beginner roadmap intro text (#6137)
Co-authored-by: Torben Labs <torben.labs@sportec-solutions.com>
2024-07-12 09:33:27 +01:00
Kamran Ahmed
26967da40b Migrate blockchain roadmap to our editor 2024-07-11 21:13:16 +01:00
Kamran Ahmed
7e09d54a65 Checkboxes not being marked as done 2024-07-11 12:52:31 +01:00
Konrad
0b47cfc981 style: remove whitespace characters in roadmaps resources (#6131) 2024-07-11 11:57:59 +01:00
Ed Lan
b7daa93f7c Small FAQ update (#6133) 2024-07-11 11:57:39 +01:00
Konrad
de624e1967 feat(roadmap/angular): add summary and resources about zones section (#6132) 2024-07-11 09:36:47 +01:00
Konrad
bcac605aeb fix(roadmaps/angular): guards roadmap information (#6129)
- remove deprecated `canLoad` angular guard
- change the description to use functional guards
2024-07-11 09:33:40 +01:00
Arik Chakma
f16aa78829 fix: todo uncheck (#6126) 2024-07-11 00:10:17 +01:00
dsh
1330e5c4b9 Terraform - Complete state topics (#6125)
* complete state topics

* added more content, fixed typo

* Update src/data/roadmaps/terraform/content/graph@vAFFgKSthyj_3Lxt-Z6pg.md

add graphviz
2024-07-10 23:44:25 +01:00
Ruslan Semagin
a4b0a72c37 add links to 'ring' in Rust Cryptography (#6120) 2024-07-10 09:11:03 +01:00
Jhonatan Mustiola
680b2241e8 Fix link labels (#6122)
* Fix link labels

* Update src/data/roadmaps/rust/content/101-language-basics/103-data-structures/113-queue.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-10 09:10:04 +01:00
Kamran Ahmed
b48f81d98d Migrate PostgreSQL roadmap to our editor 2024-07-09 23:04:51 +01:00
Konrad
f179033dd3 feat(roadmap/angular): update rxjs transformation section (#6119)
- remove deprecated flatMap operator (Renamed to mergeMap. Will be removed in v8)
- add exhaustMap
- add video for Higher-Order RxJs Mapping Operators
- sort operators by complexity
- change the type of some resources to the **official** category
2024-07-09 16:04:28 +01:00
dsh
853c228623 fix duplicate title on 8 fs dev skills guide (#6117) 2024-07-09 14:13:12 +01:00
dsh
cebb561afe Add swiftui, uikit & reactive programming content (#6114) 2024-07-09 13:09:53 +01:00
dsh
d1a698447d add output, deployment and clean up content (#6115)
* add output, deployment and clean up content

* Update src/data/roadmaps/terraform/content/deployment@pjmOK1MEMnIV_zAlaOF01.md

add period

* Apply suggestions from code review

Committed suggested changes.

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-09 13:09:34 +01:00
Kamran Ahmed
830aae4d9c Add missing topic files 2024-07-09 13:08:52 +01:00
Kamran Ahmed
f1a34b3997 Fix alignment on iOS roadmap 2024-07-09 13:08:52 +01:00
Alan Klimowski
92b519396d FIx links for sql vs nosql (#6113) 2024-07-09 09:05:29 +01:00
Brandon Gregori
e04712aa2d Add description and links relating to Netlify Functions in DevOps roadmap (#6108)
* Update netlify@hCKODV2b_l2uPit0YeP1M.md

Add description and links relating to Netlify Functions

* Update src/data/roadmaps/devops/content/netlify@hCKODV2b_l2uPit0YeP1M.md

added more to the copy.

* Update src/data/roadmaps/devops/content/netlify@hCKODV2b_l2uPit0YeP1M.md

changed tag from article to official

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-09 09:04:17 +01:00
Jhonatan Mustiola
7ac388e51c Add resources for rust (#6109)
* Update 109-hashset.md

More links were added

* Update src/data/roadmaps/rust/content/101-language-basics/103-data-structures/109-hashset.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-09 01:46:49 +01:00
Kamran Ahmed
9ddda3a255 Migrate ai and data scientist roadmap 2024-07-09 01:45:05 +01:00
Carlos Martinho
64e2e43b82 Adding info about CouchDB (#6111)
* Add info about CouchDB

* Update mongodb top posts typo

* adjust content style

* adjust content style

* Update src/data/roadmaps/backend/content/mongodb@28U6q_X-NTYf7OSKHjoWH.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-09 00:38:53 +01:00
Bit
6ec8d2a29b Fixed markdown typo (#6112) 2024-07-09 00:35:53 +01:00
Kamran Ahmed
9ec6541ad7 Fix broken UI in fullstack roadmap 2024-07-08 19:44:21 +01:00
github-actions[bot]
c190bdb6b2 chore: update dependencies to latest (#5974)
Co-authored-by: kamranahmedse <kamranahmedse@users.noreply.github.com>
2024-07-08 19:19:08 +01:00
dsh
f016fdbb72 Add introduction content for DevRel roadmap (#6062)
* completed the introduction section content

* \Update src/data/roadmaps/devrel/content/what-is-devrel@SiYUdtYMDImRPmV2_XPkH.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-08 19:18:49 +01:00
Arik Chakma
10a5268a9f fix: checkbox right click (#6103)
* fix: checkbox right click

* fix: checkbox right click

* fix: remove check

* fix: topic id
2024-07-08 19:18:04 +01:00
dsh
f08c7d5052 fix incorrect Id on SOAP api (#6107) 2024-07-08 19:15:18 +01:00
Kamran Ahmed
41109ecd90 Update full-stack roadmap alignment 2024-07-08 19:12:13 +01:00
Kamran Ahmed
fa3a3adc65 Redraw product manager roadmap 2024-07-08 19:02:46 +01:00
dsh
f4c2616b88 Add 12 in demand FE skills guide (#6029)
* add 12 in demand FE skills guide

* rename to frontend-developer-skills.md

* rename to frontend-developer-skills.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-07-08 16:11:38 +01:00
dsh
dadaa18687 Add full stack dev skill guide (#6101)
* partially complete guide staging

* complete full-stack developer skills guide
2024-07-08 16:10:53 +01:00
dsh
3c065338db fixed file name issue and added content to 2-3 trees (#6100) 2024-07-08 14:11:36 +01:00
dsh
cd057508cb correct file name for solr (#6099) 2024-07-08 13:58:51 +01:00
Kamran Ahmed
366bd61562 Fix content file not found 2024-07-08 12:26:52 +01:00
Arik Chakma
9154a57eb9 feat: implement todo and resource button (#6055)
* feat: implement todo and resource button

* feat: add hover color
2024-07-08 12:03:58 +01:00
Martins Gouveia
24f9e0c6ce Update healthkit@Jsu5f6QASpuvpky_W5q-O.md (#6097) 2024-07-08 11:53:13 +01:00
Abdallah Gaber
8b82746676 Adding console.* and more recources to 106-nodejs-command-line-apps (#6098)
* Adding console.* and more recources to 106-nodejs-command-line-apps

* Update src/data/roadmaps/nodejs/content/106-nodejs-command-line-apps/101-printing-output/index.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-08 11:24:59 +01:00
dsh
d09962b6a3 Update topic titles (#6096) 2024-07-08 10:58:35 +01:00
Maria
df3dfe9971 updating swiftlint content (#6073)
* updating swiftlint content

* making code review changes

adding standard line and removing installation instructions

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

* Update src/data/roadmaps/ios/content/swiftlint@NnTC3R8goZQTXHmfHKHbM.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-08 10:14:16 +01:00
Abdallah Gaber
ec175482bd Updates on 106-nodejs-command-line-apps (#6087)
* updates on 106-nodejs-command-line-apps

* Apply suggestions from code review

Slight style and guideline editting

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-08 10:12:10 +01:00
Damar
5aa67c2e2b Fix typo in final paragraph (#6093) 2024-07-08 10:05:01 +01:00
garvit3835
22290ae0b7 Update terraform-validate@wdYLjB-tKg76B7YcnhevQ.md (#6095)
* Update terraform-validate@wdYLjB-tKg76B7YcnhevQ.md

* Update src/data/roadmaps/terraform/content/terraform-validate@wdYLjB-tKg76B7YcnhevQ.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-08 09:59:45 +01:00
Konrad
a8f68371f0 feat(roadmap/angular): add more resources about angular routing (#6089) 2024-07-08 00:15:01 +01:00
Chad Davis
0da2cab0ab Fix capitalization (#6082)
* Replace VCS Hosting with Repo Hosting Services

* Fix capitalization on Repo Hosting Services and GitHub

* Replace VCS Hosting with Repo Hosting Services and fix capitalization on Bitbucket

* Fix capitalization on Bitbucket

* Fix capitalization on Bitbucket

* Fix capitalization on Bitbucket

* Fixed spelling mistake

Changed "None English content." to "Non-English content."
2024-07-07 18:18:52 +01:00
Konrad
bab0ec0a5d fix(roadmap/angular): remove outdated article about angular forms (#6088)
removed link to article was about angularjs version
2024-07-07 14:35:35 +01:00
Karim Safan
36b42dfaa2 Update 102-loops.md (#6071)
bug in the code
2024-07-07 14:02:50 +01:00
dsh
6cd18458db add iOS copy and links (#6059) 2024-07-05 15:57:09 +01:00
Kamran Ahmed
93eb568bbd Migrate android roadmap to new format 2024-07-05 15:47:03 +01:00
Kamran Ahmed
3997641d0b Add android content 2024-07-05 15:47:03 +01:00
Martins Gouveia
3fda008f12 Update arkit@k3uHcF0CsyHr6PK95UwR1.md (#6061)
Add content and resources to Arkit section

- Updated content about ARKit framework
- Included additional links to oficial documentation
2024-07-05 13:39:08 +01:00
Nikhil
7f1f58516e DSA | Updated 105, Sorting Algorithm links (#6063)
* DSA | Updated 105, Sorting Algorithm links

* Update src/data/roadmaps/datastructures-and-algorithms/content/105-sorting-algorithms/101-merge-sort.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 13:31:23 +01:00
Ruslan Semagin
afb0da4bd6 link to article 'How to write documentation' in 'Rust' (#6058) 2024-07-05 09:49:40 +01:00
mrgsdev
485b3d5c9a Update hig@1I5eFKqFVBxWLAXfpgNXO.md (#6032)
* Update hig@1I5eFKqFVBxWLAXfpgNXO.md

This commit includes to the Human Interface Guidelines (HIG) documentation.

* Update src/data/roadmaps/ios/content/hig@1I5eFKqFVBxWLAXfpgNXO.md

style fix

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:31:35 +01:00
mrgsdev
78e20d1e85 Update iboutlets@tuUuLInq0p-nhehe2AqPg.md (#6035)
* Update iboutlets@tuUuLInq0p-nhehe2AqPg.md

* Update src/data/roadmaps/ios/content/iboutlets@tuUuLInq0p-nhehe2AqPg.md

fix style

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:29:45 +01:00
mrgsdev
e7cd703607 Update storyboards@a2CqrCJSxGfHq6_Y9f_re.md (#6036)
* Update storyboards@a2CqrCJSxGfHq6_Y9f_re.md

* Update src/data/roadmaps/ios/content/storyboards@a2CqrCJSxGfHq6_Y9f_re.md

fix styling

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:29:03 +01:00
mrgsdev
01c78a8cf4 Update auto-layout@j2BL0sf3WjnJZZWa7cCjy.md (#6037)
* Update auto-layout@j2BL0sf3WjnJZZWa7cCjy.md

* Update src/data/roadmaps/ios/content/auto-layout@j2BL0sf3WjnJZZWa7cCjy.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:28:04 +01:00
mrgsdev
cc123f74ea Update lottie@i-T6GTqS0FZ_Llt5v4SvR.md (#6038) 2024-07-05 08:26:09 +01:00
mrgsdev
fed5f722b9 Update mvc@a-QDI7Ei-B5BRHbicFcfG.md (#6039) 2024-07-05 08:25:16 +01:00
mrgsdev
cb4b5a4cc9 Update navigation-view@IBr2P7dknWTnZ2a-fFCqN.md (#6040) 2024-07-05 08:24:24 +01:00
mrgsdev
38be5892d3 Update navigation-stacks@TLm70PlTI0K3Odn1iYxWX.md (#6041)
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:23:11 +01:00
mrgsdev
24b47d3dd7 Update uikit@-7OW2IgiMk1eot1PaYd7m.md (#6042)
* Update uikit@-7OW2IgiMk1eot1PaYd7m.md

* Update src/data/roadmaps/ios/content/uikit@-7OW2IgiMk1eot1PaYd7m.md

adding content from my draft PR

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:22:09 +01:00
mrgsdev
783e2400b7 Update navigation@FXUrfyvuIIOH7VDnT_E0z.md (#6043) 2024-07-05 08:20:23 +01:00
mrgsdev
c9390d8612 Update core-data@H4-Dp2WTA6HAZiFRQdLjx.md (#6044)
* Update core-data@H4-Dp2WTA6HAZiFRQdLjx.md

* Update src/data/roadmaps/ios/content/core-data@H4-Dp2WTA6HAZiFRQdLjx.md

swapped to a video as the course wasn't free/was behind a login.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:19:18 +01:00
mrgsdev
0cad5890ea Update swift-package-manager@KFkX8_Hv9SCFeCtZMZIQM.md (#6045)
* Update swift-package-manager@KFkX8_Hv9SCFeCtZMZIQM.md

* Update src/data/roadmaps/ios/content/swift-package-manager@KFkX8_Hv9SCFeCtZMZIQM.md

add spacing

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:17:15 +01:00
mrgsdev
f2297389a7 Update cocoapods@epr1sOEZIAOwlgb8bre7r.md (#6046) 2024-07-05 08:16:32 +01:00
mrgsdev
68906c6cf6 Update core-ml@7s9Elv80TbZX_-NZpyutj.md (#6048) 2024-07-05 08:15:39 +01:00
mrgsdev
d5ea2ed17a Update dynamic-type@0nei6iwP4Pgi_j4vVi_Qt.md (#6049)
* Update dynamic-type@0nei6iwP4Pgi_j4vVi_Qt.md

* Update src/data/roadmaps/ios/content/dynamic-type@0nei6iwP4Pgi_j4vVi_Qt.md

Removing templating

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-05 08:15:15 +01:00
mrgsdev
6118162b03 Update accessibility@1DZYPqvgY6GtwMCS7N2y-.md (#6050) 2024-07-05 08:13:59 +01:00
Florian Schweizer
0a675760ed Add Combine & NavigationStack content to the iOS roadmap (#6052)
Add content to Navigated stacks and combine
2024-07-05 08:13:25 +01:00
mrgsdev
4b5635c5e5 Update voice-over@trAMZVA4tDB7b_qAgiWNW.md (#6051) 2024-07-05 08:12:37 +01:00
mrgsdev
ee298f9959 Update keeping-updated-with-wwdc@fOOQurIL1w3PwH5Mep9x1.md (#6053) 2024-07-05 08:11:29 +01:00
mrgsdev
d09710fee6 Update new-project@BJgoAgH85U6S3RtXq7hHV.md (#6054) 2024-07-05 08:11:00 +01:00
Guilherme Carvalho de Azevedo
7d3d022d5a fix(devops-roadmap): typo fixed (Pometheus to Prometheus) (#6056) 2024-07-05 08:09:43 +01:00
mrgsdev
e81571f7fc Update history-and-why-swift@z4-1Gc95JKYAn2RPFc7hw.md (#6034) 2024-07-05 08:08:00 +01:00
Farzad Mohtasham
ed01ffbefa Tanstack/Router Added to React-Router topic (#6030)
* Added Tanstack-Router to the React Routers section
2024-07-05 08:06:38 +01:00
Farzad Mohtasham
1e5b467124 Added Zustand video tutorial for State-management topic (#6028)
Add Zustand links & Higher Order videos.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-04 16:13:17 +01:00
Konrad
03b6337388 refactor(roadmap/angular): update links to new angular.dev documentation (#6024)
additionally:
- remove duplicated links in some documentations
- improve titles
2024-07-04 15:46:38 +01:00
dsh
9aed682629 add version management subtopic (#6025)
* add version management subtopic

* Update src/data/roadmaps/terraform/content/version-management@6zFuSNOfbPaYIE_t--2nr.md

correct typo

* Update src/data/roadmaps/terraform/content/version-management@6zFuSNOfbPaYIE_t--2nr.md

Co-authored-by: Konrad <kord.stp@gmail.com>

---------

Co-authored-by: Konrad <kord.stp@gmail.com>
2024-07-04 15:45:31 +01:00
dsh
1c515f1d8f altered title and subtitle to reflect devloper advocate (#6026) 2024-07-04 14:48:27 +01:00
dsh
1ebf850882 Adding links and copy to Terraform roadmap (#5914)
* Adding links and copy to Terraform roadmap

* added hcl content

* add resource topic content

* add tf meta-argument content and copy

* add content for variables and outputs

* added more links to areas that are lacking

* Apply suggestions from code review

Corrected styling
2024-07-04 14:18:57 +01:00
Ankita soni
b7b8a935c1 Update 101-iaas-paas-saas.md (#6023)
Add popular youtube video

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-04 09:31:52 +01:00
Abdallah Gaber
3cf0a7ca8a Roadmap: MORE Node.js Content and Resources Updates and Fixes for Nearly Half the Roadmap (#6022)
Corrected type tags and links, formatted content text, added new links.
2024-07-04 09:28:53 +01:00
Kamran Ahmed
fac090c803 Fix height of the tips box 2024-07-04 01:35:13 +01:00
Kamran Ahmed
adc44ed325 Migrate data analyst roadmap 2024-07-04 01:21:18 +01:00
Kamran Ahmed
2c79d85c67 Add progress caching cleanup 2024-07-03 12:44:36 +01:00
Kamran Ahmed
e24f5dfe6a Add devops roadmap 2024-07-03 12:44:36 +01:00
Kamran Ahmed
ad712b2c4a Redraw devops roadmap with editor 2024-07-03 12:44:35 +01:00
ChuYang
f3fda96c15 chore(docs): fix typos and grammar errors for react.md (#6018) 2024-07-03 10:51:23 +01:00
Farzad Mohtasham
db1ba63e6c feat: Added 3 videos to React-Roadmap, For HOC (#6013) 2024-07-03 09:42:46 +01:00
Abdallah Gaber
f63c59d9ee Roadmap: Node.js Content and Resources Updates and Fixes (#6015)
Corrected type tags, added some extra copy, added new links.
---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-03 09:41:10 +01:00
Arik Chakma
72cc28a436 fix: label line break (#6014) 2024-07-02 22:23:07 +01:00
dsh
58e2405fa0 correct FS link to FS roadmap rather than react (#6010) 2024-07-02 13:59:03 +01:00
Amirali Toori
e5ee35acee Addition: [roadmaps/DataAnalyst] Add article for Finding Outliers (#5999) 2024-07-02 13:28:37 +01:00
Subroto Banerjee
a347c1739b Articles on API security, server security and cyber security (#6001)
Add content links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-02 13:27:36 +01:00
Timofey Veretnov
10ac77308d Concurrency in Swift by Apple (#6004)
Updated styling and copy.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-02 13:20:05 +01:00
Nikhil
de6aaa262b DSA Roadmap | Updated Links for 102 & 105 (#6007)
Update 103-quick-sort.md
2024-07-02 13:15:24 +01:00
xaanxex
1fe5512310 Update 108-exception-handling.md (#6008)
added 2 article links
2024-07-02 13:14:02 +01:00
BANO
96b8e109b1 Add viem library to blockchain roadmap (#5975) (#6009)
* Add viem library to blockchain roadmap (#5975)

* Update src/data/roadmaps/blockchain/content/109-dapps/108-client-libraries/index.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-02 13:12:10 +01:00
Kamran Ahmed
64e71574d2 Update shout-out text on devrel roadmap 2024-07-02 11:15:44 +01:00
Kamran Ahmed
5913564d94 Remove console.log 2024-07-02 00:16:48 +01:00
Kamran Ahmed
6686e9361c debug code 2024-07-02 00:07:32 +01:00
Kamran Ahmed
e738936b5e Arrow alignment fixes 2024-07-01 23:53:54 +01:00
Kamran Ahmed
b97e2c7ce1 Fix alignment of devrel engineer 2024-07-01 23:08:49 +01:00
Kamran Ahmed
3e312b6aa7 Fix alignment of devrel engineer 2024-07-01 23:04:38 +01:00
Kamran Ahmed
e8a430db47 Update FAQ for devrel engineer 2024-07-01 23:03:46 +01:00
Kamran Ahmed
47e6f8e926 Add link to devrel engineer roadmap in readme 2024-07-01 22:56:02 +01:00
Kamran Ahmed
fa6f4aa6e3 Add DevRel roadmap assets 2024-07-01 22:52:09 +01:00
Kamran Ahmed
cf0d10eeed Add DevRel roadmap 2024-07-01 22:32:59 +01:00
Amirali Toori
38d96682cf Addition: [roadmaps/DataAnalyst] Add article for Correlation Analysis (#5997) 2024-07-01 16:26:40 +01:00
Mrutyunjay Lodhi
61788edcd0 feat: Added Article for flutter internals (#5995) 2024-07-01 11:54:38 +01:00
mrgsdev
c48907c5e0 Update memory-management (#5992)
* Update memory-management@tqbg8mBJfjuXacdMlIB_L.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-01 11:40:34 +01:00
Leni Kirilov
90371b081a Java roadmap - multiple fixes (#5957)
Adding copy, content links & remove broken links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-01 10:39:44 +01:00
Leni Kirilov
c80591c1cf Java roadmap: jvm clarifications (#5945)
removed duplicate link
added JVM languages and GraalVM as a popular alternative

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-01 10:34:38 +01:00
mrgsdev
4734a8eb02 Update xcode@la5M4VoH79bhnN8qj5Izp.md (#5967)
Added two official videos from the Apple YouTube channel:
- WWDC24: What’s new in Xcode 16
- WWDC24: Xcode essentials
---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-07-01 10:31:25 +01:00
Amirali Toori
b6ceebae9c Add Article for 101-kurtosis.md in Data Science Road map (#5981)
Add a link (article) that describes the topic of Kurtosis.
2024-07-01 10:24:07 +01:00
Amirali Toori
54459a52f2 Add an article to Data Science roadmap about Skewness concept (#5982)
This is a simple and useful article, which I think might be very useful for understanding the concept of skewness.
2024-07-01 10:22:44 +01:00
Amirali Toori
446373532f Addition: [roadmaps/DataScience] Add article for Dispersion (#5983) 2024-07-01 10:22:00 +01:00
Micael Andrade
a69459ba31 fixing broken link (#5985) 2024-07-01 09:54:57 +01:00
Konrad
7f35c2f6f0 docs(contributing): remove a duplicated opensource type (#5971) 2024-06-30 01:49:53 +06:00
dsh
7e2f9d3e6b add linux permissions article and video (#5964) 2024-06-28 16:04:08 +01:00
fellalli
e4d106904e Corrected / Improved C++ roadmap (#5947)
Updated c++ content with `std::` as this is the recommended method. Added content links where needed and corrected various wording and grammar.
2024-06-28 14:26:20 +01:00
MTRX
7d694f3e56 Fix and add links in Computer Science roadmap (#5960)
Corrected daily.dev feed link & added content links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-28 14:23:44 +01:00
Jhonatan Mustiola
338bce1308 Update 108-hashmap.md (#5958)
Add Rust Hashmap content links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-28 14:20:57 +01:00
Nikhil
c9d6b36b34 Fixed Typo for DSA Roadmap (#5962)
Added content links and fixed link syntax error.
---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-28 14:17:17 +01:00
Ruslan Semagin
2874eb0a42 add links for 'Rust Macros' (#5963) 2024-06-28 14:12:59 +01:00
Kamran Ahmed
a62ed919c1 Add github URL in redirect 2024-06-28 12:36:29 +01:00
Kamran Ahmed
9ecf4a9d78 Add x URL 2024-06-28 12:33:24 +01:00
Kamran Ahmed
2c373c7574 Add links for discord, twitter and youtubeg 2024-06-28 12:18:33 +01:00
Kamran Ahmed
d9cdc95a79 Update product mangaement SEO description 2024-06-27 22:23:19 +01:00
Kamran Ahmed
3af4bde2ea Fix text wrap on TF roadmap 2024-06-27 22:23:19 +01:00
Arik Chakma
1ee6f0e125 feat: add daily dev link in profile (#5948) 2024-06-27 11:52:03 +01:00
Jhonatan Mustiola
9471bf50f9 Update 107-string.md (#5951)
More links were added to the Vector step in the Rust roadmap
---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-27 10:04:51 +01:00
Nikhil
f143d800bd DRAFT: Added link(s) for DSA Roadmap (#5935)
* Added various content links

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-27 09:55:38 +01:00
Jacob Penner
f7b42a63bf feat: Add content links to API Design roadmap (#5869)
* Add content links to 'What are APIs' section

* Add content links to 'API Documentation Tools' section

* Add content links to 'HTTP' section

* Add content links to 'HTTP Versions' section

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-27 09:46:44 +01:00
Leni Kirilov
212be69582 Update 106-files-and-apis.md (#5943)
added newer Files.* API with articles
2024-06-27 09:42:54 +01:00
MTRX
393eb6c87d Add and correct links in C++ resources section (#5950) 2024-06-27 09:40:02 +01:00
Michael Budnikov
fe6e0830eb All additional links at the end of the articles in C++ roadmap have been wrapped with 'Learn more from the following resources:' line as in contribution docs stated (#5949) 2024-06-27 09:36:19 +01:00
Ye Naing Tun
24c4221591 Add Content links to 'Vue' Section (#5934)
* added Vue content links.
2024-06-27 09:34:11 +01:00
Leni Kirilov
7744363cde added enum and records (#5940) 2024-06-26 14:06:55 +01:00
Leni Kirilov
ce6e2ff71e added lambda functions examples and articles (#5941) 2024-06-26 14:03:38 +01:00
Ruslan Semagin
09e345f48b add useful links for 'Rust Error Handling' (#5936) 2024-06-26 09:58:31 +01:00
Nguyen Trong Toan
5dff9b20e1 feat: Update iOS roadmap link to React Native (#5933)
The iOS roadmap link for React Native was updated to the correct URL. This change ensures that users are directed to the appropriate resource for learning React Native on the iOS roadmap.

Authored-by: kai <trongtoan1609ht@gmail.com>
2024-06-25 21:23:38 +01:00
Michael Budnikov
f1d6cd51cd Update index.md: Article about function pointers was added (#5916)
I added the link to the article about function pointers in C++ that helped me to learn more about it and try it on my own.
2024-06-25 16:04:06 +01:00
GGGamesXDlol
045bab002a Updated 100-spline.md: Added a video about splines (#5930)
* Added a video about splines

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-25 13:58:55 +01:00
dsh
08b1b48b5e Dansholds/update contrib doc (#5931)
* update to contribution.md
2024-06-25 13:04:01 +01:00
dsh
0b6da0e076 Correct iOS tool/component names (#5922)
* Correct iOS tool/component names

* forgot AVFoundation
2024-06-25 10:20:51 +01:00
Jhonatan Mustiola
520fa2db45 Update 106-vector.md (#5920)
More links were added to the Vector step in the Rust roadmap
2024-06-25 09:30:55 +01:00
Dale Nash
3c160e8809 Add missing space to about page (#5921)
Very minimal but sure, it's valid.
2024-06-25 09:28:55 +01:00
Kamran Ahmed
f682a6e1a2 Fix content in wrong files 2024-06-24 22:52:20 +01:00
Kamran Ahmed
3f655ad424 Add legends to backend roadmap 2024-06-24 20:03:32 +01:00
Kamran Ahmed
5b108f1fd2 chore: redraw backend roadmaps with our editor (#5917)
* Migrate backend roadmap

* Update frontend roadmap

* Fix typo in backend roadmap

* Remove local caching of progress

* Update migration count
2024-06-24 18:32:31 +01:00
dsh
0064d04ff4 Add external links to intro PM topics (#5867)
* add external links to intro PM topics

* lifecycle and development links
2024-06-24 15:51:55 +01:00
Abdallah Gaber
e98ebcfa11 Fix and Update JavaScript Recourses Links (#5896)
* Update JavaScript-asynchronous Promises resources

* Replace broken link

The previous link to the article was outdated and resulted in a 404 error.

* Fixed the JavaScript typo

* Add Video Resource JS 101-debugging-memory-leaks.md

Added a helpful YouTube video on visualizing memory leaks and debugging them in the console.

* Introduce resource (Chrome Developers) JS-debugging-performance

Added link to Chrome Developers documentation on debugging JavaScript performance in JS 102-debugging-performance.md. This provides valuable insights and best practices for optimizing code performance from the official docs.
2024-06-24 10:01:02 +01:00
Blamowizard
64bbbc2f25 Typo/grammar fixes plus copy edits for Rust roadmap (19 files) (#5906)
* Fix typos Rust/100-integers.md

* Grammatical clarity Rust/101-why-rust.md

* Sentence restructuring for Rust/102-memory-safety.md

* Additional linker explanation for newbies, Rust/103-installing-rust.md

* Wording changes, Rust/103-installing-rust.md

* "tools for debugging" -> "debugging tools" Rust/104-ides-and-rust.md

* Small clarity change Rust/105-rust-repl.md

* "systems" -> "system" (for consistency), Rust/101-why-rust.md

* Clarity, Rust/101-variables.md

* Small sentence edits, Rust/102-control-flow.md

* Another small edit, 102-control-flow.md

* Small changes + added `return` keyword info, Rust/103-functions.md

* Rust/103-functions.md

* Clarity/grammar for Rust/104-pattern-matching.md

* Sentence flow + prose about pattern matching, Rust/100-syntax/index.md

* Wording/paragraph improvements, Rust/100-syntax/index.md

* List-ified, italics-ified for Rust/101-ownership/100-rules.md

* Small changes + bullets for Rust/102-stack-heap.md

* List-ify + small clarity improvements, Rust/101-ownership/index.md

* Sentence flow & clarity for Rust/102-constructs/100-enums.md

* Rewrite of Rust/100-enums.md

* a -> an

* List-ify and small edits for Rust/101-structs.md

* Bold some stuff in Rust/101-structs.md

* Small rewrite for Rust/102-traits.md

* Rewrite Rust/103-impl-blocks.md

* List-ify + clarity edits for Rust/102-constructs/index.md

* More data types explanation for Rust/102-constructs/index.md

* define -> declare

* Update index.md

* Unbolded “traits”

* Unbolded “enum” + replaced em-dashes with commas

* “Rust is a system…”

* Replaced em-dashes with commas

* Update 102-control-flow.md

Replaced more em-dashes with commas

* Unbold “struct”

* Unbold “constructs”
2024-06-24 09:59:19 +01:00
Kamran Ahmed
2da1f61945 Update progress nudge number 2024-06-23 15:40:51 +01:00
Kamran Ahmed
894b66f026 Update progress 2024-06-23 15:22:15 +01:00
Kamran Ahmed
f5fc71aadb Redraw frontend roadmap with our editor (#5897)
* Update frontend roadmap

* Migrate content for frontend roadmap

* Add a button for beginner friendly version

* Frontend roadmap

* Implement beginner version of frontend roadmap

* Clear progress for roadmaps

* Update
2024-06-23 14:55:09 +01:00
Amit Merchant
ec9bebbcda Add article "Unlimited function parameters using Rest" (#5908) 2024-06-23 12:22:26 +01:00
Kamran Ahmed
9cf940e741 Remove badge from backend questions 2024-06-22 03:29:33 +01:00
Kamran Ahmed
f4b157b328 Update new badges 2024-06-22 03:20:05 +01:00
Kamran Ahmed
4c54e20a11 Add terraform assets 2024-06-21 21:26:15 +01:00
Kamran Ahmed
c4cc0630c0 Add basic content for hcl 2024-06-21 21:26:15 +01:00
Kamran Ahmed
a637805a24 Add directory structure for terraform roadmap 2024-06-21 21:26:15 +01:00
Kamran Ahmed
8604810a2e Add directory structure 2024-06-21 21:26:15 +01:00
Kamran Ahmed
a2481f7681 Add terraform roadmap 2024-06-21 21:26:15 +01:00
Nikita Ivanov
88926c9ba5 Fix answer for backend question about eventual consistency (#5904) 2024-06-21 18:47:10 +01:00
Ed Lan
faf12dcf8e Update faqs.astro (#5898)
Copy update
2024-06-20 15:06:09 +01:00
Kamran Ahmed
70d3e6cd39 Redraw frontend roadmap fork 2024-06-20 12:51:27 +01:00
Jhonatan Mustiola
b1d790739f More links to steps in the Rust Roadmap (#5894)
More links were added to the array step in the Rust roadmap
2024-06-20 09:46:26 +01:00
Ante Barić
6d983167c8 feat: daily.dev links (#5860)
* feat: add daily.dev link type

* feat: replace to feed label

* feat: add links to different pages
2024-06-19 15:58:20 +01:00
Kamran Ahmed
c935e2457e Add tracking of topic resource clicks 2024-06-19 12:24:34 +01:00
Ed Lan
d21e01805e Update backend.md (#5890)
Small copy tweak
2024-06-19 09:39:54 +01:00
Kamran Ahmed
b31b4e2a11 Update ios roadmap 2024-06-18 12:17:19 +01:00
Nikita Ivanov
94b245b2cf Fix link to containerization question's answer (#5885)
Corrected content for Containerization question from stateless-http to containerization.
2024-06-17 16:13:53 +01:00
dsh
f37cc57177 Add new authors; Fix devops guide routing issue (#5883)
* add william and kenny as authors

* fixed routing issue from /authors on new devops guides
2024-06-17 15:50:04 +01:00
Ed Lan
533e93e647 Update faqs.astro (#5882)
Tweak to add link to new DevOps guide.
2024-06-17 14:51:45 +01:00
Abdallah Gaber
6f6b942ba4 Update JavaScript-asynchronous resources (#5871)
Added links to two videos for better understanding. One video features comprehensive and visually appealing content, while the other from JSConf provides visuals suited for beginners.
2024-06-17 09:50:03 +01:00
Ebrahim Gamal
5cbbaa61a9 Update 100-jetpack-compose.md (#5873)
I added video resource for jetpack compose.
---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-17 09:48:27 +01:00
VIKASH LAL
e0fa460ab9 Add resource for DOM (#5232)
* Update 102-shadow-dom.md

These changes are important from a student's perspective.

* Update src/data/roadmaps/frontend/content/113-web-components/102-shadow-dom.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-17 09:40:14 +01:00
dsh
41a3f85ac2 Add iOS media layer topic content (#5846)
* add iOS media layer topic content

* Add copy around Xcode and Media Layer
2024-06-17 09:38:03 +01:00
dsh
8e2515a84b Add devops vs sre guide (#5854) 2024-06-17 09:37:36 +01:00
Snoppy
0e8613daae chore: fix typos (#5881)
Signed-off-by: snoppy <michaleli@foxmail.com>
2024-06-17 07:24:11 +01:00
Kazuki Kurahashi
3dc08388d9 Fix typo 101-hashing-encryption-encoding.md (#5878) 2024-06-16 08:39:44 +01:00
Wesley Blake
714b604546 Update 103-data-transformation.md (#5855)
Additionally, links to examples in Python and R
2024-06-14 22:01:35 +01:00
Jhonatan Mustiola
89d22aa127 Update 101-floats.md (#5859)
Added more links. Content keeps the copy
2024-06-14 14:22:51 +01:00
Ruslan Semagin
cb8f380dc0 link to 'Docker Multi-stage builds' (#5863) 2024-06-13 15:18:13 +01:00
Kamran Ahmed
b4f84b448d Add product manager roadmap to get-started and roadmaps pages 2024-06-12 23:39:07 +01:00
dsh
235c571347 Fix typos in product management roadmap (#5862)
* correct pm goal types

* corrected typos

* swapped project and product

* swap project and product on title

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-12 18:49:58 +01:00
fellalli
3025e17e4c Add Product Manager Roadmap to readme.md (#5861) 2024-06-12 18:48:15 +01:00
Kamran Ahmed
86947d83d7 Product vs project management 2024-06-12 18:41:40 +01:00
Yash Deore
0ab46ae861 Update 100-instance-types.md (#5853)
* Update 100-instance-types.md

Updated with ec2 instance types

* Update 100-instance-types.md

added @official@ documentation for ec2 instance types

* Update 100-instance-types.md

* Update src/data/roadmaps/aws/content/101-ec2/100-instance-types.md

Ok sir

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

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-12 16:36:52 +01:00
Kamran Ahmed
2046695479 Add product manager roadmap 2024-06-12 15:30:05 +01:00
Kamran Ahmed
3ed9bdb85e Resolve merge conflicts 2024-06-12 15:29:54 +01:00
Kamran Ahmed
a747a8108d Add product manager roadmap 2024-06-12 15:29:20 +01:00
Wesley Blake
17f5ca3cb0 Add resources for swap (#5850)
I thought these two were the most interesting articles on the subject.

Also provides examples on how to do it.
2024-06-11 12:16:54 +01:00
Grigory
4b12137077 docs(typescript/build-tools): update tsup link (#5851) 2024-06-11 10:56:56 +01:00
dsh
f08eae2632 Add how to become devops engineer guide (#5847)
* add how to become devops engineer guide

* Update src/data/guides/how-to-become-devops-engineer.md

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

* Update src/data/guides/how-to-become-devops-engineer.md

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

* Update src/data/guides/how-to-become-devops-engineer.md

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

* Update src/data/guides/how-to-become-devops-engineer.md

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

* Update src/data/guides/how-to-become-devops-engineer.md

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

* add newline before and after all headings

* remove double empty lines

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-11 10:56:28 +01:00
Kamran Ahmed
6f4ab78f47 Add sponsor logic for hiding 2024-06-10 18:29:35 +01:00
Kamran Ahmed
855365d897 Topic links refactoring 2024-06-09 18:30:57 +01:00
shohan kazi
8403bf7a04 Update 107-ruby.md (#5841) 2024-06-09 09:18:31 +01:00
Swapnil Sinha
042ba11870 Add content to vercel (#5834)
Documentation addition on vercel platform.
2024-06-08 13:28:25 +01:00
Maciek Sitkowski
2fbec21378 Fix typos in frontend questions about SSR (#5837) 2024-06-08 11:08:50 +01:00
JesusG16
178826683c Update resource link for OOP section (#5833)
One of the links for the introduction to object oriented programming no longer leads to the site it used to but to an unrelated one, I found a link I think would be suitable for this.
2024-06-08 09:59:42 +01:00
Kamran Ahmed
37e5cbf315 Add link to frontend questions 2024-06-07 17:46:31 +01:00
dsh
a836a1c4b5 Add iOS content (#5829)
* add iOS content

* add GitHub article

* Update src/data/roadmaps/ios/content/functional-programming@Pj-hqRZUmwx1WhmTbLoFD.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-07 16:42:48 +01:00
Kamran Ahmed
86e3921ca4 Add frontend questions (#5831) 2024-06-07 16:38:06 +01:00
Sauradip Ghosh
e765771500 Update 101-alter-table.md (#5830) 2024-06-07 15:30:46 +01:00
dsh
a4000539f6 Add iOS content (#5828)
* update iOS content, correct tcp/ip title

* add swift interoperability content
2024-06-07 14:02:13 +01:00
Ruslan Semagin
66ff58f42d add useful links for Rust ORM (#5827) 2024-06-07 11:22:04 +01:00
Ruslan Semagin
6a46b9c084 remove broken import (#5824) 2024-06-07 09:53:36 +01:00
Arik Chakma
4254446552 fix: remove is-mobile lib (#5826) 2024-06-07 09:53:26 +01:00
Arik Chakma
caf2f14e54 feat: implement mobile impressions (#5818)
* add resource link for React Native Text component (#5773)

* add resource link for React Native Text component

---------

Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>

* feat: add useful links for Rust (#5781)

* feat: add links about testing in Rust (#5791)

* Patch 1 (#5792)

Update 120-real-time-data.md (#5782)

Add links to pages containing brief explanations on the topics listed here.

Update well-architected framework.

---------

Co-authored-by: devgru-3-2 <95485002+devgru-3-2@users.noreply.github.com>
Co-authored-by: Danrley Senegalha Pires <dan.osp@outlook.com>

* Fix: Standardize using "docker container ls" command when referencing listing containers (#5787)

* Add reference link to React Native ImageBackground component (#5795)

* add reference link to React Native ImageBackground component

---------

Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>

* add links to the 'Modules and Crates' node in the Rust roadmap (#5797)

* fix broken go topic (#5800)

* feat: change the description and links in the 'log/slog' node (#5798)

* change the description and links in the 'log/slog' node
---------

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

* add links for 'awk' (#5801)

* add links for 'grep' (#5808)

* Update ci-cd.md (#5807)

* Update Property Binding to most recent link (#5774)

Update 101-property-binding.md

* Added video resources for React Components (#5810)

Signed-off-by: Archit Sharma <74408634+iArchitSharma@users.noreply.github.com>

* Update 104-reference-vars.md (#5775)

* fix: return response status code (#5815)

* feat: implement topic link's label (#5817)

* feat: implement mobile impressions

* fix: add to the body

---------

Signed-off-by: Archit Sharma <74408634+iArchitSharma@users.noreply.github.com>
Co-authored-by: Juan Gerardo Eulufi Salazar <juan.eulufi.sa@gmail.com>
Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>
Co-authored-by: Yash Deore <152061059+yashdeored@users.noreply.github.com>
Co-authored-by: devgru-3-2 <95485002+devgru-3-2@users.noreply.github.com>
Co-authored-by: Danrley Senegalha Pires <dan.osp@outlook.com>
Co-authored-by: Anthony Pun <apun97@yahoo.com>
Co-authored-by: Sion Kang <siontama@gmail.com>
Co-authored-by: Liliana Santos <liliana.t.santos@hotmail.com>
Co-authored-by: Archit Sharma <74408634+iArchitSharma@users.noreply.github.com>
2024-06-06 23:48:22 +01:00
Kamran Ahmed
6372990f76 Fix types of resources 2024-06-06 23:31:19 +01:00
Kamran Ahmed
390db65e32 Add types to links 2024-06-06 23:23:55 +01:00
Kamran Ahmed
0a579b4507 Remove geeksforgeeks links 2024-06-06 23:09:32 +01:00
Kamran Ahmed
1b79141b47 fix invalid urls 2024-06-06 23:05:23 +01:00
Kamran Ahmed
dfef66f4b5 Update topic assignment 2024-06-06 22:55:17 +01:00
Kamran Ahmed
458ae33eec Add frontend roadmap node types 2024-06-06 22:52:36 +01:00
Kamran Ahmed
4cc879104f Remove paid resources 2024-06-06 22:40:50 +01:00
Kamran Ahmed
1ac8a86f1c Remove codecademy links 2024-06-06 22:13:25 +01:00
Kamran Ahmed
79e7c10ad9 Change UI for topic labels 2024-06-06 21:32:56 +01:00
José Vivas
03d9e62aaf Add sets to 102-built-in-types.md (#5806)
* Update 120-real-time-data.md (#5782)

Added links to pages containing brief explanations on the topics listed here.

* fix: correct spelling from "Synatx" to "Syntax" (#5784)

* Update 102-built-in-types.md

---------

Co-authored-by: devgru-3-2 <95485002+devgru-3-2@users.noreply.github.com>
Co-authored-by: Danrley Senegalha Pires <dan.osp@outlook.com>
2024-06-06 21:05:11 +01:00
Arik Chakma
c68823c478 feat: implement topic link's label (#5817) 2024-06-06 21:05:11 +01:00
M-DEV-1
3af2a6b6bc added content to api security (#5814)
* added content to api security

Added a link to OWASP API Security Top 10 which lists 10, major problems with API security. It is a good resource to understand API security and the problems associated with it.

* Update src/data/roadmaps/api-design/content/api-security@qIJ6dUppjAjOTA8eQbp0n.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-06-06 19:01:17 +01:00
Kamran Ahmed
6644d8266e Remove deployments on master push 2024-06-06 18:57:45 +01:00
Arik Chakma
d2e3fee99a fix: return response status code (#5815) 2024-06-06 18:57:45 +01:00
Liliana Santos
ed40bf51b0 Update 104-reference-vars.md (#5775) 2024-06-06 18:57:45 +01:00
Archit Sharma
f90630c566 Added video resources for React Components (#5810)
Signed-off-by: Archit Sharma <74408634+iArchitSharma@users.noreply.github.com>
2024-06-06 18:57:45 +01:00
Liliana Santos
c9ce2eedb1 Update Property Binding to most recent link (#5774)
Update 101-property-binding.md
2024-06-06 18:57:45 +01:00
Sion Kang
d5249cc90e Update ci-cd.md (#5807) 2024-06-06 18:57:45 +01:00
Ruslan Semagin
1bc3464102 add links for 'grep' (#5808) 2024-06-06 18:57:45 +01:00
Ruslan Semagin
3c3b0c02a8 add links for 'awk' (#5801) 2024-06-06 18:57:45 +01:00
Ruslan Semagin
bfd0343ee9 feat: change the description and links in the 'log/slog' node (#5798)
* change the description and links in the 'log/slog' node
---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-06-06 18:57:45 +01:00
dsh
3ec301f2f5 fix broken go topic (#5800) 2024-06-06 18:57:45 +01:00
Ruslan Semagin
5a23d4d326 add links to the 'Modules and Crates' node in the Rust roadmap (#5797) 2024-06-06 18:57:45 +01:00
Juan Gerardo Eulufi Salazar
03bf058dd7 Add reference link to React Native ImageBackground component (#5795)
* add reference link to React Native ImageBackground component

---------

Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>
2024-06-06 18:57:45 +01:00
Anthony Pun
15b0e33542 Fix: Standardize using "docker container ls" command when referencing listing containers (#5787) 2024-06-06 18:57:45 +01:00
Yash Deore
be6b0128b1 Patch 1 (#5792)
Update 120-real-time-data.md (#5782)

Add links to pages containing brief explanations on the topics listed here.

Update well-architected framework.

---------

Co-authored-by: devgru-3-2 <95485002+devgru-3-2@users.noreply.github.com>
Co-authored-by: Danrley Senegalha Pires <dan.osp@outlook.com>
2024-06-06 18:57:45 +01:00
Ruslan Semagin
b67cb99f41 feat: add links about testing in Rust (#5791) 2024-06-06 18:57:45 +01:00
Ruslan Semagin
d95c1d66f0 feat: add useful links for Rust (#5781) 2024-06-06 18:57:45 +01:00
Juan Gerardo Eulufi Salazar
4a2130d7d0 add resource link for React Native Text component (#5773)
* add resource link for React Native Text component

---------

Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>
2024-06-06 18:57:45 +01:00
Danrley Senegalha Pires
a16d781681 fix: correct spelling from "Synatx" to "Syntax" (#5784) 2024-06-01 12:02:51 +01:00
devgru-3-2
65d7d06d2c Update 120-real-time-data.md (#5782)
Added links to pages containing brief explanations on the topics listed here.
2024-06-01 12:02:24 +01:00
Kamran Ahmed
4c615f85e5 Add functionality to go next and back on questions 2024-05-31 01:35:36 +01:00
Ruslan Semagin
a14d8b5f90 feat: Add useful links to documentation on serialization/deserialization in Rust (#5767)
Add Rust web framework doc links.

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-30 09:25:41 +01:00
Kamran Ahmed
eaebe7babd Add missing iOS roadmap to roadmaps and /get-started 2024-05-29 23:48:35 +01:00
Arik Chakma
bab4a1581d fix: show login popup for logged out user (#5764) 2024-05-29 22:54:13 +01:00
Juan Gerardo Eulufi Salazar
bb6d34407d Add link to Angular template statements section (#5763)
* feat: add useful links for learning generics in golang

* highlight teams on mobile view

* feat: add useful links for learning pointers in golang (#5747)

* feat: add useful links for learning pointers in golang

* feat: marking "in progress" should not close popup #5730 (#5742)

* add links to angular section

* add link to Angular template statements section

---------

Co-authored-by: Ruslan Semagin <pixel.365.24@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: Suman Kisku <sumankisku1@gmail.com>
2024-05-29 21:06:54 +01:00
dsh
0d94d99d4b add copy and links to architecture topics (#5755)
* add copy and links to architecture topics

* made content more concise for iOS architecture topics
2024-05-29 19:31:29 +01:00
Kamran Ahmed
7dc6135416 Update topic detail 2024-05-29 19:31:29 +01:00
Kamran Ahmed
bfea73d372 Fix topic details not loading for custom roadmaps (#5762)
* Update AI example roadmaps

* feat: add useful links to documentation on Rust web frameworks (#5756)

Add Rust web framework doc links.

---------

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

* Add links to readme.md (ios-roadmap, backend-questions) (#5758)

Add iOS roadmap and backend questions to readme.md.

* Fix content not shown for custom roadmaps

* Update topic detail

---------

Co-authored-by: Ruslan Semagin <53819609+pixel365@users.noreply.github.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: fellalli <fellalli@web.de>
2024-05-29 19:28:25 +01:00
Kamran Ahmed
e641f06823 Fix content not shown for custom roadmaps 2024-05-29 19:11:59 +01:00
fellalli
0c32730424 Add links to readme.md (ios-roadmap, backend-questions) (#5758)
Add iOS roadmap and backend questions to readme.md.
2024-05-29 19:11:59 +01:00
Ruslan Semagin
b639cfd6d4 feat: add useful links to documentation on Rust web frameworks (#5756)
Add Rust web framework doc links.

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-29 19:11:59 +01:00
Kamran Ahmed
c7dc0ae97d Update AI example roadmaps 2024-05-29 01:23:50 +01:00
Kamran Ahmed
e5f7628087 Fix custom roadmap marking as done not working 2024-05-29 01:05:58 +01:00
Kamran Ahmed
158e9b1ed3 Add iOS roadmap 2024-05-29 00:29:50 +01:00
Kamran Ahmed
bb848de581 Add iOS roadmap 2024-05-29 00:29:50 +01:00
fellalli
a3999d04dd Update 104-ides-and-rust.md (#5748) 2024-05-29 00:29:50 +01:00
Juan Gerardo Eulufi Salazar
190a87355e add links to angular section (#5751) 2024-05-29 00:29:50 +01:00
Suman Kisku
4a46e5e170 feat: marking "in progress" should not close popup #5730 (#5742) 2024-05-29 00:29:50 +01:00
Ruslan Semagin
627fb1deb0 feat: add useful links for learning pointers in golang (#5747)
* feat: add useful links for learning pointers in golang
2024-05-29 00:29:50 +01:00
Dan Holdsworth
00ef6bb3a0 highlight teams on mobile view 2024-05-29 00:29:50 +01:00
Ruslan Semagin
a6e8a777e6 feat: add useful links for learning generics in golang 2024-05-29 00:29:50 +01:00
Kamran Ahmed
35ef88e626 Add og images to backend articles 2024-05-27 15:35:04 +01:00
Kamran Ahmed
ba630173b8 Merge branch 'develop' of github.com:kamranahmedse/developer-roadmap into develop 2024-05-27 14:05:52 +01:00
Kamran Ahmed
073ba617ed Add gRPC to api design roadmap 2024-05-27 14:02:56 +01:00
Kamran Ahmed
13744a486a Nudge users to onboard 2024-05-27 14:02:56 +01:00
Kamran Ahmed
16e69a39d5 Add gRPC to api design roadmap 2024-05-27 14:02:18 +01:00
Kamran Ahmed
6cb543ec7d Nudge users to onboard 2024-05-27 12:51:21 +01:00
Kamran Ahmed
268acda75b Add progress nudge on roadmap 2024-05-27 12:38:22 +01:00
Artem745
0167347277 Update built-in modules text (#5737)
The paragraph was about built-in functions, not modules
2024-05-27 12:38:22 +01:00
Kamran Ahmed
8d3c6f946e Update dependencies and fix bug in overlay 2024-05-27 12:38:22 +01:00
Kablys
b2c4bcad34 Fix broken link (#5728) 2024-05-27 12:38:22 +01:00
Kamran Ahmed
6728010173 Add progress nudge on roadmap 2024-05-27 12:37:23 +01:00
Artem745
9895956531 Update built-in modules text (#5737)
The paragraph was about built-in functions, not modules
2024-05-27 11:31:17 +01:00
Kamran Ahmed
0bb784c45b Update dependencies and fix bug in overlay 2024-05-27 10:58:05 +01:00
Kamran Ahmed
0dc6128b8e Fix canonical url 2024-05-27 10:38:57 +01:00
Kamran Ahmed
61eb915fb2 Fix formatting 2024-05-27 10:38:57 +01:00
Dan Holdsworth
04f39d4e91 update contribution doc with develop rules 2024-05-27 10:38:57 +01:00
Kamran Ahmed
f14c945ff9 Fix canonical url 2024-05-27 10:38:45 +01:00
Kamran Ahmed
279aa5c8a7 Fix formatting 2024-05-27 10:38:45 +01:00
Kablys
bbe66a646f Fix broken link (#5728) 2024-05-25 11:22:49 +01:00
dsh
a5a4c9335a Merge pull request #5726 from kamranahmedse/dansholds/update-contrib-doc
update contribution doc with develop rules
2024-05-24 12:29:59 +01:00
Dan Holdsworth
56912f6ed1 update contribution doc with develop rules 2024-05-24 12:27:42 +01:00
Kamran Ahmed
e51ea1ed61 Add backend questions 2024-05-24 12:04:51 +01:00
dsh
ac2b99062e Merge pull request #5724 from wandrey7/patch-1
remove A link is not working 100-event-loop.md
2024-05-24 09:23:25 +01:00
Wandrey
3d17e8f290 Update 100-event-loop.md 2024-05-23 15:47:54 -03:00
dsh
e46ae3bd6e Merge pull request #5722 from zongsforce/patch-2
modify the sample code
2024-05-23 15:03:17 +01:00
zongsforce
38c43c1c95 modify the sample code
the original sample code's complexity is O(n) instead of O(n!)
2024-05-23 21:44:24 +08:00
Kamran Ahmed
7acdbcb4c9 Fix z-indexes 2024-05-23 11:46:24 +01:00
Kamran Ahmed
ee8fb3414a Fix overlaying account button 2024-05-23 11:17:30 +01:00
dsh
ba2f989fa8 Highlight Teams Navigation item over AI item (#5720) 2024-05-23 10:51:35 +01:00
dsh
8c9259fa1d Merge pull request #5716 from Skyth3r/fix-docker-roadmap-intro-typo
Fixed typo in Docker roadmap
2024-05-22 13:36:56 +01:00
Akash Goswami
edb8194707 Fixed typo in Docker roadmap 2024-05-22 13:28:03 +01:00
dsh
83399589c4 Merge pull request #5713 from YutharsanS/patch-1
Change of content in 104-exponential.md
2024-05-22 11:39:30 +01:00
Yutharsan
5b496e8403 Change of content in 104-exponential.md
There's a mistake in the example that has been provided.  According to the complexity analysis, the current example yields the exponential time complexity, not the previous one.
2024-05-22 11:12:31 +05:30
Kamran Ahmed
359e3e1900 Allow transferring roadmap between teams 2024-05-21 17:49:40 +01:00
Arik Chakma
f718d1895f fix: api design rate typo (#5711) 2024-05-21 16:37:51 +01:00
dsh
1b79a91295 Merge pull request #5709 from trueLoving/master
docs(frontend-performance): fix 'cssnano' website link
2024-05-21 15:30:53 +01:00
starsky
4180104402 docs(frontend-performance): fix 'cssnano' website link 2024-05-21 22:02:57 +08:00
dsh
f831258893 Merge pull request #5707 from udohjeremiah/patch-1
Correct link for Expo CLI Quickstart
2024-05-21 11:47:38 +01:00
Udoh Jeremiah
f04e0b2269 Update index.md 2024-05-21 11:47:31 +01:00
Udoh Jeremiah
ad1f1aaa5a Correct link for Expo CLI Quickstart 2024-05-21 11:39:52 +01:00
Kamran Ahmed
1943227f21 Upgrade pnpm 2024-05-21 10:21:30 +01:00
dsh
7aa44d3197 Merge pull request #5705 from BorzooMV/master
Fix Mutex typo in Golang
2024-05-21 10:00:26 +01:00
Borzoo Moazami
452ad7b06b docs(golang): fix Mutex typo 2024-05-20 18:32:11 +03:30
github-actions[bot]
e86b660e05 chore: update dependencies to latest (#5699)
Co-authored-by: kamranahmedse <kamranahmedse@users.noreply.github.com>
2024-05-20 14:40:07 +01:00
Kamran Ahmed
498b653346 Add playwright and remove vue-relay 2024-05-20 14:39:37 +01:00
dsh
303e92dceb Merge pull request #5701 from kamranahmedse/dansholds/5700-missing-ddl-subtopic
add DROP table sub-topic
2024-05-20 10:18:51 +01:00
Dan Holdsworth
f222ebddea add DROP table sub-topic 2024-05-20 10:17:48 +01:00
51L3N7
ca40b403a5 Fix broken formkit domain (#5698)
The old formkit domain has been changed to a new one
2024-05-19 01:10:20 +01:00
dsh
e3a1e1313c Merge pull request #5696 from kamranahmedse/5695-design-patterns-flutter-roadmap
remove broken video link
2024-05-17 22:21:30 +01:00
Dan Holdsworth
814f357021 remove broken video link 2024-05-17 22:20:48 +01:00
Arik Chakma
1af9829c04 Fix renderer not working on local (#5694) 2024-05-17 20:25:46 +01:00
dsh
c277ac3746 Merge pull request #5693 from kamranahmedse/dansholds/5692-links-redirecting-wrong
Remove '!' from youtube links
2024-05-17 19:28:05 +01:00
Dan Holdsworth
9f19229a22 remove '!' from youtube links 2024-05-17 19:25:06 +01:00
Kamran Ahmed
10be8820cb Add API design seo text 2024-05-17 18:07:52 +01:00
Kamran Ahmed
5d909a6023 Update team page URL in onboarding 2024-05-17 17:48:26 +01:00
Kamran Ahmed
ccb57c5ae1 Update API design URLs 2024-05-17 17:38:39 +01:00
Kamran Ahmed
fc277bb32a Add API design roadmap link 2024-05-17 17:37:07 +01:00
Kamran Ahmed
e7a17cf74f Rename API roadmap to API Design roadmap 2024-05-17 17:36:31 +01:00
Kamran Ahmed
5e50ffbc30 feat: add custom renderer for roadmaps (#5691)
* wip

* fix: update packages

* wip

* wip

* feat: editor content generator

* fix: add dimensions

* feat: add renderer

* feat: add progress modal renderer

* Add API design roadmap

* Update API roadmap rendering

* fix: button click

* fix: link item

* feat: render pdf for editor roadmaps

* Add API roadmap

* Fix broken link of full-stack roadmap

* Update content dir

* Fix typos in api roadmap

* Add assets for pdf and svg

* Add content for api roadmap

* Add todo

* fix: close on editor roadmap select

* Update link not working

* Add api roadmap to get-started and roadmaps page

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-05-17 17:28:24 +01:00
Mohamed Salman
375ad931f7 Update local development command (#5687)
* Updated readme.md file with cd command to move into that folder before running further npm command. Also removed roadmap from go

* Addressed review comment - Reverted changes in index.astro file
2024-05-17 12:04:12 +01:00
Wesley Blake
05eab5823e Add DATEDIF disclaimer (#5686)
Asterisk for DATEIF function, doesn't show as a regular function, but can still be used.
2024-05-17 00:02:42 +01:00
月光xia漫步
9b7512bbba Update code example in C++ roadmap (#5680) 2024-05-16 14:27:26 +01:00
Mohammad Kaleaji
3a976663f2 Add resource to tester mindset (#5682)
* Update 101-tester-mindset.md

Adding a reference from ISTQB to the QA Roadmap (Tester Mindset) Section

* Update src/data/roadmaps/qa/content/100-qa-basics/101-tester-mindset.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-16 14:26:21 +01:00
dsh
ebff5490b3 Merge pull request #5684 from kamranahmedse/dansholds/5683-deprecated-links-in-frontend-http-caching
remove all varvy links
2024-05-16 13:41:43 +01:00
Dan Holdsworth
d5c8a4554c remove all varvy links 2024-05-16 13:40:29 +01:00
dsh
7cd3bddeeb Merge pull request #5679 from Edlan01/patch-5
Updated og image
2024-05-16 10:59:34 +01:00
dsh
8af6a9ae58 Merge pull request #5678 from Edlan01/patch-4
Updated og image
2024-05-16 10:59:05 +01:00
Ed Lan
60d19584ee Updated og image 2024-05-16 10:48:14 +02:00
Ed Lan
ee982bf807 Updated og image 2024-05-16 10:46:33 +02:00
dsh
0467e59b28 Merge pull request #5675 from salmantec/bugfix/move-flutter-and-reactnative-to-skill-roadmap
Move Flutter and React Native to Skill-based roadmap
2024-05-16 07:03:19 +01:00
dsh
aed19d84b5 Merge pull request #5676 from mhdabdurahiman/patch-1
fixing typo Angular 101-why-use-typescript.md
2024-05-16 06:59:07 +01:00
mhdabdurahiman
aee2ca2e47 fixing typo Angular 101-why-use-typescript.md
In the doc, there was a typo, where, a 'C' was missing in the word 'compile'.
2024-05-16 09:53:56 +05:30
Mohamed Salman
b6bfbf3090 Updated Flutter and ReactNative from role to skill based skills in RoadmapsPage.tsx, flutter.md and react-native.md files 2024-05-16 09:14:45 +05:30
dsh
61089c9a09 Update/Refresh contribution guide (#5671)
* Update/Refresh contribution guide

* Add link to draw.roadmap.sh

* Update contributing.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-15 10:20:25 +01:00
Petra Donka
9d943ed773 Fix typos in prisma content file (#5670) 2024-05-15 10:15:41 +01:00
dsh
6e5ba6e892 Merge pull request #5667 from aman-yadav-05/patch-1
Update 101-linked-lists.md
2024-05-15 09:33:02 +01:00
dsh
dced08f0f6 Merge pull request #5669 from MohammadKaleaji/patch-1
Update 103-test-oracles.md
2024-05-15 09:25:29 +01:00
Aman Yadav
1bca8e4bfa Update src/data/roadmaps/datastructures-and-algorithms/content/103-basic-data-structures/101-linked-lists.md
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-15 13:55:12 +05:30
dsh
35b99cf6c0 Merge pull request #5668 from mubashir-Interware/patch-1
Update artifacts spelling mistake
2024-05-15 09:23:54 +01:00
Mohammad Kaleaji
37e866ed6e Update 103-test-oracles.md 2024-05-15 10:35:37 +03:00
Aman Yadav
f83ba31af5 added "learn more" and a youtube link along with the article. 2024-05-15 12:32:54 +05:30
mubashir-Interware
f1b7232d37 Update artifacts spelling mistake 2024-05-15 11:28:38 +05:00
Aman Yadav
f910756d35 Update 101-linked-lists.md
Added a link to an article which helped me understand more about the concept of linked list.
2024-05-15 11:23:46 +05:30
dsh
32b0159d9d Merge pull request #5664 from kamranahmedse/dansholds/add-poetry-content
Add Poetry package manager content
2024-05-14 15:23:31 +01:00
Dan Holdsworth
36bef45b5e remove poetry from index.md 2024-05-14 11:35:24 +01:00
Dan Holdsworth
0b177f971f Add Poetry package manager content 2024-05-14 11:31:12 +01:00
dsh
2c54c988ce Merge pull request #5662 from kamranahmedse/dansholds/add-rust-links
add documentation links to data-structure pages
2024-05-14 10:15:40 +01:00
Dan Holdsworth
4883530087 add documentation links to data-structure pages 2024-05-14 10:14:08 +01:00
Kamran Ahmed
2daa7cc327 chore: trigger build 2024-05-14 00:04:17 +01:00
Kamran Ahmed
fdeb6f9cd8 Make /team/member behind auth 2024-05-13 20:35:49 +01:00
Arik Chakma
f8cdd76fa9 feat: onboarding for new users (#5629)
* wip

* feat: add onboarding

* feat: implement onboarding

* Update indicator design

* Update UI for onboarding dropdown

* Changes to onboarding UI

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-13 19:50:43 +01:00
Andrii
67fbba4708 Fix resource links (#5660) 2024-05-13 17:08:57 +01:00
Kamran Ahmed
38cb3d2df6 Add banner for docker 2024-05-13 12:58:12 +01:00
Kamran Ahmed
fa589fd78f Update Vue roadmap 2024-05-13 12:19:13 +01:00
Kamran Ahmed
d53a4e8c79 Add v-model to vue roadmap 2024-05-13 12:08:00 +01:00
Kamran Ahmed
ba3803ab8c Add updates to vue roadmap 2024-05-13 12:03:42 +01:00
Kamran Ahmed
433e53926c Add java date and time 2024-05-13 11:33:53 +01:00
Kamran Ahmed
22d4f18e97 Add script to warmup URLs 2024-05-13 01:38:37 +01:00
Kamran Ahmed
4a40d89783 Add script to warmup og 2024-05-13 01:12:05 +01:00
Kamran Ahmed
fad7133959 Generate PNG images for og 2024-05-13 00:34:05 +01:00
Arik Chakma
6804c6ec00 feat: team member progress modal (#5651)
* feat: restrict members

* feat: member progress modal
2024-05-12 14:48:12 +01:00
Arik Chakma
de89e56a47 fix: edit in editor button (#5652) 2024-05-12 17:29:47 +06:00
Wagner Goulart
97e0059475 Add angular RxJS diagram videos (#5649)
* ADD: Videos explainning how marble diagrams works

Signed-off-by: Wagner <wagnergoulart0@gmail.com>

* Update src/data/roadmaps/angular/content/101-rxjs-basics/102-marble-diagrams.md

---------

Signed-off-by: Wagner <wagnergoulart0@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-12 02:17:05 +01:00
Kamran Ahmed
29c97964d1 Auto-clear cache on deployment 2024-05-12 02:14:20 +01:00
Kamran Ahmed
2071b92d3e Update suggest changes button 2024-05-11 17:21:23 +01:00
Kamran Ahmed
9674bce96e Add get-x to flutter state management 2024-05-11 17:19:56 +01:00
Kamran Ahmed
72da2d43d8 Update python frameworks 2024-05-11 17:15:39 +01:00
Kamran Ahmed
f22674a0b2 Update logging in golang roadmap 2024-05-11 16:50:49 +01:00
Kamran Ahmed
43ece4c10f Add new topics to MLOps roadmap 2024-05-11 16:33:34 +01:00
Kamran Ahmed
304efd83b6 Add sqlite to backend roadmap 2024-05-11 16:14:46 +01:00
Kamran Ahmed
4697e69e23 Replace Vue CLI with create-vue 2024-05-11 16:09:57 +01:00
Kamran Ahmed
af3bbd9320 Add pointers to golang roadmap 2024-05-11 16:07:21 +01:00
Kamran Ahmed
742b79e473 Add generics to go roadmap 2024-05-11 16:01:47 +01:00
Kamran Ahmed
1a619e1dbd Add standalone components in angular 2024-05-11 14:59:13 +01:00
Kamran Ahmed
2c9bfb3c80 Add changes to go and spring roadmaps 2024-05-11 14:54:09 +01:00
Kamran Ahmed
3102148485 Add prometheus to app monitoring 2024-05-11 14:33:16 +01:00
Kamran Ahmed
f8a7c40c11 Fix broken UI in full-stack roadmap 2024-05-11 14:17:05 +01:00
Kamran Ahmed
7603772075 Label the issues with slug 2024-05-11 11:46:08 +01:00
Dương Hồ Minh Tú
33c8528c1a fix: double scroll bar when searching (#5623)
* fix: double scroll bar when searching

* fix: use cn instead

---------

Co-authored-by: TuDHM <tudhm@ghn.vn>
Co-authored-by: Arik Chakma <arikchangma@gmail.com>
2024-05-11 10:46:37 +06:00
Machalkas
d7978d39c9 Add resource under linux roadmap (#5608)
* add url to introductory resource

* Update src/data/roadmaps/linux/content/100-navigation-basics/103-directory-hierarchy.md

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

* Update src/data/roadmaps/linux/content/100-navigation-basics/103-directory-hierarchy.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:16:10 +01:00
Lily Paczesniak
722b1c60d2 Add video resource for OOP (#5393)
* Add a video resource to 103-oop.md

* Update src/data/roadmaps/flutter/content/106-design-principles/103-oop.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:15:00 +01:00
Aditya Trivedi
b0136b0524 Update index.md (#5363)
* Update index.md

* Update src/data/roadmaps/docker/content/101-underlying-technologies/index.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:14:36 +01:00
Sakti Sriraj Mishra
7333941a38 Add kotlin resources (#5351)
* Update 100-kotlin.md

Resources to learn Kotlin were added

* Added Kotlin Learning resource to Android Roadmap

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

* Update src/data/roadmaps/android/content/100-pick-a-language/100-kotlin.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 02:13:57 +01:00
Abdelrahman Eltohamy
27934c1188 Add nexus content (#5336)
* Update 101-nexus.md 

I have added the (definition - role).

* Update src/data/roadmaps/devops/content/118-artifcats/101-nexus.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 02:11:29 +01:00
Gustavo Montini de Abreu
247b24e1a3 Add resource (#5219)
* Update 102-spark-airflow-kafka.md

Add link for website 'Spark by Examples'

* Update src/data/roadmaps/mlops/content/105-data-eng-fundamentals/102-spark-airflow-kafka.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:09:17 +01:00
Sigma Devops
fb6c56e1aa Add powershell text (#5147)
* Update 101-powershell.md

* Update src/data/roadmaps/devops/content/102-live-in-terminal/scripting/101-powershell.md

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

---------

Co-authored-by: Sigma Devops <muhammadsiddiqbe@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:08:43 +01:00
Ashutosh Kumar
db4b2487f5 Update queries (#5143)
* Update index.md

added correct syntax for renaming table or column

* Update src/data/roadmaps/sql/content/102-ddl/index.md

* Update src/data/roadmaps/sql/content/102-ddl/index.md

* Update src/data/roadmaps/sql/content/102-ddl/index.md

* Update src/data/roadmaps/sql/content/102-ddl/index.md

* Update src/data/roadmaps/sql/content/102-ddl/index.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 02:05:51 +01:00
Ashutosh Kumar
f1fbca6fc9 Fix alter table query (#5137)
* Update 101-alter-table.md

Previously :
     ALTER TABLE tableName
     ALTER COLUMN columnName TYPE newDataType;
results in syntax error

Now:
     ALTER TABLE tableName
     MODIFY COLUMN columnName newDataType;

* Update 101-alter-table.md

Added how to drop an primary key

* Update src/data/roadmaps/sql/content/102-ddl/101-alter-table.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:03:28 +01:00
Praneel Maitra
3308387e20 Add resource link (#5108)
* Update linear-algebra-calc-mathana.md

* Update src/data/roadmaps/ai-data-scientist/content/linear-algebra-calc-mathana.md

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

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
2024-05-11 02:02:39 +01:00
Yubraj khatri
ba00c917cf Add resource for useContext (#5033)
* Update 100-context.md

This article help me  a lot to grab the idea about how the context is solving the problem of the prop drilling. I think beginner should start with this article to grasp the knowledge about the problem that trying to solve by the the context

* Update src/data/roadmaps/react/content/106-state-management/100-context.md

* Update src/data/roadmaps/react/content/106-state-management/100-context.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 02:00:44 +01:00
Alucard
b476ca0080 Add resources for N+1 Problem (#4952)
Add additional resource links

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:59:37 +01:00
Jhonatan Mustiola
e9c33a405b Update rust integers section (#4821)
* Update 100-integers.md

More readable, links and more explanations were added

* Update 100-integers.md

Changes in the way the links were coded

* Update 100-integers.md

Incorrect wording corrected

* Update 100-integers.md

Incorrect markdown format corrected

* Update 100-integers.md

Incorrect line spacing was corrected and "-" sign was prepended to each link item

---------

Co-authored-by: Jhonatan Mustiola <152746443+JhonatanMustiolaCas@users.noreply.github.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:53:54 +01:00
dogukan
56247431de Add resource for function borrowing (#4725)
* Update 100-function-borrowing.md

added stackoverflow example

* Update src/data/roadmaps/javascript/content/111-javascript-this-keyword/100-function-borrowing.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:50:29 +01:00
Alex
cae46c5db6 Remove duplicate link (#4531)
* Update 101-prototypal-inheritance.md

url "The Modern JavaScript Tutorial" is the same link as "Prototype Inheritance".

* Update src/data/roadmaps/javascript/content/102-javascript-datatypes/101-object/101-prototypal-inheritance.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:49:14 +01:00
mastercoder8
9cbfbb9231 Add instrumentation link (#3534)
Add open telemetry, which is widely used in the industry and is a the standard for metrics, tracing, logs

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:48:28 +01:00
Germán González
9f49424e67 Fix typo in android roadmap (#5317) 2024-05-11 01:47:37 +01:00
Arkoh-Addo Ebenezer
f290419694 fix: broken url in minimize-http-requests.md (#5324)
* fix: broken url in minimize-http-requests.md

existing URL points to unavailable resources. I provided a more reliable URL with very good insight to the topic.
Updated description to include a little more context providing enough heads up before visiting the URL to read the details

* Update src/data/best-practices/frontend-performance/content/minimize-http-requests.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-11 01:46:29 +01:00
C E L L
82564712c3 Add up to date resource to learn Next.js (#5325) 2024-05-11 01:45:25 +01:00
Eda
ed1532d1f5 Fix small bug in code example (#5348) 2024-05-11 01:45:11 +01:00
Jakub Kaźmierczak
2b4a3f2281 fix typo in rust ownership section (#5421) 2024-05-11 01:42:37 +01:00
Mindy Flores
e1f32a13ab Fix query (#5424)
Description of having clause filter is incorrect. The current query filters for Customers with a total amount strictly greater than $3000.
2024-05-11 01:42:16 +01:00
Dennis O'Connell
5a2305193b Minor resource title change for clarity (#5434)
Specified link for W3 Schools' Golang tutorial to add clarity
2024-05-11 01:41:54 +01:00
VTolmasov
f8b9d2e271 Add CROSS JOIN in queries (#5447)
Added CROSS JOIN type
2024-05-11 01:41:28 +01:00
Deepak Mardi
a1ced7573b Add content for mongo performance optimization #4538 (#5465)
* Updating the link for DevOps Roadmap to correct URL (https://roadmap.sh/docker) previously set to (https://roadmap.sh/best-practices)

* update

* update

* Updated text content in "Performance Optimization" topic (MongoDB Roadmap)
2024-05-11 01:40:00 +01:00
nikob-dev
0ec50a1ee4 Remove topic text (#5307)
Removing no-context spam at the bottom.
2024-05-11 01:38:25 +01:00
Davee
1d74d0b223 Fix typos (#5302) 2024-05-11 01:38:04 +01:00
Abhay Naik
7333f1357e JavaScript closure explanation (#5298) 2024-05-11 01:37:40 +01:00
Abhishek Santra
82ccd5c755 fix: broken link in "Express Full Guide"(#5259) (#5294) 2024-05-11 01:36:38 +01:00
Alex Marmolejo
577d7af7f8 fix: typo in fullstack chekcpoint (#5292) 2024-05-11 01:36:04 +01:00
Kamran Ahmed
ba7c0f6517 UI design on member detail page 2024-05-11 01:32:50 +01:00
Kamran Ahmed
8c55be23cc Update user progress 2024-05-11 01:27:20 +01:00
Arik Chakma
63ad6fe1e9 feat: team member details (#5598)
* fix: change `topicIds` to `topicTitles`

* fix: comma and gap

* wip: member details page

* fix: team member empty state

* feat: add pagination

* fix: add loading screen
2024-05-11 00:59:28 +01:00
Shizan Shaikh
fb7136e1b0 Update index.md of 'Printing output' in NodeJs Roadmap (#5287)
* Update index.md of 'Printing output' in NodeJs Roadmap

Update index.md of 'Printing output' in NodeJs Roadmap

* Update src/data/roadmaps/nodejs/content/106-nodejs-command-line-apps/101-printing-output/index.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 23:37:27 +01:00
Alex Marmolejo
e814eff7e2 fix: Adjusted line height (#5286)
* fix: Adjusted line height

* Adjusted bottom margin

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 23:35:40 +01:00
Kamran Ahmed
bb093764ba Add quarkus framework in java 2024-05-10 23:33:13 +01:00
taraferguson
1f5a601370 Fix dead links in prompt hacking (#5280)
* Update 100-style-modifiers.md

Fix 404 link error

* Update index.md

fix 404 error

* Update 100-prompt-injection.md

fix 404 error

* Update 103-defensive-measures.md

fix 404 error

* Update 104-offensive-measures.md

fix 404 error

* Update 100-style-modifiers.md

fix 404 error

* Update 101-quality-boosters.md

add link

* Update 102-weighted-terms.md

add link

* Update 103-deformed-generations.md

add link

* Update src/data/roadmaps/prompt-engineering/content/108-image-prompting/103-deformed-generations.md

* Update src/data/roadmaps/prompt-engineering/content/108-image-prompting/102-weighted-terms.md

* Update src/data/roadmaps/prompt-engineering/content/108-image-prompting/101-quality-boosters.md

* Update src/data/roadmaps/prompt-engineering/content/108-image-prompting/100-style-modifiers.md

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 23:02:14 +01:00
Peter Sarossy
389d431005 Add links to realtime databases (#5279) 2024-05-10 23:00:16 +01:00
Rushikesh Tarapure
d9d8d7891e Fix : typo in suggestion block (#5274)
Co-authored-by: Rushikesh Tarapure <rushikeshtarapure@gofynd.com>
2024-05-10 22:59:44 +01:00
omahs
18631f1a1a Fix broken link (#5263) 2024-05-10 22:58:40 +01:00
boffin-education
67d0f68eb7 Add resources for technical writer (#5189) 2024-05-10 22:24:58 +01:00
dev-aly3n
82de99973c fix: remove duplicate link in smart-contract (#5128) 2024-05-10 22:22:27 +01:00
dev-aly3n
973fbd9fc6 Fix broken URL (#5125)
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 22:22:17 +01:00
Sherkhan Azimov
45ab04af04 Fix broken links (#5120)
* fix: link in retry storm (performance antipatterns) section

* fix: link in geode pattern
2024-05-10 22:19:51 +01:00
Luiz Felipe dos Santos Pereira
4d35795899 Fix typos in SQL roadmap (#5112)
The original text misleads the reader. A column subquery shouldn't use the "=" operator, but the "in" operator.
2024-05-10 22:19:14 +01:00
sreyas
6335e51f30 Fix typo in rust roadmap (#5099)
Typo correction from 'Onwnership' to 'Ownership'
2024-05-10 22:17:59 +01:00
murrrda
f5ca535b70 Added Go class by Mat to Backend resources (#5084) 2024-05-10 22:16:50 +01:00
Sherkhan Azimov
6b5cf545df Fix broken links and typos (#5075)
* fix: links in communication section

* fix: typo
2024-05-10 22:16:26 +01:00
Selva Muthu Kumaran Boopalan
62a2b34b38 Add resource (#5068)
javascript-roadmap-hoisting - newvideo-link-added
2024-05-10 22:15:53 +01:00
Oscar T
b61ca66d29 fix(signup.astro): typo unnecessary word (#5060) 2024-05-10 22:15:25 +01:00
RibeiroLucas
0ba3e6e155 Add link to resource (#5046)
Refactoring Guru added to the computer science roadmap Design Patterns section.
2024-05-10 22:15:05 +01:00
Nayan Lonkar
d2a09427ed Remove invalid link from Java roadmap (#5025) 2024-05-10 22:13:02 +01:00
Caio Portugal
752a1d44d7 Add HTTP Caching article from mozilla.org (#5022) 2024-05-10 22:12:30 +01:00
Agustin Velez
8fd4a0bd60 Add links to rust roadmap (#5009)
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 22:11:43 +01:00
Mateus Sampaio
8d9605658f feat(roadmap): add new resource to backend roadmap (#4965) 2024-05-10 22:11:03 +01:00
Ali Ashkani Nia
c1fb58dab7 Fix ADL Participation for swap in 105-copy-swap.md (#4925) 2024-05-10 22:09:49 +01:00
Debakar Roy
7c5b49876a Add underscore for dunder methods. (#4920) 2024-05-10 22:09:23 +01:00
Ali Ashkani Nia
5368f9a16a Fix weak pointer details (#4915)
Clarified reference counting for `weak_ptr`s.
2024-05-10 22:09:11 +01:00
Shanelle Marasigan
15f06d1168 Add utility types resources (#4908)
Added a new list of links/resources
2024-05-10 22:05:07 +01:00
Blesy
7f0a5984f3 Add HTML resource link (#4881) 2024-05-10 22:04:12 +01:00
wj-mk
c0f5b00979 Added link to Loops in Dart (#4870)
It felt appropriate to add a link to Loops in Dart as loops are discussed in the preceding text.
2024-05-10 22:01:47 +01:00
Juan Gerardo Eulufi Salazar
61883506b0 Added Information on Angular Interpolation and Resource References (#4852) 2024-05-10 21:59:29 +01:00
Javier Grau
e83538e510 Add description of what is ECMA (#4812)
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 21:57:54 +01:00
tombohub
e7c024032a Add a pre-order traversal link (#4805) 2024-05-10 21:56:53 +01:00
Selva Muthu Kumaran Boopalan
f114657607 roadmap-prompt-engineering-llm-intro (#4782)
roadmap-prompt-engineering-llm-intro-new link
fixes: #4754

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 21:56:30 +01:00
Marc Thayer
377cbbe8c8 QA - Fix title of Check My Links tool and improve its description (#4742)
* Update grammar in 103-check-my-links.md

* Fixed capitalization in extension name.
2024-05-10 21:53:17 +01:00
Gustavo Corrado
1834703b1e Fx typo in rust roadmap (#4726)
Fixed typo from "Onwership" to "Ownership"
2024-05-10 21:51:02 +01:00
Sadman Sobhan
a75b6b667b Add resource link for FTP Protocol (#4714)
* add spring boot content

* Update content/roadmaps/110-java/content/103-java-web-frameworks/101-spring-boot.md

* Add Java Collection Framework

* Update content/roadmaps/110-java/content/101-java-advanced-topics/102-collection-framework.md

* Add resource link for FTP Protocol

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 21:50:36 +01:00
Mohammed Alaiady
ec3ecb832a Change "OCI" to "OSI" (#4681)
There was a typo error for misspelling "OSI" word.

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 21:48:25 +01:00
Kamran Ahmed
482b9a291d Fix issues in roadmaps 2024-05-10 21:47:17 +01:00
Paul Wright
0fe8bfe0d3 Replace python 2 with 3 in resources (#4639) 2024-05-10 21:45:32 +01:00
Marco Rubin
914acd201e Fix typo (#4584) 2024-05-10 21:42:45 +01:00
Selva Muthu Kumaran Boopalan
3b88eba110 Add git learning resource (#4562)
backend-roadmap-git-new-link
introduction to git : #4561
2024-05-10 21:42:20 +01:00
Miguel Gargallo
258f800f97 Replace Tailwind with TailwindCSS #4526 (#4529) 2024-05-10 21:40:56 +01:00
Codeguage
71bfe4f03c Added new resources to List Comprehensions (#3580) 2024-05-10 21:35:59 +01:00
Codeguage
d4e5bae03b Added new resource for refs (#3574) 2024-05-10 21:35:36 +01:00
Codeguage
78503c8990 Added new resource (#3573) 2024-05-10 21:35:22 +01:00
Amin Rezaei
cbebb18418 Fix Javascript logical operators Resources (#3544)
Remove duplicate MDN source
2024-05-10 21:33:10 +01:00
Habibov Ulug'bek
9f5081a3a4 Replace deprecated URL (#3524) 2024-05-10 21:30:56 +01:00
Kamran Ahmed
a76413fd33 Fix broken build 2024-05-10 21:17:32 +01:00
Kamran Ahmed
c83a91eec4 Close stale issues script 2024-05-10 21:14:19 +01:00
Kamran Ahmed
7c68830b45 Add a script to auto-label issues 2024-05-10 21:14:19 +01:00
dsh
fbecabf3fa Merge pull request #5313 from AbrorPatidinov/patch-1
Update C++ snippet to correct indentation
2024-05-10 21:03:09 +01:00
dsh
0476b725f4 Merge pull request #5314 from AbrorPatidinov/patch-2
Correct C++ indentation standard
2024-05-10 21:01:56 +01:00
Kamran Ahmed
1733371a90 Make it deploy only when changes are in src or public folders 2024-05-10 21:00:05 +01:00
Kamran Ahmed
d0766a3865 Add labels to topic change suggestion issue 2024-05-10 20:58:13 +01:00
dsh
d2715b5978 Merge pull request #5322 from akarsanth/patch-2
Improve 102-typeof-operator.md definition
2024-05-10 20:55:47 +01:00
marvin
dd053ac706 Update 109-friction.md (#5386)
IB diploma vid discussing friction basics
2024-05-10 20:48:50 +01:00
Jean-François Greffier
04336fedae Add official Playwright get started videos (#5580)
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2024-05-10 19:18:59 +01:00
Jean-François Greffier
0bc9ae66ed chore: harmonize Playwright tutorial link (#5581) 2024-05-10 19:18:15 +01:00
Kamran Ahmed
622766fea3 Fix details for game ai 2024-05-10 19:15:16 +01:00
bitblocksplicer
bd76e760d4 Fix Typo in Shell Scripting Literal Description (#5613)
Fixed a typo in the definition of boolean literals in shell scripts that could be misleading
2024-05-10 19:12:09 +01:00
marvin
540d5030a4 Adding videos and a slightly altered description of arrays (#5637)
To give credit where credit is due, the description change is from an issue (#5600) I picked up by GitHub user 'andremarko';

https://github.com/kamranahmedse/developer-roadmap/issues/5600

im going to try to provide more videos for all languages across the data structures and algorithms flowchart
2024-05-10 19:10:51 +01:00
Kamran Ahmed
d9466717a7 Change google container registry to artifact registry 2024-05-10 18:50:46 +01:00
Kamran Ahmed
edbc22e02f Close empty issues 2024-05-10 16:44:14 +01:00
Kamran Ahmed
6c6f7021d1 Add github action to close PRs with feedback and no action 2024-05-10 16:31:38 +01:00
Utkarsh Tiwari
8862239a11 Fix #5533 Software Architect Roadmap (#5605)
Updated SAP ERP spelling
2024-05-10 16:27:34 +01:00
dsh
ca2088f553 Add go schedular content and roadmap node (#5635) 2024-05-10 15:30:00 +01:00
Rachit Agrawal
67edf2ce4d Add Video Lecture on OSI Model to CyberSecurity (#5392)
Add OSI lecture video to OSI content.
2024-05-10 14:59:33 +01:00
dsh
9857a0b981 Merge pull request #5332 from bobralks/patch-1
Add Bun as a task runner
2024-05-10 14:38:17 +01:00
dsh
d1429efaa8 Merge pull request #5626 from Edlan01/patch-1
Update backend - adjusted copy
2024-05-10 14:10:13 +01:00
dsh
223b6ae096 Merge pull request #5627 from chefemaster/patch-1
Add Link of Effective Go about functions
2024-05-10 14:06:46 +01:00
Eric
e2e40d1fdc Add w3school content (#4807)
Added W3schools resource to learn react with create react app. w3schools does a pretty great job at explaining stuff.
2024-05-10 14:02:05 +01:00
dsh
73e117e693 Merge pull request #5579 from includeSimon/patch-1
Fix typo in cocpy
2024-05-10 13:01:30 +01:00
dsh
a587503160 Merge pull request #5460 from JDeepD/patch-1
Replace article link
2024-05-10 12:59:46 +01:00
dsh
ca9aabaa63 Merge pull request #5455 from FaiqMahmood/patch-1
Add interactive shell tutorial
2024-05-10 12:52:53 +01:00
dsh
3e4f5fbfdf Merge pull request #5381 from pronob1010/patch-1
Add caching analogies to db caching copy
2024-05-10 12:33:12 +01:00
dsh
ab34fe725c Merge pull request #5377 from olawuwo/patch-1
Add SQL identifier to enable highlighting in snippet
2024-05-10 12:31:10 +01:00
dsh
70f6fcc722 Merge pull request #5352 from Abderrahmane07/patch-3
Fix typo in 103-lazy-eager-explicit-loading.md
2024-05-10 12:26:34 +01:00
dsh
10287bd9a5 Merge pull request #5582 from shto/patch-1
Fix type in copy
2024-05-10 12:07:43 +01:00
dsh
91bd69f9d1 Merge pull request #5211 from rahulbaghel007/addingZeroCostAbstractionToRust
expand rust zero cost abstractions content
2024-05-10 11:49:14 +01:00
dsh
d2de4eac41 Merge pull request #5155 from iribama/patch-1
Add developer focussed blogging platforms
2024-05-10 11:40:48 +01:00
dsh
cf206240cd Merge pull request #5149 from rishabhv2003/patch-2
Add int and std clarifications
2024-05-10 11:35:47 +01:00
dsh
09043deecc Merge pull request #5148 from rishabhv2003/patch-1
Add license disclaimer to CLion IDE
2024-05-10 11:30:30 +01:00
dsh
d686ed208f Merge pull request #5146 from Basliel25/patch-1
Add third OCI specification
2024-05-10 11:20:37 +01:00
dsh
a607a23abb Merge pull request #5145 from Vitruvius21/patch-1
Update 114-cli-apps.md rm redundant "take"
2024-05-10 11:18:40 +01:00
dsh
0603ec56ce Merge pull request #5118 from cyrionp/patch-1
Update 101-singlar-core.md to .NET 8.0
2024-05-10 11:06:47 +01:00
dsh
6de052df6b Merge pull request #5114 from MaharshiChoksi/patch-1
Add Natural Join as an example of the types of join
2024-05-10 11:05:45 +01:00
dsh
588440dcc1 Merge pull request #5095 from MarcinKozak005/patch-3
Remove duplicated link in 104-firewall.md
2024-05-10 10:57:27 +01:00
dsh
794614f6e0 Merge pull request #5092 from selvamuthukumaran1/kubernetes-roadmap
Remove inactive content link
2024-05-10 10:56:47 +01:00
dsh
f85b6f9644 Merge pull request #5072 from kamalogudah/patch-1
Fix typo in content heading
2024-05-10 10:50:32 +01:00
dsh
74629f47d9 Merge pull request #5067 from KishoreAnanth18/patch-1
Add link to AWS documentation for CPU Credits
2024-05-10 10:49:25 +01:00
dsh
d60fc67da7 Merge pull request #5065 from jafzak/patch-1
https://assets.gradlehero.com/get-going-with-gradle/get-going-with-gradle-book.pdf
2024-05-10 10:47:28 +01:00
dsh
16a2a48a88 Merge pull request #5064 from jafzak/patch-2
Add android tutorial article
2024-05-10 10:42:49 +01:00
dsh
840bb4e31a Merge pull request #5057 from timofeevAV/patch-1
Remove duplication of TouchableHighlight
2024-05-10 10:33:47 +01:00
dsh
f1212118d8 Merge pull request #5038 from Ahmad-Alsaleh/patch-1
fix grammatical error in copy
2024-05-10 10:10:56 +01:00
dsh
8cb38d3c3f Merge pull request #5031 from theMuhammadKhalid/patch-1
Add react native storage copy
2024-05-10 09:52:49 +01:00
dsh
aec54a4565 Merge pull request #5008 from TaviotBaptiste/patch-2
Add depends_on to dockerfile example
2024-05-10 09:43:56 +01:00
mufasa
88b4344a90 Add Rust enum example (#4962)
Add Rust enum example
2024-05-10 09:35:17 +01:00
dsh
476400a02e add rust video to rust intro section (#5634) 2024-05-10 09:27:23 +01:00
Deepak Mardi
bb9a911e59 Added HATEOAS resources (#5438)
Added Resource
2024-05-09 22:36:13 +01:00
Deepak Mardi
fb77e54d54 Update broken React Router resource link (#5444)
Update broken React Router resource link
2024-05-09 22:34:24 +01:00
Deepak Mardi
a4d699b3d7 Fix broken resources in javascript and nodejs Page (#5445)
Updated broken link in javascript and nodejs roadmap for settimeout Explained in 5 minutes!
2024-05-09 22:32:17 +01:00
Deepak Mardi
ec31ad339e fixes : Updated MonogDB > Collection and Methods > Validate (#5466)
removed `background` from Mongodb snippet.
2024-05-09 22:29:32 +01:00
dsh
dfa91cd085 Merge pull request #5632 from BeardedOwl1357/patch-1
Fixed link display of 101-why-rust.md
2024-05-09 22:25:01 +01:00
Sanchay Joshi
424f1d061a Update 101-why-rust.md
Unnecessary tabs makes markdown render them as "code" instead of links
2024-05-10 02:16:58 +05:30
dsh
bc52c0cfbe Merge pull request #4953 from Tiago-Vier-Preto/patch-1
Improve readability of 'Why us typescript' section
2024-05-09 20:35:39 +01:00
dsh
2d3ca43e01 Merge pull request #4901 from mehmetumutmutlu/patch-3
Capitalized 'French'
2024-05-09 19:56:21 +01:00
dsh
0bc4a11fc5 Merge pull request #4899 from mehmetumutmutlu/patch-1
Correct LLM abbreviation
2024-05-09 19:54:49 +01:00
dsh
dc63c2e9d4 Merge pull request #4876 from nsk6704/patch-1
Improve readability of 'What is technical writing' section
2024-05-09 19:49:36 +01:00
dsh
46e56ac315 Merge pull request #4834 from anavalo/patch-1
Update pagespeed insights url version
2024-05-09 19:43:49 +01:00
dsh
1903674147 Merge pull request #4816 from AliMaazKhan/patch-1
Add youtube video link on 'Vectors'
2024-05-09 19:32:17 +01:00
dsh
79023f35cb Merge pull request #4794 from ethan-butler-alight/patch-1
Fix spelling error on 100-basic-prompting.md
2024-05-09 16:36:12 +01:00
dsh
615188cba6 Merge pull request #4784 from iMuhammad3/patch-1
Update enable-compression.md
2024-05-09 16:35:16 +01:00
dsh
437973a2ba Merge pull request #4774 from kan1shq/patch-1
Add video content to the 'why rust' section
2024-05-09 16:29:59 +01:00
dsh
cd68a12b71 Merge pull request #4951 from lazydoug/patch-1
Update 100-primitive-types.md
2024-05-09 15:45:07 +01:00
dsh
d34525776d Merge pull request #5628 from kamranahmedse/dansholds/fix-appdynamics-node
fix incorrect path in JSON for appdynamics node
2024-05-09 15:38:15 +01:00
Dan Holdsworth
cb4b9c82c8 fix incorrect path in JSON for appdynamics node 2024-05-09 15:36:10 +01:00
dsh
f303b466c9 Merge pull request #4769 from collegedude9300/patch-7
Update 103-unity-3d.md
2024-05-09 15:25:38 +01:00
dsh
93ff9402b1 Merge pull request #4762 from PetroKabina/patch-1
Update index.md
2024-05-09 15:20:29 +01:00
Jeferson Martins Bruno
27c5626ef6 Add Link of Effective Go about functions 2024-05-09 10:46:44 -03:00
dsh
636192af87 Merge pull request #4749 from rishilahoti/patch-1
Update next.js youtube video link to latest
2024-05-09 14:25:18 +01:00
dsh
c84694b3bb Merge pull request #4739 from Nozarno/patch-1
Add new design pattern link
2024-05-09 14:14:24 +01:00
dsh
e825f47d0a Merge pull request #4736 from bilalrahim/patch-1
Update 101-posa-patterns.md
2024-05-09 14:08:10 +01:00
Ed Lan
fcc88b389e Update backend - adjusted copy
Adjusted copy for the Q "What does a Backend Developer do?"
2024-05-09 14:44:54 +02:00
dsh
22bd61580b Merge pull request #5625 from kamranahmedse/dansholds/fix-vulkan-node-typo
fixed vulkan typo in advanced render topic
2024-05-09 13:38:00 +01:00
Dan Holdsworth
eab0bf9494 fixed vulkan typo in advanced render topic 2024-05-09 13:36:30 +01:00
dsh
41e6682f66 Merge pull request #4696 from whitezom7/patch-1
Fix typo of Vulcan to Vulkan
2024-05-09 13:32:39 +01:00
Kamran Ahmed
aabc8e12b0 Add backend project ideas guide 2024-05-09 12:15:44 +01:00
dsh
a2487aeea8 Merge pull request #3507 from bhavuu/patch-1
Add official JavaScript documentation link
2024-05-09 09:56:47 +01:00
dsh
1e04a6cc0a Merge pull request #5624 from kamranahmedse/dansholds/4197-typo-in-input-section-of-api-security-best-practices
Fix typo in input section of API Security Best Practice Roadmap
2024-05-09 09:24:17 +01:00
Dan Holdsworth
8ed874d4ea fix typo in input section of API Security Best Practice Roadmap 2024-05-09 09:20:19 +01:00
Kamran Ahmed
2117fda50f Fix duplicate orientation/curve nodes 2024-05-08 16:56:54 +01:00
Kamran Ahmed
da1a5f6506 Change activity title 2024-05-08 11:59:59 +01:00
dsh
803f87de38 Merge pull request #5618 from kamranahmedse/dansholds/5400-removed-article-backend
Removed empty AWS Content Link
2024-05-08 11:49:28 +01:00
dsh
67948002fd Merge pull request #5619 from kamranahmedse/dansholds/4330-remove-the-tensorflow-content-from-the-c++-roadmap
Removed Python Code from C++ Content Example
2024-05-08 11:49:05 +01:00
dsh
e76617c9a9 Removed Python Code from C++ Content Example
The Tensorflow node in the C++ Roadmap used Python code as examples, I have removed this.
2024-05-08 11:39:54 +01:00
dsh
cc4fd82fef Merge pull request #4598 from hernanes338/python-roadmap-lambdas
Fix Python Lambda Functions hyperlink
2024-05-08 11:24:22 +01:00
dsh
05d379da08 Merge pull request #4923 from sonvir249/issue-4740
issue-4740: Updated the dead oracle network link.
2024-05-08 11:19:01 +01:00
dsh
8ab7f2c8b3 Merge pull request #5435 from belikedeep/deepakmardii/fix-resource-unavailable
Blockchain Rust resource updated
2024-05-08 10:19:37 +01:00
dsh
a1d0129f36 Removed casino link from Image Optimization Content (#5616)
A previously useful linke (image.guide) is now linking to a casino website.

I have removed this link.
2024-05-08 10:18:25 +01:00
dsh
0c54816b3f Removed empty AWS Content Link
The linked content now results in a 404.
2024-05-08 10:15:45 +01:00
Arik Chakma
e1c35d299d fix: update activity stream design (#5615) 2024-05-08 01:41:45 +01:00
Arik Chakma
89c6b36090 fix: activity word spacing (#5614) 2024-05-08 00:07:23 +01:00
Arik Chakma
cd35c77df1 fix: change topicIds to topicTitles (#5588)
* fix: change `topicIds` to `topicTitles`

* fix: comma and gap
2024-05-07 23:19:26 +01:00
Andrei Patru
c6648655cf Update 100-permissions.md
fix incorrect sentence
2024-05-01 17:12:27 +02:00
Pirlog Simon
d139df6a2c Update index.md
fixed spelling from "use" to "used"
2024-05-01 16:27:18 +03:00
Jaydeep Das
235567400e Update 100-horizontal-vs-vertical-scaling.md
The previous URL redirects to a whole different website which has nothing related to the topic.
2024-04-03 19:41:10 +05:30
Faiq Mahmood
e5e03c76a3 Update 100-bash-scripting.md
Added link to an interactive shell scripting tutorial
2024-04-02 23:20:33 +02:00
Deepak Mardi
58960eb6d4 update 2024-04-01 01:54:27 +05:30
Deepak Mardi
675f90adc6 Updated resource URL from figment.io(resource deleted) to Near docs(tutorial in rust) 2024-03-31 23:41:38 +05:30
Deepak Mardi
dbdfb2226b Keyboard Navigation only on vissible elements 2024-03-31 23:05:15 +05:30
Deepak Mardi
d4eef5ecd0 Fixed typo at Lazy Eager Explicit Loading topic 2024-03-31 22:47:03 +05:30
Deepak Mardi
ecf904d99f Merge pull request #1 from deepakmardii/deepakmardii/fix-docker-link
Updating the link for DevOps Roadmap to correct URL (https://roadmap.…
2024-03-31 22:31:52 +05:30
Deepak Mardi
5d43f4b1e6 Updating the link for DevOps Roadmap to correct URL (https://roadmap.sh/docker) previously set to (https://roadmap.sh/best-practices) 2024-03-31 22:21:41 +05:30
Pronob Mozumder
f1874c7637 Update 103-database-caching.md
Added a simplified explanation of database caching using analogies for easier understanding.
2024-03-20 18:27:14 +06:00
Tai
78be705f70 Update 103-avg.md
Added SQL language identifier to enable syntax highlighting
2024-03-19 19:43:36 +00:00
Abderrahmane Larchi
00df91f30d Typo - Update 103-lazy-eager-explicit-loading.md 2024-03-15 18:01:52 +01:00
Bob Ralks
64070616c0 Update index.md
add bun for running package.json scripts
2024-03-12 01:37:07 -04:00
Aakarshan Thapa
99e15b5a9b Improve 102-typeof-operator.md definition
Improved the definition of typeof operator.
2024-03-10 16:01:41 -04:00
Artorias - The Abyss Walker
f33af1dcf3 Update index.md
Just adjusted a space, now it's more readable
2024-03-08 23:14:04 +05:00
Artorias - The Abyss Walker
2a54ebb091 Update index.md 2024-03-08 22:55:49 +05:00
Rahul Baghel
b5ce2a9d36 Update 102-memory-safety.md
Add missing content of Zero Cost Abstraction in Rust
2024-02-19 11:34:22 +05:30
Rejoice Anodo
0379edc684 Update 106-blogging-platforms.md 2024-02-09 18:29:40 +01:00
Rishabh Verma
d781568f93 Update 102-first-program.md
Added additional information about the functions and return values about the program.
2024-02-06 19:58:41 +05:45
Rishabh Verma
cc95998339 Update 101-code-editors.md
A minor change to inform new users that this IDE is not pre unlike others.
2024-02-06 19:48:41 +05:45
Basliel25
1b364ae3de Propose to add content to 103-docker-and-oci.md
The OCI-specification has three core specifications while on the description written only two are mentioned. 

I added the *Distribution Specification (distribution-spec)*.

According to the website, the distro-spec defines a standardized API protocol for distributing container images and other content. It is primarly designed to ensure interoperability and consistency across different container registries and tools, regardless of their specific implementation.

I attach below links to the website of OCI and the github repo
- [https://github.com/opencontainers/distribution-spec](On the github repo of the OCI) 
- [https://opencontainers.org/about/overview/](Website of the OCI)
2024-02-06 12:22:42 +01:00
ᚷᛁᛟᚱᚷᛁ ᛒᚨᛚᚨᚲᚻᚨᛞᛉᛖ
f1a4d8d38b Update 114-cli-apps.md rm redundant "take" 2024-02-06 14:49:08 +04:00
Abdulkadir Durmaz
1b333f774a Update 101-singlar-core.md to .NET 8.0 2024-02-01 10:56:12 +03:00
Maharshi Choksi
ccbaa1fe6d Update index.md
Added a kind of join (Natural Join).
2024-01-30 17:39:45 -07:00
Marcin Kozak
78bb3155e0 Remove duplicated link in 104-firewall.md 2024-01-26 17:59:20 +01:00
Selva Muthu Kumaran Boopalan
89bad8cb11 Update 101-choosing-a-managed-provider.md 2024-01-25 22:31:10 +05:30
KISHORE ANANTH N
f8d8776667 Update 101-cpu-credits.md
Formatted the link
2024-01-23 11:05:42 +05:30
Paul Oguda
36ae1b521b Update index.md
Fix typo
2024-01-22 13:03:40 +03:00
KISHORE ANANTH N
48187393a8 Update 101-cpu-credits.md
Added a reference link.
2024-01-22 10:05:37 +05:30
Jafar Zakariya
a38961ad84 Update 105-hello-world-app.md
Added resource for creating first android app
2024-01-21 21:00:34 +01:00
Jafar Zakariya
1d6957d263 Update 104-using-gradle.md
Added PDF resource for gradle
2024-01-21 20:57:39 +01:00
Timofeev Artyom
53c9279049 Update 100-touchables.md 2024-01-20 00:38:56 +05:00
Ahmad Alsaleh
c2458fff8e Update 100-builtin-modules.md
Fixed a grammatical mistake
2024-01-15 22:55:28 +04:00
Muhammad Khalid
77fbf8a745 Update 102-storage.md 2024-01-14 23:04:12 +05:00
Baptiste TAVIOT
d90cd01fab Update 101-docker-compose.md
update : add depends_on
2024-01-09 15:02:59 +01:00
Tiago Vier
d5772901d9 Update 101-why-use-typescript.md 2023-12-31 11:42:48 -03:00
Osarodion Douglas Idumwonyi
8984d9e166 Update 100-primitive-types.md
This update highlights the distinction between primitive data types and non-primitives based on the values they hold and the properties and methods they possess.
2023-12-31 10:46:03 +01:00
sonvir249
b633702747 issue-4740: Updated the dead oracle netwrok link. 2023-12-26 18:21:13 +05:30
Umut
ea2884ed60 Update index.md
Capitalized the "French" word in the first example chunk.
2023-12-22 22:59:14 +02:00
Umut
c95919ba7f Update 100-what-are-llms.md
The definition of LLM was changed from Language Learning Models to Large Language Models.
2023-12-22 22:19:48 +02:00
Saketh Kashyap Nagendra
c8dc730fb7 Update 101-what-technical-writing.md
Added 2 points, made the layout easier to read
2023-12-18 06:07:31 +05:30
Tasos Tsournos
45462c49da Update use-non-blocking-javascript.md
v4 is deprecated
2023-12-07 16:18:13 +02:00
AliMaazKhan
a191948675 Update 101-vector.md
Added a video on the introduction to "Vectors" for game development".
2023-12-03 15:40:22 +05:30
Ethan Butler
8154a398a8 Fix spelling error on 100-basic-prompting.md 2023-11-29 20:34:51 -05:00
Muhammad Auwal
ef353e1c8f Update enable-compression.md
Fix grammar error
2023-11-28 18:58:57 +01:00
kan1shq
aaacc41c82 Update 101-why-rust.md
added links to beginner friendly videos on choosing rust
2023-11-27 13:11:48 +05:30
collegedude9300
863758b49f Update 103-unity-3d.md 2023-11-26 15:18:16 -08:00
PetroKabina
5fe66a1e4f Update index.md
ls command added to `docker container` and `docker image` to be more specific
2023-11-25 12:07:17 +02:00
Rishi
7e5c0a5716 Update 101-next-js.md
Updated to latest video of JextJS from freecodecamp
2023-11-22 22:22:14 +05:30
Nozarno
41d182e987 Update index.md
Add resource site https://refactoring.guru/
2023-11-21 23:33:38 +01:00
Bilal Rahim
bd553fa630 Update 101-posa-patterns.md
The correct abbreviation for POSA is Pattern-Oriented Software Architecture not Patterns of Scalable and Adaptable Software Architecture.

Thanks
2023-11-21 09:16:32 +05:00
Taylor
d4f48a3ebd Update and rename 101-vulcan-ray-tracing.md to 101-vulkan-ray-tracing.md
Typo in Vulkan
2023-11-14 22:37:27 +01:00
hernanes338
b8fe4e2b35 Fix Python Lambda Functions hyperlink 2023-10-18 15:22:00 +02:00
bhavuu
7f14e99fbf Update 105-javascript.md
Added official Javascript documentation link for it to learn in depth.
2023-02-28 16:11:19 +05:30
7040 changed files with 270115 additions and 325410 deletions

View File

@@ -3,6 +3,6 @@
"enabled": false
},
"_variables": {
"lastUpdateCheck": 1714413381505
"lastUpdateCheck": 1721257136269
}
}

View File

@@ -1,6 +1,6 @@
name: "✍️ Suggest Changes"
name: "✍️ Missing or Deprecated Roadmap Topics"
description: Help us improve the roadmaps by suggesting changes
labels: [suggestion]
labels: [topic-change]
assignees: []
body:
- type: markdown

50
.github/workflows/close-feedback-pr.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: Close PRs with Feedback
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
close-pr:
runs-on: ubuntu-latest
steps:
- name: Close PR if it has label "feedback left" and no changes in 7 days
uses: actions/github-script@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: pullRequests } = await github.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
base: 'master',
});
for (const pullRequest of pullRequests) {
const { data: labels } = await github.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
});
const feedbackLabel = labels.find((label) => label.name === 'feedback left');
if (feedbackLabel) {
const lastUpdated = new Date(pullRequest.updated_at);
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
if (lastUpdated < sevenDaysAgo) {
await github.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
body: 'Closing this PR because there has been no activity for the past 7 days. Feel free to reopen if you have any feedback.',
});
await github.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullRequest.number,
state: 'closed',
});
}
}
}

View File

@@ -1,10 +1,6 @@
name: Clears Cloudfront Cache
on:
# Allow manual Run
workflow_dispatch:
# Run at midnight utc
schedule:
- cron: '0 0 * * *'
jobs:
aws_costs:
runs-on: ubuntu-latest

View File

@@ -1,9 +1,6 @@
name: Deploy to EC2
on:
workflow_dispatch: # allow manual run
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
@@ -59,4 +56,17 @@ jobs:
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
cd /var/www/roadmap.sh
sudo pm2 restart web-roadmap
sudo pm2 restart web-roadmap
# --------------------
# Clear cloudfront cache
# --------------------
- name: Clear Cloudfront Caching
run: |
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GH_PAT }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \
-d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront", "is_verbose": false } }'

38
.github/workflows/label-issue.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Label Issue
on:
issues:
types: [ opened, edited ]
jobs:
label-topic-change-issue:
runs-on: ubuntu-latest
steps:
- name: Add roadmap slug to issue as label
uses: actions/github-script@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issue = context.payload.issue;
const roadmapUrl = issue.body.match(/https?:\/\/roadmap.sh\/[^ ]+/);
// if the issue is labeled as a topic-change, add the roadmap slug as a label
if (issue.labels.some(label => label.name === 'topic-change')) {
if (roadmapUrl) {
const roadmapSlug = new URL(roadmapUrl[0]).pathname.replace(/\//, '');
github.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [roadmapSlug]
});
}
// Close the issue if it has no roadmap URL
if (!roadmapUrl) {
github.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});
}
}

2
.gitignore vendored
View File

@@ -31,3 +31,5 @@ tests-examples
/editor/*
!/editor/readonly-editor.tsx
!/editor/renderer/renderer.ts
!/editor/renderer/index.tsx

View File

@@ -11,6 +11,9 @@ import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
site: 'https://roadmap.sh/',
experimental: {
rewriting: true,
},
markdown: {
shikiConfig: {
theme: 'dracula',

View File

@@ -2,40 +2,97 @@
First of all thank you for considering to contribute. Please look at the details below:
- [Contribution](#contribution)
- [New Roadmaps](#new-roadmaps)
- [Existing Roadmaps](#existing-roadmaps)
- [Adding Content](#adding-content)
- [Guidelines](#guidelines)
- [New Roadmaps](#new-roadmaps)
- [Existing Roadmaps](#existing-roadmaps)
- [Adding Content](#adding-content)
- [Guidelines](#guidelines)
## New Roadmaps
For new roadmaps, submit a roadmap by providing [a textual roadmap similar to this roadmap](https://gist.github.com/kamranahmedse/98758d2c73799b3a6ce17385e4c548a5) in an issue.
For new roadmaps, you can either:
- Submit a roadmap by providing [a textual roadmap similar to this roadmap](https://gist.github.com/kamranahmedse/98758d2c73799b3a6ce17385e4c548a5) in an [issue](https://github.com/kamranahmedse/developer-roadmap/issues).
- Create an interactive roadmap yourself using [our roadmap editor](https://draw.roadmap.sh/) & submit the link to that roadmap in an [issue](https://github.com/kamranahmedse/developer-roadmap/issues).
## Existing Roadmaps
For the existing roadmaps, please follow the details listed for the nature of contribution:
- **Fixing Typos** — Make your changes in the [roadmap JSON file](https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/roadmaps)
- **Adding or Removing Nodes** — Please open an issue with your suggestion.
- **Fixing Typos** — Make your changes in the [roadmap JSON file](https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/roadmaps) and submit a [PR](https://github.com/kamranahmedse/developer-roadmap/pulls).
- **Adding or Removing Nodes** — Please open an [issue](https://github.com/kamranahmedse/developer-roadmap/issues) with your suggestion.
**Note:** Please note that our goal is not to have the biggest list of items. Our goal is to list items or skills most relevant today.
**Note:** Please note that our goal is <strong>not to have the biggest list of items</strong>. Our goal is to list items or skills most relevant today.
## Adding Content
Find [the content directory inside the relevant roadmap](https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/roadmaps). Please keep the following guidelines in mind when submitting content:
- Content must be in English.
- Put a brief description about the topic on top of the file and the a list of links below with each link having title of the URL.
- Maximum of 8 links per topic.
- Follow the below style guide for content.
### How To Structure Content
Please adhere to the following style when adding content to a topic:
```
# Topic Title
(Content)
Visit the following resources to learn more:
- [@type@Description of link](Link)
```
`@type@` must be one of the following and describes the type of content you are adding:
- `@official@`
- `@opensource@`
- `@article@`
- `@course@`
- `@podcast@`
- `@video@`
It's important to add a valid type, this will help us categorize the content and display it properly on the roadmap.
## Guidelines
- <p><strong>Please don't use the project for self-promotion!</strong><br />
We believe this project is a valuable asset to the developer community and it includes numerous helpful resources. We kindly ask you to avoid submitting pull requests for the sole purpose of self-promotion. We appreciate contributions that genuinely add value, such as guides from maintainers of well-known frameworks, and will consider accepting these even if they're self authored. Thank you for your understanding and cooperation!
- <p><strong>Adding everything available out there is not the goal!</strong><br />
The roadmaps represent the skillset most valuable today, i.e., if you were to enter any of the listed fields today, what would you learn?! There might be things that are of-course being used today but prioritize the things that are most in demand today, e.g., agreed that lots of people are using angular.js today but you wouldn't want to learn that instead of React, Angular, or Vue. Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included.</p>
The roadmaps represent the skillset most valuable today, i.e., if you were to enter any of the listed fields today, what would you learn? There might be things that are of-course being used today but prioritize the things that are most in demand today, e.g., agreed that lots of people are using angular.js today but you wouldn't want to learn that instead of React, Angular, or Vue. Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included.</p>
- <p><strong>Do not add things you have not evaluated personally!</strong><br />
Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included. Have you read this book? Can you give a short article?</p>
- <p><strong>Create a Single PR for Content Additions</strong></p>
If you are planning to contribute by adding content to the roadmaps, I recommend you to clone the repository, add content to the [content directory of the roadmap](./src/data/roadmaps/) and create a single PR to make it easier for me to review and merge the PR.
- Write meaningful commit messages
- Look at the existing issues/pull requests before opening new ones
- <p><strong>Write meaningful commit messages</strong><br >
Meaningful commit messages help speed up the review process as well as help other contributors in gaining a good overview of the repositories commit history without having to dive into every commit.
</p>
- <p><strong>Look at the existing issues/pull requests before opening new ones</strong></p>
### Good vs Not So Good Contributions
<strong>Good</strong>
- New Roadmaps.
- Engaging, fresh content links.
- Typos and grammatical fixes.
- Content copy in topics that do not have any (or minimal copy exists).
<strong>Not So Good</strong>
- Adding whitespace that doesn't add to the readability of the content.
- Rewriting content in a way that doesn't add any value.
- Non-English content.
- PR's that don't follow our style guide, have no description and a default title.
- Links to your own blog articles.

14
editor/renderer/index.tsx Normal file
View File

@@ -0,0 +1,14 @@
export function Renderer(props: any) {
return (
<div className="fixed bottom-0 left-0 right-0 top-0 z-[9999] border bg-white p-5 text-black">
<h2 className="mb-2 text-xl font-semibold">Private Component</h2>
<p className="mb-4">
Renderer is a private component. If you are a collaborator and have
access to it. Run the following command:
</p>
<code className="mt-5 rounded-md bg-gray-800 p-2 text-white">
npm run generate-renderer
</code>
</div>
);
}

View File

@@ -0,0 +1,5 @@
export function renderFlowJSON(data: any, options?: any) {
console.warn("renderFlowJSON is not implemented");
console.warn("run the following command to generate the renderer:");
console.warn("> npm run generate-renderer");
}

12019
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,30 +9,36 @@
"build": "astro build",
"preview": "astro preview",
"format": "prettier --write .",
"gh-labels": "./scripts/create-roadmap-labels.sh",
"astro": "astro",
"deploy": "NODE_DEBUG=gh-pages gh-pages -d dist -t",
"upgrade": "ncu -u",
"roadmap-links": "node scripts/roadmap-links.cjs",
"roadmap-dirs": "node scripts/roadmap-dirs.cjs",
"roadmap-assets": "tsx scripts/editor-roadmap-assets.ts",
"editor-roadmap-dirs": "tsx scripts/editor-roadmap-dirs.ts",
"editor-roadmap-content": "tsx scripts/editor-roadmap-content.ts",
"roadmap-content": "node scripts/roadmap-content.cjs",
"generate-renderer": "sh scripts/generate-renderer.sh",
"best-practice-dirs": "node scripts/best-practice-dirs.cjs",
"best-practice-content": "node scripts/best-practice-content.cjs",
"generate:og": "node ./scripts/generate-og-images.mjs",
"warm:urls": "sh ./scripts/warm-urls.sh https://roadmap.sh/sitemap-0.xml",
"compress:images": "tsx ./scripts/compress-images.ts",
"test:e2e": "playwright test"
},
"dependencies": {
"@astrojs/node": "^8.2.5",
"@astrojs/react": "^3.3.1",
"@astrojs/sitemap": "^3.1.4",
"@astrojs/node": "^8.3.2",
"@astrojs/react": "^3.6.0",
"@astrojs/sitemap": "^3.1.6",
"@astrojs/tailwind": "^5.1.0",
"@fingerprintjs/fingerprintjs": "^4.3.0",
"@fingerprintjs/fingerprintjs": "^4.4.3",
"@nanostores/react": "^0.7.2",
"@napi-rs/image": "^1.9.2",
"@resvg/resvg-js": "^2.6.2",
"@types/react": "^18.3.1",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"astro": "^4.7.0",
"astro": "^4.11.5",
"clsx": "^2.1.1",
"dayjs": "^1.11.11",
"dom-to-image": "^2.6.0",
@@ -40,47 +46,48 @@
"gray-matter": "^4.0.3",
"htm": "^3.1.1",
"image-size": "^1.1.1",
"jose": "^5.2.4",
"jose": "^5.6.3",
"js-cookie": "^3.0.5",
"lucide-react": "^0.376.0",
"lucide-react": "^0.399.0",
"nanoid": "^5.0.7",
"nanostores": "^0.10.3",
"node-html-parser": "^6.1.13",
"npm-check-updates": "^16.14.20",
"playwright": "^1.45.2",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-calendar-heatmap": "^1.9.0",
"react-confetti": "^6.1.0",
"react-dom": "^18.3.1",
"react-tooltip": "^5.26.4",
"reactflow": "^11.11.2",
"react-tooltip": "^5.27.1",
"reactflow": "^11.11.4",
"rehype-external-links": "^3.0.0",
"remark-parse": "^11.0.0",
"roadmap-renderer": "^1.0.6",
"satori": "^0.10.13",
"satori": "^0.10.14",
"satori-html": "^0.3.2",
"sharp": "^0.33.3",
"sharp": "^0.33.4",
"slugify": "^1.6.6",
"tailwind-merge": "^2.3.0",
"tailwindcss": "^3.4.3",
"unified": "^11.0.4",
"zustand": "^4.5.2"
"tailwind-merge": "^2.4.0",
"tailwindcss": "^3.4.6",
"unified": "^11.0.5",
"zustand": "^4.5.4"
},
"devDependencies": {
"@playwright/test": "^1.43.1",
"@playwright/test": "^1.45.2",
"@tailwindcss/typography": "^0.5.13",
"@types/dom-to-image": "^2.6.7",
"@types/js-cookie": "^3.0.6",
"@types/prismjs": "^1.26.3",
"@types/prismjs": "^1.26.4",
"@types/react-calendar-heatmap": "^1.6.7",
"csv-parser": "^3.0.0",
"gh-pages": "^6.1.1",
"js-yaml": "^4.1.0",
"markdown-it": "^14.1.0",
"openai": "^4.38.5",
"prettier": "^3.2.5",
"prettier-plugin-astro": "^0.13.0",
"prettier-plugin-tailwindcss": "^0.5.14",
"tsx": "^4.7.3"
"openai": "^4.52.7",
"prettier": "^3.3.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.6.5",
"tsx": "^4.16.2"
}
}

10187
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

BIN
public/roadmaps/devrel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

BIN
public/roadmaps/ios.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

View File

@@ -36,13 +36,16 @@ Here is the list of available roadmaps with more being actively worked upon.
- [Backend Roadmap](https://roadmap.sh/backend) / [Backend Beginner Roadmap](https://roadmap.sh/backend?r=backend-beginner)
- [DevOps Roadmap](https://roadmap.sh/devops) / [DevOps Beginner Roadmap](https://roadmap.sh/devops?r=devops-beginner)
- [Full Stack Roadmap](https://roadmap.sh/full-stack)
- [API Design Roadmap](https://roadmap.sh/api-design)
- [Computer Science Roadmap](https://roadmap.sh/computer-science)
- [Data Structures and Algorithms Roadmap](https://roadmap.sh/datastructures-and-algorithms)
- [AI and Data Scientist Roadmap](https://roadmap.sh/ai-data-scientist)
- [AWS Roadmap](https://roadmap.sh/aws)
- [Linux Roadmap](https://roadmap.sh/linux)
- [Terraform Roadmap](https://roadmap.sh/terraform)
- [Data Analyst Roadmap](https://roadmap.sh/data-analyst)
- [MLOps Roadmap](https://roadmap.sh/mlops)
- [Product Manager Roadmap](https://roadmap.sh/product-manager)
- [QA Roadmap](https://roadmap.sh/qa)
- [Python Roadmap](https://roadmap.sh/python)
- [Software Architect Roadmap](https://roadmap.sh/software-architect)
@@ -58,6 +61,7 @@ Here is the list of available roadmaps with more being actively worked upon.
- [Node.js Roadmap](https://roadmap.sh/nodejs)
- [GraphQL Roadmap](https://roadmap.sh/graphql)
- [Android Roadmap](https://roadmap.sh/android)
- [iOS Roadmap](https://roadmap.sh/ios)
- [Flutter Roadmap](https://roadmap.sh/flutter)
- [Go Roadmap](https://roadmap.sh/golang)
- [Rust Roadmap](https://roadmap.sh/rust)
@@ -76,6 +80,7 @@ Here is the list of available roadmaps with more being actively worked upon.
- [Docker Roadmap](https://roadmap.sh/docker)
- [Prompt Engineering Roadmap](https://roadmap.sh/prompt-engineering)
- [Technical Writer Roadmap](https://roadmap.sh/technical-writer)
- [DevRel Engineer Roadmap](https://roadmap.sh/devrel)
There are also interactive best practices:
@@ -90,6 +95,8 @@ There are also interactive best practices:
- [JavaScript Questions](https://roadmap.sh/questions/javascript)
- [Node.js Questions](https://roadmap.sh/questions/nodejs)
- [React Questions](https://roadmap.sh/questions/react)
- [Backend Questions](https://roadmap.sh/questions/backend)
- [Frontend Questions](https://roadmap.sh/questions/frontend)
![](https://i.imgur.com/waxVImv.png)
@@ -109,6 +116,7 @@ Clone the repository, install the dependencies and start the application
```bash
git clone git@github.com:kamranahmedse/developer-roadmap.git
cd developer-roadmap
npm install
npm run dev
```

View File

@@ -0,0 +1,189 @@
const fs = require('node:fs');
const path = require('node:path');
const allRoadmapDirs = fs.readdirSync(
path.join(__dirname, '../src/data/roadmaps'),
);
allRoadmapDirs.forEach((roadmapId) => {
const roadmapDir = path.join(
__dirname,
`../src/data/roadmaps/${roadmapId}/content`,
);
function getHostNameWithoutTld(hostname) {
const parts = hostname.split('.');
return parts.slice(0, parts.length - 1).join('.');
}
function isOfficialWebsite(hostname, fileName, roadmapId) {
fileName = fileName.replace('/index.md', '').replace('.md', '');
const parts = fileName.split('/');
const lastPart = parts[parts.length - 1];
const normalizedFilename = lastPart.replace(/\d+/g, '').replace(/-/g, '');
const normalizedHostname = getHostNameWithoutTld(hostname);
if (normalizedFilename === normalizedHostname) {
return true;
}
if (normalizedFilename.includes(normalizedHostname)) {
return true;
}
return !!roadmapId.includes(normalizedHostname);
}
// websites are educational websites that are of following types:
// - @official@
// - @article@
// - @course@
// - @opensource@
// - @podcast@
// - @video@
// - @website@
// content is only educational websites
function getTypeFromHostname(hostname, fileName, roadmapId) {
hostname = hostname.replace('www.', '');
const videoHostnames = ['youtube.com', 'vimeo.com', 'youtu.be'];
const courseHostnames = ['coursera.org', 'udemy.com', 'edx.org'];
const podcastHostnames = ['spotify.com', 'apple.com'];
const opensourceHostnames = ['github.com', 'gitlab.com'];
const articleHostnames = [
'neilpatel.com',
'learningseo.io',
'htmlreference.io',
'docs.gitlab.com',
'docs.github.com',
'skills.github.com',
'cloudflare.com',
'w3schools.com',
'medium.com',
'dev.to',
'web.dev',
'css-tricks.com',
'developer.mozilla.org',
'smashingmagazine.com',
'freecodecamp.org',
'cs.fyi',
'thenewstack.io',
'html5rocks.com',
'html.com',
'javascript.info',
'css-tricks.com',
'developer.apple.com',
];
if (articleHostnames.includes(hostname)) {
return 'article';
}
if (videoHostnames.includes(hostname)) {
return 'video';
}
if (courseHostnames.includes(hostname)) {
return 'course';
}
if (podcastHostnames.includes(hostname)) {
return 'podcast';
}
if (opensourceHostnames.includes(hostname)) {
return 'opensource';
}
if (hostname === 'roadmap.sh') {
return 'roadmap.sh';
}
if (isOfficialWebsite(hostname, fileName, roadmapId)) {
return 'official';
}
return 'article';
}
function readNestedMarkdownFiles(dir, files = []) {
const dirEnts = fs.readdirSync(dir, { withFileTypes: true });
for (const dirent of dirEnts) {
const fullPath = path.join(dir, dirent.name);
if (dirent.isDirectory()) {
readNestedMarkdownFiles(fullPath, files);
} else {
if (path.extname(fullPath) === '.md') {
files.push(fullPath);
}
}
}
return files;
}
const files = readNestedMarkdownFiles(roadmapDir);
// for each of the files, assign the type of link to the beginning of each markdown link
// i.e. - [@article@abc](xyz) where @article@ is the type of link. Possible types:
// - @official@
// - @opensource@
// - @article@
// - @course@
// - @opensource@
// - @podcast@
// - @video@
files.forEach((file) => {
const content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
const newContent = lines
.map((line) => {
if (line.startsWith('- [') && !line.startsWith('- [@')) {
const type = line.match(/@(\w+)@/);
if (type) {
return line;
}
let urlMatches = line.match(/\((https?:\/\/[^)]+)\)/);
let fullUrl = urlMatches?.[1];
if (!fullUrl) {
// is it slashed URL i.e. - [abc](/xyz)
fullUrl = line.match(/\((\/[^)]+)\)/)?.[1];
if (fullUrl) {
fullUrl = `https://roadmap.sh${fullUrl}`;
}
if (!fullUrl) {
console.error('Invalid URL found in:', file);
return line;
}
}
const url = new URL(fullUrl);
const hostname = url.hostname;
let urlType = getTypeFromHostname(hostname, file, roadmapId);
const linkText = line.match(/\[([^\]]+)\]/)[1];
if (
linkText.toLowerCase().startsWith('visit dedicated') &&
linkText.toLowerCase().endsWith('roadmap')
) {
urlType = 'roadmap';
}
return line.replace('- [', `- [@${urlType}@`).replace('](', '](');
}
return line;
})
.join('\n');
fs.writeFileSync(file, newContent);
});
});

31
scripts/close-issues.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Fetch issues JSON data and parse it properly
issues=$(gh issue list --repo kamranahmedse/developer-roadmap --search "sort:created-asc" --state open --limit 500 --json number,title,createdAt,updatedAt,state,url,comments,reactionGroups,body | jq -c '.[]')
# Loop through the issues and delete the ones created in 2022 and not updated in the past year
while IFS= read -r issue; do
created_at=$(echo "$issue" | jq -r '.createdAt')
updated_at=$(echo "$issue" | jq -r '.updatedAt')
issue_number=$(echo "$issue" | jq -r '.number')
issue_title=$(echo "$issue" | jq -r '.title')
reaction_groups=$(echo "$issue" | jq -r '.reactionGroups')
has_reactions=$(echo "$issue" | jq -r '.reactionGroups | length')
comment_count=$(echo "$issue" | jq -r '.comments | length')
body_characters=$(echo "$issue" | jq -r '.body | length')
# if has empty body
if [[ "$created_at" == 2024-01* ]]; then
comment="Hey there!
Looks like this issue has been hanging around for a bit without much action. Our roadmaps have evolved quite a bit since then, and a bunch of older issues aren't really applicable anymore. So, we're tidying things up by closing out the older ones to keep our issue tracker nice and organized for future feedback.
If you still think this problem needs addressing, don't hesitate to reopen the issue. We're here to help!
Thanks a bunch!"
gh issue comment "$issue_number" --body "$comment"
gh issue close "$issue_number"
fi
done <<< "$issues"

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# get all the folder names inside src/data/roadmaps
roadmap_ids=$(ls src/data/roadmaps)
# create a label for each roadmap name on github issues using gh cli
for roadmap_id in $roadmap_ids
do
random_color=$(openssl rand -hex 3)
gh label create "$roadmap_id" --color $random_color --description "Roadmap: $roadmap_id"
done

View File

@@ -0,0 +1,76 @@
import playwright from 'playwright';
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
// ERROR: `__dirname` is not defined in ES module scope
// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Usage: tsx ./scripts/editor-roadmap-dirs.ts <roadmapId>
// Directory containing the roadmaps
const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps');
const roadmapId = process.argv[2];
const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR);
if (!roadmapId) {
console.error('Roadmap Id is required');
process.exit(1);
}
if (!allowedRoadmapIds.includes(roadmapId)) {
console.error(`Invalid roadmap key ${roadmapId}`);
console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`);
process.exit(1);
}
const roadmapFrontmatterDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.md`,
);
const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8');
const { data } = matter(roadmapFrontmatterRaw);
const roadmapFrontmatter = data as RoadmapFrontmatter;
if (!roadmapFrontmatter) {
console.error('Invalid roadmap frontmatter');
process.exit(1);
}
if (roadmapFrontmatter.renderer !== 'editor') {
console.error('Only Editor Rendered Roadmaps are allowed');
process.exit(1);
}
console.log(`Launching chromium`);
const browser = await playwright.chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
const pageUrl = `http://localhost:3000/${roadmapId}/svg`;
console.log(`Opening page ${pageUrl}`);
await page.goto(pageUrl);
await page.waitForSelector('#resource-svg-wrap');
await page.waitForTimeout(5000);
console.log(`Generating PDF ${pageUrl}`);
await page.pdf({
path: `./public/pdfs/roadmaps/${roadmapId}.pdf`,
margin: { top: 0, right: 0, bottom: 0, left: 0 },
height: roadmapFrontmatter?.dimensions?.height || 2000,
width: roadmapFrontmatter?.dimensions?.width || 968,
});
// @todo generate png from the pdf
console.log(`Generating png ${pageUrl}`);
await page.locator('#resource-svg-wrap>svg').screenshot({
path: `./public/roadmaps/${roadmapId}.png`,
type: 'png',
scale: 'device',
});
await browser.close();

View File

@@ -0,0 +1,185 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Edge, Node } from 'reactflow';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
import { slugify } from '../src/lib/slugger';
import OpenAI from 'openai';
import { runPromisesInBatchSequentially } from '../src/lib/promise';
// ERROR: `__dirname` is not defined in ES module scope
// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Usage: tsx ./scripts/editor-roadmap-content.ts <roadmapId>
const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY;
console.log('OPEN_AI_API_KEY:', OPEN_AI_API_KEY);
const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps');
const roadmapId = process.argv[2];
const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR);
if (!roadmapId) {
console.error('Roadmap Id is required');
process.exit(1);
}
if (!allowedRoadmapIds.includes(roadmapId)) {
console.error(`Invalid roadmap key ${roadmapId}`);
console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`);
process.exit(1);
}
const roadmapFrontmatterDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.md`,
);
const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8');
const { data } = matter(roadmapFrontmatterRaw);
const roadmapFrontmatter = data as RoadmapFrontmatter;
if (!roadmapFrontmatter) {
console.error('Invalid roadmap frontmatter');
process.exit(1);
}
if (roadmapFrontmatter.renderer !== 'editor') {
console.error('Only Editor Rendered Roadmaps are allowed');
process.exit(1);
}
const roadmapDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.json`,
);
const roadmapContent = await fs.readFile(roadmapDir, 'utf-8');
let { nodes, edges } = JSON.parse(roadmapContent) as {
nodes: Node[];
edges: Edge[];
};
const enrichedNodes = nodes
.filter(
(node) =>
node?.type &&
['topic', 'subtopic'].includes(node.type) &&
node.data?.label,
)
.map((node) => {
// Because we only need the parent id and title for subtopics
if (node.type !== 'subtopic') {
return node;
}
const parentNodeId =
edges.find((edge) => edge.target === node.id)?.source || '';
const parentNode = nodes.find((n) => n.id === parentNodeId);
return {
...node,
parentId: parentNodeId,
parentTitle: parentNode?.data?.label || '',
};
}) as (Node & { parentId?: string; parentTitle?: string })[];
const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content');
const stats = await fs.stat(roadmapContentDir).catch(() => null);
if (!stats || !stats.isDirectory()) {
await fs.mkdir(roadmapContentDir, { recursive: true });
}
let openai: OpenAI | undefined;
if (OPEN_AI_API_KEY) {
openai = new OpenAI({
apiKey: OPEN_AI_API_KEY,
});
}
function writeTopicContent(
roadmapTitle: string,
childTopic: string,
parentTopic?: string,
) {
let prompt = `I will give you a topic and you need to write a brief introduction for that with regards to "${roadmapTitle}". Your format should be as follows and be in strictly markdown format:
# (Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" or "Subtopic under XYZ" etc.)
(Briefly explain the topic in one paragraph using simple english with regards to "${roadmapTitle}". Don't start with explaining how important the topic is with regard to "${roadmapTitle}". Don't say something along the lines of "XYZ plays a crucial role in ${roadmapTitle}". Don't include anything saying "In the context of ${roadmapTitle}". Instead, start with a simple explanation of the topic itself. For example, if the topic is "React", you can start with "React is a JavaScript library for building user interfaces." and then you can explain how it is used in "${roadmapTitle}".)
`;
if (!parentTopic) {
prompt += `First topic is: ${childTopic}`;
} else {
prompt += `First topic is: ${childTopic} under ${parentTopic}`;
}
return new Promise((resolve, reject) => {
openai?.chat.completions
.create({
model: 'gpt-4',
messages: [
{
role: 'user',
content: prompt,
},
],
})
.then((response) => {
const article = response.choices[0].message.content;
resolve(article);
})
.catch((err) => {
reject(err);
});
});
}
async function writeNodeContent(node: Node & { parentTitle?: string }) {
const nodeDirPattern = `${slugify(node.data.label)}@${node.id}.md`;
if (!roadmapContentFiles.includes(nodeDirPattern)) {
console.log(`Missing file for: ${nodeDirPattern}`);
return;
}
const nodeDir = path.join(roadmapContentDir, nodeDirPattern);
const nodeContent = await fs.readFile(nodeDir, 'utf-8');
const isFileEmpty = !nodeContent.replace(`# ${node.data.label}`, '').trim();
if (!isFileEmpty) {
console.log(`❌ Ignoring ${nodeDirPattern}. Not empty.`);
return;
}
const topic = node.data.label;
const parentTopic = node.parentTitle;
console.log(`⏳ Generating content for ${topic}...`);
let newContentFile = '';
if (OPEN_AI_API_KEY) {
newContentFile = (await writeTopicContent(
roadmapFrontmatter.title,
topic,
parentTopic,
)) as string;
} else {
newContentFile = `# ${topic}`;
}
await fs.writeFile(nodeDir, newContentFile, 'utf-8');
console.log(`✅ Content generated for ${topic}`);
}
let roadmapContentFiles = await fs.readdir(roadmapContentDir, {
recursive: true,
});
if (!OPEN_AI_API_KEY) {
console.log('----------------------------------------');
console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...');
console.log('----------------------------------------');
}
const promises = enrichedNodes.map((node) => () => writeNodeContent(node));
await runPromisesInBatchSequentially(promises, 20);
console.log('✅ All content generated');

View File

@@ -0,0 +1,86 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Node } from 'reactflow';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
import { slugify } from '../src/lib/slugger';
// ERROR: `__dirname` is not defined in ES module scope
// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Usage: tsx ./scripts/editor-roadmap-dirs.ts <roadmapId>
// Directory containing the roadmaps
const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps');
const roadmapId = process.argv[2];
const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR);
if (!roadmapId) {
console.error('Roadmap Id is required');
process.exit(1);
}
if (!allowedRoadmapIds.includes(roadmapId)) {
console.error(`Invalid roadmap key ${roadmapId}`);
console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`);
process.exit(1);
}
const roadmapFrontmatterDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.md`,
);
const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8');
const { data } = matter(roadmapFrontmatterRaw);
const roadmapFrontmatter = data as RoadmapFrontmatter;
if (!roadmapFrontmatter) {
console.error('Invalid roadmap frontmatter');
process.exit(1);
}
if (roadmapFrontmatter.renderer !== 'editor') {
console.error('Only Editor Rendered Roadmaps are allowed');
process.exit(1);
}
const roadmapDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.json`,
);
const roadmapContent = await fs.readFile(roadmapDir, 'utf-8');
let { nodes } = JSON.parse(roadmapContent) as {
nodes: Node[];
};
nodes = nodes.filter(
(node) =>
node?.type && ['topic', 'subtopic'].includes(node.type) && node.data?.label,
);
const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content');
const stats = await fs.stat(roadmapContentDir).catch(() => null);
if (!stats || !stats.isDirectory()) {
await fs.mkdir(roadmapContentDir, { recursive: true });
}
const roadmapContentFiles = await fs.readdir(roadmapContentDir, {
recursive: true,
});
nodes.forEach(async (node, index) => {
const nodeDirPattern = `${slugify(node.data.label)}@${node.id}.md`;
if (roadmapContentFiles.includes(nodeDirPattern)) {
console.log(`Skipping ${nodeDirPattern}`);
return;
}
await fs.writeFile(
path.join(roadmapContentDir, nodeDirPattern),
`# ${node.data.label}`,
);
});

View File

@@ -475,8 +475,6 @@ function getRoadmapDefaultTemplate({ title, description }) {
function getRoadmapImageTemplate({ title, description, image, height, width }) {
return html`<div tw="bg-white relative flex flex-col h-full w-full">
<div tw="absolute flex top-0 left-0 w-full h-[18px] bg-black"></div>
<div tw="flex flex-col px-[90px] pt-[90px]">
<div tw="flex flex-col pb-0">
<div tw="text-[70px] leading-[70px] tracking-tight">

View File

@@ -29,4 +29,6 @@ done
# ignore the worktree changes for the editor directory
git update-index --assume-unchanged editor/readonly-editor.tsx || true
git update-index --assume-unchanged editor/readonly-editor.tsx || true
git update-index --assume-unchanged editor/renderer/index.tsx || true
git update-index --assume-unchanged editor/renderer/renderer.ts || true

41
scripts/label-issues.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Fetch issues JSON data and parse it properly
issues=$(gh issue list --repo kamranahmedse/developer-roadmap --search "sort:created-asc" --state open --limit 500 --json number,title,createdAt,updatedAt,state,url,comments,reactionGroups,body | jq -c '.[]')
# checks the body of issue, identifies the slug from the roadmap URLs
# and labels the issue with the corresponding slug
while IFS= read -r issue; do
created_at=$(echo "$issue" | jq -r '.createdAt')
updated_at=$(echo "$issue" | jq -r '.updatedAt')
issue_number=$(echo "$issue" | jq -r '.number')
issue_title=$(echo "$issue" | jq -r '.title')
reaction_groups=$(echo "$issue" | jq -r '.reactionGroups')
has_reactions=$(echo "$issue" | jq -r '.reactionGroups | length')
comment_count=$(echo "$issue" | jq -r '.comments | length')
body_characters=$(echo "$issue" | jq -r '.body | length')
# If the issue has no body, then skip it
if [ "$body_characters" -eq 0 ]; then
continue
fi
# Extract the roadmap URLs from the issue body
roadmap_urls=$(echo "$issue" | jq -r '.body' | grep -o 'https://roadmap\.sh/[^ ]*')
# If no roadmap URLs found, then skip it
if [ -z "$roadmap_urls" ]; then
continue
fi
# URL is like https://roadmap.sh/frontend
# Extract the slug from the URL
slug_of_first_url=$(echo "$roadmap_urls" | head -n 1 | sed 's/https:\/\/roadmap\.sh\///')
if [ -z "$slug_of_first_url" ]; then
continue
fi
# Label the issue with the slug
gh issue edit "$issue_number" --add-label "$slug_of_first_url"
done <<< "$issues"

45
scripts/warm-urls.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Usage: warm-urls.sh <sitemap-url>
# Example: warm-urls.sh https://www.example.com/sitemap.xml
# Check if sitemap url is provided
if [ -z "$1" ]; then
echo "Please provide sitemap URL" >&2
exit 1
fi
# Get all URLs from sitemap
urls=$(curl -s "$1" | grep -o "<loc>[^<]*</loc>" | sed 's#<loc>\(.*\)</loc>#\1#')
failed_urls=()
# Warm up URLs
for url in $urls; do
# Fetch the og:image URL from the meta tags
og_image_url=$(curl -s "$url" | grep -o "<meta property=\"og:image\" content=\"[^\"]*\"" | sed 's#<meta property="og:image" content="\([^"]*\)"#\1#')
# warm the URL
echo "Warming up URL: $url"
if ! curl -s -I "$url" > /dev/null; then
failed_urls+=("$url")
fi
# Warm up the og:image URL
if [ -n "$og_image_url" ]; then
echo "Warming up OG: $og_image_url"
if ! curl -s -I "$og_image_url" > /dev/null; then
failed_urls+=("$og_image_url")
fi
else
echo "No og:image found for $url"
fi
done
# Print failed URLs
if [ ${#failed_urls[@]} -gt 0 ]; then
echo "Failed to warm up the following URLs:" >&2
for failed_url in "${failed_urls[@]}"; do
echo "$failed_url" >&2
done
fi

39
src/api/roadmap.ts Normal file
View File

@@ -0,0 +1,39 @@
import { type APIContext } from 'astro';
import { api } from './api.ts';
import type { RoadmapDocument } from '../components/CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
export type ListShowcaseRoadmapResponse = {
data: Pick<
RoadmapDocument,
| '_id'
| 'title'
| 'description'
| 'slug'
| 'creatorId'
| 'visibility'
| 'createdAt'
| 'topicCount'
| 'ratings'
>[];
totalCount: number;
totalPages: number;
currPage: number;
perPage: number;
};
export function roadmapApi(context: APIContext) {
return {
listShowcaseRoadmap: async function () {
const searchParams = new URLSearchParams(context.url.searchParams);
return api(context).get<ListShowcaseRoadmapResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-list-showcase-roadmap`,
searchParams,
);
},
isShowcaseRoadmap: async function (slug: string) {
return api(context).get<{
isShowcase: boolean;
}>(`${import.meta.env.PUBLIC_API_URL}/v1-is-showcase-roadmap/${slug}`);
},
};
}

View File

@@ -18,6 +18,9 @@ export const allowedProfileVisibility = ['public', 'private'] as const;
export type AllowedProfileVisibility =
(typeof allowedProfileVisibility)[number];
export const allowedOnboardingStatus = ['done', 'pending', 'ignored'] as const;
export type AllowedOnboardingStatus = (typeof allowedOnboardingStatus)[number];
export interface UserDocument {
_id?: string;
name: string;
@@ -41,6 +44,7 @@ export interface UserDocument {
github?: string;
linkedin?: string;
twitter?: string;
dailydev?: string;
website?: string;
};
username?: string;
@@ -56,6 +60,18 @@ export interface UserDocument {
};
resetPasswordCodeAt: string;
verifiedAt: string;
// Onboarding fields
onboardingStatus?: AllowedOnboardingStatus;
onboarding?: {
updateProgress: AllowedOnboardingStatus;
publishProfile: AllowedOnboardingStatus;
customRoadmap: AllowedOnboardingStatus;
addFriends: AllowedOnboardingStatus;
roadCard: AllowedOnboardingStatus;
inviteTeam: AllowedOnboardingStatus;
};
createdAt: string;
updatedAt: string;
}

View File

@@ -1,16 +0,0 @@
type AIAnnouncementProps = {};
export function AIAnnouncement(props: AIAnnouncementProps) {
return (
<a
className="rounded-md border border-dashed border-purple-600 px-3 py-1.5 text-purple-400 transition-colors hover:border-purple-400 hover:text-purple-200"
href="/ai"
>
<span className="relative -top-[1px] mr-1 text-xs font-semibold uppercase text-white">
New
</span>{' '}
<span className={'hidden sm:inline'}>Generate visual roadmaps with AI</span>
<span className={'inline text-sm sm:hidden'}>AI Roadmap Generator!</span>
</a>
);
}

View File

@@ -1,9 +1,11 @@
import { useMemo, useState } from 'react';
import { useState } from 'react';
import { getRelativeTimeString } from '../../lib/date';
import type { ResourceType } from '../../lib/resource-progress';
import { EmptyStream } from './EmptyStream';
import { ActivityTopicsModal } from './ActivityTopicsModal.tsx';
import {Book, BookOpen, ChevronsDown, ChevronsDownUp, ChevronsUp, ChevronsUpDown} from 'lucide-react';
import { ChevronsDown, ChevronsUp } from 'lucide-react';
import { ActivityTopicTitles } from './ActivityTopicTitles.tsx';
import { cn } from '../../lib/classname.ts';
export const allowedActivityActionType = [
'in_progress',
@@ -21,31 +23,39 @@ export type UserStreamActivity = {
resourceSlug?: string;
isCustomResource?: boolean;
actionType: AllowedActivityActionType;
topicIds?: string[];
topicTitles?: string[];
createdAt: Date;
updatedAt: Date;
};
type ActivityStreamProps = {
activities: UserStreamActivity[];
className?: string;
onResourceClick?: (
resourceId: string,
resourceType: ResourceType,
isCustomResource: boolean,
) => void;
};
export function ActivityStream(props: ActivityStreamProps) {
const { activities } = props;
const { activities, className, onResourceClick } = props;
const [showAll, setShowAll] = useState(false);
const [selectedActivity, setSelectedActivity] =
useState<UserStreamActivity | null>(null);
const sortedActivities = activities
.filter((activity) => activity?.topicIds && activity.topicIds.length > 0)
.filter(
(activity) => activity?.topicTitles && activity.topicTitles.length > 0,
)
.sort((a, b) => {
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
})
.slice(0, showAll ? activities.length : 10);
return (
<div className="mx-0 px-0 py-5 md:-mx-10 md:px-8 md:py-8">
<div className={cn('mx-0 px-0 py-5 md:-mx-10 md:px-8 md:py-8', className)}>
<h2 className="mb-3 text-xs uppercase text-gray-400">
Learning Activity
</h2>
@@ -57,8 +67,8 @@ export function ActivityStream(props: ActivityStreamProps) {
resourceId={selectedActivity.resourceId}
resourceType={selectedActivity.resourceType}
isCustomResource={selectedActivity.isCustomResource}
topicIds={selectedActivity.topicIds || []}
topicCount={selectedActivity.topicIds?.length || 0}
topicTitles={selectedActivity.topicTitles || []}
topicCount={selectedActivity.topicTitles?.length || 0}
actionType={selectedActivity.actionType}
/>
)}
@@ -73,8 +83,9 @@ export function ActivityStream(props: ActivityStreamProps) {
resourceTitle,
actionType,
updatedAt,
topicIds,
topicTitles,
isCustomResource,
resourceSlug,
} = activity;
const resourceUrl =
@@ -83,20 +94,30 @@ export function ActivityStream(props: ActivityStreamProps) {
: resourceType === 'best-practice'
? `/best-practices/${resourceId}`
: isCustomResource && resourceType === 'roadmap'
? `/r/${resourceId}`
? `/r/${resourceSlug}`
: `/${resourceId}`;
const resourceLinkComponent = (
<a
className="font-medium underline transition-colors hover:cursor-pointer hover:text-black"
target="_blank"
href={resourceUrl}
>
{resourceTitle}
</a>
);
const resourceLinkComponent =
onResourceClick && resourceType !== 'question' ? (
<button
className="font-medium underline transition-colors hover:cursor-pointer hover:text-black"
onClick={() =>
onResourceClick(resourceId, resourceType, isCustomResource!)
}
>
{resourceTitle}
</button>
) : (
<a
className="font-medium underline transition-colors hover:cursor-pointer hover:text-black"
target="_blank"
href={resourceUrl}
>
{resourceTitle}
</a>
);
const topicCount = topicIds?.length || 0;
const topicCount = topicTitles?.length || 0;
const timeAgo = (
<span className="ml-1 text-xs text-gray-400">
@@ -108,32 +129,35 @@ export function ActivityStream(props: ActivityStreamProps) {
<li key={_id} className="py-2 text-sm text-gray-600">
{actionType === 'in_progress' && (
<>
Started{' '}
<button
className="font-medium underline underline-offset-2 hover:text-black"
onClick={() => setSelectedActivity(activity)}
>
{topicCount} topic{topicCount > 1 ? 's' : ''}
</button>{' '}
in {resourceLinkComponent} {timeAgo}
<p className="mb-1">
Started&nbsp;{topicCount}&nbsp;topic
{topicCount > 1 ? 's' : ''}&nbsp;in&nbsp;
{resourceLinkComponent}&nbsp;
{timeAgo}
</p>
<ActivityTopicTitles topicTitles={topicTitles || []} />
</>
)}
{actionType === 'done' && (
<>
Completed{' '}
<button
className="font-medium underline underline-offset-2 hover:text-black"
onClick={() => setSelectedActivity(activity)}
>
{topicCount} topic{topicCount > 1 ? 's' : ''}
</button>{' '}
in {resourceLinkComponent} {timeAgo}
<p className="mb-1">
Completed&nbsp;{topicCount}&nbsp;topic
{topicCount > 1 ? 's' : ''}&nbsp;in&nbsp;
{resourceLinkComponent}&nbsp;
{timeAgo}
</p>
<ActivityTopicTitles topicTitles={topicTitles || []} />
</>
)}
{actionType === 'answered' && (
<>
Answered {topicCount} question{topicCount > 1 ? 's' : ''} in{' '}
{resourceLinkComponent} {timeAgo}
<p className="mb-1">
Answered&nbsp;{topicCount}&nbsp;question
{topicCount > 1 ? 's' : ''}&nbsp;in&nbsp;
{resourceLinkComponent}&nbsp;
{timeAgo}
</p>
<ActivityTopicTitles topicTitles={topicTitles || []} />
</>
)}
</li>
@@ -146,16 +170,20 @@ export function ActivityStream(props: ActivityStreamProps) {
{activities.length > 10 && (
<button
className="mt-3 gap-2 flex items-center rounded-md border border-black pl-1.5 pr-2 py-1 text-xs uppercase tracking-wide text-black transition-colors hover:border-black hover:bg-black hover:text-white"
className="mt-3 flex items-center gap-2 rounded-md border border-black py-1 pl-1.5 pr-2 text-xs uppercase tracking-wide text-black transition-colors hover:border-black hover:bg-black hover:text-white"
onClick={() => setShowAll(!showAll)}
>
{showAll ? <>
<ChevronsUp size={14} />
Show less
</> : <>
<ChevronsDown size={14} />
Show more
</>}
{showAll ? (
<>
<ChevronsUp size={14} />
Show less
</>
) : (
<>
<ChevronsDown size={14} />
Show more
</>
)}
</button>
)}
</div>

View File

@@ -0,0 +1,43 @@
import { useState } from 'react';
import { cn } from '../../lib/classname';
type ActivityTopicTitlesProps = {
topicTitles: string[];
className?: string;
onSelectActivity?: () => void;
};
export function ActivityTopicTitles(props: ActivityTopicTitlesProps) {
const { topicTitles, onSelectActivity, className } = props;
const [showAll, setShowAll] = useState(false);
const filteredTopicTitles = topicTitles.slice(
0,
showAll ? topicTitles.length : 3,
);
const shouldShowButton = topicTitles.length > 3;
return (
<div
className={cn(
'flex flex-wrap gap-1 text-sm font-normal text-gray-600',
className,
)}
>
{filteredTopicTitles.map((topicTitle, index) => (
<span key={index} className="rounded-md bg-gray-200 px-1.5">
{topicTitle}
</span>
))}
{shouldShowButton && !showAll && (
<button
onClick={() => setShowAll(!showAll)}
className="bg-white border border-black text-black rounded-md px-1.5 hover:bg-black text-xs h-[20px] hover:text-white"
>
{showAll ? '- Show less' : `+${topicTitles.length - 3}`}
</button>
)}
</div>
);
}

View File

@@ -11,7 +11,7 @@ type ActivityTopicDetailsProps = {
resourceId: string;
resourceType: ResourceType | 'question';
isCustomResource?: boolean;
topicIds: string[];
topicTitles: string[];
topicCount: number;
actionType: AllowedActivityActionType;
onClose: () => void;
@@ -22,56 +22,12 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) {
resourceId,
resourceType,
isCustomResource,
topicIds = [],
topicTitles = [],
topicCount,
actionType,
onClose,
} = props;
const [isLoading, setIsLoading] = useState(true);
const [topicTitles, setTopicTitles] = useState<Record<string, string>>({});
const [error, setError] = useState<string | null>(null);
const loadTopicTitles = async () => {
setIsLoading(true);
setError(null);
const { response, error } = await httpPost(
`${import.meta.env.PUBLIC_API_URL}/v1-get-topic-titles`,
{
resourceId,
resourceType,
isCustomResource,
topicIds,
},
);
if (error || !response) {
setError(error?.message || 'Failed to load topic titles');
setIsLoading(false);
return;
}
setTopicTitles(response);
setIsLoading(false);
};
useEffect(() => {
loadTopicTitles().finally(() => {
setIsLoading(false);
});
}, []);
if (isLoading || error) {
return (
<ModalLoader
error={error!}
text={'Loading topics..'}
isLoading={isLoading}
/>
);
}
let pageUrl = '';
if (resourceType === 'roadmap') {
pageUrl = isCustomResource ? `/r/${resourceId}` : `/${resourceId}`;
@@ -85,8 +41,6 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) {
<Modal
onClose={() => {
onClose();
setError(null);
setIsLoading(false);
}}
>
<div className={`popup-body relative rounded-lg bg-white p-4 shadow`}>
@@ -108,9 +62,7 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) {
</a>
</span>
<ul className="flex max-h-[50vh] flex-col gap-1 overflow-y-auto max-md:max-h-full">
{topicIds.map((topicId) => {
const topicTitle = topicTitles[topicId] || 'Unknown Topic';
{topicTitles.map((topicTitle) => {
const ActivityIcon =
actionType === 'done'
? Check
@@ -119,7 +71,7 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) {
: Check;
return (
<li key={topicId} className="flex items-start gap-2">
<li key={topicTitle} className="flex items-start gap-2">
<ActivityIcon
strokeWidth={3}
className="relative top-[4px] text-green-500"

View File

@@ -4,7 +4,7 @@ export function EmptyStream() {
return (
<div className="rounded-md">
<div className="flex flex-col items-center p-7 text-center">
<List className="mb-2 h-[60px] w-[60px] opacity-10 sm:h-[120px] sm:w-[120px]" />
<List className="mb-4 h-[60px] w-[60px] opacity-10 sm:h-[60px] sm:w-[60px]" />
<h2 className="text-lg font-bold sm:text-xl">No Activities</h2>
<p className="my-1 max-w-[400px] text-balance text-sm text-gray-500 sm:my-2 sm:text-base">

View File

@@ -1,6 +1,7 @@
import { getUser } from '../../lib/jwt';
import { getPercentage } from '../../helper/number';
import { ResourceProgressActions } from './ResourceProgressActions';
import { cn } from '../../lib/classname';
type ResourceProgressType = {
resourceType: 'roadmap' | 'best-practice';
@@ -15,10 +16,17 @@ type ResourceProgressType = {
showClearButton?: boolean;
isCustomResource: boolean;
roadmapSlug?: string;
showActions?: boolean;
onResourceClick?: () => void;
};
export function ResourceProgress(props: ResourceProgressType) {
const { showClearButton = true, isCustomResource } = props;
const {
showClearButton = true,
isCustomResource,
showActions = true,
onResourceClick,
} = props;
const userId = getUser()?.id;
@@ -47,12 +55,23 @@ export function ResourceProgress(props: ResourceProgressType) {
const totalMarked = doneCount + skippedCount;
const progressPercentage = getPercentage(totalMarked, totalCount);
const Slot = onResourceClick ? 'button' : 'a';
return (
<div className="relative">
<a
target="_blank"
href={url}
className="group relative flex items-center justify-between overflow-hidden rounded-md border border-gray-300 bg-white px-3 py-2 pr-7 text-left text-sm transition-all hover:border-gray-400"
<Slot
{...(onResourceClick
? {
onClick: onResourceClick,
}
: {
href: url,
target: '_blank',
})}
className={cn(
'group relative flex w-full items-center justify-between overflow-hidden rounded-md border border-gray-300 bg-white px-3 py-2 text-left text-sm transition-all hover:border-gray-400',
showActions ? 'pr-7' : '',
)}
>
<span className="flex-grow truncate">{title}</span>
<span className="text-xs text-gray-400">
@@ -65,18 +84,20 @@ export function ResourceProgress(props: ResourceProgressType) {
width: `${progressPercentage}%`,
}}
></span>
</a>
</Slot>
<div className="absolute right-2 top-0 flex h-full items-center">
<ResourceProgressActions
userId={userId!}
resourceType={resourceType}
resourceId={resourceId}
isCustomResource={isCustomResource}
onCleared={onCleared}
showClearButton={showClearButton}
/>
</div>
{showActions && (
<div className="absolute right-2 top-0 flex h-full items-center">
<ResourceProgressActions
userId={userId!}
resourceType={resourceType}
resourceId={resourceId}
isCustomResource={isCustomResource}
onCleared={onCleared}
showClearButton={showClearButton}
/>
</div>
)}
</div>
);
}

View File

@@ -73,7 +73,7 @@ export function TriggerVerifyEmail() {
Verifying your new Email
</h2>
<div className="text-sm sm:text-base">
{isLoading && <p>Please wait while we verify your new Email..</p>}
{isLoading && <p>Please wait while we verify your new Email.</p>}
{error && <p className="text-red-700">{error}</p>}
</div>
</div>

View File

@@ -46,6 +46,7 @@ function handleGuest() {
'/team/roadmaps',
'/team/new',
'/team/members',
'/team/member',
'/team/settings',
];

View File

@@ -87,7 +87,7 @@ const isBestPracticeReady = !isUpcoming;
{
isBestPracticeReady && (
<a
href={`https://github.com/kamranahmedse/developer-roadmap/issues/new?title=[Suggestion] ${title}`}
href={`https://github.com/kamranahmedse/developer-roadmap/issues/new/choose`}
target="_blank"
class="inline-flex items-center justify-center rounded-md bg-gray-500 px-3 py-1.5 text-xs font-medium text-white hover:bg-gray-600 sm:text-sm"
aria-label="Suggest Changes"

View File

@@ -17,6 +17,8 @@ import { ClipboardIcon } from '../ReactIcons/ClipboardIcon.tsx';
import { GuideIcon } from '../ReactIcons/GuideIcon.tsx';
import { HomeIcon } from '../ReactIcons/HomeIcon.tsx';
import { VideoIcon } from '../ReactIcons/VideoIcon.tsx';
import { cn } from '../../lib/classname.ts';
import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts';
export type PageType = {
id: string;
@@ -26,6 +28,7 @@ export type PageType = {
icon?: ReactElement;
isProtected?: boolean;
metadata?: Record<string, any>;
renderer?: AllowedRoadmapRenderer;
};
const defaultPages: PageType[] = [
@@ -190,7 +193,7 @@ export function CommandMenu() {
return (
<div className="fixed left-0 right-0 top-0 z-50 flex h-full justify-center overflow-y-auto overflow-x-hidden bg-black/50">
<div className="relative top-0 h-full w-full max-w-lg p-2 sm:top-20 md:h-auto">
<div className="relative top-0 h-full w-full max-w-lg p-2 sm:mt-20 md:h-auto">
<div className="relative rounded-lg bg-white shadow" ref={modalRef}>
<input
ref={inputRef}
@@ -240,14 +243,15 @@ export function CommandMenu() {
const groupChanged = prevPage && prevPage.group !== page.group;
return (
<Fragment key={page.id}>
<Fragment key={page.group+'/'+page.id}>
{groupChanged && (
<div className="border-b border-gray-100"></div>
)}
<a
className={`flex w-full items-center rounded p-2 text-sm ${
counter === activeCounter ? 'bg-gray-100' : ''
}`}
className={cn(
'flex w-full items-center rounded p-2 text-sm',
counter === activeCounter ? 'bg-gray-100' : '',
)}
onMouseOver={() => setActiveCounter(counter)}
href={page.url}
>

View File

@@ -24,6 +24,7 @@ export type TeamResourceConfig = {
topics?: number;
sharedTeamMemberIds: string[];
sharedFriendIds: string[];
defaultRoadmapId?: string;
}[];
type RoadmapSelectorProps = {
@@ -106,6 +107,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
}
pageProgressMessage.set(`Adding roadmap to team`);
const renderer = allRoadmaps.find((r) => r.id === roadmapId)?.renderer;
const { error, response } = await httpPut<TeamResourceConfig>(
`${
import.meta.env.PUBLIC_API_URL
@@ -115,6 +117,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
resourceId: roadmapId,
resourceType: 'roadmap',
removed: [],
renderer: renderer || 'balsamiq',
},
);
@@ -124,6 +127,9 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
}
setTeamResources(response);
if (renderer === 'editor') {
setShowSelectRoadmapModal(false);
}
}
useEffect(() => {

View File

@@ -68,7 +68,7 @@ export function SelectRoadmapModal(props: SelectRoadmapModalProps) {
);
return (
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="fixed left-0 right-0 top-0 z-[100] h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="relative mx-auto h-full w-full max-w-2xl p-4 md:h-auto">
<div
ref={popupBodyEl}

View File

@@ -148,7 +148,7 @@ export function UpdateTeamResourceModal(props: ProgressMapProps) {
}, []);
return (
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="fixed left-0 right-0 top-0 z-[100] h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="relative mx-auto h-full w-full max-w-4xl p-4 md:h-auto">
<div
id={'customized-roadmap'}

View File

@@ -23,24 +23,44 @@ export const allowedCustomRoadmapType = ['role', 'skill'] as const;
export type AllowedCustomRoadmapType =
(typeof allowedCustomRoadmapType)[number];
export const allowedShowcaseStatus = ['visible', 'hidden'] as const;
export type AllowedShowcaseStatus = (typeof allowedShowcaseStatus)[number];
export interface RoadmapDocument {
_id?: string;
title: string;
description?: string;
slug?: string;
creatorId: string;
aiRoadmapId?: string;
teamId?: string;
isDiscoverable: boolean;
type: AllowedCustomRoadmapType;
topicCount: number;
visibility: AllowedRoadmapVisibility;
sharedFriendIds?: string[];
sharedTeamMemberIds?: string[];
feedbacks?: {
userId: string;
email: string;
feedback: string;
}[];
metadata?: {
originalRoadmapId?: string;
defaultRoadmapId?: string;
};
nodes: any[];
edges: any[];
isDiscoverable?: boolean;
showcaseStatus?: AllowedShowcaseStatus;
ratings: {
average: number;
breakdown: {
[key: number]: number;
};
};
createdAt: Date;
updatedAt: Date;
canManage: boolean;
isCustomResource: boolean;
}
interface CreateRoadmapModalProps {

View File

@@ -15,6 +15,10 @@ export const allowedLinkTypes = [
'course',
'website',
'podcast',
'roadmap.sh',
'official',
'roadmap',
'feed',
] as const;
export type AllowedLinkTypes = (typeof allowedLinkTypes)[number];
@@ -43,6 +47,7 @@ export type GetRoadmapResponse = RoadmapDocument & {
canManage: boolean;
creator?: CreatorType;
team?: CreatorType;
unseenRatingCount: number;
};
export function hideRoadmapLoader() {

View File

@@ -1,4 +1,11 @@
import { BadgeCheck, MessageCircleHeart, PencilRuler } from 'lucide-react';
import {
BadgeCheck,
Heart,
HeartHandshake,
MessageCircleHeart,
PencilRuler,
Search,
} from 'lucide-react';
import { showLoginPopup } from '../../lib/popup.ts';
import { isLoggedIn } from '../../lib/jwt.ts';
import { useState } from 'react';
@@ -17,14 +24,11 @@ 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">
<h2 className="text-base font-semibold text-yellow-800 sm:text-lg">
Community Roadmap
</h2>
<p className="mt-2 mb-2.5 sm:mb-1.5 sm:mt-1 text-sm text-yellow-800 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 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 items-start sm:items-center flex-col sm:flex-row gap-2">
<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"
@@ -32,20 +36,16 @@ export function CustomRoadmapAlert() {
<BadgeCheck className="h-4 w-4 stroke-[2.5]" />
Visit Official Roadmaps
</a>
<span className="font-black text-yellow-700 hidden sm:block">&middot;</span>
<button
<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"
onClick={() => {
if (!isLoggedIn()) {
showLoginPopup();
} else {
setIsCreatingRoadmap(true);
}
}}
>
<PencilRuler className="h-4 w-4 stroke-[2.5]" />
Create Your Own Roadmap
</button>
<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" />

View File

@@ -0,0 +1,90 @@
import { useState } from 'react';
import { Rating } from '../Rating/Rating';
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal';
import { CustomRoadmapRatingsModal } from './CustomRoadmapRatingsModal';
import { Star } from 'lucide-react';
type CustomRoadmapRatingsProps = {
roadmapSlug: string;
ratings: RoadmapDocument['ratings'];
canManage?: boolean;
unseenRatingCount: number;
};
export function CustomRoadmapRatings(props: CustomRoadmapRatingsProps) {
const { ratings, roadmapSlug, canManage, unseenRatingCount } = props;
const average = ratings?.average || 0;
const totalPeopleWhoRated = Object.keys(ratings?.breakdown || {}).reduce(
(acc, key) => acc + ratings?.breakdown[key as any],
0,
);
const [isDetailsOpen, setIsDetailsOpen] = useState(false);
return (
<>
{isDetailsOpen && (
<CustomRoadmapRatingsModal
roadmapSlug={roadmapSlug}
onClose={() => {
setIsDetailsOpen(false);
}}
ratings={ratings}
canManage={canManage}
/>
)}
{average === 0 && (
<>
{!canManage && (
<button
className="flex h-[34px] items-center gap-2 rounded-md border border-gray-300 bg-white py-1 pl-2 pr-3 text-sm font-medium hover:border-black"
onClick={() => {
setIsDetailsOpen(true);
}}
>
<Star className="size-4 fill-yellow-400 text-yellow-400" />
<span className="hidden md:block">Rate this roadmap</span>
<span className="block md:hidden">Rate</span>
</button>
)}
{canManage && (
<span className="flex h-[34px] cursor-default items-center gap-2 rounded-md border border-gray-300 bg-white py-1 pl-2 pr-3 text-sm font-medium opacity-50">
<Star className="size-4 fill-yellow-400 text-yellow-400" />
<span className="hidden md:block">No ratings yet</span>
<span className="block md:hidden">Rate</span>
</span>
)}
</>
)}
{average > 0 && (
<button
className="relative flex h-[34px] items-center gap-2 rounded-md border border-gray-300 bg-white py-1 pl-2 pr-3 text-sm font-medium hover:border-black"
onClick={() => {
setIsDetailsOpen(true);
}}
>
{average.toFixed(1)}
<span className="hidden lg:block">
<Rating
starSize={16}
rating={average}
className={'pointer-events-none gap-px'}
readOnly
/>
</span>
<span className="lg:hidden">
<Star className="size-5 fill-yellow-400 text-yellow-400" />
</span>
({totalPeopleWhoRated})
{canManage && unseenRatingCount > 0 && (
<span className="absolute right-0 top-0 flex size-4 -translate-y-1/2 translate-x-1/2 items-center justify-center rounded-full bg-red-500 text-[10px] font-medium leading-none text-white">
{unseenRatingCount}
</span>
)}
</button>
)}
</>
);
}

View File

@@ -0,0 +1,58 @@
import { useState } from 'react';
import { Modal } from '../Modal';
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal';
import { RateRoadmapForm } from './RateRoadmapForm';
import { ListRoadmapRatings } from './ListRoadmapRatings';
type ActiveTab = 'ratings' | 'feedback';
type CustomRoadmapRatingsModalProps = {
onClose: () => void;
roadmapSlug: string;
ratings: RoadmapDocument['ratings'];
canManage?: boolean;
};
export function CustomRoadmapRatingsModal(
props: CustomRoadmapRatingsModalProps,
) {
const { onClose, ratings, roadmapSlug, canManage = false } = props;
const [activeTab, setActiveTab] = useState<ActiveTab>(
canManage ? 'feedback' : 'ratings',
);
const tabs: {
id: ActiveTab;
label: string;
}[] = [
{
id: 'ratings',
label: 'Ratings',
},
{
id: 'feedback',
label: 'Feedback',
},
];
return (
<Modal
onClose={onClose}
bodyClassName="bg-transparent shadow-none"
wrapperClassName="h-auto"
overlayClassName="items-start md:items-center"
>
{activeTab === 'ratings' && (
<RateRoadmapForm
ratings={ratings}
roadmapSlug={roadmapSlug}
canManage={canManage}
/>
)}
{activeTab === 'feedback' && (
<ListRoadmapRatings ratings={ratings} roadmapSlug={roadmapSlug} />
)}
</Modal>
);
}

View File

@@ -62,7 +62,10 @@ export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
}
const handleTopicRightClick = useCallback((e: MouseEvent, node: Node) => {
const target = e?.currentTarget as HTMLDivElement;
const target =
node?.type === 'todo'
? document.querySelector(`[data-id="${node.id}"]`)
: (e?.currentTarget as HTMLDivElement);
if (!target) {
return;
}

View File

@@ -0,0 +1,181 @@
import { useEffect, useState } from 'react';
import { httpGet } from '../../lib/http';
import { useToast } from '../../hooks/use-toast';
import { isLoggedIn } from '../../lib/jwt';
import { Loader2, MessageCircle, ServerCrash } from 'lucide-react';
import { Rating } from '../Rating/Rating';
import { Spinner } from '../ReactIcons/Spinner.tsx';
import { getRelativeTimeString } from '../../lib/date.ts';
import { cn } from '../../lib/classname.ts';
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal.tsx';
import { Pagination } from '../Pagination/Pagination.tsx';
export interface RoadmapRatingDocument {
_id?: string;
roadmapId: string;
userId: string;
rating: number;
feedback?: string;
createdAt: Date;
updatedAt: Date;
}
type ListRoadmapRatingsResponse = {
data: (RoadmapRatingDocument & {
name: string;
avatar?: string;
})[];
totalCount: number;
totalPages: number;
currPage: number;
perPage: number;
};
type ListRoadmapRatingsProps = {
roadmapSlug: string;
ratings: RoadmapDocument['ratings'];
};
export function ListRoadmapRatings(props: ListRoadmapRatingsProps) {
const { roadmapSlug, ratings: ratingSummary } = props;
const totalWhoRated = Object.keys(ratingSummary.breakdown || {}).reduce(
(acc, key) => acc + ratingSummary.breakdown[key as any],
0,
);
const averageRating = ratingSummary.average;
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState('');
const [ratingsResponse, setRatingsResponse] =
useState<ListRoadmapRatingsResponse | null>(null);
const listRoadmapRatings = async (currPage: number = 1) => {
setIsLoading(true);
const { response, error } = await httpGet<ListRoadmapRatingsResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-list-roadmap-ratings/${roadmapSlug}`,
{
currPage,
},
);
if (!response || error) {
setError(error?.message || 'Something went wrong');
setIsLoading(false);
return;
}
setRatingsResponse(response);
setError('');
setIsLoading(false);
};
useEffect(() => {
if (!isLoggedIn()) {
return;
}
listRoadmapRatings().then();
}, []);
if (error) {
return (
<div className="flex flex-col items-center justify-center bg-white py-10">
<ServerCrash className="size-12 text-red-500" />
<p className="mt-3 text-lg text-red-500">{error}</p>
</div>
);
}
const ratings = ratingsResponse?.data || [];
return (
<div className="relative min-h-[100px] overflow-auto rounded-lg bg-white p-2 md:max-h-[550px]">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<Spinner isDualRing={false} />
</div>
)}
{!isLoading && ratings.length > 0 && (
<div className="relative">
<div className="sticky top-1.5 mb-2 flex items-center justify-center gap-1 rounded-lg bg-yellow-50 px-2 py-1.5 text-sm text-yellow-900">
<span>
Rated{' '}
<span className="font-medium">{averageRating.toFixed(1)}</span>
</span>
<Rating starSize={15} rating={averageRating} readOnly />
by{' '}
<span className="font-medium">
{totalWhoRated} user{totalWhoRated > 1 && 's'}
</span>
</div>
<div className="mb-3 flex flex-col">
{ratings.map((rating) => {
const userAvatar = rating?.avatar
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${rating.avatar}`
: '/images/default-avatar.png';
const isLastRating =
ratings[ratings.length - 1]._id === rating._id;
return (
<div
key={rating._id}
className={cn('px-2 py-2.5', {
'border-b': !isLastRating,
})}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<img
src={userAvatar}
alt={rating.name}
className="h-4 w-4 rounded-full"
/>
<span className="text-sm font-medium">{rating.name}</span>
</div>
<span className="text-xs text-gray-400">
{getRelativeTimeString(rating.createdAt)}
</span>
</div>
<div className="mt-2.5">
<Rating rating={rating.rating} readOnly />
{rating.feedback && (
<p className="mt-2 text-sm text-gray-500">
{rating.feedback}
</p>
)}
</div>
</div>
);
})}
</div>
<Pagination
variant="minimal"
totalCount={ratingsResponse?.totalCount || 1}
currPage={ratingsResponse?.currPage || 1}
totalPages={ratingsResponse?.totalPages || 1}
perPage={ratingsResponse?.perPage || 1}
onPageChange={(page) => {
listRoadmapRatings(page).then();
}}
/>
</div>
)}
{!isLoading && ratings.length === 0 && (
<div className="flex flex-col items-center justify-center py-10">
<MessageCircle className="size-12 text-gray-200" />
<p className="mt-3 text-base text-gray-600">No Feedbacks</p>
</div>
)}
</div>
);
}

View File

@@ -0,0 +1,273 @@
import { useEffect, useState } from 'react';
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal';
import { formatCommaNumber } from '../../lib/number';
import { Rating } from '../Rating/Rating';
import { httpGet, httpPost } from '../../lib/http';
import { useToast } from '../../hooks/use-toast';
import { isLoggedIn } from '../../lib/jwt';
import { Loader2, Star } from 'lucide-react';
import { cn } from '../../lib/classname';
import { showLoginPopup } from '../../lib/popup';
import { Spinner } from '../ReactIcons/Spinner.tsx';
type GetMyRoadmapRatingResponse = {
id?: string;
rating: number;
feedback?: string;
};
type RateRoadmapFormProps = {
ratings: RoadmapDocument['ratings'];
roadmapSlug: string;
canManage?: boolean;
};
export function RateRoadmapForm(props: RateRoadmapFormProps) {
const { ratings, canManage = false, roadmapSlug } = props;
const { breakdown = {}, average: _average } = ratings || {};
const average = _average || 0;
const ratingsKeys = [5, 4, 3, 2, 1];
const totalRatings = ratingsKeys.reduce(
(total, rating) => total + breakdown?.[rating] || 0,
0,
);
// if no rating then only show the ratings breakdown if the user can manage the roadmap
const showRatingsBreakdown = average > 0 || canManage;
const toast = useToast();
const [isLoading, setIsLoading] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isRatingRoadmap, setIsRatingRoadmap] = useState(!showRatingsBreakdown);
const [userRatingId, setUserRatingId] = useState<string | undefined>();
const [userRating, setUserRating] = useState(0);
const [userFeedback, setUserFeedback] = useState('');
const loadMyRoadmapRating = async () => {
// user can't have the rating for their own roadmap
if (canManage) {
setIsLoading(false);
return;
}
const { response, error } = await httpGet<GetMyRoadmapRatingResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-my-roadmap-rating/${roadmapSlug}`,
);
if (!response || error) {
toast.error(error?.message || 'Something went wrong');
setIsLoading(false);
return;
}
setUserRatingId(response?.id);
setUserRating(response?.rating);
setUserFeedback(response?.feedback || '');
setIsLoading(false);
};
const submitMyRoadmapRating = async () => {
if (userRating <= 0) {
toast.error('At least give it a star');
return;
}
setIsSubmitting(true);
const path = userRatingId
? 'v1-update-custom-roadmap-rating'
: 'v1-rate-custom-roadmap';
const { response, error } = await httpPost<{
id: string;
}>(`${import.meta.env.PUBLIC_API_URL}/${path}/${roadmapSlug}`, {
rating: userRating,
feedback: userFeedback,
});
if (!response || error) {
toast.error(error?.message || 'Something went wrong');
setIsSubmitting(false);
return;
}
window.location.reload();
};
useEffect(() => {
if (!isLoggedIn() || !roadmapSlug) {
setIsLoading(false);
return;
}
loadMyRoadmapRating().then();
}, [roadmapSlug]);
return (
<div className="flex flex-col gap-3">
{showRatingsBreakdown && !isRatingRoadmap && (
<>
<ul className="flex flex-col gap-1 rounded-lg bg-white p-5">
{ratingsKeys.map((rating) => {
const percentage =
totalRatings <= 0
? 0
: ((breakdown?.[rating] || 0) / totalRatings) * 100;
return (
<li
key={`rating-${rating}`}
className="flex items-center gap-2 text-sm"
>
<span className="shrink-0">{rating} star</span>
<div className="relative h-8 w-full overflow-hidden rounded-md border">
<div
className="h-full bg-yellow-300"
style={{ width: `${percentage}%` }}
></div>
{percentage > 0 && (
<span className="absolute right-3 top-1/2 flex -translate-y-1/2 items-center justify-center text-xs text-black">
{formatCommaNumber(breakdown?.[rating] || 0)}
</span>
)}
</div>
<span className="w-[35px] shrink-0 text-xs text-gray-500">
{parseInt(`${percentage}`, 10)}%
</span>
</li>
);
})}
</ul>
</>
)}
{!canManage && !isRatingRoadmap && (
<div className="relative min-h-[100px] rounded-lg bg-white p-4">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<Spinner isDualRing={false} className="h-5 w-5" />
</div>
)}
{!isLoading && !isRatingRoadmap && !userRatingId && (
<>
<p className="mb-2 text-center text-sm font-medium">
Rate and share your thoughts with the roadmap creator.
</p>
<button
className="flex h-10 w-full items-center justify-center rounded-full bg-black p-2.5 text-sm font-medium text-white disabled:opacity-60"
onClick={() => {
if (!isLoggedIn()) {
showLoginPopup();
return;
}
setIsRatingRoadmap(true);
}}
disabled={isLoading}
>
{isLoading ? (
<Loader2 className="size-4 animate-spin" />
) : (
'Rate Roadmap'
)}
</button>
</>
)}
{!isLoading && !isRatingRoadmap && userRatingId && (
<div>
<h3 className="mb-2.5 flex items-center justify-between text-base font-semibold">
Your Feedback
<button
className="ml-2 text-sm font-medium text-blue-500 underline underline-offset-2"
onClick={() => {
setIsRatingRoadmap(true);
}}
>
Edit Rating
</button>
</h3>
<div className="flex items-center gap-2">
<Rating rating={userRating} starSize={19} readOnly /> (
{userRating})
</div>
{userFeedback && <p className="mt-2 text-sm">{userFeedback}</p>}
</div>
)}
</div>
)}
{!canManage && isRatingRoadmap && (
<div className="rounded-lg bg-white p-5">
<h3 className="font-semibold">Rate this roadmap</h3>
<p className="mt-1 text-sm">
Share your thoughts with the roadmap creator.
</p>
<form
className="mt-4"
onSubmit={(e) => {
e.preventDefault();
submitMyRoadmapRating().then();
}}
>
<Rating
rating={userRating}
onRatingChange={(rating) => {
setUserRating(rating);
}}
starSize={32}
/>
<div className="mt-3 flex flex-col gap-1">
<label
htmlFor="rating-feedback"
className="block text-sm font-medium"
>
Feedback to Creator{' '}
<span className="font-normal text-gray-400">(Optional)</span>
</label>
<textarea
id="rating-feedback"
className="min-h-24 rounded-md border p-2 text-sm outline-none focus:border-gray-500"
placeholder="Share your thoughts with the roadmap creator"
value={userFeedback}
onChange={(e) => {
setUserFeedback(e.target.value);
}}
/>
</div>
<div className={cn('mt-4 grid grid-cols-2 gap-1')}>
<button
className="h-10 w-full rounded-full border p-2.5 text-sm font-medium disabled:opacity-60"
onClick={() => {
setIsRatingRoadmap(false);
}}
type="button"
disabled={isSubmitting}
>
Cancel
</button>
<button
className="flex h-10 w-full items-center justify-center rounded-full bg-black p-2.5 text-sm font-medium text-white disabled:opacity-60"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? (
<Loader2 className="size-4 animate-spin" />
) : userRatingId ? (
'Update Rating'
) : (
'Submit Rating'
)}
</button>
</div>
</form>
</div>
)}
</div>
);
}

View File

@@ -1,6 +1,6 @@
import { useRef, useState } from 'react';
import { useOutsideClick } from '../../hooks/use-outside-click';
import { Lock, MoreVertical, Shapes, Trash2 } from 'lucide-react';
import { Lock, MoreVertical, PenSquare, Shapes, Trash2 } from 'lucide-react';
type RoadmapActionButtonProps = {
onDelete?: () => void;
@@ -32,9 +32,23 @@ export function RoadmapActionButton(props: RoadmapActionButtonProps) {
{isOpen && (
<div
ref={menuRef}
className="align-right absolute right-0 top-full mt-1 w-[140px] rounded-md bg-slate-800 px-2 py-2 text-white shadow-md z-[9999]"
className="align-right absolute right-0 top-full z-[9999] mt-1 w-[140px] rounded-md bg-slate-800 px-2 py-2 text-white shadow-md"
>
<ul>
{onCustomize && (
<li>
<button
onClick={() => {
setIsOpen(false);
onCustomize();
}}
className="flex w-full cursor-pointer items-center rounded p-2 text-sm font-medium text-slate-100 hover:bg-slate-700"
>
<PenSquare size={14} className="mr-2" />
Edit
</button>
</li>
)}
{onUpdateSharing && (
<li>
<button
@@ -49,20 +63,6 @@ export function RoadmapActionButton(props: RoadmapActionButtonProps) {
</button>
</li>
)}
{onCustomize && (
<li>
<button
onClick={() => {
setIsOpen(false);
onCustomize();
}}
className="flex w-full cursor-pointer items-center rounded p-2 text-sm font-medium text-slate-100 hover:bg-slate-700"
>
<Shapes size={14} className="mr-2" />
Customize
</button>
</li>
)}
{onDelete && (
<li>
<button

View File

@@ -8,11 +8,9 @@ import { httpDelete, httpPut } from '../../lib/http';
import { type TeamResourceConfig } from '../CreateTeam/RoadmapSelector';
import { useToast } from '../../hooks/use-toast';
import { RoadmapActionButton } from './RoadmapActionButton';
import { Lock, Shapes } from 'lucide-react';
import { Modal } from '../Modal';
import { ShareSuccess } from '../ShareOptions/ShareSuccess';
import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx';
import { CustomRoadmapAlert } from './CustomRoadmapAlert.tsx';
import { CustomRoadmapRatings } from './CustomRoadmapRatings.tsx';
type RoadmapHeaderProps = {};
@@ -28,10 +26,12 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
creator,
team,
visibility,
ratings,
unseenRatingCount,
showcaseStatus,
} = useStore(currentRoadmap) || {};
const [isSharing, setIsSharing] = useState(false);
const [isSharingWithOthers, setIsSharingWithOthers] = useState(false);
const toast = useToast();
async function deleteResource() {
@@ -72,23 +72,6 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${creator?.avatar}`
: '/images/default-avatar.png';
const sharingWithOthersModal = isSharingWithOthers && (
<Modal
onClose={() => setIsSharingWithOthers(false)}
wrapperClassName="max-w-lg"
bodyClassName="p-4 flex flex-col"
>
<ShareSuccess
visibility="public"
roadmapSlug={roadmapSlug}
roadmapId={roadmapId!}
description={description}
onClose={() => setIsSharingWithOthers(false)}
isSharingWithOthers={true}
/>
</Modal>
);
return (
<div className="border-b">
<div className="container relative py-5 sm:py-12">
@@ -127,11 +110,12 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
<div className="flex justify-between gap-2 sm:gap-0">
<div className="flex justify-stretch gap-1 sm:gap-2">
<a
href="/roadmaps"
href="/community"
className="rounded-md bg-gray-500 px-3 py-1.5 text-xs font-medium text-white hover:bg-gray-600 sm:text-sm"
aria-label="Back to All Roadmaps"
>
&larr;<span className="hidden sm:inline">&nbsp;All Roadmaps</span>
&larr;
<span className="hidden sm:inline">&nbsp;Discover more</span>
</a>
<ShareRoadmapButton
@@ -166,26 +150,13 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
/>
)}
<a
href={`${
import.meta.env.PUBLIC_EDITOR_APP_URL
}/${$currentRoadmap?._id}`}
target="_blank"
className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:border-gray-300 hover:bg-gray-300 sm:px-3 sm:text-sm"
>
<Shapes className="mr-1.5 h-4 w-4 stroke-[2.5]" />
<span className="hidden sm:inline-block">Edit Roadmap</span>
<span className="sm:hidden">Edit</span>
</a>
<button
onClick={() => setIsSharing(true)}
className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:border-gray-300 hover:bg-gray-300 sm:px-3 sm:text-sm"
>
<Lock className="mr-1.5 h-4 w-4 stroke-[2.5]" />
Sharing
</button>
<RoadmapActionButton
onUpdateSharing={() => setIsSharing(true)}
onCustomize={() => {
window.location.href = `${
import.meta.env.PUBLIC_EDITOR_APP_URL
}/${$currentRoadmap?._id}`;
}}
onDelete={() => {
const confirmation = window.confirm(
'Are you sure you want to delete this roadmap?',
@@ -201,17 +172,13 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
</>
)}
{!$canManageCurrentRoadmap && visibility === 'public' && (
<>
{sharingWithOthersModal}
<button
onClick={() => setIsSharingWithOthers(true)}
className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:border-gray-300 hover:bg-gray-300 sm:px-3 sm:text-sm"
>
<Lock className="mr-1.5 h-4 w-4 stroke-[2.5]" />
Share with Others
</button>
</>
{((ratings?.average || 0) > 0 || showcaseStatus === 'visible') && (
<CustomRoadmapRatings
roadmapSlug={roadmapSlug!}
ratings={ratings!}
canManage={$canManageCurrentRoadmap}
unseenRatingCount={unseenRatingCount || 0}
/>
)}
</div>
</div>

View File

@@ -17,9 +17,8 @@ export function SkeletonRoadmapHeader() {
<div className="h-7 w-[35.04px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[85px]" />
</div>
<div className="flex items-center gap-2">
<div className="h-7 w-[60.52px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[139.71px]" />
<div className="h-7 w-[71.48px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[100.34px]" />
<div className="h-7 w-[32px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[89.73px]" />
<div className="h-7 w-[60.52px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[92px]" />
<div className="h-7 w-[71.48px] animate-pulse rounded-md bg-gray-300 sm:h-8 sm:w-[139px]" />
</div>
</div>

View File

@@ -0,0 +1,15 @@
import type { SVGProps } from 'react';
export function DailyDevIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 32 18" xmlns="http://www.w3.org/2000/svg" {...props}>
<g fill="currentColor" fillRule="nonzero">
<path
d="M26.633 8.69l-3.424-3.431 1.711-3.43 5.563 5.575c.709.71.709 1.861 0 2.572l-6.847 6.86c-.709.711-1.858.711-2.567 0a1.821 1.821 0 010-2.571l5.564-5.575z"
fillOpacity="0.64"
></path>
<path d="M21.07.536a1.813 1.813 0 012.568 0l1.283 1.286L9.945 16.83c-.709.71-1.858.71-2.567 0l-1.284-1.287L21.071.536zm-6.418 4.717l-2.567 2.572-3.424-3.43-4.28 4.288 3.424 3.43-1.71 3.43L.531 9.97a1.821 1.821 0 010-2.572L7.378.537A1.813 1.813 0 019.945.535l4.707 4.717z"></path>
</g>
</svg>
);
}

View File

@@ -0,0 +1,21 @@
import { ErrorIcon } from '../ReactIcons/ErrorIcon';
type DiscoverErrorProps = {
message: string;
};
export function DiscoverError(props: DiscoverErrorProps) {
const { message } = props;
return (
<div className="flex min-h-[250px] flex-col items-center justify-center rounded-xl border px-5 py-3 sm:px-0 sm:py-20">
<ErrorIcon additionalClasses="mb-4 h-8 w-8 sm:h-14 sm:w-14" />
<h2 className="mb-1 text-lg font-semibold sm:text-xl">
Oops! Something went wrong
</h2>
<p className="mb-3 text-balance text-center text-xs text-gray-800 sm:text-sm">
{message}
</p>
</div>
);
}

View File

@@ -0,0 +1,77 @@
import { ArrowDownWideNarrow, Check, ChevronDown } from 'lucide-react';
import { useRef, useState } from 'react';
import { useOutsideClick } from '../../hooks/use-outside-click';
import type { SortByValues } from './DiscoverRoadmaps';
const sortingLabels: { label: string; value: SortByValues }[] = [
{
label: 'Newest',
value: 'createdAt',
},
{
label: 'Oldest',
value: '-createdAt',
},
{
label: 'Highest Rated',
value: 'rating',
},
{
label: 'Lowest Rated',
value: '-rating',
},
];
type DiscoverRoadmapSortingProps = {
sortBy: SortByValues;
onSortChange: (sortBy: SortByValues) => void;
};
export function DiscoverRoadmapSorting(props: DiscoverRoadmapSortingProps) {
const { sortBy, onSortChange } = props;
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
const selectedValue = sortingLabels.find((item) => item.value === sortBy);
useOutsideClick(dropdownRef, () => {
setIsOpen(false);
});
return (
<div
className="min-auto relative flex flex-shrink-0 sm:min-w-[140px]"
ref={dropdownRef}
>
<button
className="py-15 flex w-full items-center justify-between gap-2 rounded-md border px-2 text-sm bg-white"
onClick={() => setIsOpen(!isOpen)}
>
<span>{selectedValue?.label}</span>
<span>
<ChevronDown className="ml-4 h-3.5 w-3.5" />
</span>
</button>
{isOpen && (
<div className="absolute right-0 top-10 z-10 min-w-40 overflow-hidden rounded-md border border-gray-200 bg-white shadow-lg">
{sortingLabels.map((item) => (
<button
key={item.value}
className="flex w-full items-center gap-2 px-4 py-2 text-sm hover:bg-gray-100"
onClick={() => {
onSortChange(item.value);
setIsOpen(false);
}}
>
<span>{item.label}</span>
{item.value === sortBy && <Check className="ml-auto h-4 w-4" />}
</button>
))}
</div>
)}
</div>
);
}

View File

@@ -0,0 +1,271 @@
import { Shapes } from 'lucide-react';
import type { ListShowcaseRoadmapResponse } from '../../api/roadmap';
import { Pagination } from '../Pagination/Pagination';
import { SearchRoadmap } from './SearchRoadmap';
import { EmptyDiscoverRoadmaps } from './EmptyDiscoverRoadmaps';
import { Rating } from '../Rating/Rating';
import { useEffect, useState } from 'react';
import { deleteUrlParam, getUrlParams, setUrlParams } from '../../lib/browser';
import { LoadingRoadmaps } from '../ExploreAIRoadmap/LoadingRoadmaps';
import { httpGet } from '../../lib/http';
import { useToast } from '../../hooks/use-toast';
import { DiscoverRoadmapSorting } from './DiscoverRoadmapSorting';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
import { Tooltip } from '../Tooltip.tsx';
type DiscoverRoadmapsProps = {};
export type SortByValues = 'rating' | '-rating' | 'createdAt' | '-createdAt';
type QueryParams = {
q?: string;
s?: SortByValues;
p?: string;
};
type PageState = {
searchTerm: string;
sortBy: SortByValues;
currentPage: number;
};
export function DiscoverRoadmaps(props: DiscoverRoadmapsProps) {
const toast = useToast();
const [pageState, setPageState] = useState<PageState>({
searchTerm: '',
sortBy: 'createdAt',
currentPage: 0,
});
const [isLoading, setIsLoading] = useState(true);
const [roadmapsResponse, setRoadmapsResponse] =
useState<ListShowcaseRoadmapResponse | null>(null);
useEffect(() => {
const queryParams = getUrlParams() as QueryParams;
setPageState({
searchTerm: queryParams.q || '',
sortBy: queryParams.s || 'createdAt',
currentPage: +(queryParams.p || '1'),
});
}, []);
useEffect(() => {
setIsLoading(true);
if (!pageState.currentPage) {
return;
}
// only set the URL params if the user modified anything
if (
pageState.currentPage !== 1 ||
pageState.searchTerm !== '' ||
pageState.sortBy !== 'createdAt'
) {
setUrlParams({
q: pageState.searchTerm,
s: pageState.sortBy,
p: String(pageState.currentPage),
});
} else {
deleteUrlParam('q');
deleteUrlParam('s');
deleteUrlParam('p');
}
loadAIRoadmaps(
pageState.currentPage,
pageState.searchTerm,
pageState.sortBy,
).finally(() => {
setIsLoading(false);
});
}, [pageState]);
const loadAIRoadmaps = async (
currPage: number = 1,
searchTerm: string = '',
sortBy: SortByValues = 'createdAt',
) => {
const { response, error } = await httpGet<ListShowcaseRoadmapResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-list-showcase-roadmap`,
{
currPage,
...(searchTerm && { searchTerm }),
...(sortBy && { sortBy }),
},
);
if (error || !response) {
toast.error(error?.message || 'Something went wrong');
return;
}
setRoadmapsResponse(response);
};
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
const roadmaps = roadmapsResponse?.data || [];
const loadingIndicator = isLoading && <LoadingRoadmaps />;
return (
<>
{isCreatingRoadmap && (
<CreateRoadmapModal
onClose={() => {
setIsCreatingRoadmap(false);
}}
/>
)}
<div className="border-b bg-white pt-10 pb-7">
<div className="container text-left">
<div className="flex flex-col items-start bg-white">
<h1 className="mb-1 text-2xl font-bold sm:text-4xl">
Community Roadmaps
</h1>
<p className="mb-3 text-base text-gray-500">
An unvetted, selected list of community-curated roadmaps
</p>
<div className="relative">
<div className="flex flex-col sm:flex-row items-center gap-1.5">
<span className="group relative normal-case">
<Tooltip
position={'bottom-left'}
additionalClass={
'translate-y-0.5 bg-yellow-300 font-normal !text-black'
}
>
Ask us to feature it once you're done!
</Tooltip>
<button
className="rounded-md bg-black px-3.5 py-1.5 text-sm font-medium text-white transition-colors hover:bg-black"
onClick={() => {
setIsCreatingRoadmap(true);
}}
>
Create your own roadmap
</button>
</span>
<span className="group relative normal-case">
<Tooltip
position={'bottom-left'}
additionalClass={
'translate-y-0.5 bg-yellow-300 font-normal !text-black'
}
>
Up-to-date and maintained by the official team
</Tooltip>
<a
href="/roadmaps"
className="inline-block rounded-md bg-gray-300 px-3.5 py-1.5 text-sm text-black sm:py-1.5 sm:text-sm"
>
Visit our official roadmaps
</a>
</span>
</div>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 py-3">
<section className="container mx-auto py-3">
<div className="mb-3.5 flex items-stretch justify-between gap-2.5">
<SearchRoadmap
total={roadmapsResponse?.totalCount || 0}
value={pageState.searchTerm}
isLoading={isLoading}
onValueChange={(value) => {
setPageState({
...pageState,
searchTerm: value,
currentPage: 1,
});
}}
/>
<DiscoverRoadmapSorting
sortBy={pageState.sortBy}
onSortChange={(sortBy) => {
setPageState({
...pageState,
sortBy,
});
}}
/>
</div>
{loadingIndicator}
{roadmaps.length === 0 && !isLoading && <EmptyDiscoverRoadmaps />}
{roadmaps.length > 0 && !isLoading && (
<>
<ul className="mb-4 grid grid-cols-1 items-stretch gap-3 sm:grid-cols-2 lg:grid-cols-3">
{roadmaps.map((roadmap) => {
const roadmapLink = `/r/${roadmap.slug}`;
const totalRatings = Object.keys(
roadmap.ratings?.breakdown || [],
).reduce(
(acc: number, key: string) =>
acc + roadmap.ratings.breakdown[key as any],
0,
);
return (
<li key={roadmap._id} className="h-full min-h-[175px]">
<a
key={roadmap._id}
href={roadmapLink}
className="flex h-full flex-col rounded-lg border bg-white p-3.5 transition-colors hover:border-gray-300 hover:bg-gray-50"
target={'_blank'}
>
<div className="grow">
<h2 className="text-balance text-base font-bold leading-tight">
{roadmap.title}
</h2>
<p className="mt-2 text-sm text-gray-500">
{roadmap.description}
</p>
</div>
<div className="flex items-center justify-between gap-2">
<span className="flex items-center gap-1 text-xs text-gray-400">
<Shapes size={15} className="inline-block" />
{Intl.NumberFormat('en-US', {
notation: 'compact',
}).format(roadmap.topicCount)}{' '}
</span>
<Rating
rating={roadmap?.ratings?.average || 0}
readOnly={true}
starSize={16}
total={totalRatings}
/>
</div>
</a>
</li>
);
})}
</ul>
<Pagination
currPage={roadmapsResponse?.currPage || 1}
totalPages={roadmapsResponse?.totalPages || 1}
perPage={roadmapsResponse?.perPage || 0}
totalCount={roadmapsResponse?.totalCount || 0}
onPageChange={(page) => {
setPageState({
...pageState,
currentPage: page,
});
}}
/>
</>
)}
</section>
</div>
</>
);
}

View File

@@ -0,0 +1,53 @@
import { Map, Wand2 } from 'lucide-react';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
export function EmptyDiscoverRoadmaps() {
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
const creatingRoadmapModal = isCreatingRoadmap && (
<CreateRoadmapModal
onClose={() => setIsCreatingRoadmap(false)}
onCreated={(roadmap) => {
window.location.href = `${
import.meta.env.PUBLIC_EDITOR_APP_URL
}/${roadmap?._id}`;
}}
/>
);
return (
<>
{creatingRoadmapModal}
<div className="flex min-h-[250px] flex-col items-center justify-center rounded-xl border px-5 py-3 sm:px-0 sm:py-20 bg-white">
<Map className="mb-4 h-8 w-8 opacity-10 sm:h-14 sm:w-14" />
<h2 className="mb-1 text-lg font-semibold sm:text-xl">
No Roadmaps Found
</h2>
<p className="mb-3 text-balance text-center text-xs text-gray-800 sm:text-sm">
Try searching for something else or create a new roadmap.
</p>
<div className="flex flex-col items-center gap-1 sm:flex-row sm:gap-1.5">
<button
className="flex w-full items-center gap-1.5 rounded-md bg-gray-900 px-3 py-1.5 text-xs text-white sm:w-auto sm:text-sm"
type="button"
onClick={() => {
setIsCreatingRoadmap(true);
}}
>
<Wand2 className="h-4 w-4" />
Create your Roadmap
</button>
<a
href="/roadmaps"
className="flex w-full items-center gap-1.5 rounded-md bg-gray-300 px-3 py-1.5 text-xs text-black hover:bg-gray-400 sm:w-auto sm:text-sm"
>
<Map className="h-4 w-4" />
Visit Official Roadmaps
</a>
</div>
</div>
</>
);
}

View File

@@ -0,0 +1,76 @@
import { Search } from 'lucide-react';
import { useEffect, useState } from 'react';
import { useDebounceValue } from '../../hooks/use-debounce';
import { Spinner } from '../ReactIcons/Spinner';
type SearchRoadmapProps = {
value: string;
total: number;
isLoading: boolean;
onValueChange: (value: string) => void;
};
export function SearchRoadmap(props: SearchRoadmapProps) {
const { total, value: defaultValue, onValueChange, isLoading } = props;
const [term, setTerm] = useState(defaultValue);
const debouncedTerm = useDebounceValue(term, 500);
useEffect(() => {
setTerm(defaultValue);
}, [defaultValue]);
useEffect(() => {
if (debouncedTerm && debouncedTerm.length < 3) {
return;
}
if (debouncedTerm === defaultValue) {
return;
}
onValueChange(debouncedTerm);
}, [debouncedTerm]);
return (
<div className="relative flex w-full items-center gap-3">
<form
className="relative flex w-full max-w-[310px] items-center"
onSubmit={(e) => {
e.preventDefault();
onValueChange(term);
}}
>
<label
className="absolute left-3 flex h-full items-center text-gray-500"
htmlFor="search"
>
<Search className="h-4 w-4" />
</label>
<input
id="q"
name="q"
type="text"
minLength={3}
placeholder="Type 3 or more characters to search..."
className="w-full rounded-md border border-gray-200 px-3 py-2 pl-9 text-sm transition-colors focus:border-black focus:outline-none"
value={term}
onChange={(e) => setTerm(e.target.value)}
/>
{isLoading && (
<span className="absolute right-3 top-0 flex h-full items-center text-gray-500">
<Spinner isDualRing={false} className={`h-3 w-3`} />
</span>
)}
</form>
{total > 0 && (
<p className="hidden flex-shrink-0 text-sm text-gray-500 sm:block">
{Intl.NumberFormat('en-US', {
notation: 'compact',
}).format(total)}{' '}
result{total > 1 ? 's' : ''} found
</p>
)}
</div>
);
}

View File

@@ -0,0 +1,106 @@
import { useEffect, useState, type CSSProperties } from 'react';
import {
EditorRoadmapRenderer,
type RoadmapRendererProps,
} from './EditorRoadmapRenderer';
import { Spinner } from '../ReactIcons/Spinner';
import {
clearMigratedRoadmapProgress,
type ResourceType,
} from '../../lib/resource-progress';
import { httpGet } from '../../lib/http';
import { ProgressNudge } from '../FrameRenderer/ProgressNudge';
import { getUrlParams } from '../../lib/browser.ts';
import { cn } from '../../lib/classname.ts';
import { getUser } from '../../lib/jwt.ts';
type EditorRoadmapProps = {
resourceId: string;
resourceType?: ResourceType;
dimensions: {
width: number;
height: number;
};
};
export function EditorRoadmap(props: EditorRoadmapProps) {
const { resourceId, resourceType = 'roadmap', dimensions } = props;
const [hasSwitchedRoadmap, setHasSwitchedRoadmap] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [roadmapData, setRoadmapData] = useState<
Omit<RoadmapRendererProps, 'resourceId'> | undefined
>(undefined);
const loadRoadmapData = async () => {
setIsLoading(true);
const { r: switchRoadmapId } = getUrlParams();
const { response, error } = await httpGet<
Omit<RoadmapRendererProps, 'resourceId'>
>(`/${switchRoadmapId || resourceId}.json`);
if (error) {
console.error(error);
return;
}
setRoadmapData(response);
setIsLoading(false);
setHasSwitchedRoadmap(!!switchRoadmapId);
};
useEffect(() => {
clearMigratedRoadmapProgress(resourceType, resourceId);
loadRoadmapData().finally();
}, [resourceId]);
const aspectRatio = dimensions.width / dimensions.height;
if (!roadmapData || isLoading) {
return (
<div
style={
!hasSwitchedRoadmap
? ({
'--aspect-ratio': aspectRatio,
} as CSSProperties)
: undefined
}
className={
'flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center'
}
>
<div className="flex w-full justify-center">
<Spinner
innerFill="#2563eb"
outerFill="#E5E7EB"
className="h-6 w-6 animate-spin sm:h-12 sm:w-12"
/>
</div>
</div>
);
}
return (
<div
style={
!hasSwitchedRoadmap
? ({
'--aspect-ratio': aspectRatio,
} as CSSProperties)
: undefined
}
className={
'flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center'
}
>
<EditorRoadmapRenderer
{...roadmapData}
dimensions={dimensions}
resourceId={resourceId}
/>
<ProgressNudge resourceId={resourceId} resourceType={resourceType} />
</div>
);
}

View File

@@ -0,0 +1,63 @@
svg text tspan {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeSpeed;
}
svg > g[data-type='topic'],
svg > g[data-type='subtopic'],
svg g[data-type='link-item'],
svg > g[data-type='button'],
svg > g[data-type='resourceButton'],
svg > g[data-type='todo-checkbox'],
svg > g[data-type='todo'] {
cursor: pointer;
}
svg > g[data-type='topic']:hover > rect {
fill: var(--hover-color);
}
svg > g[data-type='subtopic']:hover > rect {
fill: var(--hover-color);
}
svg g[data-type='button']:hover,
svg g[data-type='link-item']:hover,
svg g[data-type='resourceButton']:hover,
svg g[data-type='todo-checkbox']:hover {
opacity: 0.8;
}
svg .done rect {
fill: #cbcbcb !important;
}
svg .done text,
svg .skipped text {
text-decoration: line-through;
}
svg > g[data-type='topic'].learning > rect + text,
svg > g[data-type='topic'].done > rect + text {
fill: black;
}
svg .done text[fill='#ffffff'] {
fill: black;
}
svg > g[data-type='subtipic'].done > rect + text,
svg > g[data-type='subtipic'].learning > rect + text {
fill: #cbcbcb;
}
svg .learning rect {
fill: #dad1fd !important;
}
svg .learning text {
text-decoration: underline;
}
svg .skipped rect {
fill: #496b69 !important;
}

View File

@@ -0,0 +1,218 @@
import { useCallback, useEffect, useRef } from 'react';
import './EditorRoadmapRenderer.css';
import {
renderResourceProgress,
updateResourceProgress,
type ResourceProgressType,
renderTopicProgress,
refreshProgressCounters,
} from '../../lib/resource-progress';
import { pageProgressMessage } from '../../stores/page';
import { useToast } from '../../hooks/use-toast';
import type { Edge, Node } from 'reactflow';
import { Renderer } from '../../../editor/renderer';
import { slugify } from '../../lib/slugger';
import { isLoggedIn } from '../../lib/jwt';
import { showLoginPopup } from '../../lib/popup';
export type RoadmapRendererProps = {
resourceId: string;
nodes: Node[];
edges: Edge[];
dimensions: {
width: number;
height: number;
};
};
type RoadmapNodeDetails = {
nodeId: string;
nodeType: string;
targetGroup: SVGElement;
title?: string;
};
function getNodeDetails(svgElement: SVGElement): RoadmapNodeDetails | null {
const targetGroup = (svgElement?.closest('g') as SVGElement) || {};
const nodeId = targetGroup?.dataset?.nodeId;
const nodeType = targetGroup?.dataset?.type;
const title = targetGroup?.dataset?.title;
if (!nodeId || !nodeType) {
return null;
}
return { nodeId, nodeType, targetGroup, title };
}
const allowedNodeTypes = [
'topic',
'subtopic',
'button',
'link-item',
'resourceButton',
'todo',
'todo-checkbox',
];
export function EditorRoadmapRenderer(props: RoadmapRendererProps) {
const { resourceId, nodes = [], edges = [] } = props;
const roadmapRef = useRef<HTMLDivElement>(null);
const toast = useToast();
async function updateTopicStatus(
topicId: string,
newStatus: ResourceProgressType,
) {
pageProgressMessage.set('Updating progress');
updateResourceProgress(
{
resourceId,
resourceType: 'roadmap',
topicId,
},
newStatus,
)
.then(() => {
renderTopicProgress(topicId, newStatus);
})
.catch((err) => {
toast.error('Something went wrong, please try again.');
console.error(err);
})
.finally(() => {
pageProgressMessage.set('');
refreshProgressCounters();
});
return;
}
const handleSvgClick = useCallback((e: MouseEvent) => {
const target = e.target as SVGElement;
const { nodeId, nodeType, targetGroup, title } =
getNodeDetails(target) || {};
if (!nodeId || !nodeType || !allowedNodeTypes.includes(nodeType)) {
return;
}
if (
nodeType === 'button' ||
nodeType === 'link-item' ||
nodeType === 'resourceButton'
) {
const link = targetGroup?.dataset?.link || '';
const isExternalLink = link.startsWith('http');
if (isExternalLink) {
window.open(link, '_blank');
} else {
window.location.href = link;
}
return;
}
const isCurrentStatusLearning = targetGroup?.classList.contains('learning');
const isCurrentStatusSkipped = targetGroup?.classList.contains('skipped');
if (nodeType === 'todo-checkbox') {
e.preventDefault();
if (!isLoggedIn()) {
showLoginPopup();
return;
}
const newStatus = targetGroup?.classList.contains('done')
? 'pending'
: 'done';
updateTopicStatus(nodeId, newStatus);
return;
}
if (e.shiftKey) {
e.preventDefault();
if (!isLoggedIn()) {
showLoginPopup();
return;
}
updateTopicStatus(
nodeId,
isCurrentStatusLearning ? 'pending' : 'learning',
);
return;
} else if (e.altKey) {
e.preventDefault();
if (!isLoggedIn()) {
showLoginPopup();
return;
}
updateTopicStatus(nodeId, isCurrentStatusSkipped ? 'pending' : 'skipped');
return;
}
if (!title) {
return;
}
const detailsPattern = `${slugify(title)}@${nodeId}`;
window.dispatchEvent(
new CustomEvent('roadmap.node.click', {
detail: {
topicId: detailsPattern,
resourceId,
resourceType: 'roadmap',
},
}),
);
}, []);
const handleSvgRightClick = useCallback((e: MouseEvent) => {
e.preventDefault();
const target = e.target as SVGElement;
const { nodeId, nodeType, targetGroup } = getNodeDetails(target) || {};
if (!nodeId || !nodeType || !allowedNodeTypes.includes(nodeType)) {
return;
}
if (nodeType === 'button') {
return;
}
if (!isLoggedIn()) {
showLoginPopup();
return;
}
const isCurrentStatusDone = targetGroup?.classList.contains('done');
updateTopicStatus(nodeId, isCurrentStatusDone ? 'pending' : 'done');
}, []);
useEffect(() => {
if (!roadmapRef?.current) {
return;
}
roadmapRef?.current?.addEventListener('click', handleSvgClick);
roadmapRef?.current?.addEventListener('contextmenu', handleSvgRightClick);
return () => {
roadmapRef?.current?.removeEventListener('click', handleSvgClick);
roadmapRef?.current?.removeEventListener(
'contextmenu',
handleSvgRightClick,
);
};
}, []);
return (
<Renderer
ref={roadmapRef}
roadmap={{ nodes, edges }}
onRendered={() => {
roadmapRef.current?.setAttribute('data-renderer', 'editor');
renderResourceProgress('roadmap', resourceId).finally();
}}
/>
);
}

View File

@@ -4,7 +4,7 @@ export function LoadingRoadmaps() {
{new Array(21).fill(0).map((_, index) => (
<li
key={index}
className="h-[95px] animate-pulse rounded-md border bg-gray-100"
className="h-[175px] animate-pulse rounded-md border bg-gray-200"
/>
))}
</ul>

View File

@@ -0,0 +1,20 @@
type AIAnnouncementProps = {};
export function FeatureAnnouncement(props: AIAnnouncementProps) {
return (
<a
className="rounded-md border border-dashed border-purple-600 px-3 py-1.5 text-purple-400 transition-colors hover:border-purple-400 hover:text-purple-200"
href="/community"
>
<span className="relative -top-[1px] mr-1 text-xs font-semibold uppercase text-white">
New
</span>{' '}
<span className={'hidden sm:inline'}>
Explore community made roadmaps
</span>
<span className={'inline text-sm sm:hidden'}>
Community roadmaps explorer!
</span>
</a>
);
}

View File

@@ -1,35 +1,47 @@
---
import type { GuideFileType } from '../lib/guide';
import GuideListItem from './GuideListItem.astro';
import { QuestionGroupType } from '../lib/question-group';
export interface Props {
heading: string;
guides: GuideFileType[];
questions: QuestionGroupType[];
}
const { heading, guides } = Astro.props;
const { heading, guides, questions = [] } = Astro.props;
const sortedGuides: (QuestionGroupType | GuideFileType)[] = [
...guides,
...questions,
].sort((a, b) => {
const aDate = new Date(a.frontmatter.date);
const bDate = new Date(b.frontmatter.date);
return bDate.getTime() - aDate.getTime();
});
---
<div class='container'>
<h2 class='text-2xl sm:text-3xl font-bold block'>{heading}</h2>
<h2 class='block text-2xl font-bold sm:text-3xl'>{heading}</h2>
<div class='mt-3 sm:my-5'>
{guides.map((guide) => <GuideListItem guide={guide} />)}
{sortedGuides.map((guide) => <GuideListItem guide={guide} />)}
</div>
<a
href='/guides'
class='hidden sm:inline transition-colors py-2 px-3 text-xs font-medium rounded-full bg-gradient-to-r from-slate-600 to-black hover:from-blue-600 hover:to-blue-800 text-white'
class='hidden rounded-full bg-gradient-to-r from-slate-600 to-black px-3 py-2 text-xs font-medium text-white transition-colors hover:from-blue-600 hover:to-blue-800 sm:inline'
>
View All Guides &rarr;
</a>
<div class='block sm:hidden mt-3'>
<div class='mt-3 block sm:hidden'>
<a
href='/guides'
class='text-sm font-regular block p-2 border border-black text-black rounded-md text-center hover:bg-black hover:text-gray-50'
class='font-regular block rounded-md border border-black p-2 text-center text-sm text-black hover:bg-black hover:text-gray-50'
>
View All Guides &nbsp;&rarr;
</a>
</div>
</div>
</div>

View File

@@ -52,7 +52,7 @@ svg .done rect {
fill: #cbcbcb !important;
}
svg .done rect[stroke="rgb(255,229,153)"] {
svg .done rect[stroke='rgb(255,229,153)'] {
stroke: #cbcbcb !important;
}
@@ -133,10 +133,12 @@ svg .removed path {
}
}
#customized-roadmap #resource-svg-wrap g:not([class]),
#customized-roadmap #resource-svg-wrap circle,
#customized-roadmap #resource-svg-wrap path[stroke='#fff'],
#customized-roadmap #resource-svg-wrap g[data-group-id$='-note'] {
#customized-roadmap #resource-svg-wrap:not([data-renderer]) g:not([class]),
#customized-roadmap #resource-svg-wrap:not([data-renderer]) circle,
#customized-roadmap #resource-svg-wrap:not([data-renderer]) path[stroke='#fff'],
#customized-roadmap
#resource-svg-wrap:not([data-renderer])
g[data-group-id$='-note'] {
display: none;
}

View File

@@ -51,7 +51,7 @@ 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}</span> of <span>{$totalRoadmapNodes}</span> Done
<span>{done > $totalRoadmapNodes ? $totalRoadmapNodes : done}</span> of <span>{$totalRoadmapNodes}</span> Done
</span>
<span

View File

@@ -152,6 +152,10 @@ export class Renderer {
return;
}
if (/^check:/.test(topicId)) {
topicId = topicId.replace('check:', '');
}
pageProgressMessage.set('Updating progress');
updateResourceProgress(
{

View File

@@ -7,12 +7,14 @@ import { useToast } from '../../hooks/use-toast';
import { TrashIcon } from '../ReactIcons/TrashIcon';
import { AddedUserIcon } from '../ReactIcons/AddedUserIcon';
import { AddUserIcon } from '../ReactIcons/AddUserIcon';
import type { AllowedRoadmapRenderer } from '../../lib/roadmap';
type FriendProgressItemProps = {
friend: ListFriendsResponse[0];
onShowResourceProgress: (
resourceId: string,
isCustomResource?: boolean
isCustomResource?: boolean,
renderer?: AllowedRoadmapRenderer,
) => void;
onReload: () => void;
};
@@ -27,7 +29,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
pageProgressMessage.set('Please wait...');
const { response, error } = await httpDelete(
`${import.meta.env.PUBLIC_API_URL}/v1-delete-friend/${userId}`,
{}
{},
);
if (error || !response) {
@@ -43,7 +45,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
pageProgressMessage.set('Please wait...');
const { response, error } = await httpPost(
`${import.meta.env.PUBLIC_API_URL}/v1-add-friend/${userId}`,
{}
{},
);
if (error || !response) {
@@ -92,7 +94,8 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
onClick={() =>
onShowResourceProgress(
progress.resourceId,
progress.isCustomResource
progress.isCustomResource,
progress?.renderer,
)
}
className="group relative overflow-hidden rounded-md border p-2 hover:border-gray-300 hover:text-black focus:outline-none"
@@ -160,7 +163,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
deleteFriend(friend.userId, 'Friend removed').finally(
() => {
pageProgressMessage.set('');
}
},
);
}}
>
@@ -198,7 +201,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
addFriend(friend.userId, 'Friend request accepted').finally(
() => {
pageProgressMessage.set('');
}
},
);
}}
>
@@ -225,7 +228,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
deleteFriend(friend.userId, 'Friend request removed').finally(
() => {
pageProgressMessage.set('');
}
},
);
}}
>
@@ -267,7 +270,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
onClick={() => {
deleteFriend(
friend.userId,
'Friend request withdrawn'
'Friend request withdrawn',
).finally(() => {
pageProgressMessage.set('');
});
@@ -304,7 +307,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
addFriend(friend.userId, 'Friend request accepted').finally(
() => {
pageProgressMessage.set('');
}
},
);
}}
className="mb-1 block w-full max-w-[150px] rounded-md bg-black py-1.5 text-sm text-white"
@@ -316,7 +319,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) {
onClick={() => {
deleteFriend(
friend.userId,
'Friend request rejected'
'Friend request rejected',
).finally(() => {
pageProgressMessage.set('');
});

View File

@@ -11,6 +11,7 @@ import { UserProgressModal } from '../UserProgress/UserProgressModal';
import { InviteFriendPopup } from './InviteFriendPopup';
import { UserCustomProgressModal } from '../UserProgress/UserCustomProgressModal';
import { UserIcon } from 'lucide-react';
import type { AllowedRoadmapRenderer } from '../../lib/roadmap';
type FriendResourceProgress = {
updatedAt: string;
@@ -22,6 +23,7 @@ type FriendResourceProgress = {
skipped: number;
done: number;
total: number;
renderer?: AllowedRoadmapRenderer;
};
export type ListFriendsResponse = {
@@ -55,6 +57,7 @@ export function FriendsPage() {
resourceId: string;
friend: ListFriendsResponse[0];
isCustomResource?: boolean;
renderer?: AllowedRoadmapRenderer;
}>();
const [isLoading, setIsLoading] = useState(true);
@@ -92,8 +95,8 @@ export function FriendsPage() {
(grouping) => grouping.value === selectedGrouping,
);
const filteredFriends = friends.filter(
(friend) => selectedGroupingType?.statuses.includes(friend.status),
const filteredFriends = friends.filter((friend) =>
selectedGroupingType?.statuses.includes(friend.status),
);
const receivedRequests = friends.filter(
@@ -124,6 +127,7 @@ export function FriendsPage() {
resourceType={'roadmap'}
onClose={() => setShowFriendProgress(undefined)}
isCustomResource={showFriendProgress?.isCustomResource}
renderer={showFriendProgress?.renderer}
/>
);
@@ -182,11 +186,16 @@ export function FriendsPage() {
{filteredFriends.map((friend) => (
<FriendProgressItem
friend={friend}
onShowResourceProgress={(resourceId, isCustomResource) => {
onShowResourceProgress={(
resourceId,
isCustomResource,
renderer,
) => {
setShowFriendProgress({
resourceId,
friend,
isCustomResource,
renderer,
});
}}
key={friend.userId}

View File

@@ -25,20 +25,14 @@ import { Ban, Cog, Download, PenSquare, Save, Wand } from 'lucide-react';
import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx';
import { httpGet, httpPost } from '../../lib/http.ts';
import { pageProgressMessage } from '../../stores/page.ts';
import {
deleteUrlParam,
getUrlParams,
setUrlParams,
} from '../../lib/browser.ts';
import { deleteUrlParam, getUrlParams } from '../../lib/browser.ts';
import { downloadGeneratedRoadmapImage } from '../../helper/download-image.ts';
import { showLoginPopup } from '../../lib/popup.ts';
import { cn } from '../../lib/classname.ts';
import { RoadmapTopicDetail } from './RoadmapTopicDetail.tsx';
import { AIRoadmapAlert } from './AIRoadmapAlert.tsx';
import { OpenAISettings } from './OpenAISettings.tsx';
import { IS_KEY_ONLY_ROADMAP_GENERATION } from '../../lib/ai.ts';
import { AITermSuggestionInput } from './AITermSuggestionInput.tsx';
import { useParams } from '../../hooks/use-params.ts';
import { IncreaseRoadmapLimit } from './IncreaseRoadmapLimit.tsx';
import { AuthenticationForm } from '../AuthenticationFlow/AuthenticationForm.tsx';
@@ -294,7 +288,10 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
setIsLoading(false);
pageProgressMessage.set('');
return response.roadmapSlug;
return {
roadmapId: response.roadmapId,
roadmapSlug: response.roadmapSlug,
};
};
const downloadGeneratedRoadmapContent = async () => {
@@ -686,9 +683,9 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
<button
className="inline-flex items-center justify-center gap-2 rounded-md bg-gray-200 py-1.5 pl-2.5 pr-3 text-xs font-medium text-black transition-colors duration-300 hover:bg-gray-300 sm:text-sm"
onClick={async () => {
const roadmapSlug = await saveAIRoadmap();
if (roadmapSlug) {
window.location.href = `/r/${roadmapSlug}`;
const response = await saveAIRoadmap();
if (response?.roadmapSlug) {
window.location.href = `/r/${response.roadmapSlug}`;
}
}}
disabled={isLoading}
@@ -703,10 +700,10 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
<button
className="hidden items-center justify-center gap-2 rounded-md bg-gray-200 py-1.5 pl-2.5 pr-3 text-xs font-medium text-black transition-colors duration-300 hover:bg-gray-300 sm:inline-flex sm:text-sm"
onClick={async () => {
const roadmapId = await saveAIRoadmap();
if (roadmapId) {
const response = await saveAIRoadmap();
if (response?.roadmapId) {
window.open(
`${import.meta.env.PUBLIC_EDITOR_APP_URL}/${roadmapId}`,
`${import.meta.env.PUBLIC_EDITOR_APP_URL}/${response?.roadmapId}`,
'_blank',
);
}

View File

@@ -42,7 +42,7 @@ export function RoadmapSearch(props: RoadmapSearchProps) {
setIsAuthenticatedUser(isLoggedIn());
}, []);
const randomTerms = ['OAuth', 'APIs', 'UX Design', 'gRPC'];
const randomTerms = ['OAuth', 'UI / UX', 'SRE', 'DevRel'];
return (
<div className="flex flex-grow flex-col items-center px-4 py-6 sm:px-6 md:my-24 lg:my-32">

View File

@@ -124,7 +124,7 @@ export function RoadmapTopicDetail(props: RoadmapTopicDetailProps) {
const openAIKey = getOpenAIKey();
return (
<div className={'relative z-50'}>
<div className={'relative z-[90]'}>
<div
ref={topicRef}
tabIndex={0}

View File

@@ -1,22 +1,39 @@
---
import type { GuideFileType } from '../lib/guide';
import type { GuideFileType, GuideFrontmatter } from '../lib/guide';
import { replaceVariables } from '../lib/markdown';
import { QuestionGroupType } from '../lib/question-group';
export interface Props {
guide: GuideFileType;
guide: GuideFileType | QuestionGroupType;
}
function isQuestionGroupType(
guide: GuideFileType | QuestionGroupType,
): guide is QuestionGroupType {
return (guide as QuestionGroupType).questions !== undefined;
}
const { guide } = Astro.props;
const { frontmatter, id } = guide;
let pageUrl = '';
let guideType = '';
if (isQuestionGroupType(guide)) {
pageUrl = `/questions/${id}`;
guideType = 'Questions';
} else {
const excludedBySlug = (frontmatter as GuideFrontmatter).excludedBySlug;
pageUrl = excludedBySlug ? excludedBySlug : `/guides/${id}`;
guideType = (frontmatter as GuideFrontmatter).type;
}
---
<a
class:list={[
'text-md group block flex items-center justify-between border-b py-2 text-gray-600 no-underline hover:text-blue-600',
]}
href={frontmatter.excludedBySlug
? frontmatter.excludedBySlug
: `/guides/${id}`}
href={pageUrl}
>
<span
class='text-sm transition-transform group-hover:translate-x-2 md:text-base'
@@ -38,7 +55,7 @@ const { frontmatter, id } = guide;
}
</span>
<span class='hidden text-xs capitalize text-gray-500 sm:block'>
{frontmatter.type}
{guideType}
</span>
<span class='block text-xs text-gray-400 sm:hidden'> &raquo;</span>

View File

@@ -1,5 +1,5 @@
import { CheckIcon } from '../ReactIcons/CheckIcon';
import { AIAnnouncement } from '../AIAnnouncement.tsx';
import { FeatureAnnouncement } from '../FeatureAnnouncement.tsx';
type EmptyProgressProps = {
title?: string;
@@ -23,7 +23,7 @@ export function EmptyProgress(props: EmptyProgressProps) {
<p className={'text-sm text-gray-400 sm:text-base'}>{message}</p>
<p className="mt-5">
<AIAnnouncement />
<FeatureAnnouncement />
</p>
</div>
);

View File

@@ -7,7 +7,7 @@ import { MapIcon, Users2 } from 'lucide-react';
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { type ReactNode, useState } from 'react';
import { AIAnnouncement } from '../AIAnnouncement.tsx';
import { FeatureAnnouncement } from '../FeatureAnnouncement.tsx';
type ProgressRoadmapProps = {
url: string;
@@ -97,7 +97,7 @@ export function HeroRoadmaps(props: ProgressListProps) {
return (
<div className="relative pb-12 pt-4 sm:pt-7">
<p className="mb-7 mt-2 text-sm">
<AIAnnouncement />
<FeatureAnnouncement />
</p>
{isCreatingRoadmap && (
<CreateRoadmapModal

View File

@@ -1,6 +1,6 @@
---
import { FavoriteRoadmaps } from './FavoriteRoadmaps';
import { AIAnnouncement } from "../AIAnnouncement";
import { FeatureAnnouncement } from "../FeatureAnnouncement";
---
<div
@@ -10,12 +10,12 @@ import { AIAnnouncement } from "../AIAnnouncement";
class='container px-5 py-6 pb-14 text-left transition-opacity duration-300 sm:px-0 sm:py-20 sm:text-center'
id='hero-text'
>
<p class='-mt-4 mb-7 sm:-mt-10'>
<AIAnnouncement />
<p class='-mt-4 mb-7 sm:-mt-10 sm:mb-4'>
<FeatureAnnouncement />
</p>
<h1
class='mb-2 bg-gradient-to-b from-amber-50 to-purple-500 bg-clip-text text-2xl font-bold text-transparent sm:mb-4 sm:text-5xl'
class='mb-2 bg-gradient-to-b from-amber-50 to-purple-500 bg-clip-text text-2xl font-bold text-transparent sm:mb-4 sm:text-5xl sm:leading-tight'
>
Developer Roadmaps
</h1>

View File

@@ -1,68 +1,173 @@
import { useRef, useState } from 'react';
import { ChevronDown } from 'lucide-react';
import { isLoggedIn } from '../../lib/jwt';
import { useEffect, useRef, useState } from 'react';
import { ChevronDown, User } from 'lucide-react';
import { getUser, isLoggedIn } from '../../lib/jwt';
import { AccountDropdownList } from './AccountDropdownList';
import { DropdownTeamList } from './DropdownTeamList';
import { useOutsideClick } from '../../hooks/use-outside-click';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
import { OnboardingModal } from './OnboardingModal.tsx';
import { httpGet } from '../../lib/http.ts';
import { useToast } from '../../hooks/use-toast.ts';
import type { UserDocument } from '../../api/user.ts';
import { NotificationIndicator } from './NotificationIndicator.tsx';
import { OnboardingNudge } from '../OnboardingNudge.tsx';
export type OnboardingConfig = Pick<
UserDocument,
'onboarding' | 'onboardingStatus'
>;
export function AccountDropdown() {
const toast = useToast();
const dropdownRef = useRef(null);
const [showDropdown, setShowDropdown] = useState(false);
const [isTeamsOpen, setIsTeamsOpen] = useState(false);
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
const [isConfigLoading, setIsConfigLoading] = useState(false);
const [isOnboardingModalOpen, setIsOnboardingModalOpen] = useState(false);
const [onboardingConfig, setOnboardingConfig] = useState<
OnboardingConfig | undefined
>(undefined);
const currentUser = getUser();
const shouldShowOnboardingStatus =
currentUser?.onboardingStatus === 'pending' ||
onboardingConfig?.onboardingStatus === 'pending';
const loadOnboardingConfig = async () => {
if (!isLoggedIn() || !shouldShowOnboardingStatus) {
return;
}
setIsConfigLoading(true);
const { response, error } = await httpGet<OnboardingConfig>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-onboarding-config`,
);
if (error || !response) {
toast.error(error?.message || 'Failed to load onboarding config');
}
setOnboardingConfig(response);
};
useOutsideClick(dropdownRef, () => {
setShowDropdown(false);
setIsTeamsOpen(false);
setIsConfigLoading(true);
});
useEffect(() => {
if (!isLoggedIn() || !showDropdown) {
return;
}
loadOnboardingConfig().finally(() => {
setIsConfigLoading(false);
});
}, [showDropdown]);
useEffect(() => {
const loadConfig = () => {
loadOnboardingConfig().finally(() => {
setIsConfigLoading(false);
});
};
window.addEventListener('visibilitychange', loadConfig);
return () => {
window.removeEventListener('visibilitychange', loadConfig);
};
}, []);
if (!isLoggedIn()) {
return null;
}
const onboardingDoneCount = Object.values(
onboardingConfig?.onboarding || {},
).filter((status) => status !== 'pending').length;
const onboardingCount = Object.keys(
onboardingConfig?.onboarding || {},
).length;
return (
<div className="relative z-50 animate-fade-in">
{isCreatingRoadmap && (
<CreateRoadmapModal
onClose={() => {
setIsCreatingRoadmap(false);
<>
{shouldShowOnboardingStatus && !isOnboardingModalOpen && (
<OnboardingNudge
onStartOnboarding={() => {
loadOnboardingConfig().then(() => {
setIsOnboardingModalOpen(true);
});
}}
/>
)}
<button
className="flex h-8 w-40 items-center justify-center gap-1.5 rounded-full bg-gradient-to-r from-purple-500 to-purple-700 px-4 py-2 text-sm font-medium text-white hover:from-purple-500 hover:to-purple-600"
onClick={() => {
setIsTeamsOpen(false);
setShowDropdown(!showDropdown);
}}
>
<span className="inline-flex items-center">
Account&nbsp;<span className="text-gray-300">/</span>&nbsp;Teams
</span>
<ChevronDown className="h-4 w-4 shrink-0 stroke-[2.5px]" />
</button>
<div className="relative z-[90] animate-fade-in">
{isOnboardingModalOpen && onboardingConfig && (
<OnboardingModal
onboardingConfig={onboardingConfig}
onClose={() => {
setIsOnboardingModalOpen(false);
}}
onIgnoreTask={(taskId, status) => {
loadOnboardingConfig().finally(() => {});
}}
/>
)}
{isCreatingRoadmap && (
<CreateRoadmapModal
onClose={() => {
setIsCreatingRoadmap(false);
}}
/>
)}
{showDropdown && (
<div
ref={dropdownRef}
className="absolute right-0 z-50 mt-2 min-h-[152px] w-48 rounded-md bg-slate-800 py-1 shadow-xl"
<button
className="relative flex h-8 w-40 items-center justify-center gap-1.5 rounded-full bg-gradient-to-r from-purple-500 to-purple-700 px-4 py-2 text-sm font-medium text-white hover:from-purple-500 hover:to-purple-600"
onClick={() => {
setIsTeamsOpen(false);
setShowDropdown(!showDropdown);
}}
>
{isTeamsOpen ? (
<DropdownTeamList setIsTeamsOpen={setIsTeamsOpen} />
) : (
<AccountDropdownList
onCreateRoadmap={() => {
setIsCreatingRoadmap(true);
setShowDropdown(false);
}}
setIsTeamsOpen={setIsTeamsOpen}
/>
<span className="inline-flex items-center">
Account&nbsp;<span className="text-gray-300">/</span>&nbsp;Teams
</span>
<ChevronDown className="h-4 w-4 shrink-0 stroke-[2.5px]" />
{shouldShowOnboardingStatus && !showDropdown && (
<NotificationIndicator />
)}
</div>
)}
</div>
</button>
{showDropdown && (
<div
ref={dropdownRef}
className="absolute right-0 z-50 mt-2 min-h-[152px] w-48 rounded-md bg-slate-800 py-1 shadow-xl"
>
{isTeamsOpen ? (
<DropdownTeamList setIsTeamsOpen={setIsTeamsOpen} />
) : (
<AccountDropdownList
onCreateRoadmap={() => {
setIsCreatingRoadmap(true);
setShowDropdown(false);
}}
setIsTeamsOpen={setIsTeamsOpen}
onOnboardingClick={() => {
setIsOnboardingModalOpen(true);
setShowDropdown(false);
}}
shouldShowOnboardingStatus={shouldShowOnboardingStatus}
isConfigLoading={isConfigLoading}
onboardingConfigCount={onboardingCount}
doneConfigCount={onboardingDoneCount}
/>
)}
</div>
)}
</div>
</>
);
}

View File

@@ -6,21 +6,67 @@ import {
SquareUserRound,
User2,
Users2,
Handshake,
} from 'lucide-react';
import { logout } from './navigation';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
import { useState } from 'react';
import { cn } from '../../lib/classname.ts';
import { NotificationIndicator } from './NotificationIndicator.tsx';
import { Spinner } from '../ReactIcons/Spinner.tsx';
import { CheckIcon } from '../ReactIcons/CheckIcon.tsx';
type AccountDropdownListProps = {
onCreateRoadmap: () => void;
setIsTeamsOpen: (isOpen: boolean) => void;
onOnboardingClick: () => void;
isConfigLoading: boolean;
shouldShowOnboardingStatus?: boolean;
onboardingConfigCount: number;
doneConfigCount: number;
};
export function AccountDropdownList(props: AccountDropdownListProps) {
const { setIsTeamsOpen, onCreateRoadmap } = props;
const {
setIsTeamsOpen,
onCreateRoadmap,
onOnboardingClick,
isConfigLoading = true,
shouldShowOnboardingStatus = false,
onboardingConfigCount,
doneConfigCount,
} = props;
return (
<ul>
{shouldShowOnboardingStatus && (
<li className="mb-1 px-1">
<button
className={cn(
'flex h-9 w-full items-center rounded py-1 pl-3 pr-2 text-sm font-medium text-slate-100 hover:opacity-80',
isConfigLoading
? 'striped-loader-darker flex border-slate-800 opacity-70'
: 'border-slate-600 bg-slate-700',
)}
onClick={onOnboardingClick}
disabled={isConfigLoading}
>
<NotificationIndicator className="-left-0.5 -top-0.5" />
{isConfigLoading ? (
<></>
) : (
<>
<Handshake className="mr-2 h-4 w-4 text-slate-400 group-hover:text-white" />
<span>Onboarding</span>
<span className="ml-auto flex items-center gap-1.5 text-xs text-slate-400">
{doneConfigCount} of {onboardingConfigCount}
</span>
</>
)}
</button>
</li>
)}
<li className="px-1">
<a
href="/account"

View File

@@ -3,6 +3,7 @@ import { Menu } from 'lucide-react';
import Icon from '../AstroIcon.astro';
import { NavigationDropdown } from '../NavigationDropdown';
import { AccountDropdown } from './AccountDropdown';
import NewIndicator from './NewIndicator.astro';
---
<div class='bg-slate-900 py-5 text-white sm:py-8'>
@@ -17,20 +18,20 @@ import { AccountDropdown } from './AccountDropdown';
</a>
<a
href='/ai'
class='group inline sm:hidden relative !mr-2 text-blue-300 hover:text-white'
href='/teams'
class='group relative !mr-2 inline text-blue-300 hover:text-white sm:hidden'
>
AI Roadmaps&nbsp;
Teams
<span class='absolute -right-[11px] top-0'>
<span class='relative flex h-2 w-2'>
<span
class='absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75'
></span>
<span class='relative inline-flex h-2 w-2 rounded-full bg-sky-500'
></span>
</span>
<span class='relative flex h-2 w-2'>
<span
class='absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75'
></span>
<span class='relative inline-flex h-2 w-2 rounded-full bg-sky-500'
></span>
</span>
</span>
</a>
<!-- Desktop navigation items -->
@@ -39,30 +40,27 @@ import { AccountDropdown } from './AccountDropdown';
<a href='/get-started' class='text-gray-400 hover:text-white'>
Start Here
</a>
<a href='/teams' class='text-gray-400 hover:text-white'> Teams</a>
<a
href='/ai'
href='/teams'
class='group relative text-gray-400 hover:text-white'
>
Teams
</a>
<a href='/ai' class='text-gray-400 hover:text-white'> AI</a>
<a
href='/community'
class='group relative !mr-2 text-blue-300 hover:text-white'
>
AI Roadmaps
<span class='absolute -right-[11px] top-0'>
<span class='relative flex h-2 w-2'>
<span
class='absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75'
></span>
<span class='relative inline-flex h-2 w-2 rounded-full bg-sky-500'
></span>
</span>
</span>
Community
<NewIndicator />
</a>
<button
data-command-menu
class='hidden items-center rounded-md border border-gray-800 px-2.5 py-1.5 text-sm text-gray-400 hover:cursor-pointer hover:bg-gray-800 md:flex'
>
<Icon icon='search' class='h-3 w-3' />
<span class='ml-2'>Search</span>
</button>
<!--<button-->
<!-- data-command-menu-->
<!-- class='hidden items-center rounded-md border border-gray-800 px-2.5 py-1.5 text-sm text-gray-400 hover:cursor-pointer hover:bg-gray-800 md:flex'-->
<!--&gt;-->
<!-- <Icon icon='search' class='h-3 w-3' />-->
<!-- <span class='ml-2'>Search</span>-->
<!--</button>-->
</div>
</div>

View File

@@ -0,0 +1,8 @@
<span class='absolute -right-[11px] top-0'>
<span class='relative flex h-2 w-2'>
<span
class='absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75'
></span>
<span class='relative inline-flex h-2 w-2 rounded-full bg-sky-500'></span>
</span>
</span>

View File

@@ -0,0 +1,20 @@
import { cn } from '../../lib/classname.ts';
type NotificationIndicatorProps = {
className?: string;
};
export function NotificationIndicator(props: NotificationIndicatorProps) {
const { className = '' } = props;
return (
<span
className={cn(
'absolute -top-1 right-0 h-3 w-3 text-xs uppercase tracking-wider',
className,
)}
>
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span>
</span>
);
}

View File

@@ -0,0 +1,253 @@
import { ArrowUpRight, Check } from 'lucide-react';
import { Modal } from '../Modal';
import { cn } from '../../lib/classname';
import { useEffect, useMemo, useState } from 'react';
import type { AllowedOnboardingStatus } from '../../api/user';
import { pageProgressMessage } from '../../stores/page';
import { httpPatch } from '../../lib/http';
import { useToast } from '../../hooks/use-toast';
import type { OnboardingConfig } from './AccountDropdown';
import { setAuthToken } from '../../lib/jwt';
import { NUDGE_ONBOARDING_KEY } from '../OnboardingNudge.tsx';
type Task = {
id: string;
title: string;
description: string;
status: AllowedOnboardingStatus;
url: string;
urlText: string;
onClick?: () => void;
};
type OnboardingModalProps = {
onClose: () => void;
onboardingConfig: OnboardingConfig;
onIgnoreTask?: (taskId: string, status: AllowedOnboardingStatus) => void;
};
export function OnboardingModal(props: OnboardingModalProps) {
const { onboardingConfig, onClose, onIgnoreTask } = props;
const toast = useToast();
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
const tasks = useMemo(() => {
return [
{
id: 'updateProgress',
title: 'Update your Progress',
description: 'Mark your progress on roadmaps',
status: onboardingConfig?.onboarding?.updateProgress || 'pending',
url: '/roadmaps',
urlText: 'Roadmaps List',
},
{
id: 'publishProfile',
title: 'Claim a Username',
description: 'Optionally create a public profile to share your skills',
status: onboardingConfig?.onboarding?.publishProfile || 'pending',
url: '/account/update-profile',
urlText: 'Update Profile',
},
{
id: 'customRoadmap',
title: 'Custom Roadmaps',
description: 'Create your own roadmap from scratch',
status: onboardingConfig?.onboarding?.customRoadmap || 'pending',
url: import.meta.env.DEV
? 'http://localhost:4321'
: 'https://draw.roadmap.sh',
urlText: 'Create Roadmap',
},
{
id: 'addFriends',
title: 'Invite your Friends',
description: 'Invite friends to join you on roadmaps',
status: onboardingConfig?.onboarding?.addFriends || 'pending',
url: '/account/friends',
urlText: 'Add Friends',
onClick: () => {
ignoreOnboardingTask(
'addFriends',
'done',
'Updating status..',
).finally(() => pageProgressMessage.set(''));
},
},
{
id: 'roadCard',
title: 'Create your Roadmap Card',
description: 'Embed your skill card on your github or website',
status: onboardingConfig?.onboarding?.roadCard || 'pending',
url: '/account/road-card',
urlText: 'Create Road Card',
onClick: () => {
ignoreOnboardingTask('roadCard', 'done', 'Updating status..').finally(
() => pageProgressMessage.set(''),
);
},
},
{
id: 'inviteTeam',
title: 'Invite your Team',
description: 'Invite your team to collaborate on roadmaps',
status: onboardingConfig?.onboarding?.inviteTeam || 'pending',
url: '/team/new',
urlText: 'Create Team',
},
];
}, [onboardingConfig]);
const ignoreOnboardingTask = async (
taskId: string,
status: AllowedOnboardingStatus,
message: string = 'Ignoring Task',
) => {
pageProgressMessage.set(message);
const { response, error } = await httpPatch(
`${import.meta.env.PUBLIC_API_URL}/v1-update-onboarding-config`,
{
id: taskId,
status,
},
);
if (error || !response) {
toast.error(error?.message || 'Failed to ignore task');
return;
}
onIgnoreTask?.(taskId, status);
setSelectedTask(null);
};
const ignoreForever = async () => {
const { response, error } = await httpPatch<{ token: string }>(
`${import.meta.env.PUBLIC_API_URL}/v1-ignore-onboarding-forever`,
{},
);
if (error || !response) {
toast.error(error?.message || 'Failed to ignore onboarding');
return;
}
setAuthToken(response.token);
window.location.reload();
};
const isAllTasksDone = tasks.every(
(task) => task.status === 'done' || task.status === 'ignored',
);
useEffect(() => {
if (!isAllTasksDone) {
return;
}
pageProgressMessage.set('Finishing Onboarding');
ignoreForever().finally(() => {});
}, [isAllTasksDone]);
return (
<Modal onClose={onClose} bodyClassName="text-black h-auto">
<div className="px-4 pb-2 pl-11 pt-4">
<h2 className="mb-0.5 text-xl font-semibold">Welcome to roadmap.sh</h2>
<p className="text-balance text-sm text-gray-500">
Complete the tasks below to get started!
</p>
</div>
<ul
className={cn('flex flex-col divide-y', {
'border-b': tasks[tasks.length - 1]?.status === 'done',
})}
>
{/*sort to put completed tasks at the end */}
{tasks.map((task, taskCounter) => {
const isDone = task.status === 'done';
const isActive = selectedTask?.id === task.id;
return (
<li
key={task.id}
data-active={isActive}
data-status={task.status}
className={cn('group/task px-4 py-2.5', {
'bg-gray-100': isDone,
'border-t': taskCounter === 0 && isDone,
})}
>
<div
className={cn('flex items-start gap-2', {
'opacity-50': task.status === 'done',
})}
>
<span className="relative top-px flex h-5 w-5 items-center justify-center">
{isDone ? (
<Check className="h-4 w-4 stroke-[3px] text-green-500" />
) : (
<div
className={cn(
'h-4 w-4 rounded-md border border-gray-300',
task.status === 'ignored'
? 'bg-gray-200'
: 'bg-transparent',
)}
/>
)}
</span>
<div className="group-data-[status=ignored]/task:text-gray-400">
<h3 className="flex items-center text-sm font-semibold group-data-[status=done]/task:line-through">
{task.title}
<a
href={task.url}
target="_blank"
className={cn(
'ml-1 inline-block rounded-xl border border-black bg-white pl-1.5 pr-1 text-xs font-normal text-black hover:bg-black hover:text-white',
)}
aria-label="Open task in new tab"
onClick={() => {
if (!task?.onClick) {
return;
}
task.onClick();
}}
>
{task.urlText}
<ArrowUpRight className="relative -top-[0.5px] ml-0.5 inline-block h-3.5 w-3.5 stroke-[2px]" />
</a>
</h3>
<p className="text-xs text-gray-500 group-data-[status=ignored]/task:text-gray-400">
{task.description}
</p>
</div>
</div>
</li>
);
})}
</ul>
<div className="mt-2 px-11 pb-5">
<button
className="w-full rounded-md bg-gradient-to-r from-purple-500 to-purple-700 px-4 py-2 text-sm font-medium text-white hover:from-purple-500 hover:to-purple-600"
onClick={onClose}
>
Do it later
</button>
<button
className="mt-3 text-sm text-gray-500 underline underline-offset-2 hover:text-black"
onClick={() => {
pageProgressMessage.set('Ignoring Onboarding');
ignoreForever().finally();
}}
>
Ignore forever
</button>
</div>
</Modal>
);
}

View File

@@ -0,0 +1,69 @@
import { cn } from '../lib/classname.ts';
import { memo, useEffect, useState } from 'react';
import { useScrollPosition } from '../hooks/use-scroll-position.ts';
import { X } from 'lucide-react';
type OnboardingNudgeProps = {
onStartOnboarding: () => void;
};
export const NUDGE_ONBOARDING_KEY = 'should_nudge_onboarding';
export function OnboardingNudge(props: OnboardingNudgeProps) {
const { onStartOnboarding } = props;
const [isLoading, setIsLoading] = useState(false);
const { y: scrollY } = useScrollPosition();
useEffect(() => {
if (localStorage.getItem(NUDGE_ONBOARDING_KEY) === null) {
localStorage.setItem(NUDGE_ONBOARDING_KEY, 'true');
}
}, []);
if (localStorage.getItem(NUDGE_ONBOARDING_KEY) !== 'true') {
return null;
}
if (scrollY < 100) {
return null;
}
return (
<div
className={cn(
'fixed left-0 right-0 top-0 z-[91] flex w-full items-center justify-center bg-yellow-300 border-b border-b-yellow-500/30 pt-1.5 pb-2',
{
'striped-loader': isLoading,
},
)}
>
<p className="text-base font-semibold text-yellow-950">
Welcome! Please take a moment to{' '}
<button
type="button"
onClick={() => {
setIsLoading(true);
localStorage.setItem(NUDGE_ONBOARDING_KEY, 'false');
onStartOnboarding();
}}
className="underline"
>
complete onboarding
</button>
<button
type="button"
className="relative top-[3px] ml-1 px-1 py-1 text-yellow-600 hover:text-yellow-950"
onClick={(e) => {
e.stopPropagation();
localStorage.setItem(NUDGE_ONBOARDING_KEY, 'false');
setIsLoading(true);
}}
>
<X className="h-4 w-4" strokeWidth={3} />
</button>
</p>
</div>
);
}

View File

@@ -24,7 +24,7 @@ const discordInfo = await getDiscordInfo();
class='mt-5 grid grid-cols-1 justify-between gap-2 divide-x-0 sm:my-11 sm:grid-cols-3 sm:gap-0 sm:divide-x mb-4 sm:mb-0'
>
<OpenSourceStat text='GitHub Stars' value={starCount} />
<OpenSourceStat text='Registered Users' value={'850k'} />
<OpenSourceStat text='Registered Users' value={'+1M'} />
<OpenSourceStat
text='Discord Members'
value={discordInfo.totalFormatted}

View File

@@ -28,7 +28,7 @@ const isDiscordMembers = text.toLowerCase() === 'discord members';
{
isRegistered && (
<p class='flex items-center text-sm text-blue-500 sm:flex'>
<span class='mr-1.5 rounded-md bg-blue-500 px-1 text-white'>+55k</span>
<span class='mr-1.5 rounded-md bg-blue-500 px-1 text-white'>+75k</span>
every month
</p>
)
@@ -44,7 +44,7 @@ const isDiscordMembers = text.toLowerCase() === 'discord members';
}
<div class="flex flex-row items-center sm:flex-col my-1 sm:my-0">
<p
class='relative my-0 sm:my-4 mr-1 sm:mr-0 text-base font-bold lowercase sm:w-auto sm:text-5xl'
class='relative my-0 sm:my-4 mr-1 sm:mr-0 text-base font-bold sm:w-auto sm:text-5xl'
>
{value}
</p>

View File

@@ -28,7 +28,7 @@ export function PageProgress(props: Props) {
return (
<div>
{/* Tailwind based spinner for full page */}
<div className="fixed left-0 top-0 z-50 flex h-full w-full items-center justify-center bg-white bg-opacity-75">
<div className="fixed left-0 top-0 z-[100] flex h-full w-full items-center justify-center bg-white bg-opacity-75">
<div className="flex items-center justify-center rounded-md border bg-white px-4 py-2 ">
<Spinner
className="h-4 w-4 sm:h-4 sm:w-4"

View File

@@ -4,6 +4,8 @@ import { sponsorHidden } from '../stores/page';
import { useStore } from '@nanostores/react';
import { X } from 'lucide-react';
import { setViewSponsorCookie } from '../lib/jwt';
import { isMobile } from '../lib/is-mobile';
import Cookies from 'js-cookie';
export type PageSponsorType = {
company: string;
@@ -25,6 +27,22 @@ type PageSponsorProps = {
gaPageIdentifier?: string;
};
const CLOSE_SPONSOR_KEY = 'sponsorClosed';
function markSponsorHidden(sponsorId: string) {
Cookies.set(`${CLOSE_SPONSOR_KEY}-${sponsorId}`, '1', {
path: '/',
expires: 1,
sameSite: 'lax',
secure: true,
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
});
}
function isSponsorMarkedHidden(sponsorId: string) {
return Cookies.get(`${CLOSE_SPONSOR_KEY}-${sponsorId}`) === '1';
}
export function PageSponsor(props: PageSponsorProps) {
const { gaPageIdentifier } = props;
const $isSponsorHidden = useStore(sponsorHidden);
@@ -50,6 +68,7 @@ export function PageSponsor(props: PageSponsorProps) {
`${import.meta.env.PUBLIC_API_URL}/v1-get-sponsor`,
{
href: window.location.pathname,
mobile: isMobile() ? 'true' : 'false',
},
);
@@ -58,12 +77,16 @@ export function PageSponsor(props: PageSponsorProps) {
return;
}
if (!response?.sponsor) {
if (
!response?.sponsor ||
!response.id ||
isSponsorMarkedHidden(response.id)
) {
return;
}
setSponsor(response.sponsor);
setSponsorId(response?.id || null);
setSponsorId(response.id);
window.fireEvent({
category: 'SponsorImpression',
@@ -75,9 +98,15 @@ export function PageSponsor(props: PageSponsorProps) {
};
const clickSponsor = async (sponsorId: string) => {
const { response, error } = await httpPatch<{ status: 'ok' }>(
const clickUrl = new URL(
`${import.meta.env.PUBLIC_API_URL}/v1-view-sponsor/${sponsorId}`,
{},
);
const { response, error } = await httpPatch<{ status: 'ok' }>(
clickUrl.toString(),
{
mobile: isMobile(),
},
);
if (error || !response) {
@@ -103,7 +132,7 @@ export function PageSponsor(props: PageSponsorProps) {
href={url}
target="_blank"
rel="noopener sponsored nofollow"
className="fixed bottom-[15px] right-[15px] z-50 flex max-w-[350px] bg-white shadow-lg outline-0 outline-transparent"
className="fixed bottom-0 left-0 right-0 z-50 flex bg-white shadow-lg outline-0 outline-transparent sm:bottom-[15px] sm:left-auto sm:right-[15px] sm:max-w-[350px]"
onClick={async () => {
window.fireEvent({
category: 'SponsorClick',
@@ -114,26 +143,32 @@ export function PageSponsor(props: PageSponsorProps) {
}}
>
<span
className="absolute right-1.5 top-1.5 text-gray-300 hover:text-gray-800"
className="absolute right-1 top-1 text-gray-400 hover:text-gray-800 sm:right-1.5 sm:top-1.5 sm:text-gray-300"
aria-label="Close"
onClick={(e) => {
e.preventDefault();
markSponsorHidden(sponsorId || '');
sponsorHidden.set(true);
}}
>
<X className="h-4 w-4" />
<X className="h-5 w-5 sm:h-4 sm:w-4" />
</span>
<img
src={imageUrl}
className="block h-[150px] object-cover lg:h-[169px] lg:w-[118.18px]"
alt="Sponsor Banner"
/>
<span className="flex flex-1 flex-col justify-between text-sm">
<span>
<img
src={imageUrl}
className="block h-[106px] object-cover sm:h-[169px] sm:w-[118.18px]"
alt="Sponsor Banner"
/>
</span>
<span className="flex flex-1 flex-col justify-between text-xs sm:text-sm">
<span className="p-[10px]">
<span className="mb-0.5 block font-semibold">{title}</span>
<span className="block text-gray-500">{description}</span>
</span>
<span className="sponsor-footer">Partner Content</span>
<span className="sponsor-footer hidden sm:block">Partner Content</span>
<span className="block pb-1 text-center text-[10px] uppercase text-gray-400 sm:hidden">
Partner Content
</span>
</span>
</a>
);

View File

@@ -13,28 +13,19 @@ type ProgressStatButtonProps = {
icon: ReactNode;
label: string;
count: number;
onClick: () => void;
};
function ProgressStatButton(props: ProgressStatButtonProps) {
const { icon, label, count, onClick, isDisabled = false } = props;
function ProgressStatLabel(props: ProgressStatButtonProps) {
const { icon, label, count } = props;
return (
<button
disabled={isDisabled}
onClick={onClick}
className="group relative flex flex-1 items-center overflow-hidden rounded-md border border-gray-300 bg-white px-2 py-2 text-sm text-black transition-colors hover:border-black disabled:pointer-events-none disabled:opacity-50 sm:rounded-xl sm:px-4 sm:py-3 sm:text-base"
>
<span className="group relative flex flex-1 items-center overflow-hidden rounded-md border border-gray-300 bg-white px-2 py-2 text-sm text-black transition-colors disabled:opacity-50 sm:rounded-xl sm:px-4 sm:py-3 sm:text-base">
{icon}
<span className="flex flex-grow justify-between">
<span>{label}</span>
<span>{count}</span>
</span>
<span className="absolute left-0 right-0 top-full flex h-full items-center justify-center border border-black bg-black text-white transition-all duration-200 group-hover:top-0">
Restart Asking
</span>
</button>
</span>
);
}
@@ -43,12 +34,11 @@ type QuestionFinishedProps = {
didNotKnowCount: number;
skippedCount: number;
totalCount: number;
onReset: (type: QuestionProgressType | 'reset') => void;
onReset: () => void;
};
export function QuestionFinished(props: QuestionFinishedProps) {
const { knowCount, didNotKnowCount, skippedCount, totalCount, onReset } =
props;
const { knowCount, didNotKnowCount, skippedCount, onReset } = props;
return (
<div className="relative flex flex-grow flex-col items-center justify-center px-4 sm:px-0">
@@ -63,31 +53,25 @@ export function QuestionFinished(props: QuestionFinishedProps) {
</p>
<div className="mb-5 mt-5 flex w-full flex-col gap-1.5 px-2 sm:flex-row sm:gap-3 sm:px-16">
<ProgressStatButton
<ProgressStatLabel
icon={<ThumbsUp className="mr-1 h-4" />}
label="Knew"
count={knowCount}
isDisabled={knowCount === 0}
onClick={() => onReset('know')}
/>
<ProgressStatButton
<ProgressStatLabel
icon={<Sparkles className="mr-1 h-4" />}
label="Learned"
count={didNotKnowCount}
isDisabled={didNotKnowCount === 0}
onClick={() => onReset('dontKnow')}
/>
<ProgressStatButton
<ProgressStatLabel
icon={<SkipForward className="mr-1 h-4" />}
label="Skipped"
count={skippedCount}
isDisabled={skippedCount === 0}
onClick={() => onReset('skip')}
/>
</div>
<div className="mb-4 mt-2 text-sm sm:mb-0">
<button
onClick={() => onReset('reset')}
onClick={() => onReset()}
className="flex items-center gap-0.5 text-sm text-red-700 hover:text-black sm:text-base"
>
<RefreshCcw className="mr-1 h-4" />

View File

@@ -0,0 +1,154 @@
---
import {
getGuideTableOfContent,
type GuideFileType,
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 { QuestionsList } from './QuestionsList';
interface Props {
questionGroup: QuestionGroupType;
}
const { questionGroup } = Astro.props;
const allHeadings = questionGroup.getHeadings();
const tableOfContent: HeadingGroupType[] = [
...getGuideTableOfContent(allHeadings),
{
depth: 2,
title: 'Test with Flashcards',
children: [],
slug: 'test-with-flashcards',
text: 'Test yourself with Flashcards',
},
{
depth: 2,
title: 'Questions List',
children: [
{
depth: 2,
title: 'Beginner Level',
children: [],
slug: 'beginner-level',
text: 'Beginner Level',
} as HeadingGroupType,
{
depth: 2,
title: 'Intermediate Level',
children: [],
slug: 'intermediate-level',
text: 'Intermediate Level',
} as HeadingGroupType,
{
depth: 2,
title: 'Advanced Level',
children: [],
slug: 'advanced-level',
text: 'Advanced Level',
} as HeadingGroupType,
],
slug: 'questions-list',
text: 'Questions List',
},
];
const showTableOfContent = tableOfContent.length > 0;
const { frontmatter: guideFrontmatter, author } = questionGroup;
---
<article class='lg:grid lg:max-w-full lg:grid-cols-[1fr_minmax(0,700px)_1fr]'>
{
showTableOfContent && (
<div class='bg-gradient-to-r from-gray-50 py-0 lg:col-start-3 lg:col-end-4 lg:row-start-1'>
<TableOfContent toc={tableOfContent} client:load />
</div>
)
}
<div
class:list={[
'col-start-2 col-end-3 row-start-1 mx-auto max-w-[700px] py-5 sm:py-10',
{
'lg:border-r': showTableOfContent,
},
]}
>
<MarkdownFile>
<h1 class='mb-3 text-balance text-4xl font-bold'>
{replaceVariables(guideFrontmatter.title)}
</h1>
{
author && (
<p class='my-0 flex items-center justify-start text-sm text-gray-400'>
<a
href={`/authors/${author?.id}`}
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}
class='mb-0 mr-2 inline h-5 w-5 rounded-full'
/>
{author.frontmatter.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}`}
target='_blank'
>
Improve this Guide
</a>
</p>
)
}
<questionGroup.Content />
<h2 id='test-with-flashcards'>Test yourself with Flashcards</h2>
<p>
You can either use these flashcards or jump to the questions list
section below to see them in a list format.
</p>
<div class='mx-0 sm:-mb-32'>
<QuestionsList
groupId={questionGroup.id}
questions={questionGroup.questions}
client:load
/>
</div>
<h2 id='questions-list'>Questions List</h2>
<p>
If you prefer to see the questions in a list format, you can find them
below.
</p>
{
['beginner', 'intermediate', 'advanced'].map((questionLevel) => (
<div class='mb-5'>
<h3 id={`${questionLevel}-level`} class='mb-0 capitalize'>
{questionLevel} Level
</h3>
{questionGroup.questions
.filter((q) => {
return q.topics
.map((t) => t.toLowerCase())
.includes(questionLevel);
})
.map((q) => (
<div class='mb-5'>
<h4>{q.question}</h4>
<div set:html={markdownToHtml(q.answer, false)} />
</div>
))}
</div>
))
}
</MarkdownFile>
</div>
</article>

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