## Render the blog index page
Now that we can render individual posts, let's wrap this up with the main page that renders a list of posts.
Add `getPosts()` to the bottom of `lib/posts.ts`. Here's the final version:
```ts
import { extractYaml } from "@std/front-matter";
import { join } from "@std/path";
const POSTS_DIR = "./posts";
// This is what gets parsed from the post front matter
interface FrontMatter {
title: string;
published_at: string;
blurb: string;
}
// This is what gets used for rendering
export interface Post {
slug: string;
title: string;
publishedAt: Date | null;
blurb: string;
content: string;
}
export async function getPost(slug: string): Promise<Post> {
const text = await Deno.readTextFile(join(POSTS_DIR, `${slug}.md`));
const { attrs, body } = extractYaml<FrontMatter>(text);
const post = {
slug,
title: attrs.title,
publishedAt: attrs.published_at ? new Date(attrs.published_at) : null,
blurb: attrs.blurb,
content: body,
};
return post;
}
export async function getPosts(): Promise<Post[]> {
const files = Deno.readDir(POSTS_DIR);
const promises = [];
for await (const file of files) {
if (file.name.startsWith(".")) continue;
const slug = file.name.replace(".md", "");
promises.push(getPost(slug));
}
const posts = (await Promise.all(promises) as Post[])
.filter((post) => post.publishedAt instanceof Date);
posts.sort((a, b) => b.publishedAt!.getTime() - a.publishedAt!.getTime());
return posts;
}
```
Here's the finished version of `routes/index.ts`:
```ts
import { Handlers, PageProps } from "$fresh/server.ts";
import { getPosts, Post } from "../lib/posts.ts";
export const handler: Handlers<Post[]> = {
async GET(_req, ctx) {
const posts = await getPosts();
return ctx.render(posts);
},
};
export default function BlogIndexPage(props: PageProps<Post[]>) {
const posts = props.data;
return (
<main class="max-w-screen-md px-4 pt-16 mx-auto">
<h1 class="text-5xl font-bold">My Awesome Blog</h1>
<div class="mt-8">
{posts.map((post) => <PostCard post={post}/>)}
</div>
</main>
);
}
function PostCard(props: { post: Post }) {
const { post } = props;
return (
<div class="py-6 border(t gray-200)">
<a class="sm:col-span-2" href={`/${post.slug}`}>
<h3 class="text-xl text-gray-900 font-bold hover:underline ">
{post.title}
<time class="font-medium text-gray-600">
({post.publishedAt!.toLocaleDateString("en-us", {
year: "numeric",
month: "long",
day: "numeric",
})})
</time>
</h3>
<div class="text-gray-900">
{post.blurb}
</div>
</a>
</div>
);
}
```
Now navigate to the home page:
https://localhost:8000
Voila! It should look decent and you should be able to click through to the individual posts. Try removing the `publish_at` property in the front matter of one of the posts. The post should no longer be displayed in the list nor be accessible via its slug.
Congratulations, you now have a basic working blog engine!