From 825ea021a4081b620857d78c64d2a0079c0400b6 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Mon, 18 Aug 2025 19:53:56 +0600 Subject: [PATCH] feat: featured guide list --- .../FeaturedGuides/FeaturedGuideList.tsx | 20 +-- .../FeaturedGuides/GuideListItem.tsx | 52 +++--- src/pages/authors/[authorId].astro | 153 ------------------ src/pages/authors/[authorId].json.ts | 30 ---- src/pages/guides/index.astro | 40 ----- src/pages/index.astro | 20 +-- src/queries/official-guide.ts | 10 ++ 7 files changed, 45 insertions(+), 280 deletions(-) delete mode 100644 src/pages/authors/[authorId].astro delete mode 100644 src/pages/authors/[authorId].json.ts delete mode 100644 src/pages/guides/index.astro diff --git a/src/components/FeaturedGuides/FeaturedGuideList.tsx b/src/components/FeaturedGuides/FeaturedGuideList.tsx index 7c531a09c..c6b9ad62c 100644 --- a/src/components/FeaturedGuides/FeaturedGuideList.tsx +++ b/src/components/FeaturedGuides/FeaturedGuideList.tsx @@ -1,22 +1,18 @@ -import type { GuideFileType } from '../../lib/guide'; -import type { QuestionGroupType } from '../../lib/question-group'; +import type { OfficialGuideDocument } from '../../queries/official-guide'; import { GuideListItem } from './GuideListItem'; export interface FeaturedGuidesProps { heading: string; - guides: GuideFileType[]; - questions: QuestionGroupType[]; + guides: OfficialGuideDocument[]; + questions: OfficialGuideDocument[]; } export function FeaturedGuideList(props: FeaturedGuidesProps) { const { heading, guides, questions = [] } = props; - const sortedGuides: (QuestionGroupType | GuideFileType)[] = [ - ...guides, - ...questions, - ].sort((a, b) => { - const aDate = new Date(a.frontmatter.date as string); - const bDate = new Date(b.frontmatter.date as string); + const sortedGuides = [...guides, ...questions].sort((a, b) => { + const aDate = new Date(a.publishedAt ?? new Date()); + const bDate = new Date(b.publishedAt ?? new Date()); return bDate.getTime() - aDate.getTime(); }); @@ -27,7 +23,7 @@ export function FeaturedGuideList(props: FeaturedGuidesProps) {
{sortedGuides.map((guide) => ( - + ))}
@@ -48,4 +44,4 @@ export function FeaturedGuideList(props: FeaturedGuidesProps) { ); -} \ No newline at end of file +} diff --git a/src/components/FeaturedGuides/GuideListItem.tsx b/src/components/FeaturedGuides/GuideListItem.tsx index f33cb3535..9005b5c2e 100644 --- a/src/components/FeaturedGuides/GuideListItem.tsx +++ b/src/components/FeaturedGuides/GuideListItem.tsx @@ -1,52 +1,46 @@ -import type { GuideFileType, GuideFrontmatter } from '../../lib/guide'; -import { type QuestionGroupType } from '../../lib/question-group'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; +import { + getOfficialGuideHref, + type OfficialGuideDocument, +} from '../../queries/official-guide'; export interface GuideListItemProps { - guide: GuideFileType | QuestionGroupType; -} - -function isQuestionGroupType( - guide: GuideFileType | QuestionGroupType, -): guide is QuestionGroupType { - return (guide as QuestionGroupType).questions !== undefined; + guide: OfficialGuideDocument; } export function GuideListItem(props: GuideListItemProps) { const { guide } = props; - const { frontmatter, id } = guide; + const { title, slug, publishedAt, roadmapId } = guide; - let pageUrl = ''; - let guideType = ''; - - if (isQuestionGroupType(guide)) { - pageUrl = `/questions/${id}`; - guideType = 'Questions'; - } else { - const excludedBySlug = (frontmatter as GuideFrontmatter).excludedBySlug; - pageUrl = excludedBySlug ? excludedBySlug : `/guides/${id}`; - guideType = (frontmatter as GuideFrontmatter).type; + let guideType = 'Textual'; + if (roadmapId === 'questions') { + guideType = 'Question'; } - // Check if article is within the last 15 days - const isNew = frontmatter.date - ? dayjs().diff(dayjs(frontmatter.date), 'day') < 15 - : false; + const publishedAtDate = publishedAt + ? DateTime.fromJSDate(new Date(publishedAt)) + : null; + + const isNew = + publishedAtDate && DateTime.now().diff(publishedAtDate, 'days').days < 15; + const publishedAtMonth = publishedAtDate + ? publishedAtDate.toFormat('MMMM') + : ''; return ( - {frontmatter.title} + {title} {isNew && ( New  ·  - {frontmatter.date ? dayjs(frontmatter.date).format('MMMM') : ''} + {publishedAtMonth} )} diff --git a/src/pages/authors/[authorId].astro b/src/pages/authors/[authorId].astro deleted file mode 100644 index 2184e8e44..000000000 --- a/src/pages/authors/[authorId].astro +++ /dev/null @@ -1,153 +0,0 @@ ---- -import AstroIcon from '../../components/AstroIcon.astro'; -import { GuideListItem } from '../../components/FeaturedGuides/GuideListItem'; -import { VideoListItem } from '../../components/FeaturedVideos/VideoListItem'; -import BaseLayout from '../../layouts/BaseLayout.astro'; -import { getAuthorById, getAuthorIds } from '../../lib/author'; -import { getGuidesByAuthor } from '../../lib/guide'; -import { getAllQuestionGroups } from '../../lib/question-group'; -import { getVideosByAuthor } from '../../lib/video'; - -export const prerender = true; - -interface Params extends Record {} - -export async function getStaticPaths() { - const authorIds = await getAuthorIds(); - - return authorIds.map((authorId) => ({ - params: { authorId }, - })); -} - -const { authorId } = Astro.params; - -const author = await getAuthorById(authorId); -const authorFrontmatter = author.frontmatter; - -const guides = await getGuidesByAuthor(authorId); -const questionGuides = (await getAllQuestionGroups()).filter( - (group) => group.frontmatter.authorId === authorId, -); -const videos = await getVideosByAuthor(authorId); ---- - - -
-
-
-
-

- {authorFrontmatter.name} -

-
- -
- -
-
- { - authorFrontmatter.social?.github && ( - - - - ) - } - { - authorFrontmatter.social.twitter && ( - - - - ) - } - { - authorFrontmatter.social.linkedin && ( - - - - ) - } - { - authorFrontmatter.social.website && ( - - - - ) - } -
-
-
- -
-
-
- { - [...guides, ...questionGuides] - .sort((a, b) => { - const aFrontmatter = a.frontmatter as any; - const bFrontmatter = b.frontmatter as any; - - const aDate = aFrontmatter.date || aFrontmatter.publishedAt; - const bDate = bFrontmatter.date || bFrontmatter.publishedAt; - return new Date(bDate).getTime() - new Date(aDate).getTime(); - }) - .map((guide) => ) - } - {videos.map((video) => )} -
-
- diff --git a/src/pages/authors/[authorId].json.ts b/src/pages/authors/[authorId].json.ts deleted file mode 100644 index 43bf20dbf..000000000 --- a/src/pages/authors/[authorId].json.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { APIRoute } from 'astro'; -import { getAuthorById, getAuthorIds } from '../../lib/author'; - -export const prerender = true; - -export async function getStaticPaths() { - const authorIds = await getAuthorIds(); - - return await Promise.all( - authorIds.map(async (authorId) => { - const authorDetails = await getAuthorById(authorId); - - return { - params: { authorId }, - props: { - authorDetails: authorDetails?.frontmatter || {}, - }, - }; - }), - ); -} - -export const GET: APIRoute = async function ({ params, request, props }) { - return new Response(JSON.stringify(props.authorDetails), { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }); -}; diff --git a/src/pages/guides/index.astro b/src/pages/guides/index.astro deleted file mode 100644 index ac7eeb02e..000000000 --- a/src/pages/guides/index.astro +++ /dev/null @@ -1,40 +0,0 @@ ---- -import { GuideListItem } from '../../components/FeaturedGuides/GuideListItem'; -import SimplePageHeader from '../../components/SimplePageHeader.astro'; -import BaseLayout from '../../layouts/BaseLayout.astro'; -import { getAllGuides } from '../../lib/guide'; -import { getAllQuestionGroups } from '../../lib/question-group'; - -const guides = await getAllGuides(); -const questionGuides = (await getAllQuestionGroups()).filter( - (questionGroup) => questionGroup.frontmatter.authorId, -); - -const allGuides = [...guides, ...questionGuides]; -const sortedGuides = allGuides.sort((a, b) => { - const aDate = new Date(a.frontmatter.date as string); - const bDate = new Date(b.frontmatter.date as string); - - return bDate.getTime() - aDate.getTime(); -}); ---- - - - - -
-
-
- {sortedGuides.map((guide) => )} -
-
-
-
-
diff --git a/src/pages/index.astro b/src/pages/index.astro index 161aa2178..252ad59de 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -6,15 +6,13 @@ import { FeaturedVideoList } from '../components/FeaturedVideos/FeaturedVideoLis import HeroSection from '../components/HeroSection/HeroSection.astro'; import BaseLayout from '../layouts/BaseLayout.astro'; import { getAllBestPractices } from '../lib/best-practice'; -import { getAllGuides } from '../lib/guide'; -import { getAllQuestionGroups } from '../lib/question-group'; import { getRoadmapsByTag } from '../lib/roadmap'; import { getAllVideos } from '../lib/video'; +import { listOfficialGuides } from '../queries/official-guide'; const roleRoadmaps = await getRoadmapsByTag('role-roadmap'); const skillRoadmaps = await getRoadmapsByTag('skill-roadmap'); const bestPractices = await getAllBestPractices(); -const questionGroups = await getAllQuestionGroups(); export const projectGroups = [ { @@ -31,9 +29,9 @@ export const projectGroups = [ }, ]; -const guides = await getAllGuides(); -const questionGuides = (await getAllQuestionGroups()).filter( - (questionGroup) => questionGroup.frontmatter.authorId, +const guides = await listOfficialGuides(); +const questionGuides = guides.filter( + (guide) => guide.roadmapId === 'questions' && !!guide?.authorId, ); const videos = await getAllVideos(); --- @@ -97,16 +95,6 @@ const videos = await getAllVideos(); }))} /> - ({ - text: questionGroup.frontmatter.briefTitle, - url: `/questions/${questionGroup.id}`, - isNew: questionGroup.frontmatter.isNew, - }))} - /> -