diff --git a/src/components/FrameRenderer/renderer.ts b/src/components/FrameRenderer/renderer.ts index 82172420c..bbc0848be 100644 --- a/src/components/FrameRenderer/renderer.ts +++ b/src/components/FrameRenderer/renderer.ts @@ -14,6 +14,7 @@ import type { import { pageProgressMessage } from '../../stores/page'; import { showLoginPopup } from '../../lib/popup'; import { replaceChildren } from '../../lib/dom.ts'; +import {setUrlParams} from "../../lib/browser.ts"; export class Renderer { resourceId: string; @@ -141,19 +142,8 @@ export class Renderer { const newJsonFileSlug = newJsonUrl.split('/').pop()?.replace('.json', ''); - // Update the URL and attach the new roadmap type - if (window?.history?.pushState) { - const url = new URL(window.location.href); - const type = this.resourceType[0]; // r for roadmap, b for best-practices - - url.searchParams.delete(type); - - if (newJsonFileSlug !== this.resourceId) { - url.searchParams.set(type, newJsonFileSlug!); - } - - window.history.pushState(null, '', url.toString()); - } + const type = this.resourceType[0]; // r for roadmap, b for best-practices + setUrlParams({ [type]: newJsonFileSlug! }) this.jsonToSvg(newJsonUrl)?.then(() => {}); } diff --git a/src/components/Roadmaps/RoadmapsPage.tsx b/src/components/Roadmaps/RoadmapsPage.tsx new file mode 100644 index 000000000..4f818f55e --- /dev/null +++ b/src/components/Roadmaps/RoadmapsPage.tsx @@ -0,0 +1,432 @@ +import { useEffect, useState } from 'react'; +import { cn } from '../../lib/classname.ts'; + +const groupNames = [ + 'Absolute Beginners', + 'Web Development', + 'Languages / Platforms', + 'Frameworks', + 'Mobile Development', + 'Databases', + 'Computer Science', + 'Machine Learning', + 'Game Development', + 'Design', + 'DevOps', + 'Blockchain', + 'Cyber Security', +]; + +type AllowGroupNames = (typeof groupNames)[number]; + +type GroupType = { + group: AllowGroupNames; + roadmaps: { + title: string; + link: string; + type: 'role' | 'skill'; + }[]; +}; + +const groups: GroupType[] = [ + { + group: 'Absolute Beginners', + roadmaps: [ + { + title: 'Frontend Beginner', + link: '/frontend?r=frontend-beginner', + type: 'role', + }, + { + title: 'Backend Beginner', + link: '/backend?r=backend-beginner', + type: 'role', + }, + { + title: 'DevOps Beginner', + link: '/devops?r=devops-beginner', + type: 'role', + }, + { + title: 'Full-Stack Developer', + link: '/fullstack', + type: 'role', + }, + ], + }, + { + group: 'Web Development', + roadmaps: [ + { + title: 'Frontend', + link: '/frontend', + type: 'role', + }, + { + title: 'Backend', + link: '/backend', + type: 'role', + }, + { + title: 'DevOps', + link: '/devops', + type: 'role', + }, + { + title: 'Full Stack', + link: '/full-stack', + type: 'role', + }, + { + title: 'QA', + link: '/qa', + type: 'role', + }, + { + title: 'GraphQL', + link: '/graphql', + type: 'skill', + }, + ], + }, + { + group: 'DevOps', + roadmaps: [ + { + title: 'DevOps', + link: '/devops', + type: 'role', + }, + { + title: 'Docker', + link: '/docker', + type: 'skill', + }, + { + title: 'Kubernetes', + link: '/kubernetes', + type: 'skill', + }, + { + title: 'AWS', + link: '/aws', + type: 'skill', + }, + ], + }, + { + group: 'Languages / Platforms', + roadmaps: [ + { + title: 'JavaScript', + link: '/javascript', + type: 'skill', + }, + { + title: 'TypeScript', + link: '/typescript', + type: 'skill', + }, + { + title: 'Node.js', + link: '/nodejs', + type: 'skill', + }, + { + title: 'C++', + link: '/cpp', + type: 'skill', + }, + { + title: 'Go', + link: '/golang', + type: 'skill', + }, + { + title: 'Rust', + link: '/rust', + type: 'skill', + }, + { + title: 'Python', + link: '/python', + type: 'skill', + }, + { + title: 'Java', + link: '/java', + type: 'skill', + }, + { + title: 'SQL', + link: '/sql', + type: 'skill', + }, + ], + }, + { + group: 'Frameworks', + roadmaps: [ + { + title: 'React', + link: '/react', + type: 'skill', + }, + { + title: 'Vue', + link: '/vue', + type: 'skill', + }, + { + title: 'Angular', + link: '/angular', + type: 'skill', + }, + { + title: 'Spring Boot', + link: '/spring-boot', + type: 'skill', + }, + { + title: 'ASP.NET Core', + link: '/aspnet-core', + type: 'skill', + }, + ], + }, + { + group: 'Mobile Development', + roadmaps: [ + { + title: 'React Native', + link: '/react-native', + type: 'role', + }, + { + title: 'Flutter', + link: '/flutter', + type: 'role', + }, + { + title: 'Android', + link: '/android', + type: 'role', + }, + ], + }, + { + group: 'Databases', + roadmaps: [ + { + title: 'PostgreSQL', + link: '/postgresql-dba', + type: 'role', + }, + { + title: 'MongoDB', + link: '/mongodb', + type: 'skill', + }, + ], + }, + { + group: 'Computer Science', + roadmaps: [ + { + title: 'Computer Science', + link: '/computer-science', + type: 'skill', + }, + { + title: 'Data Structures', + link: '/data-structures-and-algorithms', + type: 'skill', + }, + { + title: 'System Design', + link: '/system-design', + type: 'skill', + }, + { + title: 'Design and Architecture', + link: '/software-design-architecture', + type: 'skill', + }, + { + title: 'Software Architect', + link: '/software-architect', + type: 'role', + }, + { + title: 'Code Review', + link: '/code-review', + type: 'skill', + }, + { + title: 'Technical Writer', + link: '/technical-writer', + type: 'role', + }, + ], + }, + { + group: 'Machine Learning', + roadmaps: [ + { + title: 'AI and Data Scientist', + link: '/ai-data-scientist', + type: 'role', + }, + { + title: 'MLOps', + link: '/mlops', + type: 'role', + }, + { + title: 'Prompt Engineering', + link: '/prompt-engineering', + type: 'skill', + }, + ], + }, + { + group: 'Game Development', + roadmaps: [ + { + title: 'Client Side Game Dev.', + link: '/game-developer', + type: 'role', + }, + { + title: 'Server Side Game Dev.', + link: '/server-side-game-developer', + type: 'role', + }, + ], + }, + { + group: 'Design', + roadmaps: [ + { + title: 'UX Design', + link: '/ux-design', + type: 'role', + }, + { + title: 'Design System', + link: '/design-system', + type: 'skill', + }, + ], + }, + { + group: 'Blockchain', + roadmaps: [ + { + title: 'Blockchain', + link: '/blockchain', + type: 'role', + }, + ], + }, + { + group: 'Cyber Security', + roadmaps: [ + { + title: 'Cyber Security', + link: '/cyber-security', + type: 'role', + }, + ], + }, +]; + +export function RoadmapsPage() { + const [activeGroup, setActiveGroup] = useState(''); + const [visibleGroups, setVisibleGroups] = useState([]); + + useEffect(() => { + if (!activeGroup) { + const roleRoadmaps = groups.flatMap((group) => + group.roadmaps.filter((roadmap) => roadmap.type === 'role'), + ); + const skillRoadmaps = groups.flatMap((group) => + group.roadmaps.filter((roadmap) => roadmap.type === 'skill'), + ); + + setVisibleGroups([ + { + group: 'Role Based Roadmaps', + roadmaps: roleRoadmaps, + }, + { + group: 'Skill Based Roadmaps', + roadmaps: skillRoadmaps, + }, + ]); + } else { + const group = groups.find((group) => group.group === activeGroup); + + if (group) { + setVisibleGroups([group]); + } + } + }, [activeGroup]); + + return ( +
+
+
+
+
+ + {groups.map((group) => ( + + ))} +
+
+
+
+ {visibleGroups.map((group) => ( +
+

+ {group.group} +

+ +
+ {group.roadmaps.map((roadmap) => ( + + {roadmap.title} + + ))} +
+
+ ))} +
+
+
+ ); +} diff --git a/src/data/roadmaps/aspnet-core/aspnet-core.md b/src/data/roadmaps/aspnet-core/aspnet-core.md index 697b6bf5f..e96715754 100644 --- a/src/data/roadmaps/aspnet-core/aspnet-core.md +++ b/src/data/roadmaps/aspnet-core/aspnet-core.md @@ -57,5 +57,5 @@ sitemap: tags: - 'roadmap' - 'main-sitemap' - - 'role-roadmap' + - 'skill-roadmap' --- diff --git a/src/data/roadmaps/cpp/cpp.md b/src/data/roadmaps/cpp/cpp.md index 67beccd37..a5b7d411a 100644 --- a/src/data/roadmaps/cpp/cpp.md +++ b/src/data/roadmaps/cpp/cpp.md @@ -52,5 +52,5 @@ sitemap: tags: - 'roadmap' - 'main-sitemap' - - 'role-roadmap' + - 'skill-roadmap' --- diff --git a/src/data/roadmaps/datastructures-and-algorithms/datastructures-and-algorithms.md b/src/data/roadmaps/datastructures-and-algorithms/datastructures-and-algorithms.md index 5b201bcd1..d7d43d70a 100644 --- a/src/data/roadmaps/datastructures-and-algorithms/datastructures-and-algorithms.md +++ b/src/data/roadmaps/datastructures-and-algorithms/datastructures-and-algorithms.md @@ -35,5 +35,5 @@ sitemap: tags: - 'roadmap' - 'main-sitemap' - - 'role-roadmap' + - 'skill-roadmap' --- diff --git a/src/lib/browser.ts b/src/lib/browser.ts index b8a3fa4d9..202732226 100644 --- a/src/lib/browser.ts +++ b/src/lib/browser.ts @@ -32,11 +32,20 @@ export function setUrlParams(params: Record) { } const url = new URL(window.location.href); + let hasUpdatedUrl = false; for (const [key, value] of Object.entries(params)) { + if (url.searchParams.get(key) === String(value)) { + continue; + } + url.searchParams.delete(key); url.searchParams.set(key, value); + + hasUpdatedUrl = true; } - window.history.pushState(null, '', url.toString()); + if (hasUpdatedUrl) { + window.history.pushState(null, '', url.toString()); + } } diff --git a/src/pages/roadmaps.astro b/src/pages/roadmaps.astro index 671e3955f..c5cd1cdee 100644 --- a/src/pages/roadmaps.astro +++ b/src/pages/roadmaps.astro @@ -1,340 +1,9 @@ --- +import { RoadmapsPage } from '../components/Roadmaps/RoadmapsPage'; import GridItem from '../components/GridItem.astro'; import SimplePageHeader from '../components/SimplePageHeader.astro'; import BaseLayout from '../layouts/BaseLayout.astro'; import { getRoadmapsByTag } from '../lib/roadmap'; - -const groups = [ - { - group: 'Absolute Beginners', - roadmaps: [ - { - title: 'Frontend Beginner', - link: '/frontend?r=frontend-beginner', - }, - { - title: 'Backend Beginner', - link: '/backend?r=backend-beginner', - }, - { - title: 'DevOps Beginner', - link: '/devops?r=devops-beginner', - }, - { - title: 'Full-Stack Developer', - link: '/fullstack', - }, - ], - }, - { - group: 'Web Development', - roadmaps: [ - { - title: 'Frontend', - link: '/frontend', - type: 'role', - }, - { - title: 'Backend', - link: '/backend', - type: 'role', - }, - { - title: 'DevOps', - link: '/devops', - type: 'role', - }, - { - title: 'Full Stack', - link: '/full-stack', - type: 'role', - }, - { - title: 'QA', - link: '/qa', - type: 'role', - }, - { - title: 'GraphQL', - link: '/graphql', - type: 'role', - }, - ], - }, - { - group: 'Languages / Platforms', - roadmaps: [ - { - title: 'JavaScript', - link: '/javascript', - type: 'skill', - }, - { - title: 'TypeScript', - link: '/typescript', - type: 'skill', - }, - { - title: 'Node.js', - link: '/nodejs', - type: 'role', - }, - { - title: 'C++', - link: '/cpp', - type: 'skill', - }, - { - title: 'Go', - link: '/golang', - type: 'skill', - }, - { - title: 'Rust', - link: '/rust', - type: 'skill', - }, - { - title: 'Python', - link: '/python', - type: 'skill', - }, - { - title: 'Java', - link: '/java', - type: 'skill', - }, - { - title: 'SQL', - link: '/sql', - type: 'skill', - }, - ], - }, - { - group: 'Frameworks', - roadmaps: [ - { - title: 'React', - link: '/react', - type: 'skill', - }, - { - title: 'Vue', - link: '/vue', - type: 'skill', - }, - { - title: 'Angular', - link: '/angular', - type: 'skill', - }, - { - title: 'Spring Boot', - link: '/spring-boot', - type: 'skill', - }, - { - title: 'ASP.NET Core', - link: '/aspnet-core', - type: 'skill', - }, - ], - }, - { - group: 'Mobile Development', - roadmaps: [ - { - title: 'React Native', - link: '/react-native', - type: 'skill', - }, - { - title: 'Flutter', - link: '/flutter', - type: 'skill', - }, - { - title: 'Android', - link: '/android', - type: 'skill', - }, - ], - }, - { - group: 'Databases', - roadmaps: [ - { - title: 'PostgreSQL', - link: '/postgresql-dba', - type: 'role', - }, - { - title: 'MongoDB', - link: '/mongodb', - type: 'skill', - }, - ], - }, - { - group: 'Computer Science', - roadmaps: [ - { - title: 'Computer Science', - link: '/computer-science', - type: 'skill', - }, - { - title: 'Data Structures', - link: '/data-structures-and-algorithms', - type: 'skill', - }, - { - title: 'System Design', - link: '/system-design', - type: 'skill', - }, - { - title: 'Design and Architecture', - link: '/software-design-architecture', - type: 'skill', - }, - { - title: 'Software Architect', - link: '/software-architect', - type: 'role', - }, - { - title: 'Code Review', - link: '/code-review', - type: 'skill', - }, - { - title: 'Technical Writer', - link: '/technical-writer', - type: 'skill', - }, - ], - }, - { - group: 'Machine Learning', - roadmaps: [ - { - title: 'AI and Data Scientist', - link: '/ai-data-scientist', - type: 'skill', - }, - { - title: 'MLOps', - link: '/mlops', - type: 'skill', - }, - { - title: 'Prompt Engineering', - link: '/prompt-engineering', - type: 'skill', - }, - ], - }, - { - group: 'Game Development', - roadmaps: [ - { - title: 'Client Side Development', - link: '/game-developer', - type: 'skill', - }, - { - title: 'Server Side Development', - link: '/server-side-game-developer', - type: 'skill', - }, - ], - }, - { - group: 'Design', - roadmaps: [ - { - title: 'UX Design', - link: '/ux-design', - }, - { - title: 'Design System', - link: '/design-system', - }, - ], - }, - { - group: 'DevOps', - roadmaps: [ - { - title: 'DevOps', - link: '/devops', - }, - { - title: 'Docker', - link: '/docker', - }, - { - title: 'Kubernetes', - link: '/kubernetes', - }, - { - title: 'AWS', - link: '/aws', - }, - ], - }, - { - group: 'Blockchain', - roadmaps: [ - { - title: 'Blockchain', - link: '/blockchain', - }, - ], - }, - { - group: 'Cyber Security', - roadmaps: [ - { - title: 'Cyber Security', - link: '/cyber-security', - }, - ], - }, -]; - -const shownTitles = groups - .map((group) => group.roadmaps.map((roadmap) => roadmap.title)) - .flat() - .concat([ - 'Frontend Beginner', - 'Backend Beginner', - 'DevOps Beginner', - 'Full-Stack Developer', - 'Data Structures & Algorithms', - 'Server Side Game Developer', - 'Game Developer', - ]); - -const roleRoadmaps = (await getRoadmapsByTag('role-roadmap')).filter( - (roadmap) => !shownTitles.includes(roadmap.frontmatter.briefTitle), -); -const skillRoadmaps = (await getRoadmapsByTag('skill-roadmap')).filter( - (roadmap) => !shownTitles.includes(roadmap.frontmatter.briefTitle), -); - -const otherRoadmaps = roleRoadmaps.concat(skillRoadmaps); -if (otherRoadmaps.length > 0) { - groups.push({ - group: 'Uncategorized', - roadmaps: otherRoadmaps.map((roadmap) => ({ - title: roadmap.frontmatter.briefTitle, - link: roadmap.url, - })), - }); -} --- 0) {

Developer Roadmaps

-

+

Browse ever-growing list of up-to-date, community driven roadmaps

-

- +

+ Draw your own roadmap - + Generate Roadmap with AI

@@ -362,48 +37,6 @@ if (otherRoadmaps.length > 0) {
-
-
-
-
-
- All Roadmaps - { - groups.map((group) => ( - - {group.group} - - )) - } -
-
-
-
- { - groups.map((group) => ( -
-

- {group.group} -

- -
- {group.roadmaps.map((roadmap) => ( - - {roadmap.title} - - ))} -
-
- )) - } -
-
-
+