With renewed enthusiasm I head back to Simeās kitchen again in Kaikoura, New Zealand for an inspired atmosphere.

The goal today is to implement the blogās home page as per the design after migrating to figma components.
I was going to need to get the CSS + content out of Figma and place it in my blank Astro project. I immediately discovered that Figmaās ādev modeā is a paid only feature, but this really doesnāt matter as you can right-click Copy as->Copy as code->CSS which gives you the most useful aspect of dev mode anyway.
This is my first time working with Astro. As a stubborn JSX lover I arrived looking to utilise React components. However, taking a look at Astro components there really is little between them: Astro just has frontmatter delimiters to separate out data preparation from the return JSX. Iāve previously spent much time battling to get TSX support with Eleventy so the out-of-the box astro component experience is pretty slick.
Iām a tailwind convert. Prior to that I loved styled components: a key feature I liked was the semantic naming of the elements in the JSX which makes the code very descriptive, but tailwind is a seamless experience with almost zero faff. Less typing combined with its inline nature are the fundamental winning features. Astro makes it super simple to add, just an npx astro add tailwind
and youāre away. Iām liking Astro so far.
For adding fonts I popped over to google-web-font helper. This site allows you to easily download Google web fonts for self hosting. Self hosting is generally more performant because even if visitors have a cached version of Google hosted fonts you still have to do double step of hitting Googleās servers and then asking for the (cached) fonts. Iāve seen situations where this is significantly slower. It also increases user privacy.
I was additionally going to need a new favicon. It feels like it has to be some variation of the hamburger. I tried out a few options:

The one on the right feels the most logo-likeā¦ š.
Next up is the date display. Iām on the passionate side when it comes to internationalisation (i18n) and with that in mind I look to use the Intl api for date display. react-intl
from FormatJS is my go to wrapper library for internationalisation concerns, however, this will require an IntlProvider
react context setup, and of course Astroās rendering model doesnāt really cater to this paradigm. It will take me a more deeper look to understand the HTML output rendering context, but suppose it would be more of a template renderer than straight JS execution. Astro can mix and match components from different libraries in the same template, so the rendering is probably done in fragments. Regardless, itās different enough that context doesnāt work. I decide to lean into Astro components vs React ones here and just build a FormattedDate
Astro component for now:
---
const {
date: dateString,
lang = Astro.currentLocale
} = Astro.props;
const date = new Date(dateString);
---
<time datetime={date.toISOString()}>
{
date.toLocaleDateString(lang, {
year: '2-digit',
month: 'short',
day: 'numeric',
})
}
</time>
Note that this required setting up i18n in astro to enable the Astro.currentLocale
setting.
astro.config.mjs:
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
routing: {
prefixDefaultLocale: true,
},
},
I know this wonāt be the end of it though, I will want a fully-fledged i18n approach in Astro land. For example, Iām going to additionally need to internationalise my post tags, and that wonāt be content driven. More on this in my next post.
We now have the basic home page design implemented, butā¦

ā¦but not content driven. We still have to make the page source from mdx
files (aka markdown jsx). It canāt just be plain markdown because we want to import e.g. the FormattedDate
component we just created. Astro again makes this out of the box easy: yarn astro add mdx
.
Astro has the concept of ācollectionsā which are simply any content files placed in a subfolder of the content
folder. Rather than importing posts directly which can be done, you declare a schema (pertaining to keys in the mdx files frontmatter) for your collections in content/config.ts like so:
import { defineCollection, z } from "astro:content";
export const collections = {
type: "content",
posts: defineCollection({
schema: z.object({
date: z.date(),
title: z.string(),
tags: z.array(z.string()),
excerpt: z.string(),
pinned: z.optional(z.boolean()),
}),
}),
};
and then we need to create a template that has a wildcard parameter in itās file name like [slug].astro
and declare which slugs it exports. Of course the slugs it exports will just be the contents that are available, so all in all:
import { getCollection } from "astro:content";
export async function getStaticPaths() {
return (await getCollection("posts")).map(({ id }) => ({
params: { slug: id },
}));
}
From there itās just a matter of wiring up the frontmatter data and the goal for today is achieved!