{ config, options, lib, pkgs, ... }: let inherit (lib) mkOption types ; templates = import ./templates.nix { inherit lib; }; in { options.templates = let # arbitrarily nested attribute set where the leaves are of type `type` # NOTE: due to how `either` works, the first match is significant, # so if `type` happens to be an attrset, the typecheck will consider # `type`, not `attrsOf` recursiveAttrs = type: with types; attrsOf (either type (recursiveAttrs type)); in mkOption { description = '' Collection of named functions to convert document contents to a string representation Each template function takes the complete site `config` and the document's data structure. ''; # TODO: this function should probably take a single attrs, # otherwise it's quite inflexible. # named parameters would also help with readability at the call site type = recursiveAttrs (with types; functionTo (functionTo str)); }; config.templates.html = let commonmark = name: markdown: pkgs.runCommand "${name}.html" { buildInputs = [ pkgs.cmark ]; } '' cmark ${builtins.toFile "${name}.md" markdown} > $out ''; in { nav = lib.mkDefault templates.nav; page = lib.mkDefault (config: page: templates.html { head = ''