To ring in the new year, I’m excited to share a new version of this site (something like the 5th version in as many years, but who’s counting) that I’ve been working on for what feels like way too long.

A post by me on Mastodon from September 2023, saying 'it me, I'm redesigning my site instead of writing the next blog post.'

But, here it is, and I’m quite happy with where things are at and where things are headed as I continue to think up fun additions. Let me give you a quick tour of everything, and if you’d like, let me know what you think of it! Those interested can also check out the source code on GitHub.

The Design

The design coalesces a bunch of different themes that I have been exploring over the last few years in both my graphic and web design work, and definitely feels like an authentic expression of “my style” at the moment: a primary focus on considered, timeless, and legible typography, in this case anchored by the inimitable Brix Sans and spiced up with Fjalla One; a color scheme rooted in historical graphic design expressions; layouts reminiscent of book side margins, rules, and indexes; an overall sense of sophistication-meets-approachability, something that doesn’t take itself quite so seriously and that, most importantly, doesn’t get in the way of the content.

Although I have always striven to realize many of these elements in my designs, the thing that made the biggest difference with this iteration of the site is that I spent a lot of time intentionally experimenting with and planning out design ideas before building anything. It’s something that is obviously baked into the process when I’m working with a client, but when it comes to my own work, I tend to overlook this phase, which makes no sense! All design is intention and planning, and busting out Figma to prototype a handful of ideas before going to code is for me always a great way to visually solidify what I am envisioning.

I also want to shout out some of the inspirations for this site. There are a lot of cool people out there making some very cool personal sites. Go check them out!

The Site

I used Lume to build this site, a static site generator (SSG) for Deno. Although it’s a relatively small project at the moment (one which I’m happily contributing to), I loved working with it because of the native Deno environment and all of the features Lume comes with. Lume’s creator Óscar Otero has done a fantastic job building on other SSGs and designing an ergonomic, robust piece of software that feels very intuitive to use.

The last version of my site was built with 11ty, which is also a fantastic SSG, and there were definitely some tradeoffs involved in making the switch (one thing I’m ambivalent about at the moment is having to use Deno Deploy to host the site). But I enjoyed working with Lume for a handful of reasons:

src/_includes/layouts/archive.vto
{{ set archivedPosts = search.pages("type=posts", "date=desc") |> groupby("archiveYear") }}
  <div class="archive">
    {{ for year of archivedPosts }}
      <details>
        <summary>{{ year.type }} Posts</summary>
        <div>...</div>
      </details>
    {{ /for }}
  </div>

Overall Improvements

A new design was also a chance to make a bunch of improvements to the site’s organization, content, and overall code. Some of this was just a result of experience and wanting to do things in more efficient and sensible ways, and some was wanting to pare down and clean up some detritus that had accumulated over time.

Highlights and Fun Stuff

My website has always been a place for me to try out new things and play around with whatever is interesting at the moment, and this iteration of the site is chock-full of my random little experimentations:

CSS

As mentioned above, the CSS for the site is living on the cutting-edge, and it’s been super fun to write. We’ve got nesting, the :has() selector, container queries, and custom properties out the wazoo; using LightningCSS also lets me use colors in the lch space.

One of the major styling features is not only a light/dark/system theme toggler, but an accent color toggler that enables you to cycle through a total of 10 different color schemes. The theme toggles use the native details HTML element, which means no JavaScript needed. I love how this turned out! There are lots of other fun little CSS moments and animations throughout the site as well.

Books

I have incorporated elements of my Airtable reading tracker into the site—on the home page, I’m fetching some of my latest reading activity records to show a glance at my bookshelf. These entries pull data from Airtable, and, as a bonus, link to the associated books in the counterpart website, which I’m continuing to build out.

A fun part of this was writing a function to download the images from Airtable after the fetch response and write them to the project directory, since Airtable’s media links expire after a few hours. This way, I could save them locally, run them through the Lume image transforms, and finally display them in templates.

HTMX

HTMX is getting a lot of buzz at the moment, and it has been interesting to learn more about the philosophical underpinning of a client-server interaction model that is in many ways fundamentally at odds with the React-driven world we’ve lived in for last decade.

You can see my small implementation of this in the “current interests” block on the home page. This block has a button that sends a GET request to a Deno server running in the background; rather than returning JSON data, the server responds with HTML that live replaces the targeted HTML on the page, complete with a nifty animation and no page reload. This is HTMX in a nutshell, and it’s really kind of mind-blowing when you see how easy it is.

After compiling the data for the different categories (thoughts and tools come from manually edited .yaml files, and music comes from making a fetch request to my scrobbles from the Last.fm API), I run a simple randomizing function to get a new item on each click of the “Refresh” button. Then each of the items is inserted in an HTML template that gets sent down to the page via HTMX.

server.js
import { Application, Router } from "https://deno.land/x/oak@v10.2.0/mod.ts";
import { list as thoughtsList } from "../src/_data/thoughts.js";
import { albums } from "../src/_data/music.js";
import { list as toolsList } from "../src/_data/tools.js";
import getRandomItem from "../src/utils/getRandom.js";

// Use Deno Oak to start a new application server
const app = new Application();

function htmxResponse() {
    const randomThought = getRandomItem(thoughtsList);
    const randomAlbum = getRandomItem(albums);
    const randomTool = getRandomItem(toolsList);

    // Some HTML elements below edited out for brevity
    return (
        `<p id="thoughts" class="animate-reponse">${randomThought}</p>` +
        `<p id="albums" hx-swap-oob="true" class="animate-response">${randomAblum.name}</p>` +
        `<p id="tools" hx-swap-oob="true" class="animate-response">${randomTool.name}</p>`
    );
}

// Initialize an app router with Deno Oak
const router = new Router();

// This is the endpoint that HTMX hits when a user clicks the "Refresh" button
router.get("/api/interests", (ctx) => {
    ctx.response.body = htmxResponse();
});

The great part about this is that the Vento templates can use the same data sources to build for the initial state of the static site. A button then uses hx-get to send a request to the endpoint defined above. Using hx-swap="outerHTML" in conjunction with the response items having an attribute of hx-swap-oob="true" means the targeting/replacement can happen “out-of-band”, i.e., at different parts of the DOM tree.

I’m excited to play around with this further to see how else I can extend the interactivity of this site.

Hav a look around the rest of the site!