A New Hugo Theme

| #meta #nix #hugo #colors

Oh hi, it’s been a while. What am I doing with this site again?

I don’t have a good answer for that right now. But maybe I’m getting a little closer to knowing.

I was recently reading some articles about the “small web” and it got me thinking about this site again. It inspired me to simplify it by writing my own theme. And of course, I made it all complicated again by bringing nix into another project.

Creating a new theme

I thought that creating a theme would be a huge effort, but I was surprised to find that it wasn’t as hard as I thought it’d be. First off, I’m better at CSS than I realized! It’s probably because of all the time I’ve spent configuring my waybar theme.

But also Hugo gives you a lot of helpful scaffolding when you create a new theme with

hugo new theme my-theme-name

And I was happy to find that Hugo can output the CSS of an existing syntax highlighting theme so I didn’t have to write that from scratch either:

hugo gen chromastyles --style=monokai > syntax.css

Inspiration and Restrictions

I spend a lot of time working on my dotfiles. So I felt like it was only natural that my website should look similar to my neovim and waybar themes:

sway screenshot
A floating neovim window in glorious 1024x768 sway with waybar

That meant that I followed the same guidelines I use for all the themes in my dotfiles:

In a way, I think this was a form of creative limitation. Creating a theme sounds daunting because it’s so open-ended, but with this goal and these restrictions it was so much more attainable. I spent significantly more of my time learning about HTML and CSS than obsessing over the look of it.

Basix for base16 colors

In my dotfiles, I use Basix to expose base16 colorschemes as Nix attribute sets. I brought it into the build process of this site as well.

I can switch the site to different base16 themes easily, just like in my dotfiles!

Here it is with gruvbox-dark and a green accent color:

gruvbox with green accent color

Here’s my old favorite helios with a magenta accent color:

helios with magenta accent color

Do I change colorschemes often enough to justify making it work this way? Probably not. But it was fun to make.

Under the hood

In my Hugo theme, I reference a colors.css file but the file is ephemeral. It doesn’t exist when you clone the repository. It’s even gitignored so it can’t be accidentally committed. Nix generates the colors.css file based on a base16 color palette from Basix.

In flake.nix, I initialize a colorsCss variable that contains the file contents that will be put into colors.css:

let
  palette = basix.schemeData.base16."0x96f".palette;
  
  accent = palette.base09; # orange
  accent-hover = palette.base0E; # magenta
  bg = palette.base00;
  fg = palette.base07;
  
  colorsCss = /* css */ ''
    :root {
      --base00: ${palette.base00};
      --base01: ${palette.base01};
      --base02: ${palette.base02};
      --base03: ${palette.base03};
      --base04: ${palette.base04};
      --base05: ${palette.base05};
      --base06: ${palette.base06};
      --base07: ${palette.base07};
      --base08: ${palette.base08}; /* red */
      --base09: ${palette.base09}; /* orange */
      --base0A: ${palette.base0A}; /* yellow */
      --base0B: ${palette.base0B}; /* green */
      --base0C: ${palette.base0C}; /* cyan */
      --base0D: ${palette.base0D}; /* blue */
      --base0E: ${palette.base0E}; /* magenta */
      --base0F: ${palette.base0F}; /* brown */
  
      --main-bg-color: ${bg};
      --main-text-color: ${fg};
      --accent-color: ${accent};
      --accent-hover-color: ${accent-hover};
    }
  '';
in # ...

I have a package/derivation that builds the colors.css file:

packages.colors = pkgs.stdenv.mkDerivation {
  name = "mattbun.github.io/colors";
  src = self;
  buildInputs = buildInputs;

  buildPhase = ''
    cp ${pkgs.writeText "colors.css" colorsCss} colors.css
  '';

  installPhase = "cp colors.css $out";
};

And there’s a another (default) package that builds the whole site, including colors.css, that I use in GitHub Actions:

packages.default = pkgs.stdenv.mkDerivation {
  name = "mattbun.github.io";
  src = self;
  buildInputs = buildInputs;

  buildPhase = ''
    cp ${pkgs.writeText "colors.css" colorsCss} themes/dotfiles/assets/css/colors.css
    ${pkgs.hugo}/bin/hugo
    cp CNAME public/CNAME
  '';

  installPhase = "cp -r public $out";
};

To run the site locally, the develop make target has a dependency on the colors.css file. The colors.css target builds the #colors nix package to generate colors.css:

develop: themes/dotfiles/assets/css/colors.css
	nix develop --command hugo server -D --bind 0.0.0.0

MAKEFLAGS += --check-symlink-times
themes/dotfiles/assets/css/colors.css: flake.nix flake.lock
	nix build .#colors -o ./themes/dotfiles/assets/css/colors.css

--check-symlink-times is necessary to prevent it from always rebuilding colors.css. The -o ./themes/dotfiles/assets/css/colors.css flag instructs nix to symbolic link the built package directly at that path. By default, make will only look at the timestamp of the file that the link points to. In this case, it comes from the nix store which has a timestamp of zero.

Closing thoughts, what am I doing here?

Ok I do have some ideas about what I want to do with the site moving forward. Some general goals:

We’ll see how it goes!

Or maybe I’ll come back here in a couple years with another major rewrite of the site. At least it’s been fun to build.