Building Eddy, my terminal reading log

Last updated

I love lazygit. It has been my sole Git interface for years: it’s fast, focused and usually one key away from anything I want to do.

I wanted that same experience for logging my reading, so I built Eddy.

Eddy’s main screen
Eddy’s main screen

Eddy is built with React and Ink. Its interaction model comes from lazygit: numbered panels, single-key actions, j/k navigation, contextual shortcuts and space for secondary actions. There is little to memorise because the interface always shows what is available.

Letting the terminal choose the colours

The first version used hand-picked colours. It looked fine in my usual theme, then fell apart as soon as I switched to light mode: poor contrast, mismatched modal backgrounds and highlighted rows that swallowed the text.

Switching to ANSI colours fixed it. The terminal theme decides how they are rendered, so Eddy stays readable without needing separate light and dark palettes.

Modals and overlays

Ink can position a modal over the interface, but terminals have no opacity or translucent backdrop to separate the layers. I fake that part with a small React context: when a modal opens, it applies ANSI dimming to the text and borders behind it, steps brighter colours down (bright cyan becomes regular cyan) and swaps the blue selection row for grey. The modal stays untouched, so it feels like it is floating above the app even though nothing is actually transparent. The effect works surprisingly well!

Eddy’s custom New book modal
Note the translucent backdrop

The cover is swapped for a dimmed placeholder at the same time. It is a tiny detail, but stopping the brightest part of the Details panel from shining through helps sell the effect.

Putting an actual book cover in a terminal

Actual book cover in a terminal
Kitty graphics protocol is used to render cover images

On clients that support the Kitty graphics protocol, ink-picture can render the real cover inside the Details panel. Every image occupies the same bottom-aligned frame, keeping the title and author fixed while I move through books with covers of different proportions.

Fallback book cover made of block elements
Cover fallback for clients that don’t support Kitty

On terminals without native graphics support, Eddy resizes the cover and packs each 2×2 group of pixels into a coloured Unicode block element.

Keeping it fast

Authentication runs through GitHub and Supabase’s PKCE flow, with the session stored in macOS’s Keychain. Eddy only enables writes when the verified token includes my admin claim.

On startup, Eddy renders the book list from a local JSON cache, then refreshes it from Supabase in the background. It feels instant without treating the cache as the source of truth.

I liked using Eddy so much that I removed book management from the website altogether. All editing now happens in eddy :)

Demo

Here’s a short demo of the app in action: