Guides listing page

astro
Kamran Ahmed 2 years ago
parent 274060a08f
commit 9b74a5fa62
  1. 40
      src/components/GuideListItem.astro
  2. 59
      src/lib/guide.ts
  3. 11
      src/lib/roadmap.ts
  4. 2
      src/lib/topic.ts
  5. 23
      src/pages/guides.astro

@ -0,0 +1,40 @@
---
import type { GuideFileType } from "../lib/guide";
export interface Props {
guide: GuideFileType;
}
const { guide } = Astro.props;
const { frontmatter, id } = guide;
---
<a
class:list={[
"block no-underline py-2 group text-md items-center text-gray-600 hover:text-blue-600 flex justify-between border-b",
]}
href={`/guides/${id}`}
>
<span class="group-hover:translate-x-2 transition-transform">
{frontmatter.title}
{
frontmatter.isNew && (
<span class="bg-green-300 text-green-900 text-xs font-medium px-1.5 py-0.5 rounded-sm uppercase ml-1.5">
New
<span class="hidden sm:inline">
&middot;
{new Date(frontmatter.date).toLocaleString("default", {
month: "long",
})}
</span>
</span>
)
}
</span>
<span class="capitalize text-gray-500 text-xs hidden sm:block">
{frontmatter.type}
</span>
<span class="text-gray-400 text-xs block sm:hidden"> &raquo;</span>
</a>

@ -0,0 +1,59 @@
import type { MarkdownFileType } from "./file";
export interface GuideFrontmatter {
title: string;
description: string;
author: {
name: string;
url: string;
imageUrl: string;
};
seo: {
title: string;
description: string;
};
isNew: boolean;
type: "visual" | "textual";
date: string;
sitemap: {
priority: number;
changefreq: "daily" | "weekly" | "monthly" | "yealry";
};
tags: string[];
}
export type GuideFileType = MarkdownFileType<GuideFrontmatter> & {
id: string;
};
/**
* Generates id from the given guide file
* @param filePath Markdown file path
*
* @returns unique guide identifier
*/
function guidePathToId(filePath: string): string {
return filePath.replace("/src/guides/", "").replace(".md", "");
}
/**
* Gets all the guides sorted by the publishing date
* @returns Promisifed guide files
*/
export async function getAllGuides(): Promise<GuideFileType[]> {
const guides = await import.meta.glob<GuideFileType>("/src/guides/*.md", {
eager: true,
});
const guideFiles = Object.values(guides);
const enrichedGuides = guideFiles.map((guideFile) => ({
...guideFile,
id: guidePathToId(guideFile.file),
}));
return enrichedGuides.sort(
(a, b) =>
new Date(b.frontmatter.date).valueOf() -
new Date(a.frontmatter.date).valueOf()
);
}

@ -1,8 +1,5 @@
import type { MarkdownFileType } from "./File";
import type { MarkdownFileType } from "./file";
export type RoadmapFileType = MarkdownFileType<RoadmapFrontmatter> & {
id: string;
};
export interface RoadmapFrontmatter {
jsonUrl: string;
@ -32,6 +29,10 @@ export interface RoadmapFrontmatter {
tags: string[];
}
export type RoadmapFileType = MarkdownFileType<RoadmapFrontmatter> & {
id: string;
};
function roadmapPathToId(filePath: string):string {
const fileName = filePath.split("/").pop() || "";
@ -44,7 +45,7 @@ function roadmapPathToId(filePath: string):string {
* @returns string[] Array of roadmap IDs
*/
export async function getRoadmapIds() {
const roadmapFiles = await import.meta.glob<string>("/src/roadmaps/*/*.md", {
const roadmapFiles = await import.meta.glob<RoadmapFileType>("/src/roadmaps/*/*.md", {
eager: true,
});

@ -1,4 +1,4 @@
import type { MarkdownFileType } from './File';
import type { MarkdownFileType } from './file';
import type { RoadmapFrontmatter } from './roadmap';
// Generates URL from the topic file path e.g.

@ -0,0 +1,23 @@
---
import GuideListItem from "../components/GuideListItem.astro";
import SimplePageHeader from "../components/SimplePageHeader.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
import { getAllGuides } from "../lib/guide";
const guides = await getAllGuides();
---
<BaseLayout title="Guides">
<SimplePageHeader
title="Guides"
description="Succinct graphical explanations to engineering topics."
/>
<div class="pb-20 pt-2 bg-gray-50">
<div class="container">
<div class="mt-3 sm:my-5">
{guides.map((guide) => <GuideListItem guide={guide} />)}
</div>
</div>
</div>
</BaseLayout>
Loading…
Cancel
Save