From 4762618956744c226005e0e019f7a7e7cfc841f2 Mon Sep 17 00:00:00 2001 From: valentin gagarin Date: Wed, 13 Nov 2024 15:24:41 +0100 Subject: [PATCH] make page templates granularly overridable --- content/default.nix | 14 ++++++++++--- lib.nix | 3 +++ presentation/default.nix | 2 +- presentation/templates.nix | 22 ++++++++++---------- structure/article.nix | 10 +--------- structure/collections.nix | 2 +- structure/default.nix | 6 ++---- structure/page.nix | 41 +++++++++++++++++--------------------- 8 files changed, 49 insertions(+), 51 deletions(-) diff --git a/content/default.nix b/content/default.nix index a6962907..649b5d38 100644 --- a/content/default.nix +++ b/content/default.nix @@ -1,13 +1,14 @@ { config, lib, ... }: let inherit (config) pages; + cfg = config; in { imports = lib.nixFiles ./.; - collections.news.type = config.content-types.article; + collections.news.type = cfg.content-types.article; - pages.index = { link, ... }: { + pages.index = { config, link, ... }: { title = "Fediversity"; description = "Fediversity web site"; summary = '' @@ -52,12 +53,19 @@ in ${ let - sorted = with lib; reverseList (sortOn (entry: entry.date) config.collections.news.entry); + sorted = with lib; reverseList (sortOn (entry: entry.date) cfg.collections.news.entry); in lib.join "\n" (map (article: '' - ${article.date} [${article.title}](${link article}) '') sorted) } ''; + outputs.html = (cfg.templates.html.page config).override { + html.body.content = lib.mkForce [ + # don't show the page title as a heading + (cfg.menus.main.outputs.html config) + (cfg.templates.html.markdown { inherit (config) name body; }) + ]; + }; }; } diff --git a/lib.nix b/lib.nix index f3cb7e4b..aa8cdaa7 100644 --- a/lib.nix +++ b/lib.nix @@ -1,5 +1,8 @@ { lib }: rec { + template = g: f: x: + (g (f x)) // { override = o: g (lib.recursiveUpdate (f x) o); }; + /** Recursively replace occurrences of `from` with `to` within `string` diff --git a/presentation/default.nix b/presentation/default.nix index 3e9e266b..8f74b91c 100644 --- a/presentation/default.nix +++ b/presentation/default.nix @@ -21,7 +21,7 @@ in description = '' Collection of named helper functions for conversion different structured representations which can be rendered to a string ''; - type = recursiveAttrs (with types; functionTo (coercedTo attrs toString str)); + type = recursiveAttrs (with types; functionTo (either str attrs)); }; options.files = mkOption { diff --git a/presentation/templates.nix b/presentation/templates.nix index c76cd3a4..7a688f70 100644 --- a/presentation/templates.nix +++ b/presentation/templates.nix @@ -4,19 +4,21 @@ let mkOption types ; - # 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 { config.templates.html = { + dom = document: + let + eval = lib.evalModules { + class = "DOM"; + modules = [ document (import ./dom.nix) ]; + }; + in + { + __toString = _: toString eval.config; + value = eval.config; + }; + markdown = { name, body }: let commonmark = pkgs.runCommand "${name}.html" diff --git a/structure/article.nix b/structure/article.nix index 67ec6045..04c6e65e 100644 --- a/structure/article.nix +++ b/structure/article.nix @@ -5,14 +5,6 @@ let types ; cfg = config; - render-html = document: - let - eval = lib.evalModules { - class = "DOM"; - modules = [ document (import ../presentation/dom.nix) ]; - }; - in - toString eval.config; in { content-types.article = { config, collection, ... }: { @@ -35,7 +27,7 @@ in }; }; config.name = lib.slug config.title; - config.outputs.html = lib.mkForce (render-html { + config.outputs.html = lib.mkForce (cfg.templates.html.dom { html = { head = { title.text = config.title; diff --git a/structure/collections.nix b/structure/collections.nix index b171c1f3..7dd12610 100644 --- a/structure/collections.nix +++ b/structure/collections.nix @@ -68,7 +68,7 @@ in in with lib; foldl (acc: elem: acc // { - "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html; + "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" "${elem.outputs.html}"; }) { } collections; diff --git a/structure/default.nix b/structure/default.nix index 4e1cdb9d..62102927 100644 --- a/structure/default.nix +++ b/structure/default.nix @@ -53,13 +53,11 @@ in # names is soft. default = target: with lib; "${relativePath (head config.locations) (head target.locations)}.html"; }; - outputs.html = mkOption { - # TODO: make this of type DOM and convert to string at the output. - # the output aggregator then only needs something string-coercible + outputs = mkOption { description = '' Representations of the document in different formats ''; - type = with types; str; + type = with types; attrsOf (either str attrs); }; }; }; diff --git a/structure/page.nix b/structure/page.nix index 8eef14e6..8d255c14 100644 --- a/structure/page.nix +++ b/structure/page.nix @@ -5,14 +5,6 @@ let types ; cfg = config; - render-html = document: - let - eval = lib.evalModules { - class = "DOM"; - modules = [ document (import ../presentation/dom.nix) ]; - }; - in - toString eval.config; in { # TODO: enable i18n, e.g. via a nested attribute for language-specific content @@ -27,7 +19,7 @@ in (acc: elem: acc // { # TODO: create static redirects from `tail page.locations` # TODO: the file name could correspond to the canonical location in the HTML representation - "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html; + "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" "${elem.outputs.html}"; }) { } (attrValues config.pages); @@ -59,19 +51,22 @@ in type = types.str; }; }; - config.outputs.html = render-html { - html = { - head = { - title.text = config.title; - meta.description = config.description; - link.canonical = lib.head config.locations; - }; - body.content = [ - (cfg.menus.main.outputs.html config) - { section.heading.content = config.title; } - (cfg.templates.html.markdown { inherit (config) name body; }) - ]; - }; - }; + + config.outputs.html = cfg.templates.html.page config; }; + + config.templates.html.page = lib.template cfg.templates.html.dom (page: { + html = { + head = { + title.text = page.title; + meta.description = page.description; + link.canonical = lib.head page.locations; + }; + body.content = [ + (cfg.menus.main.outputs.html page) + { section.heading.content = page.title; } + (cfg.templates.html.markdown { inherit (page) name body; }) + ]; + }; + }); }