mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-01 06:50:26 +02:00
Add related questions below roadmaps
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
---
|
||||
import { getQuestionGroupsByIds } from '../lib/question-group';
|
||||
import { getRoadmapsByIds, RoadmapFrontmatter } from '../lib/roadmap';
|
||||
import { Map, Clipboard } from 'lucide-react';
|
||||
|
||||
export interface Props {
|
||||
roadmap: RoadmapFrontmatter;
|
||||
@@ -8,35 +10,87 @@ export interface Props {
|
||||
const { roadmap } = Astro.props;
|
||||
|
||||
const relatedRoadmaps = roadmap.relatedRoadmaps || [];
|
||||
if (!relatedRoadmaps.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const relatedRoadmapDetails = await getRoadmapsByIds(relatedRoadmaps);
|
||||
|
||||
const relatedQuestions = roadmap.relatedQuestions || [];
|
||||
const relatedQuestionDetails = await getQuestionGroupsByIds(relatedQuestions);
|
||||
---
|
||||
|
||||
<div class='border-t bg-gray-100'>
|
||||
<div class='container'>
|
||||
<div class='flex justify-between relative -top-5'>
|
||||
<span class='text-md font-medium py-1 px-3 border bg-white rounded-md'>Related Roadmaps</span>
|
||||
<a href='/roadmaps' class='text-md font-medium py-1 px-3 border bg-white rounded-md hover:bg-gray-50'>
|
||||
<span class='hidden sm:inline'>All Roadmaps →</span>
|
||||
<span class='inline sm:hidden'>More →</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class='flex flex-col gap-1 pb-8'>
|
||||
{
|
||||
relatedRoadmapDetails.map((relatedRoadmap) => (
|
||||
{
|
||||
relatedQuestionDetails.length > 0 && (
|
||||
<div class='border-t bg-gray-100 pb-3'>
|
||||
<div class='container'>
|
||||
<div class='relative -top-5 flex justify-between'>
|
||||
<span class='text-md flex items-center rounded-md border bg-white px-3 py-1 font-medium'>
|
||||
<Clipboard className='mr-1.5 text-black' size='17px' />
|
||||
Test your Knowledge
|
||||
<span class='ml-2 rounded-md border border-yellow-300 bg-yellow-100 px-1 py-0.5 text-xs uppercase'>
|
||||
New
|
||||
</span>
|
||||
</span>
|
||||
<a
|
||||
href={`/${relatedRoadmap.id}`}
|
||||
class='py-2 px-3.5 bg-white border rounded-md hover:bg-gray-50 flex flex-col sm:flex-row gap-0.5 sm:gap-0'
|
||||
href='/roadmaps'
|
||||
class='text-md rounded-md border bg-white px-3 py-1 font-medium hover:bg-gray-50'
|
||||
>
|
||||
<span class='font-medium inline-block min-w-[150px]'>{relatedRoadmap.frontmatter.briefTitle}</span>
|
||||
<span class='text-gray-500'>{relatedRoadmap.frontmatter.briefDescription}</span>
|
||||
<span class='hidden sm:inline'>All Quizzes →</span>
|
||||
<span class='inline sm:hidden'>More →</span>
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class='flex flex-col gap-1 pb-8'>
|
||||
{relatedQuestionDetails.map((relatedQuestionGroup) => (
|
||||
<a
|
||||
href={`/questions/${relatedQuestionGroup.id}`}
|
||||
class='flex flex-col gap-0.5 rounded-md border bg-white px-3.5 py-2 hover:bg-gray-50 sm:flex-row sm:gap-0'
|
||||
>
|
||||
<span class='inline-block min-w-[150px] font-medium'>
|
||||
{relatedQuestionGroup.title}
|
||||
</span>
|
||||
<span class='text-gray-500'>
|
||||
{relatedQuestionGroup.description}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
relatedRoadmaps.length && (
|
||||
<div class='border-t bg-gray-100'>
|
||||
<div class='container'>
|
||||
<div class='relative -top-5 flex justify-between'>
|
||||
<span class='text-md flex items-center rounded-md border bg-white px-3 py-1 font-medium'>
|
||||
<Map className='text-black mr-1.5' size='17px' />
|
||||
Related Roadmaps
|
||||
</span>
|
||||
<a
|
||||
href='/roadmaps'
|
||||
class='text-md rounded-md border bg-white px-3 py-1 font-medium hover:bg-gray-50'
|
||||
>
|
||||
<span class='hidden sm:inline'>All Roadmaps →</span>
|
||||
<span class='inline sm:hidden'>More →</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class='flex flex-col gap-1 pb-8'>
|
||||
{relatedRoadmapDetails.map((relatedRoadmap) => (
|
||||
<a
|
||||
href={`/${relatedRoadmap.id}`}
|
||||
class='flex flex-col gap-0.5 rounded-md border bg-white px-3.5 py-2 hover:bg-gray-50 sm:flex-row sm:gap-0'
|
||||
>
|
||||
<span class='inline-block min-w-[150px] font-medium'>
|
||||
{relatedRoadmap.frontmatter.briefTitle}
|
||||
</span>
|
||||
<span class='text-gray-500'>
|
||||
{relatedRoadmap.frontmatter.briefDescription}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@@ -37,6 +37,8 @@ relatedRoadmaps:
|
||||
- 'react'
|
||||
- 'vue'
|
||||
- 'nodejs'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -63,6 +63,8 @@ relatedRoadmaps:
|
||||
- 'javascript'
|
||||
- 'nodejs'
|
||||
- 'postgresql-dba'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -61,6 +61,9 @@ relatedRoadmaps:
|
||||
- 'angular'
|
||||
- 'vue'
|
||||
- 'design-system'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
- 'react'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -45,6 +45,9 @@ relatedRoadmaps:
|
||||
- 'react'
|
||||
- 'angular'
|
||||
- 'vue'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
- 'react'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -75,6 +75,8 @@ relatedRoadmaps:
|
||||
- 'system-design'
|
||||
- 'graphql'
|
||||
- 'frontend'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -40,6 +40,9 @@ relatedRoadmaps:
|
||||
- 'vue'
|
||||
- 'nodejs'
|
||||
- 'design-system'
|
||||
relatedQuestions:
|
||||
- 'react'
|
||||
- 'javascript'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -49,6 +49,8 @@ relatedRoadmaps:
|
||||
- 'react'
|
||||
- 'angular'
|
||||
- 'nodejs'
|
||||
relatedQuestions:
|
||||
- 'javascript'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
|
@@ -54,7 +54,7 @@ export async function getAllQuestionGroups(): Promise<QuestionGroupType[]> {
|
||||
`/src/data/question-groups/*/*.md`,
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const answerFilesMap = await import.meta.glob<string>(
|
||||
@@ -63,7 +63,7 @@ export async function getAllQuestionGroups(): Promise<QuestionGroupType[]> {
|
||||
{
|
||||
eager: true,
|
||||
as: 'raw',
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return Object.values(questionGroupFilesMap)
|
||||
@@ -116,3 +116,32 @@ export async function getAllQuestionGroups(): Promise<QuestionGroupType[]> {
|
||||
})
|
||||
.sort((a, b) => a.frontmatter.order - b.frontmatter.order);
|
||||
}
|
||||
|
||||
export async function getQuestionGroupsByIds(
|
||||
ids: string[],
|
||||
): Promise<{ id: string; title: string; description: string }[]> {
|
||||
if (!ids?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const questionGroupFilesMap = import.meta.glob<
|
||||
MarkdownFileType<RawQuestionGroupFrontmatter>
|
||||
>(`/src/data/question-groups/*/*.md`, {
|
||||
eager: true,
|
||||
});
|
||||
|
||||
return Object.values(questionGroupFilesMap)
|
||||
.map((group) => {
|
||||
const fileId = group?.file?.split('/')?.pop()?.replace('.md', '');
|
||||
const frontmatter = group.frontmatter;
|
||||
|
||||
return {
|
||||
id: fileId!,
|
||||
title: frontmatter.briefTitle,
|
||||
description: `${frontmatter.questions.length} Questions`,
|
||||
};
|
||||
})
|
||||
.filter((group) => {
|
||||
return ids.includes(group.id);
|
||||
});
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ export interface RoadmapFrontmatter {
|
||||
imageUrl: string;
|
||||
};
|
||||
relatedRoadmaps: string[];
|
||||
relatedQuestions: string[];
|
||||
sitemap: {
|
||||
priority: number;
|
||||
changefreq: string;
|
||||
@@ -61,7 +62,7 @@ export async function getRoadmapIds() {
|
||||
'/src/data/roadmaps/*/*.md',
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return Object.keys(roadmapFiles).map(roadmapPathToId);
|
||||
@@ -74,13 +75,13 @@ export async function getRoadmapIds() {
|
||||
* @returns Promisified RoadmapFileType[]
|
||||
*/
|
||||
export async function getRoadmapsByTag(
|
||||
tag: string
|
||||
tag: string,
|
||||
): Promise<RoadmapFileType[]> {
|
||||
const roadmapFilesMap = await import.meta.glob<RoadmapFileType>(
|
||||
'/src/data/roadmaps/*/*.md',
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const roadmapFiles = Object.values(roadmapFilesMap);
|
||||
@@ -92,7 +93,7 @@ export async function getRoadmapsByTag(
|
||||
}));
|
||||
|
||||
return filteredRoadmaps.sort(
|
||||
(a, b) => a.frontmatter.order - b.frontmatter.order
|
||||
(a, b) => a.frontmatter.order - b.frontmatter.order,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ export async function getRoadmapById(id: string): Promise<RoadmapFileType> {
|
||||
'/src/data/roadmaps/*/*.md',
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const roadmapFile = Object.values(roadmapFilesMap).find((roadmapFile) => {
|
||||
@@ -119,7 +120,11 @@ export async function getRoadmapById(id: string): Promise<RoadmapFileType> {
|
||||
}
|
||||
|
||||
export async function getRoadmapsByIds(
|
||||
ids: string[]
|
||||
ids: string[],
|
||||
): Promise<RoadmapFileType[]> {
|
||||
if (!ids?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Promise.all(ids.map((id) => getRoadmapById(id)));
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ if (roadmapData.schema) {
|
||||
datePublished: roadmapSchema.datePublished,
|
||||
dateModified: roadmapSchema.dateModified,
|
||||
imageUrl: roadmapSchema.imageUrl,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ if (roadmapFAQs.length) {
|
||||
/>
|
||||
|
||||
<FAQs faqs={roadmapFAQs} />
|
||||
|
||||
<RelatedRoadmaps roadmap={roadmapData} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
Reference in New Issue
Block a user