Compare commits

...

5 Commits

Author SHA1 Message Date
Arik Chakma
326aad3277 Merge branch 'fix/table-overflow' of github.com:kamranahmedse/developer-roadmap into fix/table-overflow 2025-11-18 22:54:52 +06:00
Arik Chakma
0da0c331e5 wip 2025-11-18 22:16:32 +06:00
Arik Chakma
ad5523b938 Merge branch 'master' into fix/table-overflow 2025-11-05 08:58:06 +06:00
Arik Chakma
4f7bcb01e2 fix: use em not rem 2025-11-05 08:57:31 +06:00
Arik Chakma
f9947b78cf fix: table overflow 2025-11-05 08:50:00 +06:00
60 changed files with 20 additions and 3103 deletions

View File

@@ -3,6 +3,6 @@
"enabled": false
},
"_variables": {
"lastUpdateCheck": 1762257454897
"lastUpdateCheck": 1763344576632
}
}

View File

@@ -4,7 +4,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "astro dev --port 3000",
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",

View File

@@ -5,7 +5,11 @@ import { COURSE_PURCHASE_PARAM } from '../../lib/jwt';
import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
import { Spinner } from '../ReactIcons/Spinner.tsx';
import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx';
import { triggerUtmRegistration, urlToId, getLastPath } from '../../lib/browser.ts';
import {
triggerUtmRegistration,
urlToId,
getLastPath,
} from '../../lib/browser.ts';
import { cn } from '../../lib/classname.ts';
type GoogleButtonProps = {
@@ -161,7 +165,7 @@ export function GoogleButton(props: GoogleButtonProps) {
Continue with Google
</button>
{error && (
<p className="mb-2 mt-1 text-sm font-medium text-red-600">{error}</p>
<p className="mt-1 mb-2 text-sm font-medium text-red-600">{error}</p>
)}
</>
);

View File

@@ -1,9 +1,9 @@
---
import { FeatureAnnouncement } from "../FeatureAnnouncement";
import { FeatureAnnouncement } from '../FeatureAnnouncement';
---
<div
class='min-h-auto relative min-h-[192px] border-b border-b-[#1e293c] transition-all sm:min-h-[281px]'
class='relative min-h-[192px] min-h-auto border-b border-b-[#1e293c] transition-all sm:min-h-[281px]'
>
<div
class='container px-5 py-6 pb-14 text-left transition-opacity duration-300 sm:px-0 sm:py-20 sm:text-center'

View File

@@ -208,7 +208,7 @@ export function PersonalizedRoadmap(props: PersonalizedRoadmapProps) {
/>
) : (
<button
className="group hidden sm:inline-flex items-center gap-1.5 border-b-2 border-b-transparent pb-2.5 text-sm font-normal text-gray-500 transition-colors hover:text-black"
className="group hidden items-center gap-1.5 border-b-2 border-b-transparent pb-2.5 text-sm font-normal text-gray-500 transition-colors hover:text-black sm:inline-flex"
onClick={() => {
if (!isLoggedIn()) {
showLoginPopup();

View File

@@ -96,10 +96,7 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) {
</span>
</h2>
)}
<div
className="bg-gray-100 p-3 text-base [&>h2]:mt-5 [&>h2]:mb-2 [&>h2]:text-[17px] [&>h2]:font-medium [&>p]:mb-3 [&>p]:leading-relaxed [&>p]:font-normal [&>p]:text-gray-800 [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>ul>li]:mb-2 [&>ul>li]:font-normal"
// dangerouslySetInnerHTML={{ __html: markdownToHtml(answer, false) }}
>
<div className="bg-gray-100 p-3 text-base [&>h2]:mt-5 [&>h2]:mb-2 [&>h2]:text-[17px] [&>h2]:font-medium [&>p]:mb-3 [&>p]:leading-relaxed [&>p]:font-normal [&>p]:text-gray-800 [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>ul>li]:mb-2 [&>ul>li]:font-normal">
{guideRenderer.render(answer)}
</div>
</div>

View File

@@ -196,7 +196,12 @@ const groups: GroupType[] = [
title: 'JavaScript',
link: '/javascript',
type: 'skill',
otherGroups: ['Web Development', 'DevOps', 'Mobile Development', 'Absolute Beginners'],
otherGroups: [
'Web Development',
'DevOps',
'Mobile Development',
'Absolute Beginners',
],
},
{
title: 'Kotlin',

View File

@@ -1,28 +0,0 @@
import type { APIRoute } from 'astro';
import { officialRoadmapDetails } from '../queries/official-roadmap';
export const prerender = false;
export const GET: APIRoute = async function ({ params }) {
const { roadmapId } = params;
if (!roadmapId) {
return new Response('Roadmap ID is required', {
status: 400,
});
}
const roadmapJson = await officialRoadmapDetails(roadmapId);
if (!roadmapJson) {
return new Response('Roadmap not found', {
status: 404,
});
}
return new Response(JSON.stringify(roadmapJson), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
};

View File

@@ -1,124 +0,0 @@
---
import fs from 'node:fs';
import path from 'node:path';
import MarkdownIt from 'markdown-it-async';
import { fileURLToPath } from 'node:url';
import {
getOfficialGuide,
type OfficialGuideResponse,
} from '../../queries/official-guide';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { GuideContent } from '../../components/Guide/GuideContent';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import {
getOfficialRoadmapTopic,
prepareOfficialRoadmapTopicContent,
} from '../../queries/official-roadmap-topic';
export const prerender = false;
const { topicId, roadmapId } = Astro.params;
if (!topicId || !roadmapId) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
const isTopic = topicId?.includes('@') || topicId?.includes('/');
let gitHubUrl = '';
let htmlContent = '';
let guide: OfficialGuideResponse | null = null;
let permalink = '';
let ogImageUrl = '';
if (isTopic) {
// Handle nested paths by joining the segments
const topicPath = Array.isArray(topicId) ? topicId.join('/') : topicId;
// Get the project root directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// hack to make it work. TODO: Fix
const projectRoot = path.resolve(__dirname, '../../..').replace(/dist$/, '');
// Construct the path to the markdown file
let contentPath = path.join(
projectRoot,
'src',
'data',
'roadmaps',
roadmapId,
'content',
`${topicPath}.md`,
);
const nodeId = topicPath.split('@')?.[1];
if (!nodeId) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
const topic = await getOfficialRoadmapTopic({
roadmapSlug: roadmapId,
nodeId,
});
if (topic) {
const md = MarkdownIt();
htmlContent = await md.renderAsync(
prepareOfficialRoadmapTopicContent(topic),
);
} else {
htmlContent = '<h1>Not found</h1>';
}
const fileWithoutBasePath = contentPath.replace(
/.+?\/src\/data/,
'/src/data',
);
gitHubUrl = `https://github.com/kamranahmedse/developer-roadmap/tree/master${fileWithoutBasePath}`;
} else {
guide = await getOfficialGuide(topicId, roadmapId);
if (!guide) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
permalink = `/${roadmapId}/${topicId}`;
ogImageUrl =
guide?.featuredImage ||
getOpenGraphImageUrl(
{
group: 'guide',
resourceId: topicId,
},
{
roadmapId,
},
);
}
---
{
isTopic ? (
<>
<div data-github-url={gitHubUrl} />
<Fragment set:html={htmlContent} />
</>
) : (
<BaseLayout
title={guide?.seo?.metaTitle ?? guide?.title ?? ''}
description={guide?.seo?.metaDescription ?? guide?.description ?? ''}
permalink={permalink}
ogImageUrl={ogImageUrl}
>
<GuideContent guide={guide!} client:load />
<div slot='changelog-banner' />
</BaseLayout>
)
}

View File

@@ -1,154 +0,0 @@
---
import RoadmapHeader from '../../components/RoadmapHeader.astro';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import { listOfficialProjects } from '../../queries/official-project';
import { officialRoadmapDetails } from '../../queries/official-roadmap';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const roadmapData = await officialRoadmapDetails(roadmapId);
if (!roadmapData) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
// update og for projects
const ogImageUrl =
roadmapData?.openGraph?.image ||
getOpenGraphImageUrl({
group: 'roadmap',
resourceId: roadmapId,
});
const descriptionNoun: Record<string, string> = {
'AI and Data Scientist': 'AI and Data Science',
'Game Developer': 'Game Development',
'Technical Writer': 'Technical Writing',
'Product Manager': 'Product Management',
};
const title = `${roadmapData?.title.card} Courses`;
const description = `Premium courses to help you master ${descriptionNoun[roadmapData?.title.card] || roadmapData?.title.card}`;
const seoTitle = `${roadmapData?.title.card} Courses`;
const nounTitle =
descriptionNoun[roadmapData.title.card] || roadmapData.title.card;
const seoDescription = `Seeking ${nounTitle.toLowerCase()} courses to enhance your skills? Explore our top free and paid courses to help you become a ${nounTitle} expert!`;
const projects = await listOfficialProjects({ roadmapId });
const courses = roadmapData?.courses || [];
---
<BaseLayout
permalink={`/${roadmapId}`}
title={seoTitle}
description={seoDescription}
briefTitle={roadmapData.title.card}
ogImageUrl={ogImageUrl}
keywords={roadmapData.seo.keywords}
resourceId={roadmapId}
resourceType='roadmap'
noIndex={true}
>
<div class='bg-gray-50'>
<RoadmapHeader
title={title}
description={description}
partner={roadmapData.partner}
roadmapId={roadmapId}
isForkable={true}
coursesCount={courses.length}
projectCount={projects.length}
activeTab='courses'
hasAIChat={true}
/>
<div class='container'>
<div class='relative mt-2.5 mb-8'>
<div class='my-4 flex items-center justify-between'>
<p class='border-l-4 border-black pl-2 text-sm text-black'>
Official Courses by <span class='font-semibold'> roadmap.sh </span>
team
</p>
<div class='hidden text-sm text-gray-500 sm:block'>
More coming soon
</div>
</div>
<div class='grid grid-cols-1 gap-5 md:grid-cols-1'>
{
courses.map((course) => (
<a
href={course.link}
class='block rounded-lg border border-gray-200 bg-white p-6 duration-300 hover:border-gray-400/60'
>
<div class='flex justify-between'>
<div class='flex-1'>
<h3 class='mb-2 text-2xl font-bold text-black'>
{course.title}
</h3>
<p class='text-base text-gray-600'>{course.description}</p>
{course.features.length > 0 && (
<>
<div class='my-6 flex flex-wrap gap-2'>
{course.features.map((feature) => (
<span class='rounded-full border border-gray-200 bg-gray-100 px-2 py-0.5 text-xs text-gray-700'>
{feature}
</span>
))}
</div>
<div class='mt-6 flex flex-col items-start justify-between gap-3 sm:mt-0 sm:flex-row sm:items-center sm:gap-0'>
<div class='flex items-center'>
<img
src={course.instructor.image}
alt={course.instructor.name}
class='mr-3 h-12 w-12 rounded-full border border-gray-200'
/>
<div>
<p class='text-base font-medium text-gray-900'>
{course.instructor.name}
</p>
<p class='text-sm text-gray-500'>
{course.instructor.title}
</p>
</div>
</div>
<span class='group mt-3 w-full rounded-lg border border-gray-900 bg-gray-900 px-4 py-2 text-sm font-medium text-white transition-colors duration-300 hover:opacity-80 sm:mt-0 sm:w-auto sm:py-1.5'>
View Course <span class='ml-1'>&rarr;</span>
</span>
</div>
</>
)}
</div>
</div>
</a>
))
}
</div>
{
courses.length === 0 && (
<div class='rounded-lg border border-gray-200 bg-white py-10 text-center'>
<h3 class='mb-2 text-lg font-medium text-gray-700'>
No courses available yet
</h3>
<p class='text-sm text-gray-500'>
We're working on creating premium courses for this roadmap.
Check back soon!
</p>
</div>
)
}
</div>
</div>
</div>
</BaseLayout>

View File

@@ -1,179 +0,0 @@
---
import { EditorRoadmap } from '../../components/EditorRoadmap/EditorRoadmap';
import { FAQs } from '../../components/FAQs/FAQs';
import RelatedRoadmaps from '../../components/RelatedRoadmaps.astro';
import RoadmapHeader from '../../components/RoadmapHeader.astro';
import { ShareIcons } from '../../components/ShareIcons/ShareIcons';
import { TopicDetail } from '../../components/TopicDetail/TopicDetail';
import { UserProgressModal } from '../../components/UserProgress/UserProgressModal';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { isNewRoadmap } from '../../queries/official-roadmap';
import {
generateArticleSchema,
generateFAQSchema,
} from '../../lib/jsonld-schema';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import { RoadmapTitleQuestion } from '../../components/RoadmapTitleQuestion';
import ResourceProgressStats from '../../components/ResourceProgressStats.astro';
import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification';
import { officialRoadmapDetails } from '../../queries/official-roadmap';
import { DateTime } from 'luxon';
import { listOfficialProjects } from '../../queries/official-project';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const roadmapData = await officialRoadmapDetails(roadmapId);
if (!roadmapData) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
let jsonLdSchema = [];
const datePublished = DateTime.fromJSDate(
new Date(roadmapData?.createdAt),
).toFormat('yyyy-MM-dd');
const dateModified = DateTime.fromJSDate(
new Date(roadmapData?.updatedAt),
).toFormat('yyyy-MM-dd');
const baseUrl = import.meta.env.DEV
? `http://localhost:8080`
: `https://roadmap.sh`;
jsonLdSchema.push(
generateArticleSchema({
url: `https://roadmap.sh/${roadmapId}`,
headline: roadmapData?.seo?.title || roadmapData?.title?.page,
description: roadmapData?.description,
datePublished,
dateModified,
imageUrl: `${baseUrl}/roadmaps/${roadmapId}.png`,
}),
);
const ogImageUrl =
roadmapData?.openGraph?.image ||
getOpenGraphImageUrl({
group: 'roadmap',
resourceId: roadmapId,
});
const question = roadmapData?.questions?.find(
(question) => question.type === 'main',
);
const faqs =
roadmapData?.questions?.filter((question) => question.type === 'faq') || [];
if (faqs.length) {
jsonLdSchema.push(generateFAQSchema(faqs));
}
const projects = await listOfficialProjects({ roadmapId });
const courses = roadmapData.courses || [];
const isNew = isNewRoadmap(roadmapData.createdAt);
---
<BaseLayout
permalink={`/${roadmapId}`}
title={roadmapData?.seo?.title || roadmapData?.title.page}
briefTitle={roadmapData.title.card}
ogImageUrl={ogImageUrl}
description={roadmapData.seo.description}
keywords={roadmapData.seo.keywords}
noIndex={false}
jsonLd={jsonLdSchema}
resourceId={roadmapId}
resourceType='roadmap'
>
<link
rel='preload'
href='/fonts/balsamiq.woff2'
as='font'
type='font/woff2'
crossorigin
slot='after-header'
/>
<TopicDetail
resourceId={roadmapId}
resourceType='roadmap'
renderer='editor'
client:idle
canSubmitContribution={true}
/>
<div class='bg-gray-50'>
<RoadmapHeader
title={roadmapData.title.page}
description={roadmapData.description}
partner={roadmapData.partner}
roadmapId={roadmapId}
isForkable={true}
isNew={isNew}
projectCount={projects.length}
coursesCount={courses.length}
hasAIChat={true}
/>
<div class='container mt-2.5'>
<div class='rounded-md border bg-white'>
<ResourceProgressStats resourceId={roadmapId} resourceType='roadmap' />
{
question?.title && (
<RoadmapTitleQuestion
client:load
roadmapId={roadmapId}
question={question?.title}
answer={question?.description}
/>
)
}
</div>
</div>
<div class='relative container max-w-[1000px]!'>
<ShareIcons
resourceId={roadmapId}
resourceType='roadmap'
description={roadmapData.description}
pageUrl={`https://roadmap.sh/${roadmapId}`}
client:load
/>
<EditorRoadmap
resourceId={roadmapId}
resourceType='roadmap'
dimensions={roadmapData.dimensions!}
client:load
/>
</div>
<UserProgressModal
resourceId={roadmapId}
resourceType='roadmap'
renderer='editor'
client:only='react'
/>
{
roadmapId === 'docker' && (
<p class='mb-8 px-5 text-center text-xs text-gray-400 sm:mb-12'>
Roadmap owner Insight Partners is an investor in Docker.
</p>
)
}
<FAQs faqs={faqs} client:load />
<RelatedRoadmaps relatedRoadmaps={roadmapData?.relatedRoadmaps || []} />
</div>
<CheckSubscriptionVerification client:load />
<div slot='changelog-banner'></div>
</BaseLayout>

View File

@@ -1,94 +0,0 @@
---
import RoadmapHeader from '../../components/RoadmapHeader.astro';
import { EmptyProjects } from '../../components/Projects/EmptyProjects';
import { ProjectsList } from '../../components/Projects/ProjectsList';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import { projectApi } from '../../api/project';
import { officialRoadmapDetails } from '../../queries/official-roadmap';
import { listOfficialProjects } from '../../queries/official-project';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const roadmapData = await officialRoadmapDetails(roadmapId);
if (!roadmapData) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
// update og for projects
const ogImageUrl =
roadmapData?.openGraph?.image ||
getOpenGraphImageUrl({
group: 'roadmap',
resourceId: roadmapId,
});
const descriptionNoun: Record<string, string> = {
'AI and Data Scientist': 'AI and Data Science',
'Game Developer': 'Game Development',
'Technical Writer': 'Technical Writing',
'Product Manager': 'Product Management',
};
const title = `${roadmapData.title.card} Projects`;
const description = `Project ideas to take you from beginner to advanced in ${descriptionNoun[roadmapData.title.card] || roadmapData.title.card}`;
// `Seeking backend projects to enhance your skills? Explore our top 20 project ideas, from simple apps to complex systems. Start building today!`
const seoTitle = `${roadmapData.title.card} Projects`;
const nounTitle =
descriptionNoun[roadmapData?.title.card] || roadmapData.title.card;
const seoDescription = `Seeking ${nounTitle.toLowerCase()} projects to enhance your skills? Explore our top 20 project ideas, from simple apps to complex systems. Start building today!`;
const projects = await listOfficialProjects({ roadmapId });
const projectIds = projects.map((project) => project.slug);
const projectApiClient = projectApi(Astro);
const { response: userCounts } =
await projectApiClient.listProjectsUserCount(projectIds);
---
<BaseLayout
permalink={`/${roadmapId}/projects`}
title={seoTitle}
description={seoDescription}
briefTitle={roadmapData.title.card}
ogImageUrl={ogImageUrl}
keywords={roadmapData.seo.keywords}
noIndex={projects.length === 0}
resourceId={roadmapId}
resourceType='roadmap'
>
<div class='bg-gray-50'>
<RoadmapHeader
title={title}
description={description}
partner={roadmapData.partner}
roadmapId={roadmapId}
isForkable={true}
activeTab='projects'
projectCount={projects.length}
coursesCount={roadmapData.courses?.length || 0}
hasAIChat={true}
/>
<div class='container'>
{projects.length === 0 && <EmptyProjects client:load />}
{
projects.length > 0 && (
<ProjectsList
projects={projects}
userCounts={userCounts || {}}
client:load
/>
)
}
</div>
</div>
</BaseLayout>

View File

@@ -1,49 +0,0 @@
---
import { EditorRoadmap } from '../../components/EditorRoadmap/EditorRoadmap';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import { officialRoadmapDetails } from '../../queries/official-roadmap';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const roadmapData = await officialRoadmapDetails(roadmapId);
if (!roadmapData) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
const ogImageUrl =
roadmapData?.openGraph?.image ||
getOpenGraphImageUrl({
group: 'roadmap',
resourceId: roadmapId,
});
---
<SkeletonLayout
permalink={`/${roadmapId}`}
title={roadmapData?.seo?.title || roadmapData.title.page}
briefTitle={roadmapData.title.card}
ogImageUrl={ogImageUrl}
description={roadmapData.seo.description}
keywords={roadmapData.seo.keywords}
resourceId={roadmapId}
resourceType='roadmap'
noIndex={true}
>
<div class='relative container max-w-[1000px]!'>
<EditorRoadmap
resourceId={roadmapId}
resourceType='roadmap'
dimensions={roadmapData.dimensions!}
client:load
hasChat={false}
/>
</div>
</SkeletonLayout>

View File

@@ -1,209 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { getRepositoryRank } from '../lib/github.ts';
const repoRank = await getRepositoryRank('kamranahmedse/developer-roadmap');
---
<BaseLayout title='About roadmap.sh' permalink={'/about'}>
<div class='bg-white border-b pt-7 pb-7 sm:pt-12 sm:pb-10'>
<div class='container'>
<div class='flex items-center'>
<img
style='--aspect-ratio:170/170'
src='/authors/kamran.jpeg'
class='h-[170px] w-[170px] rounded-full mr-6 hidden sm:block'
alt='Kamran Ahmed'
/>
<div>
<h1 class='text-3xl sm:text-4xl mb-3 font-bold'>
<span class='hidden sm:inline'>Hello,</span>&nbsp;I am Kamran Ahmed
</h1>
<p class='text-gray-500 text-md mb-5'>
I created roadmap.sh to help developers find their path if they are
confused and help them learn and grow in their career.
</p>
<p class='flex flex-col sm:flex-row gap-1.5'>
<a
class='bg-blue-600 hover:bg-blue-700 font-medium text-white px-2 py-1.5 rounded-md inline-flex items-center'
target='_blank'
href='https://twitter.com/kamrify'
>
<span class='ml-1.5 mr-1'>@kamrify</span>
</a>
<a
class='bg-gray-500 hover:bg-gray-700 font-medium text-white px-3 py-1.5 rounded-md inline-flex items-center'
target='_blank'
href='mailto:kamranahmed.se@gmail.com'
>
kamranahmed.se@gmail.com
</a>
</p>
</div>
</div>
</div>
</div>
<div class='bg-gray-50 py-7 sm:py-10'>
<div class='container'>
<main id='main-content'>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>What is roadmap.sh?</h2>
<p class='mb-3'>
<span class='font-bold'>roadmap.sh</span> contains community-curated
roadmaps, study plans, paths, and resources for developers. There are
role-based roadmaps, listing skills you should know for any given role, as
well as skill-based roadmaps listing items to learn for any given skill.
</p>
<p class='mb-3'>
It started as a set of <a
href='https://github.com/kamranahmedse/developer-roadmap'
class='font-bold underline'
target='_blank'>visual charts on GitHub</a
> to guide developers who are confused about what they should learn
next, but then expanded into interactive roadmaps where you can click
and get resources to learn any given resource, contribute by adding new
roadmaps, suggest changes to existing roadmaps, track your progress as
you follow a roadmap and so on.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>How are roadmaps created?</h2>
<p class='mb-3'>
The project has a strong community that powers everything on the
website. It is <a
href='https://github.com/search?o=desc&q=stars%3A%3E100000&s=stars&type=Repositories'
target='_blank'
class='font-bold underline'
>the {repoRank} most starred opensource project on GitHub</a
> and gets visited by hundreds of thousands of developers every month.
We also have newsletter with 150,000+ developers. All the roadmaps are
created and reviewed by community and several subject matter experts.
Also, anyone can suggest changes to any roadmap and we have a process
to review and approve them.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>
What are the plans for roadmap.sh?
</h2>
<p class='mb-3'>
Our long-term plan is to make roadmap.sh a go-to place for
developers whenever they plan on learning something new. We started
with roadmaps, guides, videos and other visual content but we plan
on introducing best practices, best-practices for certain tasks, quizzes
to test your knowledge and prepare yourself for the interviews,
project ideas to work on while following the roadmaps, public
profiles to share your progress and interact with the other learners
and so on.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>How is roadmap.sh built?</h2>
<p class='mb-3'>
The website is built with <a
href='https://astro.build/'
class='font-bold underline'
target='_blank'
rel='nofollow'>Astro</a
> and <a
href='https://tailwindcss.com/'
class='font-bold underline'
target='_blank'
rel='nofollow'>Tailwind</a
> and is deployed to <a
href='https://pages.github.com/'
class='font-bold underline'
target='_blank'
rel='nofollow'>GitHub pages</a
>. The project is open-core and the codebase
<a
href='https://github.com/kamranahmedse/developer-roadmap'
class='font-bold underline'
target='_blank'>can be found on GitHub</a
>
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>How can I add a new roadmap?</h2>
<p class='mb-3'>
For new roadmaps, please open an issue with the textual description
of the roadmap in the form of bulleted list. Here is an <a
target='_blank'
class='font-bold underline'
href='https://github.com/kamranahmedse/developer-roadmap/issues/1387#issue-1329276631'
>example contribution of a new roadmap</a
>.
</p>
<p class='mb-3'>
Find more details in the <a
href='https://github.com/kamranahmedse/developer-roadmap/blob/master/contributing.md'
class='font-bold underline'
target='_blank'>contribution docs</a
>.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>
How can I update an existing roadmap?
</h2>
<p class='mb-3'>
Please have a look at the <a
href='https://github.com/kamranahmedse/developer-roadmap/blob/master/contributing.md'
class='font-bold underline'
target='_blank'>contribution docs</a
> for details.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>
How can I add content to existing roadmaps?
</h2>
<p class='mb-3'>
Please have a look at the <a
href='https://github.com/kamranahmedse/developer-roadmap/blob/master/contributing.md'
class='font-bold underline'
target='_blank'>contribution docs</a
> for details.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>
Can I redistribute the content?
</h2>
<p>
No, the license of the content on this website does not allow you to
redistribute any of the content on this website anywhere. You can
use it for personal use or share the link to the content if you have
to but redistribution is not allowed.
</p>
</div>
<div class='mb-5'>
<h2 class='text-2xl font-bold mb-2'>
What is the best way to contact you?
</h2>
<p>
Tweet or send me a message <a
class='underline font-bold'
href='https://twitter.com/kamrify'
target='_blank'>@kamrify</a
> or email me at
<a
class='underline font-bold'
href='mailto:kamranahmed.se@gmail.com'
target='_blank'>kamranahmed.se@gmail.com</a
>. I get lots of messages so apologies in advance if you don't hear
back from me soon but I do reply to everyone.
</p>
</div>
</main>
</div>
</div>
</BaseLayout>

View File

@@ -1,40 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { getRepositoryRank } from '../lib/github.ts';
import { AdvertiseForm } from '../components/AdvertiseForm';
---
<BaseLayout title='Advertise with roadmap.sh' permalink={'/advertise'}>
<div class='bg-white py-8 sm:py-20'>
<div class='container'>
<div class='mb-2 sm:mb-8 flex items-center'>
<div>
<h1 class='mb-0 sm:mb-3 text-2xl font-bold sm:text-4xl'>
Advertise with roadmap.sh
</h1>
<p class='text-lg sm:text-xl text-gray-500'>
The best way to reach developers
</p>
</div>
</div>
<p class='mb-5'>
With hundreds of thousands of monthly visitors and over 1 million
registered users, roadmap.sh is the resource developers choose to skill
up and advance their careers. This community effort creates guides and
educational content where developers can choose their path to success.
</p>
<p class='mb-4 sm:mb-9'>
<span class='font-bold'>roadmap.sh</span> also provides opportunities to
advertise to developers where your message stands out on our platform to
generate valuable results. Do more with your budget and achieve your marketing
goals by targeting your ideal segments of our developer audience. Dont wait
to get your message in front of aspirational developers.
</p>
<AdvertiseForm client:load />
</div>
</div>
<div slot="changelog-banner" />
</BaseLayout>

View File

@@ -1,22 +0,0 @@
---
import { AIRoadmap } from '../../components/AIRoadmap/AIRoadmap';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
aiRoadmapSlug: string;
}
const { aiRoadmapSlug } = Astro.params as Params;
---
<SkeletonLayout
title='AI Tutor'
briefTitle='AI Tutor'
description='AI Tutor'
keywords={['ai', 'tutor', 'education', 'learning']}
canonicalUrl={`/ai-roadmaps/${aiRoadmapSlug}`}
>
<AIRoadmap client:load roadmapSlug={aiRoadmapSlug} />
</SkeletonLayout>

View File

@@ -1,9 +0,0 @@
---
import { ExploreAIRoadmap } from '../../components/ExploreAIRoadmap/ExploreAIRoadmap';
import BaseLayout from '../../layouts/BaseLayout.astro';
---
<BaseLayout title='Explore AI Generated Roadmaps' permalink="/ai-roadmaps/explore">
<ExploreAIRoadmap client:load />
<div slot="changelog-banner" />
</BaseLayout>

View File

@@ -1,10 +0,0 @@
---
import { GenerateRoadmap } from '../../components/GenerateRoadmap/GenerateRoadmap';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification';
---
<BaseLayout title='Roadmap AI' permalink='/ai-roadmaps'>
<GenerateRoadmap client:load />
<CheckSubscriptionVerification client:load />
</BaseLayout>

View File

@@ -1,14 +0,0 @@
---
import AccountLayout from '../layouts/AccountLayout.astro';
import { Befriend } from '../components/Befriend';
import LoginPopup from "../components/AuthenticationFlow/LoginPopup.astro";
---
<AccountLayout
title='Respond Invite'
noIndex={true}
initialLoadingMessage={'Loading invite'}
>
<LoginPopup />
<Befriend client:only="react" />
</AccountLayout>

View File

@@ -1,34 +0,0 @@
import type { APIRoute } from 'astro';
import { getDefaultOpenGraphImageBuffer } from '../../../lib/open-graph';
import { getRoadCard } from '../../../lib/road-card';
export const prerender = false;
type Params = {
version: 'tall' | 'wide';
userId: string;
};
export const GET: APIRoute<any, Params> = async (context) => {
const { userId, version } = context.params;
if (!userId || !version) {
const buffer = await getDefaultOpenGraphImageBuffer();
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
}
const searchParams = new URLSearchParams(context.url.searchParams);
const variant = (searchParams.get('variant') as 'dark' | 'light') || 'dark';
const roadmaps = searchParams.get('roadmaps') || '';
const svg = await getRoadCard(version, userId, variant, roadmaps);
return new Response(svg, {
headers: {
'Content-Type': 'image/svg+xml',
},
});
};

View File

@@ -1,46 +0,0 @@
---
import ChangelogItem from '../components/Changelog/ChangelogItem.astro';
import ChangelogLaunch from '../components/Changelog/ChangelogLaunch.astro';
import BaseLayout from '../layouts/BaseLayout.astro';
import { listChangelog } from '../queries/changelog';
const allChangelogs = await listChangelog();
---
<BaseLayout
title='Changelogs'
description='Changelogs for the updates and changes to roadmap.sh'
permalink='/changelog'
noIndex={true}
>
<div class='bg-gray-100 px-4'>
<div class='-mx-4 border-b bg-white text-left'>
<div
class='mx-auto max-w-[500px] px-4 py-5 text-left sm:pb-10 sm:pt-12 sm:text-center'
>
<h1 class='mb-0.5 text-2xl font-semibold sm:mb-3 sm:text-4xl'>
Changelog
</h1>
<p class='text-balance text-sm sm:text-base'>
We are constantly improving and updating roadmap.sh
</p>
</div>
</div>
<div class='relative mx-auto max-w-[600px] pb-8 pt-8'>
<div
class='absolute inset-y-0 -left-5 hidden w-px -translate-x-[0.5px] bg-gray-300 sm:block'
>
</div>
{
allChangelogs.map((changelog) => (
<ChangelogItem changelog={changelog} />
))
}
<ChangelogLaunch />
</div>
</div>
<div slot="changelog-banner"></div>
</BaseLayout>

View File

@@ -1,13 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { DiscoverRoadmaps } from '../components/DiscoverRoadmaps/DiscoverRoadmaps';
const title = 'Discover Custom Roadmaps';
const description =
'Explore the community-created roadmaps to learn new skills, tools, and technologies. You can also create your own roadmap and share it with the world.';
---
<BaseLayout title={title} description={description} permalink="/community">
<DiscoverRoadmaps client:load />
<div slot="changelog-banner" />
</BaseLayout>

View File

@@ -1,110 +0,0 @@
---
import { SQLCourseVariantPage } from '../../components/SQLCourseVariant/SQLCourseVariantPage.tsx';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
---
<SkeletonLayout
title='Master SQL'
briefTitle='Learn SQL from the ground up'
ogImageUrl='https://assets.roadmap.sh/guest/sql-course-bjc53.png'
description='Learn SQL from the ground up. This SQL programming class is designed to help you go from beginner to expert through hands-on practice with real-world scenarios, mastering everything from basic to complex queries.'
keywords={[
'sql',
'database',
'database management',
'database administration',
]}
canonicalUrl='/courses/master-sql'
noIndex={true}
jsonLd={[
{
"@context": "https://schema.org",
"@type": "Course",
"@id": "https://roadmap.sh/courses/sql",
"name": "Master SQL",
"description": "A comprehensive SQL course designed to take you from beginner to advanced levels, featuring 55+ lessons, 100+ challenges, an integrated IDE, and an AI tutor. Ideal for developers, data analysts, and anyone working with data.",
"provider": {
"@type": "Organization",
"name": "roadmap.sh",
"url": "https://roadmap.sh"
},
"publisher": {
"@type": "Organization",
"name": "roadmap.sh",
"url": "https://roadmap.sh"
},
"timeRequired": "PT60H",
"isAccessibleForFree": false,
"offers": {
"@type": "Offer",
"url": "https://roadmap.sh/courses/sql",
"price": "59.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"category": "paid"
},
"image": [
"https://assets.roadmap.sh/guest/sql-course-bjc53.png"
],
"coursePrerequisites": [],
"teaches": [
"SQL syntax and queries",
"Data filtering and sorting",
"Joins and subqueries",
"Aggregate functions",
"Stored procedures",
"Views and indexes",
"Transactions and ACID properties",
"Query optimization techniques"
],
"educationalLevel": "Beginner to Advanced",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"ratingCount": 500
},
"inLanguage": "en",
"review": [
{
"@type": "Review",
"reviewBody": "This course was absolutely brilliant! The integrated database environment to practice what I learned was the best part.",
"author": {
"@type": "Person",
"name": "Gourav Khunger"
}
},
{
"@type": "Review",
"reviewBody": "Kamran has clearly put a lot of thought into this course. The content, structure and exercises were all great.",
"author": {
"@type": "Person",
"name": "Meabed"
}
},
{
"@type": "Review",
"reviewBody": "I already knew SQL but this course taught me a bunch of new things. Practical examples and challenges were great. Highly recommended!",
"author": {
"@type": "Person",
"name": "Mohsin Aheer"
}
}
],
"educationalCredentialAwarded": {
"@type": "EducationalOccupationalCredential",
"name": "Certificate of Completion",
"credentialCategory": "Certificate",
"url": "https://roadmap.sh/courses/sql"
},
"hasCourseInstance": [
{
"@type": "CourseInstance",
"courseMode": "Online",
"courseWorkload": "PT60H",
}
]
}
]}
>
<SQLCourseVariantPage client:load />
</SkeletonLayout>

View File

@@ -1,117 +0,0 @@
---
import { SQLCoursePage } from '../../components/SQLCourse/SQLCoursePage.tsx';
import { SQLCourseVariantPage } from '../../components/SQLCourseVariant/SQLCourseVariantPage';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
---
<SkeletonLayout
title='Master SQL'
briefTitle='Learn SQL from the ground up'
ogImageUrl='https://assets.roadmap.sh/guest/sql-course-bjc53.png'
description='Learn SQL from the ground up. This SQL programming class is designed to help you go from beginner to expert through hands-on practice with real-world scenarios, mastering everything from basic to complex queries.'
keywords={[
'sql',
'database',
'database management',
'database administration',
]}
canonicalUrl='/courses/sql'
jsonLd={[
{
'@context': 'https://schema.org',
'@type': 'Course',
'@id': 'https://roadmap.sh/courses/sql',
name: 'Master SQL',
description:
'A comprehensive SQL course designed to take you from beginner to advanced levels, featuring 55+ lessons, 100+ challenges, an integrated IDE, and an AI tutor. Ideal for developers, data analysts, and anyone working with data.',
provider: {
'@type': 'Organization',
name: 'roadmap.sh',
url: 'https://roadmap.sh',
},
publisher: {
'@type': 'Organization',
name: 'roadmap.sh',
url: 'https://roadmap.sh',
},
timeRequired: 'PT60H',
isAccessibleForFree: false,
offers: {
'@type': 'Offer',
url: 'https://roadmap.sh/courses/sql',
price: '59.99',
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
category: 'paid',
},
image: ['https://assets.roadmap.sh/guest/sql-course-bjc53.png'],
coursePrerequisites: [],
teaches: [
'SQL syntax and queries',
'Data filtering and sorting',
'Joins and subqueries',
'Aggregate functions',
'Stored procedures',
'Views and indexes',
'Transactions and ACID properties',
'Query optimization techniques',
],
educationalLevel: 'Beginner to Advanced',
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: 500,
},
inLanguage: 'en',
review: [
{
'@type': 'Review',
reviewBody:
'This course was absolutely brilliant! The integrated database environment to practice what I learned was the best part.',
author: {
'@type': 'Person',
name: 'Gourav Khunger',
},
},
{
'@type': 'Review',
reviewBody:
'Kamran has clearly put a lot of thought into this course. The content, structure and exercises were all great.',
author: {
'@type': 'Person',
name: 'Meabed',
},
},
{
'@type': 'Review',
reviewBody:
'I already knew SQL but this course taught me a bunch of new things. Practical examples and challenges were great. Highly recommended!',
author: {
'@type': 'Person',
name: 'Mohsin Aheer',
},
},
],
educationalCredentialAwarded: {
'@type': 'EducationalOccupationalCredential',
name: 'Certificate of Completion',
credentialCategory: 'Certificate',
url: 'https://roadmap.sh/courses/sql',
},
hasCourseInstance: [
{
'@type': 'CourseInstance',
courseMode: 'Online',
courseWorkload: 'PT60H',
},
],
},
]}
>
<div class='course-variant-1'>
<SQLCoursePage client:load />
</div>
<div class='course-variant-2 !hidden'>
<SQLCourseVariantPage client:load />
</div>
</SkeletonLayout>

View File

@@ -1,6 +0,0 @@
---
export const prerender = false;
const discordLink = 'https://discord.gg/GBY7zEc3uB';
return Astro.redirect(discordLink);
---

View File

@@ -1,37 +0,0 @@
---
import { ForgotPasswordForm } from '../components/AuthenticationFlow/ForgotPasswordForm';
import AccountLayout from '../layouts/AccountLayout.astro';
import {AccountTerms} from "../components/AccountTerms";
---
<AccountLayout title='Forgot Password' noIndex={true} permalink="/forgot-password">
<div class='container'>
<div
class='mx-auto flex flex-col items-start justify-start pb-28 pt-10 sm:max-w-[400px] sm:items-center sm:justify-center sm:pt-20'
>
<div class='mb-2 text-left sm:mb-5 sm:text-center'>
<h1 class='mb-2 text-3xl font-semibold sm:mb-5 sm:text-5xl'>
Forgot Password?
</h1>
<p class='mb-3 text-base leading-6 text-gray-600'>
Enter your email address below and we will send you a link to reset
your password.
</p>
</div>
<ForgotPasswordForm client:load />
<div
class='mt-3 w-full rounded-md border py-2 text-center text-sm text-slate-600'
>
Don't have an account?{' '}
<a
href='/signup'
class='font-medium text-blue-700 hover:text-blue-600 hover:underline'
>
Sign up
</a>
</div>
</div>
</div>
</AccountLayout>

View File

@@ -1,570 +0,0 @@
---
import {
Blocks,
Bot,
Braces,
CheckSquare,
Coins,
Component,
FolderKanban,
Gamepad2,
GitBranch,
Globe2,
GraduationCap,
Megaphone,
MessageCircle,
MessageCircleCode,
PenSquare,
Server,
ServerCog,
Shield,
ShieldHalf,
Smartphone,
SquareKanban,
UsersRound,
Waypoints,
Workflow,
} from 'lucide-react';
import ChangelogBanner from '../components/ChangelogBanner.astro';
import { RoadmapCard } from '../components/GetStarted/RoadmapCard';
import { RoadmapMultiCard } from '../components/GetStarted/RoadmapMultiCard';
import { RoleRoadmaps } from '../components/GetStarted/RoleRoadmaps';
import { SectionBadge } from '../components/GetStarted/SectionBadge';
import { TipItem } from '../components/GetStarted/TipItem';
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout
title='Developer Roadmaps'
description={'Step by step guides and paths to learn different tools or technologies'}
permalink={'/get-started'}
>
<!-- AI Chat Section -->
<div class='border-b bg-linear-to-b from-gray-200 to-white py-12 sm:py-16'>
<div class='container'>
<div class='max-w-3xl'>
<Bot className='mb-4 size-8 text-black sm:size-12' />
<h2 class='mb-3 text-2xl font-bold text-black sm:text-3xl'>
Get AI-Powered Learning Guidance
</h2>
<p class='mb-6 text-sm text-gray-600 sm:text-base'>
Our AI Tutor analyzes your experience, suggests relevant roadmaps, and
provides detailed answers to help you progress in your tech career.
</p>
<a
href='/ai/chat'
class='inline-flex items-center gap-2 rounded-xl bg-black px-4 py-2 text-sm font-medium text-white transition-colors hover:opacity-80 sm:px-6 sm:py-3 sm:text-base'
>
<MessageCircle className='size-3 fill-current sm:size-5' />
Chat with AI Tutor
</a>
</div>
</div>
</div>
<div class='bg-linear-to-b from-gray-200 to-white py-4 sm:py-8 md:py-12'>
<div class='container'>
<div class='text-left'>
<SectionBadge title='Beginner Roadmaps' />
</div>
<div class='my-3 text-left md:my-5'>
<h2 class='mb-0 text-xl font-semibold sm:mb-1 sm:text-3xl'>
Are you an Absolute beginner?
</h2>
<p class='text-sm text-gray-500 sm:text-base'>
Here are some beginner friendly roadmaps you should start with.
</p>
</div>
<div class='grid gap-3 sm:grid-cols-2 md:grid-cols-3'>
<RoadmapCard
icon={Globe2}
title='Frontend Developer'
link='/frontend?r=frontend-beginner'
description='Develop the part of web apps that users interact with i.e. things rendered in the browser.'
/>
<RoadmapCard
icon={ServerCog}
title='Backend Developer'
link='/backend?r=backend-beginner'
description='Develop the part hidden from the user e.g. things like APIs, databases, search engines etc.'
/>
<RoadmapCard
icon={Globe2}
icon2={ServerCog}
title='Full Stack Developer'
link='/full-stack'
description='Develop both the frontend and backend side of the web apps i.e. the whole development stack.'
/>
</div>
<p class='my-4 text-sm sm:my-7 sm:text-base'>
There is also a <a
target='_blank'
class='font-medium underline underline-offset-2'
href='/devops?r=devops-beginner'>beginner DevOps roadmap</a
> which requires you to have some backend knowledge and entails a lot of
operations work i.e. deploying, scaling, monitoring, and maintaining applications.
</p>
<div class='rounded-xl border bg-white p-3 sm:p-4'>
<h2 class='mb-0 text-lg font-semibold sm:mb-1 sm:text-xl'>
Tips for Beginners
</h2>
<p class='text-sm sm:text-base'>
Learning to code can be overwhelming, here are some tips to help you
get started:
</p>
<div class='mt-3 flex flex-col gap-1'>
<TipItem
title='Avoid Tutorial Hell'
description="Don't get stuck in tutorial hell. It's easy to get caught up in tutorials and never actually build anything. Tutorials are great for learning, but the best way to learn is by doing. An example of this is to watch a project-based tutorial, code along with the instructor. After finishing the tutorial, try to build the same project from scratch without the tutorial (if you can't, it's okay to go back to the tutorial). Repeat this process until you can build the project without the tutorial. After that, try to add new features to the project or build something similar from scratch."
client:load
/>
<TipItem
title='Consistent study habits'
description="Commit to regular, consistent study sessions. It's better to study for 30 minutes every day than to cram for 10 hours once a week."
client:load
/>
<TipItem
title='Set a clear goal'
description='Establish a clear, significant goal that motivates you. It could be building a company, an app, a website, or anything that personally resonates with you.'
client:load
/>
<TipItem
title='Embrace the marathon mindset'
description="You will feel lost in the beginning. Avoid comparing yourself to others; everyone progresses at their own pace. Understand that challenges are part of the journey, and it's okay to take your time."
client:load
/>
<TipItem
title='Build projects'
description="The best way to learn is by doing. Start building projects as soon as possible. It's okay if they're simple at first; the goal is to learn and improve. Build upon code-alongs and tutorials to create your projects and learn through hands-on experience"
client:load
/>
<TipItem
title='Learn to get unstuck'
description="Once you start learning to code, you're going to run into problems that you don't know how to solve. This is normal and part of the process. You don't really learn unless you struggle through it. That said, you won't always be able to move forward without some help. So how do you find that help? First off, forget books. They aren't a great place to start here, because the number and types of errors they can cover is so small. Online is the easiest place to find help. Most devs look for solutions on StackOverflow or just google the error message (if they have one). Other solutions are to find newsgroups or forums dedicated to the language you're using."
client:load
/>
<TipItem
title='Join a community'
description="Join a community of learners, such as a local coding group, a Discord server, or a subreddit. It's a great way to get help, share your progress, and learn from others."
client:load
/>
</div>
</div>
</div>
</div>
<RoleRoadmaps
badge='Self-taught Developer'
title='Are you a self-taught developer?'
description='How about taking a peek at the Computer Science roadmap aimed at self-taught developers?'
>
<RoadmapCard
icon={GraduationCap}
title='Computer Science'
link='/computer-science'
description='Learn the fundamental concepts of computer science and programming.'
/>
<RoadmapCard
icon={Blocks}
title='Data Structures'
link='/datastructures-and-algorithms'
description='Learn all about data structures and algorithms.'
/>
<RoadmapMultiCard
roadmaps={[{ title: 'System Design', link: '/system-design' }]}
description='Learn how to design large scale systems and prepare for system design interviews.'
secondaryRoadmaps={[
{
title: 'Design and Architecture',
link: '/software-design-architecture',
},
]}
secondaryDescription='Or learn how to design and architect software systems.'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='Frontend Developer'
title='Are you a Frontend Developer?'
description='How about skimming through the frontend or JavaScript roadmaps to see if there is anything you missed? TypeScript is all the rage these days, maybe it is time to learn it?'
>
<RoadmapCard
icon={Globe2}
title='Frontend'
link='/frontend'
description='Learn all you need to know to become a frontend developer.'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'HTML', link: '/html' },
{ title: 'CSS', link: '/css' },
{ title: 'JavaScript', link: '/javascript' },
{ title: 'TypeScript', link: '/typescript' },
]}
description='How about mastering the language of the web: JavaScript? or maybe TypeScript? or maybe HTML or CSS?'
secondaryRoadmaps={[
{
title: 'Frontend Performance',
link: '/best-practices/frontend-performance',
},
]}
secondaryDescription='Or learn how to improve the performance of your web apps?'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'React', link: '/react' },
{ title: 'Vue', link: '/vue' },
{ title: 'Angular', link: '/angular' },
{ title: 'Next.js', link: '/nextjs' },
]}
description='Or learn a framework?'
secondaryRoadmaps={[{ title: 'Design Systems', link: '/design-system' }]}
secondaryDescription='or learn about design systems?'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='Backend Developer'
title='Are you a Backend Developer?'
description='Explore the general backend roadmap or dive into a specific technology like Node.js, Python, Java etc'
>
<div class='flex flex-col gap-3'>
<RoadmapCard
icon={ServerCog}
title='Backend'
link='/backend'
description='Learn all you need to know to become a backend developer.'
/>
<RoadmapCard
icon={Braces}
title='API Design'
link='/api-design'
description='Learn all you need to know to design robust APIs.'
/>
</div>
<RoadmapMultiCard
roadmaps={[
{ title: 'Node.js', link: '/nodejs' },
{ title: 'PHP', link: '/php' },
{ title: 'Rust', link: '/rust' },
{ title: 'Go', link: '/golang' },
{ title: 'Python', link: '/python' },
{ title: 'Java', link: '/java' },
{ title: 'Kotlin', link: '/kotlin' },
{ title: 'ASP.NET Core', link: '/aspnet-core' },
{ title: 'C++', link: '/cpp' },
]}
description='Or learn a specific technology?'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'System Design', link: '/system-design' },
{
title: 'Design and Architecture',
link: '/software-design-architecture',
},
]}
description='How about improving your System Design skills?'
secondaryRoadmaps={[
{ title: 'SQL', link: '/sql' },
{ title: 'PostgreSQL', link: '/postgresql-dba' },
{ title: 'MongoDB', link: '/mongodb' },
{ title: 'Redis', link: '/redis' },
]}
secondaryDescription='Or perhaps improve your database skills?'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='DevOps Engineer'
title='DevOps or a Wanna-be DevOps Engineer?'
description='Explore the general DevOps roadmap or dive into a specific technology like Docker, Kubernetes etc'
>
<RoadmapCard
icon={Server}
title='DevOps'
link='/devops'
description='Learn all you need to know to become a DevOps Engineer.'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'AWS', link: '/aws' },
{ title: 'Cloudflare', link: '/cloudflare' },
]}
description='or perhaps you want to learn AWS or Cloudflare?'
secondaryRoadmaps={[{ title: 'Terraform', link: '/terraform' }]}
secondaryDescription='Or learn to automate your infrastructure using Terraform?'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'Docker', link: '/docker' },
{ title: 'Kubernetes', link: '/kubernetes' },
{ title: 'Linux', link: '/linux' },
]}
description='or perhaps you want to learn Docker, Kubernetes or Linux?'
secondaryRoadmaps={[
{ title: 'Python', link: '/python' },
{ title: 'Go', link: '/golang' },
{ title: 'Rust', link: '/rust' },
{ title: 'Shell / Bash', link: '/shell-bash'}
]}
secondaryDescription='Or maybe improve your automation skills?'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='Mobile Developer'
title='Are you a Mobile Developer?'
description='How about beefing up your mobile development skills?'
>
<RoadmapCard
icon={Smartphone}
title='Android'
link='/android'
description='Learn all you need to know to become an Android Developer.'
/>
<RoadmapCard
icon={Smartphone}
title='iOS'
link='/ios'
description='Learn all you need to know to become an iOS Developer.'
/>
<RoadmapMultiCard
roadmaps={[
{ title: 'React Native', link: '/react-native' },
{ title: 'Flutter', link: '/flutter' },
{ title: 'Kotlin', link: '/kotlin' },
]}
description='Or learn a cross-platform framework?'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='AI and Machine Learning'
title='Are you an AI or Machine Learning enthusiast?'
description='How about diving into the AI or Machine Learning roadmaps?'
>
<RoadmapCard
icon={Bot}
title='Machine Learning'
link='/machine-learning'
description='Learn all you need to know to become an ML Engineer.'
/>
<RoadmapCard
icon={Bot}
title='AI and Data Science'
link='/ai-data-scientist'
description='Learn all you need to know to become an AI or Data Scientist.'
/>
<RoadmapCard
icon={Bot}
title='AI Engineer'
link='/ai-engineer'
description='Learn all you need to become an AI Engineer.'
/>
<RoadmapCard
icon={ServerCog}
title='AI Agents'
link='/ai-agents'
description='Learn how to design, build and ship AI agents in 2025.'
/>
<RoadmapCard
icon={Bot}
title='Data Analyst'
link='/data-analyst'
description='Learn all you need to know to become a Data Analyst.'
/>
<RoadmapCard
icon={Bot}
title='BI Analyst'
link='/bi-analyst'
description='Learn to become a Business Intelligence Analyst in 2025.'
/>
<RoadmapCard
icon={Bot}
title='Data Engineer'
link='/data-engineer'
description='Learn all you need to know to become a Data Engineer.'
/>
<RoadmapCard
icon={MessageCircleCode}
title='Prompt Engineering'
link='/prompt-engineering'
description='Learn how to write better prompts for GPT-* and other language models.'
/>
<RoadmapCard
icon={Shield}
title='AI Red Teaming'
link='/ai-red-teaming'
description='Learn how to red team your AI applications with this interactive step by step guide.'
/>
<RoadmapCard
icon={Bot}
icon2={ServerCog}
title='MLOps'
link='/mlops'
description='Learn how to deploy and manage machine learning models.'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='Product or Engineering Management'
title='Thinking about a career in management?'
description='How about diving into our product or engineering management roadmaps?'
>
<RoadmapCard
icon={SquareKanban}
title='Product Manager'
link='/product-manager'
description='Learn all you need to know to become a Product Manager.'
/>
<RoadmapCard
icon={UsersRound}
title='Engineering Manager'
link='/engineering-manager'
description='Learn all you need to become an Engineering Manager.'
/>
</RoleRoadmaps>
<RoleRoadmaps
badge='More Roles'
title='Fancy something else?'
description='Explore the following roadmaps about UX, Game Development, Software Architect and more'
>
<div class='flex flex-col justify-start gap-3'>
<RoadmapCard
icon={ShieldHalf}
title='Cyber Security'
link='/cyber-security'
description='Learn to become a Cyber Security Expert.'
/>
<RoadmapCard
icon={Workflow}
title='UX Designer'
link='/ux-design'
description='Learn all you need to know to become a UX Designer.'
/>
<RoadmapCard
icon={Coins}
title='Blockchain'
link='/blockchain'
description='Learn all you need to know to become a Blockchain Developer.'
/>
</div>
<div class='flex flex-col justify-start gap-3'>
<RoadmapCard
icon={Gamepad2}
title='Game Development'
link='/game-developer'
description='Learn all you need to know to become a Game Developer.'
/>
<RoadmapCard
icon={PenSquare}
title='Technical Writer'
link='/technical-writer'
description='Learn all you need to know to become a Technical Writer.'
/>
<RoadmapCard
icon={Megaphone}
title='DevRel Engineer'
link='/devrel'
description='Learn all you need to know to become a DevRel Engineer.'
/>
</div>
<div class='flex flex-col justify-start gap-3'>
<RoadmapCard
icon={FolderKanban}
title='Product Manager'
link='/product-manager'
description='Learn all you need to know to become a Project Manager.'
/>
<RoadmapCard
icon={Component}
title='Software Architect'
link='/software-architect'
description='Learn all you need to know to become a Software Architect.'
/>
<RoadmapCard
icon={GitBranch}
title='Git and GitHub'
link='/git-github'
description='Learn all you need to know to become a Git and GitHub expert.'
/>
</div>
</RoleRoadmaps>
<div class='container'>
<div class='-mt-5 mb-12 rounded-3xl bg-black p-5'>
<h2 class='mb-0.5 text-xl font-semibold text-white sm:mb-1 sm:text-2xl'>
There is more!
</h2>
<p class='text-sm text-gray-400 sm:text-base'>
We have a lot more content for you to explore.
</p>
<div
class='my-4 grid grid-cols-1 gap-2 sm:my-5 sm:grid-cols-2 sm:gap-3 md:grid-cols-3'
>
<a
href='/roadmaps'
class='grow rounded-lg bg-linear-to-br from-gray-800 to-gray-700 p-4 text-sm text-white transition-all hover:from-gray-700 hover:to-gray-700 sm:text-base'
>
<Waypoints className='mb-3 h-5 w-5 text-gray-500 sm:mb-2' />
Explore all Roadmaps
</a>
<a
href='/best-practices'
class='grow rounded-lg bg-linear-to-br from-gray-800 to-gray-700 p-4 text-sm text-white transition-all hover:from-gray-700 hover:to-gray-700 sm:text-base'
>
<CheckSquare className='mb-3 h-5 w-5 text-gray-500 sm:mb-2' />
Explore Best Practices
</a>
<a
href='/questions'
class='grow rounded-lg bg-linear-to-br from-gray-800 to-gray-700 p-4 text-sm text-white transition-all hover:from-gray-700 hover:to-gray-700 sm:text-base'
>
<CheckSquare className='mb-3 h-5 w-5 text-gray-500 sm:mb-2' />
Explore Questions
</a>
</div>
<p class='text-sm text-gray-400 sm:text-base'>
Or visit our <a
href='/guides'
class='rounded-lg bg-gray-700 px-2 py-1 text-gray-300 transition-colors hover:bg-gray-600 hover:text-white'
>guides</a
> and <a
href='/videos'
class='rounded-lg bg-gray-700 px-2 py-1 text-gray-300 transition-colors hover:bg-gray-600 hover:text-white'
>videos</a
> for long-form content.
</p>
</div>
</div>
<ChangelogBanner slot='changelog-banner' />
</BaseLayout>

View File

@@ -1,6 +0,0 @@
---
export const prerender = false;
const githubLink = 'https://github.com/kamranahmedse/developer-roadmap';
return Astro.redirect(githubLink);
---

View File

@@ -1,21 +0,0 @@
---
import { LeaderboardPage } from '../components/Leaderboard/LeaderboardPage';
import { ErrorPage } from '../components/Leaderboard/ErrorPage';
import BaseLayout from '../layouts/BaseLayout.astro';
import { leaderboardApi } from '../api/leaderboard';
export const prerender = false;
const leaderboardClient = leaderboardApi(Astro);
const { response: leaderboardStats, error: leaderboardError } =
await leaderboardClient.listLeaderboardStats();
---
<BaseLayout title='Leaderboard' permalink="/leaderboard">
{leaderboardError && <ErrorPage error={leaderboardError} />}
{
leaderboardStats && (
<LeaderboardPage stats={leaderboardStats!} client:load />
)
}
</BaseLayout>

View File

@@ -1,41 +0,0 @@
---
import { AccountTerms } from '../components/AccountTerms';
import { AuthenticationForm } from '../components/AuthenticationFlow/AuthenticationForm';
import AccountLayout from '../layouts/AccountLayout.astro';
---
<AccountLayout
title='Login - roadmap.sh'
description='Register yourself to receive occasional emails about new roadmaps, updates, guides and videos'
permalink={'/login'}
noIndex={true}
>
<div class='container'>
<div
class='mx-auto flex flex-col items-start justify-start pb-28 pt-10 sm:max-w-[400px] sm:items-center sm:justify-center sm:pt-20'
>
<div class='mb-2 text-left sm:mb-5 sm:text-center'>
<h1 class='mb-2 text-3xl font-semibold sm:mb-5 sm:text-5xl'>Login</h1>
<p class='mb-3 text-base leading-6 text-gray-600'>
Welcome back! Let's take you to your account.
</p>
</div>
<AuthenticationForm client:load />
<div
class='mt-3 w-full rounded-md border py-2 text-center text-sm text-slate-600'
>
Don't have an account?{' '}
<a
href='/signup'
class='font-medium text-blue-700 hover:text-blue-600 hover:underline'
>
Sign up
</a>
</div>
<AccountTerms />
</div>
</div>
</AccountLayout>

View File

@@ -1,34 +0,0 @@
import type { APIRoute } from 'astro';
import {
getDefaultOpenGraphImageBuffer,
getResourceOpenGraph,
} from '../../../lib/open-graph';
import { Transformer } from '@napi-rs/image';
export const prerender = false;
type Params = {
slug: string;
};
export const GET: APIRoute<any, Params> = async (context) => {
const { slug } = context.params;
if (!slug) {
const buffer = await getDefaultOpenGraphImageBuffer();
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
}
const svg = await getResourceOpenGraph('best-practice', slug);
const transformer = Transformer.fromSvg(svg).crop(0, 0, 1200, 630);
return new Response(await transformer.png(), {
headers: {
'Content-Type': 'image/png',
},
});
};

View File

@@ -1,40 +0,0 @@
import type { APIRoute } from 'astro';
import {
getDefaultOpenGraphImageBuffer,
getResourceOpenGraph,
} from '../../../lib/open-graph';
import { Transformer } from '@napi-rs/image';
export const prerender = false;
type Params = {
slug: string;
};
export const GET: APIRoute<any, Params> = async (context) => {
const { slug } = context.params;
const { searchParams } = context.url;
if (!slug) {
const buffer = await getDefaultOpenGraphImageBuffer();
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
}
const svg = await getResourceOpenGraph(
'guide',
slug,
Object.fromEntries(searchParams.entries()),
);
const transformer = Transformer.fromSvg(svg).crop(0, 0, 1200, 630);
// @ts-expect-error - Buffer is not assignable to BodyInit
return new Response(await transformer.png(), {
headers: {
'Content-Type': 'image/png',
},
});
};

View File

@@ -1,35 +0,0 @@
import { Transformer } from '@napi-rs/image';
import type { APIRoute } from 'astro';
import {
getDefaultOpenGraphImageBuffer,
getResourceOpenGraph,
} from '../../../lib/open-graph';
export const prerender = false;
type Params = {
slug: string;
};
export const GET: APIRoute<any, Params> = async (context) => {
const { slug } = context.params;
if (!slug) {
const buffer = await getDefaultOpenGraphImageBuffer();
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
}
const svg = await getResourceOpenGraph('roadmap', slug);
const transformer = Transformer.fromSvg(svg).crop(0, 0, 1200, 630);
return new Response(await transformer.png(), {
headers: {
'Content-Type': 'image/png',
},
});
};

View File

@@ -1,35 +0,0 @@
import type { APIRoute } from 'astro';
import { getDefaultOpenGraphImageBuffer } from '../../../lib/open-graph';
import { Transformer } from '@napi-rs/image';
export const prerender = false;
type Params = {
username: string;
};
export const GET: APIRoute<any, Params> = async (context) => {
const { username } = context.params;
if (!username || !/^[a-zA-Z0-9]*?[a-zA-Z]+?[a-zA-Z0-9]*?$/.test(username)) {
const buffer = await getDefaultOpenGraphImageBuffer();
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
}
const response = await fetch(
`${import.meta.env.PUBLIC_API_URL}/v1-profile-open-graph/${username}`,
);
const svg = await response.text();
const transformer = Transformer.fromSvg(svg).crop(0, 0, 1200, 630);
return new Response(await transformer.png(), {
headers: {
'Content-Type': 'image/png',
},
});
};

View File

@@ -1,97 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { PremiumPage } from '../components/Premium/PremiumPage';
---
<BaseLayout
title='Premium Features - AI-Powered Learning | roadmap.sh'
description='Unlock unlimited AI-powered learning with roadmap.sh Premium. Generate unlimited courses, get career guidance, instant AI answers, and access exclusive features for just $10/month.'
ogImageUrl='https://assets.roadmap.sh/guest/ai-tutor-og-6hm9j.png'
keywords={[
'roadmap.sh premium',
'ai learning platform',
'developer education',
'programming courses',
'career guidance',
'ai tutor',
'coding roadmaps',
'tech learning subscription',
'developer tools',
'unlimited courses',
'ai-powered education',
'programming mentor'
]}
permalink={'/premium'}
jsonLd={[
{
'@context': 'https://schema.org',
'@type': 'Product',
name: 'roadmap.sh Premium',
description: 'AI-powered learning platform for developers with unlimited courses, career guidance, and instant AI support.',
image: 'https://assets.roadmap.sh/guest/ai-tutor-og-6hm9j.png',
brand: {
'@type': 'Brand',
name: 'roadmap.sh'
},
offers: [
{
'@type': 'Offer',
name: 'Monthly Plan',
price: '10.00',
priceCurrency: 'USD',
priceValidUntil: '2025-12-31',
availability: 'https://schema.org/InStock',
url: 'https://roadmap.sh/premium',
hasMerchantReturnPolicy: {
'@type': 'MerchantReturnPolicy',
applicableCountry: 'US',
returnPolicyCategory: 'https://schema.org/MerchantReturnNotPermitted'
},
shippingDetails: {
'@type': 'OfferShippingDetails',
shippingRate: {
'@type': 'MonetaryAmount',
value: 0,
currency: 'USD'
},
doesNotShip: true
}
},
{
'@type': 'Offer',
name: 'Yearly Plan',
price: '100.00',
priceCurrency: 'USD',
priceValidUntil: '2025-12-31',
availability: 'https://schema.org/InStock',
url: 'https://roadmap.sh/premium',
hasMerchantReturnPolicy: {
'@type': 'MerchantReturnPolicy',
applicableCountry: 'US',
returnPolicyCategory: 'https://schema.org/MerchantReturnNotPermitted'
},
shippingDetails: {
'@type': 'OfferShippingDetails',
shippingRate: {
'@type': 'MonetaryAmount',
value: 0,
currency: 'USD'
},
doesNotShip: true
}
}
],
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
bestRating: '5',
ratingCount: '1000'
}
}
]}
>
<PremiumPage client:load />
<div slot='changelog-banner'></div>
<div slot='open-source-banner'></div>
</BaseLayout>

View File

@@ -1,81 +0,0 @@
---
layout: ../layouts/MarkdownLayout.astro
title: Privacy Policy - roadmap.sh
noIndex: true
permalink: /privacy
---
# Privacy Policy
By using or accessing the Services in any manner, you acknowledge that you accept the practices and policies outlined in this Privacy Policy, and you hereby consent that we will collect, use, and share your information in the following ways. Remember that your use of roadmap.shs Services is at all times subject to the [Terms of Use](/terms), which incorporates this Privacy Policy. Any terms we use in this Policy without defining them have the definitions given to them in the Terms of Use.
## What does this Privacy Policy cover?
This Privacy Policy covers our treatment of personally identifiable information ("Personal Information") that we gather when you are accessing or using our Services, but not to the practices of companies we dont own or control, or people that we dont manage. We gather various types of Personal Information from our users, as explained in more detail below, and we use this Personal Information internally in connection with our Services, including to personalize, provide, and improve our services, to allow you to set up a user account and profile, to contact you and allow other users to contact you, to fulfill your requests for certain products and services, and to analyze how you use the Services. In certain cases, we may also share some Personal Information with third parties, but only as described below.
As noted in the Terms of Use, we do not knowingly collect or solicit personal information from anyone under the age of 13. If you are under 13, please do not attempt to register for the Services or send any personal information about yourself to us. If we learn that we have collected personal information from a child under age 13, we will delete that information as quickly as possible. If you believe that a child under 13 may have provided us personal information, please contact us at info@roadmap.sh.
## Will roadmap.sh ever change this Privacy Policy?
Were constantly trying to improve our Services, so we may need to change this Privacy Policy from time to time as well, but we will alert you to changes by updating the services on the website, placing a notice on the Services, by sending you an email, and/or by some other means. Please note that if youve opted not to receive legal notice emails from us (or you havent provided us with your email address), those legal notices will still govern your use of the Services, and you are still responsible for reading and understanding them. If you use the Services after any changes to the Privacy Policy have been posted, that means you agree to all of the changes. Use of information we collect now is subject to the Privacy Policy in effect at the time such information is used or collected.
## What Information does roadmap.sh Collect?
Information You Provide to Us:
We receive and store any information you knowingly provide to us. For example, through the registration process and/or through your account settings, we may collect Personal Information such as your name, title, email address, phone number, and third-party account credentials (for example, your log-in credentials for Twitter or other third party sites. If you provide your third-party account credentials to us or otherwise sign in to the Services through a third party site or service, you understand some content and/or information in those accounts (“Third Party Account Information”) may be transmitted into your account with us if you authorize such transmissions], and that Third Party Account Information transmitted to our Services is covered by this Privacy Policy. Certain information may be required to register with us or to take advantage of some of our features.
We may communicate with you if youve provided us the means to do so. For example, if youve given us your email address, we may send you promotional email offers on behalf of other businesses, or email you about your use of the Services. Also, we may receive a confirmation when you open an email from us. This confirmation helps us make our communications with you more interesting and improve our services. If you do not want to receive communications from us, please email us at info@roadmap.sh.
## Information Collected Automatically
Whenever you interact with our Services, we automatically receive and record information on our server logs from your browser or device, which may include your IP address, geolocation data, device identification, “cookie” information, the type of browser and/or device youre using to access our Services, and the page or feature you requested. “Cookies” are identifiers we transfer to your browser or device that allow us to recognize your browser or device and tell us how and when pages and features in our Services are visited and by how many people. You may be able to change the preferences on your browser or device to prevent or limit your devices acceptance of cookies, but this may prevent you from taking advantage of some of our features. Our advertising partners may also transmit cookies to your browser or device, when you click on ads that appear on the Services. Also if you click on a link to a third party website or service, such third party may also transmit cookies to you. Again, this Privacy Policy does not cover the use of cookies by any third parties, and we arent responsible for their privacy policies and practices.
When we collect the usage information described above, we only use this data in aggregate form, and not in a manner that would identify you personally. For example, this aggregate data can tell us how often users use a particular feature of the Services, and we can use that knowledge to make the Services interesting to as many users as possible.
## Will roadmap.sh Share Any of the Personal Information it Receives?
We may share your Personal Information with third parties as described in this section:
Information thats no longer personally identifiable. We may anonymize your Personal Information so that you are not individually identified, and provide that information to our partners. We may also provide aggregate usage information to our partners, who may use such information to understand how often and in what ways people use our Services, so that they, too, can provide you with an optimal online experience. However, we never disclose aggregate information to a partner in a manner that would identify you personally, as an individual.
Advertisers: We may allow advertisers and/or merchant partners (“Advertisers”) to choose the demographic information of users who will see their advertisements and/or promotional offers and you agree that we may provide any of the information we have collected from you in non-personally identifiable form to an Advertiser, in order for that Advertiser to select the appropriate audience for those advertisements and/or offers. For example, we might use the fact you are located in San Francisco to show you ads or offers for San Francisco businesses, but we will not tell such businesses who you are. Note that if an advertiser asks us to show an ad to a certain audience or audience segment and you respond to that ad, the advertiser may conclude that you fit the description of the audience they were trying to reach.
We may deliver a file to you through the Services (known as a “web beacon”) from an ad network. Web beacons allow ad networks to provide anonymized, aggregated auditing, research and reporting for us and for advertisers. Web beacons also enable ad networks to serve targeted advertisements to you when you visit other websites. Because your web browser must request these advertisements and web beacons from the ad networks servers, these companies can view, edit, or set their own cookies, just as if you had requested a web page from their site. You may be able to opt-out of web beacon tracking by adjusting the settings on your browser.
Affiliated Businesses: In certain situations, businesses or third party websites were affiliated with may sell or provide products or services to you through or in connection with the Services (either alone or jointly with us). You can recognize when an affiliated business is associated with such a transaction or service, and we will share your Personal Information with that affiliated business only to the extent that it is related to such transaction or service. One such service may include the ability for you to automatically transmit Third Party Account Information to your Services profile or to automatically transmit information in your Services profile to your third party account; for example, you may sign into your roadmap.sh account using your Twitter account. We have no control over the policies and practices of third party websites or businesses as to privacy or anything else, so if you choose to take part in any transaction or service relating to an affiliated website or business, please review all such business or websites policies.
Our Agents: We employ other companies and people to perform tasks on our behalf and need to share your information with them to provide products or services to you. Unless we tell you differently, our agents do not have any right to use the Personal Information we share with them beyond what is necessary to assist us.
User Profiles and Submissions: Certain user profile information, including your name, location, and any video or image content that such user has uploaded to the Services, may be displayed to other users to facilitate user interaction within the Services or address your request for our services. Please remember that any content you upload to your public user profile, along with any Personal Information or content that you voluntarily disclose online in a manner other users can view (on discussion boards, in messages and chat areas, etc.) becomes publicly available, and can be collected and used by anyone. Your user name may also be displayed to other users if and when you send messages or comments or upload images or videos through the Services and other users can contact you through messages and comments. Additionally, if you sign into the Services through a third party social networking site or service, your list of “friends” from that site or service may be automatically imported to the Services, and such “friends,” if they are also registered users of the Services, may be able to access certain non-public information you have entered in your Services user profile. Again, we do not control the policies and practices of any other third party site or service.
Business Transfers: We may choose to buy or sell assets. In these types of transactions, customer information is typically one of the business assets that would be transferred. Also, if we (or our assets) are acquired, or if we go out of business, enter bankruptcy, or go through some other change of control, Personal Information could be one of the assets transferred to or acquired by a third party.
Protection of roadmap.sh and Others: We reserve the right to access, read, preserve, and disclose any information that we reasonably believe is necessary to comply with law or court order; enforce or apply our terms of use and other agreements; or protect the rights, property, or safety of roadmap.sh, our employees, our users, or others.
## Is Personal Information about me secure?
Your account is protected by a password for your privacy and security. If you access your account via a third party site or service, you may have additional or different sign-on protections via that third party site or service. You must prevent unauthorized access to your account and Personal Information by selecting and protecting your password and/or other sign-on mechanism appropriately and limiting access to your computer or device and browser by signing off after you have finished accessing your account. We endeavor to protect the privacy of your account and other Personal Information we hold in our records, but unfortunately, we cannot guarantee complete security. Unauthorized entry or use, hardware or software failure, and other factors, may compromise the security of user information at any time.
## What Personal Information can I access?
Through your account settings, you may access, and, in some cases, edit or delete the following information youve provided to us:
- first and last name
- location of residence
- age or birthday
- username
The information you can view, update, and delete may change as the Services change. If you have any questions about viewing or updating information we have on file about you, please contact us at info@roadmap.sh.
Under California Civil Code Sections 1798.83-1798.84, California residents are entitled to ask us for a notice identifying the categories of Personal Information which we share with our affiliates and/or third parties for marketing purposes, and providing contact information for such affiliates and/or third parties. If you are a California resident and would like a copy of this notice, please submit a written request to: info@roadmap.sh.
## What choices do I have?
You can always opt not to disclose information to us, but keep in mind some information may be needed to register with us or to take advantage of some of our features.
You may be able to add, update, or delete information as explained above. When you update information, however, we may maintain a copy of the unrevised information in our records. You may request deletion of your account by contacting us at info@roadmap.sh and we will disassociate our email address and Twitter account from any content or other information provided to us. Some information may remain in our records after your deletion of such information from your account. We may use any aggregated data derived from or incorporating your Personal Information after you update or delete it, but not in a manner that would identify you personally.
## What if I have questions about this policy?
If you have any questions or concerns regarding our privacy policies, please send us a detailed message to info@roadmap.sh, and we will try to resolve your concerns.

View File

@@ -1,74 +0,0 @@
---
import BaseLayout from '../../../layouts/BaseLayout.astro';
import { Badge } from '../../../components/Badge';
import { ProjectStepper } from '../../../components/Projects/StatusStepper/ProjectStepper';
import { ProjectTabs } from '../../../components/Projects/ProjectTabs';
import { officialProjectDetails } from '../../../queries/official-project';
import { ProjectContent } from '../../../components/Projects/ProjectContent';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
projectId: string;
}
const { projectId } = Astro.params as Params;
const project = await officialProjectDetails(projectId);
if (!project) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
const parentRoadmapId = project?.roadmapIds?.[0] || '';
---
<BaseLayout
permalink={`/projects/${projectId}`}
title={project?.seo?.title || project?.title}
briefTitle={project?.title}
description={project?.seo?.description || project?.description}
keywords={project?.seo?.keywords || []}
resourceId={projectId}
>
<div class='bg-gray-50'>
<div class='container'>
<ProjectTabs
parentRoadmapId={parentRoadmapId}
projectId={projectId}
activeTab='details'
/>
<div
class='mb-4 rounded-lg border bg-linear-to-b from-gray-100 to-white to-10% p-4 py-2 sm:p-5'
>
<div class='relative'>
<div class='mb-4 hidden items-center justify-between sm:flex'>
<div class='flex flex-row flex-wrap gap-1.5'>
{
project?.skills.map((skill) => (
<Badge variant='green' text={skill} />
))
}
</div>
<Badge variant='yellow' text={project?.difficulty} />
</div>
<div class='my-2 flex items-center justify-between gap-2 sm:my-7'>
<div class=''>
<h1 class='mb-1 text-xl font-semibold sm:mb-2 sm:text-3xl'>
{project?.title}
</h1>
<p class='text-sm text-balance text-gray-500'>
{project?.description}
</p>
</div>
</div>
</div>
<ProjectStepper projectId={projectId} client:load />
<ProjectContent project={project} client:load />
</div>
</div>
</div>
</BaseLayout>

View File

@@ -1,56 +0,0 @@
---
import BaseLayout from '../../../layouts/BaseLayout.astro';
import { ProjectTabs } from '../../../components/Projects/ProjectTabs';
import { ListProjectSolutions } from '../../../components/Projects/ListProjectSolutions';
import { ProjectSolutionModal } from '../../../components/Projects/ProjectSolutionModal';
import { officialProjectDetails } from '../../../queries/official-project';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
projectId: string;
}
const { projectId } = Astro.params as Params;
const project = await officialProjectDetails(projectId);
if (!project) {
Astro.response.status = 404;
Astro.response.statusText = 'Not found';
return Astro.rewrite('/404');
}
const parentRoadmapId = project?.roadmapIds?.[0] || '';
---
<BaseLayout
permalink={`/projects/${projectId}/solutions`}
title={project?.seo?.title || project.title}
briefTitle={project.title}
description={project.seo.description || project.description}
keywords={project.seo.keywords}
resourceId={projectId}
>
<div class='bg-gray-50'>
<div class='container'>
<ProjectTabs
parentRoadmapId={parentRoadmapId}
projectId={projectId}
activeTab='solutions'
/>
<ListProjectSolutions
project={project}
projectId={projectId}
client:load
/>
<ProjectSolutionModal
projectId={projectId}
projectTitle={project.title}
projectDescription={project.description}
client:only='react'
/>
</div>
</div>
</BaseLayout>

View File

@@ -1,52 +0,0 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { ProjectsPageHeader } from '../../components/Projects/ProjectsPageHeader';
import { ProjectsPage } from '../../components/Projects/ProjectsPage';
import { projectApi } from '../../api/project';
import { listOfficialRoadmaps } from '../../queries/official-roadmap';
import { getRoadmapsProjects } from '../../queries/official-project';
export const prerender = false;
const roadmapProjects = await getRoadmapsProjects();
const allRoadmapIds = Object.keys(roadmapProjects);
const roadmaps = await listOfficialRoadmaps();
const allRoadmaps = roadmaps.filter((roadmap) =>
allRoadmapIds.includes(roadmap.slug),
);
const enrichedRoadmaps = allRoadmaps.map((roadmap) => {
const projects = (roadmapProjects[roadmap.slug] || []).sort((a, b) => {
return a.order - b.order;
});
return {
id: roadmap.slug,
title: roadmap.title.card,
projects,
};
});
const projectIds = allRoadmapIds
.map((id) => roadmapProjects[id])
.flat()
.map((project) => project.slug);
const projectApiClient = projectApi(Astro);
const { response: userCounts } =
await projectApiClient.listProjectsUserCount(projectIds);
---
<BaseLayout
title='Project Ideas'
description='Explore project ideas to take you from beginner to advanced in different technologies'
permalink='/projects'
>
<ProjectsPageHeader client:load />
<ProjectsPage
roadmapsProjects={enrichedRoadmaps}
userCounts={userCounts || {}}
client:load
/>
<div slot='changelog-banner'></div>
</BaseLayout>

View File

@@ -1,36 +0,0 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { CustomRoadmap } from '../../components/CustomRoadmap/CustomRoadmap';
import { SkeletonRoadmapHeader } from '../../components/CustomRoadmap/SkeletonRoadmapHeader';
import Loader from '../../components/Loader.astro';
import ProgressHelpPopup from '../../components/ProgressHelpPopup.astro';
import { roadmapApi } from '../../api/roadmap';
export const prerender = false;
const { customRoadmapSlug } = Astro.params;
const roadmapClient = roadmapApi(Astro);
const { response, error } = await roadmapClient.isShowcaseRoadmap(
customRoadmapSlug!,
);
---
<BaseLayout
title='Roadmaps'
noIndex={!response?.isShowcase}
permalink={`/r/${customRoadmapSlug}`}
>
<ProgressHelpPopup />
<div>
<div class='flex min-h-[550px] flex-col'>
<div data-roadmap-loader class='flex w-full grow flex-col'>
<SkeletonRoadmapHeader />
<div class='flex grow items-center justify-center'>
<Loader />
</div>
</div>
<CustomRoadmap slug={customRoadmapSlug} client:only='react' />
</div>
</div>
</BaseLayout>

View File

@@ -1,31 +0,0 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { CustomRoadmap } from '../../components/CustomRoadmap/CustomRoadmap';
import { SkeletonRoadmapHeader } from '../../components/CustomRoadmap/SkeletonRoadmapHeader';
import Loader from '../../components/Loader.astro';
import ProgressHelpPopup from '../../components/ProgressHelpPopup.astro';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
import Icon from "../../components/AstroIcon.astro";
---
<SkeletonLayout title='Roadmaps' noIndex={true}>
<div class='relative flex min-h-[550px] flex-col'>
<div data-roadmap-loader class='flex w-full grow flex-col'>
<div class='flex grow items-center justify-center'>
<Loader />
</div>
</div>
<CustomRoadmap isEmbed={true} client:only='react' />
<div class='fixed bottom-5 right-4'>
<a
target='_blank'
class='rounded-md bg-gray-600 py-2 pr-2 pl-1.5 text-white hover:bg-black flex items-center gap-0.5'
href='https://roadmap.sh'
>
<Icon icon='logo' class="h-5" />
roadmap.sh
</a>
</div>
</div>
</SkeletonLayout>

View File

@@ -1,22 +0,0 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { CustomRoadmap } from '../../components/CustomRoadmap/CustomRoadmap';
import { SkeletonRoadmapHeader } from '../../components/CustomRoadmap/SkeletonRoadmapHeader';
import Loader from '../../components/Loader.astro';
import ProgressHelpPopup from '../../components/ProgressHelpPopup.astro';
---
<BaseLayout title='Roadmaps' noIndex={true}>
<ProgressHelpPopup />
<div>
<div class='flex min-h-[550px] flex-col'>
<div data-roadmap-loader class='flex w-full grow flex-col'>
<SkeletonRoadmapHeader />
<div class='flex grow items-center justify-center'>
<Loader />
</div>
</div>
<CustomRoadmap client:only='react' />
</div>
</div>
</BaseLayout>

View File

@@ -1,23 +0,0 @@
---
import { ResetPasswordForm } from '../components/AuthenticationFlow/ResetPasswordForm';
import AccountLayout from '../layouts/AccountLayout.astro';
---
<AccountLayout title='Reset Password' noIndex={true}>
<div class='container'>
<div
class='mx-auto flex flex-col items-start justify-start pb-28 pt-10 sm:max-w-[400px] sm:items-center sm:justify-center sm:pt-20'
>
<div class='mb-2 text-left sm:mb-5 sm:text-center'>
<h1 class='mb-2 text-3xl font-semibold sm:mb-5 sm:text-5xl'>
Reset Password
</h1>
<p class='mb-3 text-base leading-6 text-gray-600'>
Enter and confirm your new password below.
</p>
</div>
<ResetPasswordForm client:load />
</div>
</div>
</AccountLayout>

View File

@@ -1,14 +0,0 @@
---
import AccountLayout from '../layouts/AccountLayout.astro';
import { RespondInviteForm } from '../components/RespondInviteForm';
import LoginPopup from "../components/AuthenticationFlow/LoginPopup.astro";
---
<AccountLayout
title='Respond Invite'
noIndex={true}
initialLoadingMessage={'Loading invite'}
>
<LoginPopup />
<RespondInviteForm client:only="react" />
</AccountLayout>

View File

@@ -1,16 +0,0 @@
---
import { RoadmapsPage } from '../components/Roadmaps/RoadmapsPage';
import { RoadmapsPageHeader } from '../components/Roadmaps/RoadmapsPageHeader';
import BaseLayout from '../layouts/BaseLayout.astro';
import ChangelogBanner from '../components/ChangelogBanner.astro';
---
<BaseLayout
title='Developer Roadmaps'
description={'Step by step guides and paths to learn different tools or technologies'}
permalink={'/roadmaps'}
>
<RoadmapsPageHeader client:load />
<RoadmapsPage client:load />
<ChangelogBanner slot='changelog-banner' />
</BaseLayout>

View File

@@ -1,41 +0,0 @@
---
import { AuthenticationForm } from '../components/AuthenticationFlow/AuthenticationForm';
import AccountLayout from '../layouts/AccountLayout.astro';
import {AccountTerms} from "../components/AccountTerms";
---
<AccountLayout
title='Signup - roadmap.sh'
description='Create an account to track your progress, showcase your skillset'
permalink={'/signup'}
noIndex={true}
>
<div class='container'>
<div
class='mx-auto flex flex-col items-start justify-start pb-28 pt-10 sm:max-w-[400px] sm:items-center sm:justify-center sm:pt-20'
>
<div class='mb-2 text-left sm:mb-5 sm:text-center'>
<h1 class='mb-2 text-3xl font-semibold sm:mb-5 sm:text-5xl'>Sign Up</h1>
<p class='mb-3 hidden text-base leading-6 text-gray-600 sm:block'>
Create an account to track your progress, showcase your skill-set and
be a part of the community.
</p>
<p class='mb-3 block text-sm text-gray-600 sm:hidden'>
Create an account to track your progress, showcase your skill-set and
be a part of the community.
</p>
</div>
<AuthenticationForm type='signup' client:load />
<div class='mt-3 w-full rounded-md border py-2 text-center text-sm text-slate-600'>
Already have an account? <a
href='/login'
class='font-medium text-blue-700 hover:text-blue-600'>Login</a
>
</div>
<AccountTerms />
</div>
</div>
</AccountLayout>

View File

@@ -1,15 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { TeamHeroBanner } from '../components/TeamMarketing/TeamHeroBanner';
import { TeamTools } from '../components/TeamMarketing/TeamTools';
import { TeamDemo } from '../components/TeamMarketing/TeamDemo';
import { TeamPricing } from '../components/TeamMarketing/TeamPricing';
---
<BaseLayout title='Roadmaps for teams' permalink={'/teams'}>
<TeamHeroBanner client:load />
<TeamTools />
<TeamDemo client:load />
<TeamPricing client:load />
<div slot="changelog-banner" />
</BaseLayout>

View File

@@ -1,46 +0,0 @@
---
layout: ../layouts/MarkdownLayout.astro
title: Terms of Sale - roadmap.sh
noIndex: true
permalink: /terms-of-sale
---
# Terms of Sale
roadmap.sh is a publication of Insight Media Group, LLC. When you purchase any products or services from Insight Media Group, LLC ("roadmap.sh") through roadmap.sh, you agree to these Terms of Sale ("Terms"). These Terms are incorporated by reference into our Terms of Use, which govern your use of our Website, including any services we make available through the Website. Any capitalized Terms that aren't defined in these Terms are defined in the Terms of Use.
## Pricing
The price of any product or service that you purchase from us, including any courses and subscriptions that we offer, will be made available to you at the time of purchase. From time to time, we may offer discounts (which may be subject to additional terms or requirements, as communicated to you).
Depending on your location, roadmap.sh may be required to collect and remit the applicable sales taxes, goods and services taxes, or value added taxes based on your country or regions consumer sales tax requirements. Any prices that we advertise do not include applicable taxes.
We reserve the right to change the price of products or services at any time.
## Availability of Products and Services
The products or services may be available for a period of time. Where products and services are offered on a limited-time basis (e.g., courses), you will only be able to access the product and service during such period. At the expiration of such period, you will no longer have access to the products and services (and, in the case of courses, regardless of whether or not you completed the course).
## Subscriptions and Renewals
If you purchase products and services on a subscription basis, the subscription will automatically renew (and your payment method will be automatically charged) at the end of the subscription period unless you notify us of cancellation at least 30 days prior to renewal.
## Payments and Payment Methods
By purchasing products and services, you agree to pay all fees associated with your purchase. Full payment must be made at the time of purchase.
You authorize roadmap.sh or its third-party providers, to charge your debit or credit card or to process any other accepted means of payment, for payment of fees, including any renewals. You agree not to provide or use an invalid or unauthorized method of payment. We reserve the right to disable or terminate your access to any course or content for which we have not received the required payment.
## Refunds and Refund Credits (Courses Only)
If for any reason you wish to cancel your purchase of a course, you may request a refund within thirty (30) days of the original purchase date. You may request a refund by submitting a request to info@roadmap.sh. We will not issue refunds if the request is received after the 30-day time limit. Refunds will be prorated based on the date you provide a valid notice of cancellation to us. For example, if you purchase a course for $100 and provide us notice 15 days after the date of purchase, we will issue a refund of 50% or $50. We will apply your refund to your original payment method.
If we determine that you are abusing our refund policy, we reserve the right to deny your refund, restrict your receipt of future refunds, and/or restrict your access to the use of our Services.
## Modifications and Notice
We reserve the right to update these Terms at any time. Your continued use of the course or other Services, after the effective date of any such change, will be considered acceptance of the updated Terms.
## Incorporation by Reference
These Terms are incorporated by reference into and form part of our Terms of Use. By agreeing to these Terms, you agree that the Terms of Use apply to and govern these Terms.

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { ThankYouPage } from '../components/ThankYou/ThankYouPage';
---
<BaseLayout title='Thank you'>
<ThankYouPage client:load />
<div slot='page-footer'></div>
</BaseLayout>

View File

@@ -1,6 +0,0 @@
---
export const prerender = false;
const twitterLink = 'https://twitter.com/roadmapsh';
return Astro.redirect(twitterLink);
---

View File

@@ -1,75 +0,0 @@
---
import { getProjectList } from '../../api/roadmap';
import { userApi } from '../../api/user';
import { UserPublicProfilePage } from '../../components/UserPublicProfile/UserPublicProfilePage';
import BaseLayout from '../../layouts/BaseLayout.astro';
export const prerender = false;
interface Params extends Record<string, string | undefined> {
username: string;
}
const { username } = Astro.params as Params;
if (!username) {
return Astro.redirect('/404');
}
const userClient = userApi(Astro as any);
const { response: userDetails, error } =
await userClient.getPublicProfile(username);
let errorMessage = '';
if (error || !userDetails) {
errorMessage = error?.message || 'User not found';
}
const projectDetails = await getProjectList();
const origin = Astro.url.origin;
const ogImage = `${origin}/og/user/${username}`;
const hasAnyRoadmaps = (userDetails?.roadmaps || []).length > 0;
---
<BaseLayout
title={`${userDetails?.name || 'Unknown'} - Skill Profile at roadmap.sh`}
description='Check out my skill profile at roadmap.sh'
ogImageUrl={ogImage}
noIndex={!hasAnyRoadmaps}
>
{
!errorMessage && (
<UserPublicProfilePage
{...userDetails!}
projectDetails={projectDetails}
client:load
/>
)
}
{
errorMessage && (
<div class='container my-24 flex flex-col'>
<picture>
<source
srcset='https://fonts.gstatic.com/s/e/notoemoji/latest/1f61e/512.webp'
type='image/webp'
/>
<img
src='https://fonts.gstatic.com/s/e/notoemoji/latest/1f61e/512.gif'
alt='😞'
width='120'
height='120'
/>
</picture>
<h2 class='my-2 text-2xl font-bold sm:my-3 sm:text-4xl'>
Problem loading user!
</h2>
<p class='text-lg'>
<span class='rounded-md bg-red-600 px-2 py-1 text-white'>
{errorMessage}
</span>
</p>
</div>
)
}
</BaseLayout>

View File

@@ -1,7 +0,0 @@
import { execSync } from 'child_process';
export const prerender = false;
export async function GET() {
return new Response(JSON.stringify({}), {});
}

View File

@@ -1,33 +0,0 @@
import { execSync } from 'child_process';
export const prerender = true;
export async function GET() {
const commitHash = execSync('git rev-parse HEAD').toString().trim();
const commitDate = execSync('git log -1 --format=%cd').toString().trim();
const commitMessage = execSync('git log -1 --format=%B').toString().trim();
const prevCommitHash = execSync('git rev-parse HEAD~1').toString().trim();
const prevCommitDate = execSync('git log -1 --format=%cd HEAD~1')
.toString()
.trim();
const prevCommitMessage = execSync('git log -1 --format=%B HEAD~1')
.toString()
.trim();
return new Response(
JSON.stringify({
current: {
hash: commitHash,
date: commitDate,
message: commitMessage,
},
previous: {
hash: prevCommitHash,
date: prevCommitDate,
message: prevCommitMessage,
},
}),
{},
);
}

View File

@@ -1,10 +0,0 @@
---
import { VerificationEmailMessage } from '../components/AuthenticationFlow/VerificationEmailMessage';
import AccountLayout from '../layouts/AccountLayout.astro';
---
<AccountLayout title='Verify Email' noIndex={true}>
<section class='container py-8 sm:py-20'>
<VerificationEmailMessage client:load />
</section>
</AccountLayout>

View File

@@ -1,10 +0,0 @@
---
import { TriggerVerifyAccount } from '../components/AuthenticationFlow/TriggerVerifyAccount';
import AccountLayout from '../layouts/AccountLayout.astro';
---
<AccountLayout title='Verify account' noIndex={true}>
<div class='container py-16'>
<TriggerVerifyAccount client:load />
</div>
</AccountLayout>

View File

@@ -1,10 +0,0 @@
---
import AccountLayout from '../layouts/AccountLayout.astro';
import { TriggerVerifyEmail } from '../components/AuthenticationFlow/TriggerVerifyEmail';
---
<AccountLayout title='Verify email' noIndex={true}>
<div class='container py-16'>
<TriggerVerifyEmail client:load />
</div>
</AccountLayout>

View File

@@ -1,6 +0,0 @@
---
export const prerender = false;
const twitterLink = 'https://x.com/roadmapsh';
return Astro.redirect(twitterLink);
---

View File

@@ -1,6 +0,0 @@
---
export const prerender = false;
const youtubeLink = 'https://youtube.com/@roadmapsh';
return Astro.redirect(youtubeLink);
---

View File

@@ -190,7 +190,7 @@ a > code:before {
}
/* Hide scrollbars */
.scrollbar-none {
.scrollbar-none {
scrollbar-width: none;
-ms-overflow-style: none;
}
@@ -201,5 +201,5 @@ a > code:before {
.prose-xl
:where(table):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
font-size: 0.875rem !important;
font-size: 0.875em !important;
}