mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-12 17:51:53 +08:00
Compare commits
5 Commits
1af19e70c9
...
fix/table-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326aad3277 | ||
|
|
0da0c331e5 | ||
|
|
ad5523b938 | ||
|
|
4f7bcb01e2 | ||
|
|
f9947b78cf |
@@ -3,6 +3,6 @@
|
||||
"enabled": false
|
||||
},
|
||||
"_variables": {
|
||||
"lastUpdateCheck": 1762257454897
|
||||
"lastUpdateCheck": 1763344576632
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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'>→</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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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> 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>
|
||||
@@ -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. Don’t wait
|
||||
to get your message in front of aspirational developers.
|
||||
</p>
|
||||
|
||||
<AdvertiseForm client:load />
|
||||
</div>
|
||||
</div>
|
||||
<div slot="changelog-banner" />
|
||||
</BaseLayout>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
const discordLink = 'https://discord.gg/GBY7zEc3uB';
|
||||
|
||||
return Astro.redirect(discordLink);
|
||||
---
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
const githubLink = 'https://github.com/kamranahmedse/developer-roadmap';
|
||||
|
||||
return Astro.redirect(githubLink);
|
||||
---
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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.sh’s 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 don’t own or control, or people that we don’t 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?
|
||||
|
||||
We’re 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 you’ve opted not to receive legal notice emails from us (or you haven’t 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 you’ve provided us the means to do so. For example, if you’ve 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 you’re 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 device’s 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 aren’t 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 that’s 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 network’s 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 we’re 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 you’ve 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.
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
const twitterLink = 'https://twitter.com/roadmapsh';
|
||||
|
||||
return Astro.redirect(twitterLink);
|
||||
---
|
||||
@@ -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>
|
||||
@@ -1,7 +0,0 @@
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
export async function GET() {
|
||||
return new Response(JSON.stringify({}), {});
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
}),
|
||||
{},
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
const twitterLink = 'https://x.com/roadmapsh';
|
||||
|
||||
return Astro.redirect(twitterLink);
|
||||
---
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
const youtubeLink = 'https://youtube.com/@roadmapsh';
|
||||
|
||||
return Astro.redirect(youtubeLink);
|
||||
---
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user