forked from Fediversity/Fediversity
Valentin Gagarin
4aeb9579d6
the templates collection will soon only be there for reusable snippets, while the HTML representation of document types will be attached to those types directly.
121 lines
3.6 KiB
Nix
121 lines
3.6 KiB
Nix
{ config, options, lib, pkgs, ... }:
|
|
let
|
|
inherit (lib)
|
|
mkOption
|
|
types
|
|
;
|
|
templates = import ./templates.nix { inherit lib; };
|
|
# TODO: optionally run the whole thing through the validator
|
|
# https://github.com/validator/validator
|
|
render-html = document:
|
|
let
|
|
eval = lib.evalModules {
|
|
class = "DOM";
|
|
modules = [ document (import ./dom.nix) ];
|
|
};
|
|
in
|
|
toString eval.config;
|
|
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 = {
|
|
markdown = name: text:
|
|
let
|
|
commonmark = pkgs.runCommand "${name}.html"
|
|
{
|
|
buildInputs = [ pkgs.cmark ];
|
|
} ''
|
|
cmark ${builtins.toFile "${name}.md" text} > $out
|
|
'';
|
|
in
|
|
builtins.readFile commonmark;
|
|
nav = menu: page:
|
|
let
|
|
render-item = item:
|
|
if item ? menu then ''
|
|
<li>${item.menu.label}
|
|
${lib.indent " " (item.menu.outputs.html page)}
|
|
</li>
|
|
''
|
|
else if item ? page then ''<li><a href="${page.link item.page}">${item.page.title}</a></li>''
|
|
else ''<li><a href="${item.link.url}">${item.link.label}</a></li>''
|
|
;
|
|
in
|
|
''
|
|
<nav>
|
|
<ul>
|
|
${with lib; indent " " (join "\n" (map render-item menu.items))}
|
|
</ul>
|
|
</nav>
|
|
'';
|
|
|
|
};
|
|
|
|
options.files = mkOption {
|
|
description = ''
|
|
Files that make up the site, mapping from output path to contents
|
|
|
|
By default, all elements in `option`{pages} are converted to files using their template or the default template.
|
|
Add more files to the output by assigning to this attribute set.
|
|
'';
|
|
# TODO: this should be attrsOf string-coercible instead.
|
|
# we can convert this to file at the very end.
|
|
type = with types; attrsOf path;
|
|
};
|
|
|
|
config.files =
|
|
# TODO: create static redirects from `tail page.locations`
|
|
let
|
|
pages = lib.attrValues config.pages;
|
|
collections = with lib; concatMap (collection: collection.entry) (attrValues config.collections);
|
|
in
|
|
with lib; foldl
|
|
(acc: elem: acc // {
|
|
# TODO: we may or may not want to enforce the mapping of file types to output file name suffixes
|
|
"${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html;
|
|
})
|
|
{ }
|
|
(pages ++ collections);
|
|
|
|
options.build = mkOption {
|
|
description = ''
|
|
The final output of the web site
|
|
'';
|
|
type = types.package;
|
|
default =
|
|
let
|
|
script = ''
|
|
mkdir $out
|
|
'' + lib.join "\n" copy;
|
|
copy = lib.mapAttrsToList
|
|
(
|
|
path: file: ''
|
|
mkdir -p $out/$(dirname ${path})
|
|
cp -r ${file} $out/${path}
|
|
''
|
|
)
|
|
config.files;
|
|
in
|
|
pkgs.runCommand "source" { } script;
|
|
};
|
|
}
|