Keeping Track of My Reading Journey

For more than twelve years, I have maintained a comprehensive list of all the books I have read. It all started back in 2011 when I scribbled the titles on the last page of a worn-out school notebook. Over time, I transitioned to Liblib (Cloud Cataloging) and eventually settled on Goodreads itself.

The Goodreads experience

Initially, my main goal was to challenge myself and surpass my reading targets. I wasn't particularly interested in writing book reviews or following others' reading progress.

All I wanted was to reflect on the year's end, gazing upon a magnificent shelf adorned with an array of remarkable books. However, there was one major drawback—I couldn't fully appreciate Goodreads due to its lackluster presentation. The book covers displayed on the platform were of abysmal quality, as if they had been through a shredder. While I understand that judging a book solely by its cover is unfair, I couldn't even see the covers properly in the first place!

Moreover, locating and selecting the exact editions of the books I read and owned became a cumbersome process. The UI was unattractive and clunky, overwhelming me with an excess of unnecessary features. Every time I opened Goodreads to add a book, I would involuntarily cringe and feel a sense of displeasure.

To be fair, I must acknowledge that Goodreads excels in its social features. However, I personally didn't desire yet another social network. Whenever I sought recommendations for my next read, I preferred to rely on suggestions from friends, which consistently proved to be spot-on. Though I can't help but hold a grudge against the individual who recommended "Dubliners" to me; the only redeeming quality of that book is its conclusion.

Using Googdreads’ API

After going through several iterations, I finally arrived at the solution you see today.

Initially, I utilized gatsby-source-goodreads to import my book data into Gatsby.js. This process proved to be remarkably straightforward. With a bit of GraphQL and CSS tinkering, I successfully set up the entire page.

While the bookshelf now appeared more appealing without the cluttered Goodreads interface, the shredded appearance of the book covers still persisted.

When I later redesigned this website using Next.js, I made the decision to start from scratch and eliminate any dependency on Goodreads altogether.

Transitioning to Next.js and Contentlayer

During the creation of my blog, I opted for Contentlayer to transform my Markdown (MDX) posts into a suitable format. Initially, I considered using Markdown for the book entries as well, but ultimately found YAML to be better suited for the task.

Each book entry is now a simple YAML file, containing fields such as title, author, and read or reading status. When I begin reading a book, I replace read with reading, which automatically adds it to the "currently reading" list. Once I finish reading, I update the status accordingly, including the date. It's a neat and efficient system, isn't it?

Here’s how a book entry looks like:

title: One Piece
author: Oda, Eiichiro
read: 2011-01-01

And here's the complete Contentlayer document setup:

const Book = defineDocumentType(() => ({
  name: "Book",
  filePathPattern: `books/**/*.yml`,
  contentType: "yml",
  fields: {
    title: { type: "string", required: true },
    author: { type: "string", required: true },
    read: { type: "date" },
    reading: { type: "date" },
  },
  computedFields: {
    img: {
      type: "object",
      resolve: (doc) => {
        const filePath = `/covers/${doc._raw.sourceFileName.replace(
          /\.yml$/,
          ".jpg"
        )}`;
        const { width, height } = sizeOf(`public${filePath}`);
        return { filePath, width, height };
      },
    },
  },
}));

Take note of the computedFields section. It retrieves the YAML filename, replaces the extension, and automatically determines the image's location. This eliminates the need for additional manual references. Furthermore, I utilize image-size to obtain the width and height of each image, preventing any unpleasant Cumulative Layout Shift.

To serve appropriately sized images based on device specifications, I leverage next/image. It also employs modern formats and ensures that images load only when they come within the viewport area.

What’s next?

Next, I intend to incorporate support for re-reads. I find great joy in revisiting my favorite books each year (hello again, Frodo), so that feature is definitely on the cards.

Additionally, I plan to introduce some basic metrics, such as the number of books read per year. It would also be nice to enable filtering by author and genre.

Check out the final result live →


Note: some books are still being added to GoodReads because Kindle does it automatically.