Skip to content

Commit 032f825

Browse files
Merge pull request #57 from kamranahmedse/master
Create a new pull request by comparing changes across two branches
2 parents 5577aae + 927aa0a commit 032f825

File tree

91 files changed

+987
-607
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+987
-607
lines changed

astro.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { serializeSitemap, shouldIndexPage } from './sitemap.mjs';
99
export default defineConfig({
1010
site: 'https://roadmap.sh',
1111
markdown: {
12+
shikiConfig: {
13+
theme: 'dracula'
14+
},
1215
rehypePlugins: [
1316
[
1417
rehypeExternalLinks,

public/images/ambassador-img.png

101 KB
Loading

src/components/FAQs/FAQs.astro

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
1+
---
2+
import Answer from './Answer.astro';
3+
import Question from './Question.astro';
4+
5+
export type FAQType = {
6+
question: string;
7+
answer: string[];
8+
};
9+
10+
export interface Props {
11+
faqs: FAQType[];
12+
}
13+
14+
const { faqs } = Astro.props;
15+
16+
if (faqs.length === 0) {
17+
return '';
18+
}
19+
---
20+
121
<div class='border-t bg-gray-100'>
222
<div class='container'>
323
<div class='flex justify-between relative -top-5'>
4-
<h1 class='text-sm sm:text-base font-medium py-1 px-3 border bg-white rounded-md'>
5-
Frequently Asked Questions
6-
</h1>
24+
<h1 class='text-sm sm:text-base font-medium py-1 px-3 border bg-white rounded-md'>Frequently Asked Questions</h1>
725
</div>
826

927
<div class='flex flex-col gap-1 pb-8'>
10-
<slot />
28+
{
29+
faqs.map((faq, questionIndex) => (
30+
<Question isActive={questionIndex === 0} question={faq.question}>
31+
<Answer>
32+
{faq.answer.map((answer, index) => (
33+
<p class:list={{ 'mb-3': index !== faq.answer.length - 1 }}>{answer}</p>
34+
))}
35+
</Answer>
36+
</Question>
37+
))
38+
}
1139
</div>
1240
</div>
1341
</div>

src/components/Footer.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import Icon from './Icon.astro';
4343
<span class='text-gray-400 mx-2'>by</span>
4444
<a
4545
class='bg-blue-600 text-sm py-1 px-1.5 font-regular hover:bg-blue-700 rounded-md'
46-
href='https://twitter.com/kamranahmedse'
46+
href='https://twitter.com/intent/user?screen_name=kamranahmedse'
4747
target='_blank'
4848
>
4949
<span class='hidden sm:inline'>@kamranahmedse</span>

src/components/MarkdownRoadmap.astro

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
---
2-
import '../styles/prism.css';
32
import DownloadPopup from './DownloadPopup.astro';
4-
import ShareIcons from './ShareIcons.astro';
53
import SubscribePopup from './SubscribePopup.astro';
64
75
export interface Props {
@@ -12,7 +10,7 @@ export interface Props {
1210
const { roadmapId, description } = Astro.props;
1311
---
1412

15-
<div class='bg-gray-50 py-4 sm:py-10'>
13+
<div class='bg-gray-50 py-2'>
1614
<div
1715
class='container prose prose-headings:mt-4 prose-headings:mb-2 prose-p:mb-0.5 relative prose-code:text-white'
1816
>

src/layouts/BaseLayout.astro

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface Props {
1616
noIndex?: boolean;
1717
permalink?: string;
1818
sponsor?: SponsorType;
19+
jsonLd?: Record<string, unknown>[];
1920
}
2021
2122
const {
@@ -25,17 +26,13 @@ const {
2526
noIndex = false,
2627
permalink = '',
2728
sponsor,
29+
jsonLd = [],
2830
} = Astro.props;
2931
3032
// Remove trailing slashes to consider the page as canonical
31-
const currentPageAbsoluteUrl = `https://roadmap.sh${permalink.replace(
32-
/\/$/,
33-
''
34-
)}`;
33+
const currentPageAbsoluteUrl = `https://roadmap.sh${permalink}`;
3534
36-
const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
37-
import.meta.env.GITHUB_SHA
38-
}`;
35+
const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${import.meta.env.GITHUB_SHA}`;
3936
---
4037

4138
<!DOCTYPE html>
@@ -72,43 +69,23 @@ const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
7269

7370
<meta name='mobile-web-app-capable' content='yes' />
7471
<meta name='apple-mobile-web-app-capable' content='yes' />
75-
<meta
76-
name='apple-mobile-web-app-status-bar-style'
77-
content='black-translucent'
78-
/>
72+
<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />
7973
<meta name='apple-mobile-web-app-title' content='roadmap.sh' />
8074
<meta name='application-name' content='roadmap.sh' />
8175

82-
<link
83-
rel='apple-touch-icon'
84-
sizes='180x180'
85-
href='/manifest/apple-touch-icon.png'
86-
/>
76+
<link rel='apple-touch-icon' sizes='180x180' href='/manifest/apple-touch-icon.png' />
8777
<meta name='msapplication-TileColor' content='#101010' />
8878
<meta name='theme-color' content='#848a9a' />
8979

9080
<link rel='manifest' href='/manifest/manifest.json' />
91-
<link
92-
rel='icon'
93-
type='image/png'
94-
sizes='32x32'
95-
href='/manifest/icon32.png'
96-
/>
97-
<link
98-
rel='icon'
99-
type='image/png'
100-
sizes='16x16'
101-
href='/manifest/icon16.png'
102-
/>
103-
<link
104-
rel='shortcut icon'
105-
href='/manifest/favicon.ico'
106-
type='image/x-icon'
107-
/>
81+
<link rel='icon' type='image/png' sizes='32x32' href='/manifest/icon32.png' />
82+
<link rel='icon' type='image/png' sizes='16x16' href='/manifest/icon16.png' />
83+
<link rel='shortcut icon' href='/manifest/favicon.ico' type='image/x-icon' />
10884

10985
<link rel='icon' href='/manifest/favicon.ico' type='image/x-icon' />
11086

11187
<slot name='after-header' />
88+
{jsonLd.length > 0 && <script type='application/ld+json' set:html={JSON.stringify(jsonLd)} />}
11289
</head>
11390
<body>
11491
<YouTubeBanner />

src/lib/jsonld-schema.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { FAQType } from '../components/FAQs/FAQs.astro';
2+
3+
type ArticleSchemaProps = {
4+
url: string;
5+
headline: string;
6+
description: string;
7+
imageUrl: string;
8+
datePublished: string;
9+
dateModified: string;
10+
};
11+
12+
export function generateArticleSchema(article: ArticleSchemaProps) {
13+
const { url, headline, description, imageUrl, datePublished, dateModified } = article;
14+
15+
return {
16+
'@context': 'https://schema.org',
17+
'@type': 'BlogPosting',
18+
mainEntityOfPage: {
19+
'@type': 'WebPage',
20+
'@id': url,
21+
},
22+
headline: headline,
23+
description: description,
24+
image: imageUrl,
25+
author: {
26+
'@type': 'Person',
27+
name: 'Kamran Ahmed',
28+
url: 'https://twitter.com/kamranahmedse',
29+
},
30+
publisher: {
31+
'@type': 'Organization',
32+
name: 'roadmap.sh',
33+
logo: {
34+
'@type': 'ImageObject',
35+
url: 'https://roadmap.sh/images/brand-square.png',
36+
},
37+
},
38+
datePublished: datePublished,
39+
dateModified: dateModified,
40+
};
41+
}
42+
43+
export function generateFAQSchema(faqs: FAQType[]) {
44+
return {
45+
'@context': 'https://schema.org',
46+
'@type': 'FAQPage',
47+
mainEntity: faqs.map((faq) => ({
48+
'@type': 'Question',
49+
name: faq.question,
50+
acceptedAnswer: {
51+
'@type': 'Answer',
52+
text: faq.answer.join(' '),
53+
},
54+
})),
55+
};
56+
}

src/lib/roadmap.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export interface RoadmapFrontmatter {
2222
description: string;
2323
keywords: string[];
2424
};
25+
schema?: {
26+
headline: string;
27+
description: string;
28+
datePublished: string;
29+
dateModified: string;
30+
imageUrl: string;
31+
};
2532
relatedRoadmaps: string[];
2633
sitemap: {
2734
priority: number;
@@ -46,12 +53,9 @@ function roadmapPathToId(filePath: string): string {
4653
* @returns string[] Array of roadmap IDs
4754
*/
4855
export async function getRoadmapIds() {
49-
const roadmapFiles = await import.meta.glob<RoadmapFileType>(
50-
'/src/roadmaps/*/*.md',
51-
{
52-
eager: true,
53-
}
54-
);
56+
const roadmapFiles = await import.meta.glob<RoadmapFileType>('/src/roadmaps/*/*.md', {
57+
eager: true,
58+
});
5559

5660
return Object.keys(roadmapFiles).map(roadmapPathToId);
5761
}
@@ -62,15 +66,10 @@ export async function getRoadmapIds() {
6266
* @param tag Tag assigned to roadmap
6367
* @returns Promisified RoadmapFileType[]
6468
*/
65-
export async function getRoadmapsByTag(
66-
tag: string
67-
): Promise<RoadmapFileType[]> {
68-
const roadmapFilesMap = await import.meta.glob<RoadmapFileType>(
69-
'/src/roadmaps/*/*.md',
70-
{
71-
eager: true,
72-
}
73-
);
69+
export async function getRoadmapsByTag(tag: string): Promise<RoadmapFileType[]> {
70+
const roadmapFilesMap = await import.meta.glob<RoadmapFileType>('/src/roadmaps/*/*.md', {
71+
eager: true,
72+
});
7473

7574
const roadmapFiles = Object.values(roadmapFilesMap);
7675
const filteredRoadmaps = roadmapFiles
@@ -80,7 +79,5 @@ export async function getRoadmapsByTag(
8079
id: roadmapPathToId(roadmapFile.file),
8180
}));
8281

83-
return filteredRoadmaps.sort(
84-
(a, b) => a.frontmatter.order - b.frontmatter.order
85-
);
82+
return filteredRoadmaps.sort((a, b) => a.frontmatter.order - b.frontmatter.order);
8683
}

src/pages/[...topicId].astro

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import Breadcrumbs from '../components/Breadcrumbs.astro';
33
import RoadmapBanner from '../components/RoadmapBanner.astro';
44
import BaseLayout from '../layouts/BaseLayout.astro';
55
import { getTopicFiles, TopicFileType } from '../lib/topic';
6-
import '../styles/prism.css';
76
87
export async function getStaticPaths() {
98
const topicPathMapping = await getTopicFiles();
@@ -15,8 +14,7 @@ export async function getStaticPaths() {
1514
}
1615
1716
const { topicId } = Astro.params;
18-
const { file, breadcrumbs, roadmapId, roadmap, heading } =
19-
Astro.props as TopicFileType;
17+
const { file, breadcrumbs, roadmapId, roadmap, heading } = Astro.props as TopicFileType;
2018
---
2119

2220
<BaseLayout
@@ -29,9 +27,7 @@ const { file, breadcrumbs, roadmapId, roadmap, heading } =
2927
<div class='bg-gray-50'>
3028
<Breadcrumbs breadcrumbs={breadcrumbs} roadmapId={roadmapId} />
3129

32-
<div
33-
class='container pb-16 prose prose-p:mt-0 prose-h1:mb-4 prose-h2:mb-3 prose-h2:mt-0'
34-
>
30+
<div class='container pb-16 prose prose-p:mt-0 prose-h1:mb-4 prose-h2:mb-3 prose-h2:mt-0'>
3531
<main id='main-content'>
3632
<file.Content />
3733
</main>

src/pages/[roadmapId]/index.astro

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
---
22
import CaptchaScripts from '../../components/Captcha/CaptchaScripts.astro';
3-
import FAQs from '../../components/FAQs.astro';
3+
import FAQs from '../../components/FAQs/FAQs.astro';
44
import InteractiveRoadmap from '../../components/InteractiveRoadmap/InteractiveRoadmap.astro';
55
import MarkdownRoadmap from '../../components/MarkdownRoadmap.astro';
66
import RoadmapHeader from '../../components/RoadmapHeader.astro';
77
import UpcomingRoadmap from '../../components/UpcomingRoadmap.astro';
88
import BaseLayout from '../../layouts/BaseLayout.astro';
9+
import { generateArticleSchema, generateFAQSchema } from '../../lib/jsonld-schema';
910
import { getRoadmapIds, RoadmapFrontmatter } from '../../lib/roadmap';
1011
1112
export async function getStaticPaths() {
@@ -22,8 +23,28 @@ interface Params extends Record<string, string | undefined> {
2223
2324
const { roadmapId } = Astro.params as Params;
2425
const roadmapFile = await import(`../../roadmaps/${roadmapId}/${roadmapId}.md`);
25-
const questions = await import (`../../roadmaps/${roadmapId}/faqs.astro`);
26+
const { faqs: roadmapFAQs = [] } = await import(`../../roadmaps/${roadmapId}/faqs.astro`);
2627
const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
28+
29+
let jsonLdSchema = [];
30+
31+
if (roadmapData.schema) {
32+
const roadmapSchema = roadmapData.schema;
33+
jsonLdSchema.push(
34+
generateArticleSchema({
35+
url: `https://roadmap.sh/${roadmapId}`,
36+
headline: roadmapSchema.headline,
37+
description: roadmapSchema.description,
38+
datePublished: roadmapSchema.datePublished,
39+
dateModified: roadmapSchema.dateModified,
40+
imageUrl: roadmapSchema.imageUrl,
41+
})
42+
);
43+
}
44+
45+
if (roadmapFAQs.length) {
46+
jsonLdSchema.push(generateFAQSchema(roadmapFAQs));
47+
}
2748
---
2849

2950
<BaseLayout
@@ -33,6 +54,7 @@ const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
3354
keywords={roadmapData.seo.keywords}
3455
sponsor={roadmapData.sponsor}
3556
noIndex={roadmapData.isUpcoming}
57+
jsonLd={jsonLdSchema}
3658
>
3759
<RoadmapHeader
3860
description={roadmapData.description}
@@ -55,17 +77,15 @@ const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
5577

5678
{
5779
!roadmapData.isUpcoming && !roadmapData.jsonUrl && (
58-
<MarkdownRoadmap
59-
roadmapId={roadmapId}
60-
description={roadmapData.description}
61-
>
80+
<MarkdownRoadmap roadmapId={roadmapId} description={roadmapData.description}>
6281
<roadmapFile.Content />
6382
</MarkdownRoadmap>
6483
)
6584
}
6685

6786
{roadmapData.isUpcoming && <UpcomingRoadmap />}
6887

69-
<questions.default />
88+
<FAQs faqs={roadmapFAQs} />
89+
7090
<CaptchaScripts slot='after-footer' />
7191
</BaseLayout>

0 commit comments

Comments
 (0)