Add topics listing page

astro
Kamran Ahmed 2 years ago
parent 6d68542f25
commit 6f337f6b53
  1. 2
      src/components/Breadcrumbs.astro
  2. 23
      src/lib/topic.ts
  3. 47
      src/pages/[roadmapId].astro
  4. 47
      src/pages/[roadmapId]/index.astro
  5. 66
      src/pages/[roadmapId]/topics.astro

@ -12,8 +12,6 @@ const { breadcrumbs, roadmapId } = Astro.props;
<div class='py-7 pb-6'>
<!-- Desktop breadcrums -->
<p class='text-gray-500 container hidden sm:block'>
<a href='/roadmaps' class='hover:text-gray-800'>Roadmaps</a>
<span>&middot;</span>
{ breadcrumbs.map((breadcrumb, counter) => {
const isLast = counter === breadcrumbs.length - 1;

@ -80,6 +80,7 @@ export interface TopicFileContentType {
export interface TopicFileType {
url: string;
text: string;
file: TopicFileContentType;
roadmap: RoadmapFrontmatter;
roadmapId: string;
@ -101,9 +102,8 @@ export async function getTopicFiles(): Promise<Record<string, TopicFileType>> {
const fileHeadings = fileContent.getHeadings();
const firstHeading = fileHeadings[0];
const [, roadmapId, pathInsideContent] =
const [, roadmapId] =
filePath.match(/^\/src\/roadmaps\/(.+)?\/content\/(.+)?$/) || [];
const topicUrl = generateTopicUrl(filePath);
const currentRoadmap = await import(
@ -112,6 +112,7 @@ export async function getTopicFiles(): Promise<Record<string, TopicFileType>> {
mapping[topicUrl] = {
url: topicUrl,
text: firstHeading?.text,
file: fileContent,
roadmap: currentRoadmap.frontmatter,
roadmapId: roadmapId,
@ -130,6 +131,10 @@ export async function getTopicFiles(): Promise<Record<string, TopicFileType>> {
// Breadcrumbs for the file
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Roadmaps',
url: '/roadmaps',
},
{
title: currentRoadmap.featuredTitle,
url: `${roadmapUrl}`,
@ -146,3 +151,17 @@ export async function getTopicFiles(): Promise<Record<string, TopicFileType>> {
return mapping;
}
/**
* Gets the the topics for a given roadmap
* @param roadmapId Roadmap id for which you want the topics
* @returns Promise<TopicFileType[]>
*/
export async function getTopicsByRoadmapId(roadmapId: string): Promise<TopicFileType[]> {
const topicFileMapping = await getTopicFiles();
const allTopics = Object.values(topicFileMapping);
return Object.values(allTopics).filter(
(topic) => topic.roadmapId === roadmapId
);
}

@ -1,47 +0,0 @@
---
import InteractiveRoadamp from "../components/InteractiveRoadmap/InteractiveRoadmap.astro";
import MarkdownRoadmap from "../components/MarkdownRoadmap.astro";
import RoadmapHeader from "../components/RoadmapHeader.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
import { getRoadmapIds, RoadmapFrontmatter } from "../lib/roadmap";
export async function getStaticPaths() {
const roadmapIds = await getRoadmapIds();
return roadmapIds.map((roadmapId) => ({
params: { roadmapId },
}));
}
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const file = await import(`../roadmaps/${roadmapId}/${roadmapId}.md`);
const frontmatter = file.frontmatter as RoadmapFrontmatter;
---
<BaseLayout title="">
<RoadmapHeader
description={frontmatter.description}
title={frontmatter.title}
roadmapPermalink={`/${roadmapId}`}
/>
{
frontmatter.jsonUrl && (
<InteractiveRoadamp
roadmapId={roadmapId}
description={frontmatter.description}
roadmapPermalink={`/${roadmapId}`}
jsonUrl={frontmatter.jsonUrl}
dimensions={frontmatter.dimensions}
/>
)
}
<MarkdownRoadmap>
<file.Content />
</MarkdownRoadmap>
</BaseLayout>

@ -0,0 +1,47 @@
---
import InteractiveRoadamp from '../../components/InteractiveRoadmap/InteractiveRoadmap.astro';
import MarkdownRoadmap from '../../components/MarkdownRoadmap.astro';
import RoadmapHeader from '../../components/RoadmapHeader.astro';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getRoadmapIds, RoadmapFrontmatter } from '../../lib/roadmap';
export async function getStaticPaths() {
const roadmapIds = await getRoadmapIds();
return roadmapIds.map((roadmapId) => ({
params: { roadmapId },
}));
}
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
const { roadmapId } = Astro.params as Params;
const roadmapFile = await import(`../../roadmaps/${roadmapId}/${roadmapId}.md`);
const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
---
<BaseLayout title="">
<RoadmapHeader
description={roadmapData.description}
title={roadmapData.title}
roadmapPermalink={`/${roadmapId}`}
/>
{
roadmapData.jsonUrl && (
<InteractiveRoadamp
roadmapId={roadmapId}
description={roadmapData.description}
roadmapPermalink={`/${roadmapId}`}
jsonUrl={roadmapData.jsonUrl}
dimensions={roadmapData.dimensions}
/>
)
}
<MarkdownRoadmap>
<roadmapFile.Content />
</MarkdownRoadmap>
</BaseLayout>

@ -0,0 +1,66 @@
---
import RoadmapHeader from '../../components/RoadmapHeader.astro';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getRoadmapIds, RoadmapFrontmatter } from '../../lib/roadmap';
import { getTopicsByRoadmapId } from '../../lib/topic';
interface Params extends Record<string, string | undefined> {
roadmapId: string;
}
export async function getStaticPaths() {
const roadmapIds = await getRoadmapIds();
return roadmapIds.map((roadmapId) => ({
params: { roadmapId },
}));
}
const { roadmapId } = Astro.params as Params;
const topics = await getTopicsByRoadmapId(roadmapId);
const roadmapFile = await import(`../../roadmaps/${roadmapId}/${roadmapId}.md`);
const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
---
<BaseLayout title="Topics">
<RoadmapHeader
description={roadmapData.description}
title={roadmapData.title}
roadmapPermalink={`/${roadmapId}`}
hasSearch={true}
hasTopics={false}
/>
<div class="bg-gray-50 pt-5 pb-8 sm:pt-10 sm:pb-16">
<div class="container">
{
topics.map((topic) => {
// Breadcrumbs have three additional items e.g.
//
// Roadmaps / Frontend / Topics / Internet / HTTP
// ---^----------^---------^----
//
// Subtracting 3 to get the total parent count
const totalParentCount = topic.breadcrumbs.length - 3;
return (
<a
data-topic={topic.text.toLowerCase()}
class:list={[
'cursor-pointer text-sm sm:text-md border-gray-200 border py-1.5 px-2 sm:py-2 sm:px-2.5 rounded-md block mb-0.5 sm:mb-1',
{
'bg-gray-400 hover:bg-gray-500': totalParentCount === 1,
'bg-gray-300 hover:bg-gray-400': totalParentCount === 2,
'bg-gray-200 hover:bg-gray-300': totalParentCount === 3,
},
]}
href={topic.url}
>
{topic.text}
</a>
);
})
}
</div>
</div>
</BaseLayout>
Loading…
Cancel
Save