I am a big fan of Notion. I use it as my second brain and follow the PARA method to organize everything. One of my Notion databases is called “Web Clips”. I use this database to save links that I find on the web.
I wanted to share some of the links I collect on my blog. I had a few options I was considering:
- ❌ I could make this Notion database public, but I want to keep some links private, so this was not a good option.
- ✅ I could use the Notion API to render all the links I want to show dynamically. This would be a lot of work, but that is what this blog is for. The finished result is here: samedwardes.com/links.
Project Elements
I would need to build a few things to make this all work:
-
A query that gets only the links I want to share publicly. The query should be able to optionally filter links based on a search field, tags, and other meta-data. See the GitHub Repo for the final query.
-
I’d like to create a page that displays all the links. Since I have a lot of links, the page will also need pagination.
-
A component to make each link look good.
You can see the final implementation of my code here: https://github.com/SamEdwardes/samedwardes.com/tree/main/src/pages/links.
Workflow
My workflow is now like this:
I find a link I want to save. If I am on my computer, I use the Notion extension to send the link to my “Web Clips” database. If I am on my iPhone, the Notion app has a built-in action in the “share tray” to send a page to the database. By default, all links are private. If I want to share a link, I must opt-in to make it public. To do so, I check the “Public” field in Notion for that database item. I then enter more metadata, including “Public Tags” and “Public Description.” These two fields will be rendered as part of the component.
Whenever someone visits https://samedwardes.com/links, a query is sent to the Notion API to render a page with all my links dynamically. If desired, the user can search all of my links through my website, which will modify the query and update the page.
Astro
My website is built on Astro. As of August 2024, the entire site is statically generated except for /links
. One of the parts I like about Astro is that you can opt to have some pages server-side rendered while other pages can be statically rendered. The /links
page has to be server-side rendered every time because the links could change at any moment.
You can see how I implemented the links page here: https://github.com/SamEdwardes/samedwardes.com/blob/main/src/pages/links/index.astro.
src/pages/links/index.astro
This page “sets up the query” by getting all the tags I need to present to the user for filtering. It also makes the htmx calls that will handle the pagination.
src/pages/links/partials/grid.astro
This page is where the query primary Notion query to get the links is executed. The JavaScript queries my Notion database and then renders a grid nested into src/pages/links/index.astro
.
htmx
I use htmx to handle the pagination. I could not find a clean way to do this in just Astro, and I was already familiar with htmx so I thought I would give it a try. The end result is pretty easy to reason about and maintain.
The easiest way to understand the htmx implementation is to review the code: https://github.com/SamEdwardes/samedwardes.com/tree/main/src/pages/links. In short, on the index.astro page
:
- When the page first loads, htmx makes a request to
/links/partials/grid
to render the initial grid. - When a filter changes, the entire grid is “reset” and replace with an updated query.
The grid.astro
partial handles the pagination. When the bottom of the page is reached, the query is triggered again to get the next page.
Demo
Visit samedwardes.com/link or watch the GIF below to see it in action.