From 214799b0c2d312ed442477c306bac74dc8fd8288 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Thu, 21 Aug 2025 09:25:42 +0600 Subject: [PATCH] chore: replace topic content --- src/pages/[roadmapId]/[...topicId].astro | 39 +++++-------- src/queries/official-roadmap-topic.ts | 70 ++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 src/queries/official-roadmap-topic.ts diff --git a/src/pages/[roadmapId]/[...topicId].astro b/src/pages/[roadmapId]/[...topicId].astro index 488df4c2f..c3c23bf33 100644 --- a/src/pages/[roadmapId]/[...topicId].astro +++ b/src/pages/[roadmapId]/[...topicId].astro @@ -1,7 +1,6 @@ --- import fs from 'node:fs'; import path from 'node:path'; -import matter from 'gray-matter'; import MarkdownIt from 'markdown-it-async'; import { fileURLToPath } from 'node:url'; import { @@ -11,6 +10,10 @@ import { 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; @@ -52,41 +55,27 @@ if (isTopic) { `${topicPath}.md`, ); + const topic = await getOfficialRoadmapTopic({ + roadmapSlug: roadmapId, + nodeId: topicPath, + }); + // Check if file exists - if (!fs.existsSync(contentPath)) { - const indexFilePath = path.join( - projectRoot, - 'src', - 'data', - 'roadmaps', - roadmapId, - 'content', - `${topicPath}/index.md`, - ); + if (!fs.existsSync(contentPath) || !topic) { + Astro.response.status = 404; + Astro.response.statusText = 'Not found'; - if (!fs.existsSync(indexFilePath)) { - Astro.response.status = 404; - Astro.response.statusText = 'Not found'; - - return Astro.rewrite('/404'); - } - - contentPath = indexFilePath; + return Astro.rewrite('/404'); } - // Read and parse the markdown file - const fileContent = fs.readFileSync(contentPath, 'utf-8'); - const { content } = matter(fileContent); - const fileWithoutBasePath = contentPath.replace( /.+?\/src\/data/, '/src/data', ); const md = MarkdownIt(); - + htmlContent = await md.renderAsync(prepareOfficialRoadmapTopicContent(topic)); gitHubUrl = `https://github.com/kamranahmedse/developer-roadmap/tree/master${fileWithoutBasePath}`; - htmlContent = await md.renderAsync(content); } else { guide = await getOfficialGuide(topicId, roadmapId); if (!guide) { diff --git a/src/queries/official-roadmap-topic.ts b/src/queries/official-roadmap-topic.ts new file mode 100644 index 000000000..4155829d3 --- /dev/null +++ b/src/queries/official-roadmap-topic.ts @@ -0,0 +1,70 @@ +import { FetchError, httpGet } from '../lib/query-http'; + +export const allowedOfficialRoadmapTopicResourceType = [ + 'roadmap', + 'official', + 'opensource', + 'article', + 'course', + 'podcast', + 'video', + 'book', + 'feed', +] as const; +export type AllowedOfficialRoadmapTopicResourceType = + (typeof allowedOfficialRoadmapTopicResourceType)[number]; + +type OfficialRoadmapTopicResource = { + _id: string; + type: AllowedOfficialRoadmapTopicResourceType; + title: string; + url: string; +}; + +export interface OfficialRoadmapTopicContentDocument { + _id: string; + roadmapSlug: string; + nodeId: string; + description: string; + resources: OfficialRoadmapTopicResource[]; + createdAt: Date; + updatedAt: Date; +} + +type GetOfficialRoadmapTopicOptions = { + roadmapSlug: string; + nodeId: string; +}; + +export async function getOfficialRoadmapTopic( + options: GetOfficialRoadmapTopicOptions, +) { + const { roadmapSlug, nodeId } = options; + + try { + const topic = await httpGet( + `/v1-official-roadmap-topic/${roadmapSlug}/${nodeId}`, + ); + + return topic; + } catch (error) { + if (FetchError.isFetchError(error) && error.status === 404) { + return null; + } + + throw error; + } +} + +export function prepareOfficialRoadmapTopicContent( + topic: OfficialRoadmapTopicContentDocument, +) { + const { description, resources = [] } = topic; + + let content = description; + if (resources.length > 0) { + content += `\n\nVisit the following resources to learn more:\n\n${resources.map((resource) => `- [@${resource.type}@${resource.title}](${resource.url})`).join('\n')}`; + } + + return content; +}