mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-02 13:52:46 +02:00
feat: roadmap courses
This commit is contained in:
committed by
Kamran Ahmed
parent
c4c28944ee
commit
f9f38101f9
@@ -9,6 +9,9 @@ type FAQsProps = {
|
||||
|
||||
export function FAQs(props: FAQsProps) {
|
||||
const { faqs } = props;
|
||||
if (faqs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [activeQuestionIndex, setActiveQuestionIndex] = useState(0);
|
||||
|
||||
@@ -22,18 +25,35 @@ export function FAQs(props: FAQsProps) {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 pb-14">
|
||||
{faqs.map((faq, questionIndex) => (
|
||||
<Question
|
||||
key={faq._id}
|
||||
isActive={questionIndex === activeQuestionIndex}
|
||||
question={faq.title}
|
||||
onClick={() => setActiveQuestionIndex(questionIndex)}
|
||||
>
|
||||
<div className="text-md rounded-br-md rounded-bl-md border-t border-t-gray-300 bg-gray-100 p-2 text-left text-sm leading-relaxed text-gray-800 sm:p-4 sm:text-base [&>p:not(:last-child)]:mb-3 [&>p>a]:text-blue-700 [&>p>a]:underline">
|
||||
{guideRenderer.render(faq.description)}
|
||||
</div>
|
||||
</Question>
|
||||
))}
|
||||
{faqs.map((faq, questionIndex) => {
|
||||
const isTextDescription =
|
||||
typeof faq?.description === 'string' &&
|
||||
faq?.description?.length > 0;
|
||||
|
||||
return (
|
||||
<Question
|
||||
key={faq._id}
|
||||
isActive={questionIndex === activeQuestionIndex}
|
||||
question={faq.title}
|
||||
onClick={() => setActiveQuestionIndex(questionIndex)}
|
||||
>
|
||||
<div
|
||||
className="text-md rounded-br-md rounded-bl-md border-t border-t-gray-300 bg-gray-100 p-2 text-left text-sm leading-relaxed text-gray-800 sm:p-4 sm:text-base [&>p:not(:last-child)]:mb-3 [&>p>a]:text-blue-700 [&>p>a]:underline"
|
||||
{...(isTextDescription
|
||||
? {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: faq.description,
|
||||
},
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{!isTextDescription
|
||||
? guideRenderer.render(faq.description)
|
||||
: null}
|
||||
</div>
|
||||
</Question>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,19 +1,20 @@
|
||||
<!-- ---
|
||||
---
|
||||
import RoadmapHeader from '../../components/RoadmapHeader.astro';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { getOpenGraphImageUrl } from '../../lib/open-graph';
|
||||
import { type RoadmapFrontmatter, getRoadmapIds } from '../../lib/roadmap';
|
||||
import CourseStep from '../../components/courses/CourseStep.astro';
|
||||
import Milestone from '../../components/courses/Milestone.astro';
|
||||
import { getProjectsByRoadmapId } from '../../lib/project';
|
||||
import {
|
||||
listOfficialRoadmaps,
|
||||
officialRoadmapDetails,
|
||||
} from '../../queries/official-roadmap';
|
||||
|
||||
export const prerender = true;
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const roadmapIds = await getRoadmapIds();
|
||||
const roadmaps = await listOfficialRoadmaps();
|
||||
|
||||
return roadmapIds.map((roadmapId) => ({
|
||||
params: { roadmapId },
|
||||
return roadmaps.map((roadmap) => ({
|
||||
params: { roadmapId: roadmap.slug },
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -22,15 +23,14 @@ interface Params extends Record<string, string | undefined> {
|
||||
}
|
||||
|
||||
const { roadmapId } = Astro.params as Params;
|
||||
const roadmapFile = await import(
|
||||
`../../data/roadmaps/${roadmapId}/${roadmapId}.md`
|
||||
);
|
||||
|
||||
const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
|
||||
const roadmapData = await officialRoadmapDetails(roadmapId);
|
||||
if (!roadmapData) {
|
||||
return Astro.redirect('/404', 404);
|
||||
}
|
||||
|
||||
// update og for projects
|
||||
const ogImageUrl =
|
||||
roadmapData?.seo?.ogImageUrl ||
|
||||
roadmapData?.openGraph?.image ||
|
||||
getOpenGraphImageUrl({
|
||||
group: 'roadmap',
|
||||
resourceId: roadmapId,
|
||||
@@ -43,23 +43,26 @@ const descriptionNoun: Record<string, string> = {
|
||||
'Product Manager': 'Product Management',
|
||||
};
|
||||
|
||||
const title = `${roadmapData.briefTitle} Courses`;
|
||||
const description = `Premium courses to help you master ${descriptionNoun[roadmapData.briefTitle] || roadmapData.briefTitle}`;
|
||||
const title = `${roadmapData?.title.card} Courses`;
|
||||
const description = `Premium courses to help you master ${descriptionNoun[roadmapData?.title.card] || roadmapData?.title.card}`;
|
||||
|
||||
const seoTitle = `${roadmapData.briefTitle} Courses`;
|
||||
const seoTitle = `${roadmapData?.title.card} Courses`;
|
||||
const nounTitle =
|
||||
descriptionNoun[roadmapData.briefTitle] || roadmapData.briefTitle;
|
||||
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 getProjectsByRoadmapId(roadmapId);
|
||||
const courses = roadmapData.courses || [];
|
||||
const question = roadmapData?.questions?.find(
|
||||
(question) => question.type === 'main',
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
permalink={`/${roadmapId}`}
|
||||
title={seoTitle}
|
||||
description={seoDescription}
|
||||
briefTitle={roadmapData.briefTitle}
|
||||
briefTitle={roadmapData.title.card}
|
||||
ogImageUrl={ogImageUrl}
|
||||
keywords={roadmapData.seo.keywords}
|
||||
resourceId={roadmapId}
|
||||
@@ -72,10 +75,7 @@ const courses = roadmapData.courses || [];
|
||||
description={description}
|
||||
partner={roadmapData.partner}
|
||||
roadmapId={roadmapId}
|
||||
hasTopics={roadmapData.hasTopics}
|
||||
isUpcoming={roadmapData.isUpcoming}
|
||||
isForkable={roadmapData.isForkable}
|
||||
question={roadmapData.question}
|
||||
isForkable={true}
|
||||
coursesCount={courses.length}
|
||||
projectCount={projects.length}
|
||||
activeTab='courses'
|
||||
@@ -163,4 +163,4 @@ const courses = roadmapData.courses || [];
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BaseLayout> -->
|
||||
</BaseLayout>
|
||||
|
@@ -83,7 +83,7 @@ if (faqs.length) {
|
||||
}
|
||||
|
||||
const projects = await getProjectsByRoadmapId(roadmapId);
|
||||
// const courses = roadmapData.courses || [];
|
||||
const courses = roadmapData.courses || [];
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -123,7 +123,7 @@ const projects = await getProjectsByRoadmapId(roadmapId);
|
||||
roadmapId={roadmapId}
|
||||
isForkable={true}
|
||||
projectCount={projects.length}
|
||||
coursesCount={0}
|
||||
coursesCount={courses.length}
|
||||
hasAIChat={true}
|
||||
/>
|
||||
|
||||
|
@@ -19,8 +19,21 @@ export type OfficialRoadmapQuestion = {
|
||||
description: any;
|
||||
};
|
||||
|
||||
export interface OfficialRoadmapDocument {
|
||||
export type OfficialRoadmapCourse = {
|
||||
_id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
instructor: {
|
||||
name: string;
|
||||
image: string;
|
||||
title: string;
|
||||
};
|
||||
features: string[];
|
||||
};
|
||||
|
||||
export interface OfficialRoadmapDocument {
|
||||
_id?: string;
|
||||
order: number;
|
||||
|
||||
title: {
|
||||
@@ -30,12 +43,12 @@ export interface OfficialRoadmapDocument {
|
||||
description: string;
|
||||
|
||||
slug: string;
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
nodes: any[];
|
||||
edges: any[];
|
||||
|
||||
draft: {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
nodes: any[];
|
||||
edges: any[];
|
||||
};
|
||||
|
||||
seo: {
|
||||
@@ -59,6 +72,7 @@ export interface OfficialRoadmapDocument {
|
||||
|
||||
questions?: OfficialRoadmapQuestion[];
|
||||
relatedRoadmaps?: string[];
|
||||
courses?: OfficialRoadmapCourse[];
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
Reference in New Issue
Block a user