Since I revived this website last year I’ve wanted to add to it more. It’s a bit bare at the moment, right?
My problem was that I’d structured my blog posts to use markdown. I’m not used to writing in markdown so it was a proper struggle to get myself to write stuff. I needed to switch to a solution that already fit my way of doing things.
Enter Notion.
It’s no secret that I already love and use Notion every day. It’s a big part of my life and it helps me keep things organised and logged properly. But I also found that I could get some other wins from using it:
- I could work on blog posts on my phone as well as my laptop
- I wouldn’t need to upload assets like photos separately, I could just add them in line as I type
- I could use Notion’s in-built properties to know which posts are live and which are in draft
I had a few hours free this weekend so it seemed like a good time to try it out.
Implementation
I used a combination of this blog post, the Notion API docs, and some advice from Copilot to get things up and running. I did hit some speedbumps along the way but got there eventually…
When you’re fetching page content through Notion’s API it’ll give you a big stack of blocks which you then need to parse individually into your page components. I did this with map() and a switch statement for every type of block, which then meant I could apply my custom css classes where I needed to.
I also had a jammy situation with lists. Notion would give you the bulleted item individually, so you wouldn’t know if it had any siblings. I worked around this by checking the immediate siblings to see if they had the same class and returned different HTML depending on if it was at the start, middle, or end of the list.
case "numbered_list_item":
if (blocks[i - 1].type != "numbered_list_item") {
return `- ${block.numbered_list_item.rich_text
.map((text) => text.plain_text)
.join("")}
`;
}
else if (blocks[i + 1].type != "numbered_list_item") {
return `- ${block.numbered_list_item.rich_text
.map((text) => text.plain_text)
.join("")}
`;
}
else {
return `${block.numbered_list_item.rich_text
.map((text) => text.plain_text)
.join("")} `;
}
I’m not a huge fan of this but it’ll do since this is my personal blog. As long as I remember not to start or end a post with a list, which I don’t think is likely!
Final thoughts
My personal site is always going to be a work in progress. But with this Notion CMS in place I’m hoping that I’ll get the motivation to add more content to it over time.
One big plus is how much I learned through doing this. I didn’t know about dynamic routes in Astro before so that was a win. I’ve also struggled in the past with using variables in .env and how that interacts with the live site and I feel like I’ve gotten more comfortable with that through this little experiment.
A downside is that my blog posts load quite slowly compared to the old ones. Pulling from multiple sources is probably not that efficient!
I also built the function for turning Notion blocks into HTML myself so I know I’m missing some common Notion blocks (e.g. callouts) and I don’t think it’ll handle colours and columns very well at the moment.
But it’s a start. And it gives me something to work towards next time I get a free moment.