diff --git a/website/content/navigation.nix b/website/content/navigation.nix index f62263e7..e7eb7dad 100644 --- a/website/content/navigation.nix +++ b/website/content/navigation.nix @@ -10,12 +10,8 @@ in menu.label = "Consortium"; menu.items = map (page: { inherit page; }) (with pages; [ nlnet oid tweag nordunet ]); } - { - page = pages.fediversity; - } - { - page = pages.grants; - } + { page = pages.fediversity; } + { page = pages.grants; } ]; }; } diff --git a/website/structure/article.nix b/website/structure/article.nix new file mode 100644 index 00000000..2cc82c17 --- /dev/null +++ b/website/structure/article.nix @@ -0,0 +1,35 @@ +{ config, options, lib, ... }: +let + inherit (lib) + mkOption + types + ; + cfg = config; +in +{ + content-types. article = { config, collection, ... }: { + imports = [ cfg.content-types.page ]; + options = { + collection = mkOption { + description = "Collection this article belongs to"; + type = options.collections.type.nestedTypes.elemType; + default = collection; + }; + date = mkOption { + description = "Publication date"; + type = with types; str; + default = null; + }; + author = mkOption { + description = "Page author"; + type = with types; either str (nonEmptyListOf str); + default = null; + }; + }; + config.name = lib.slug config.title; + # TODO: this should be covered by the TBD `link` function instead, + # taking a historical list of collection names into account + config.outPath = "${collection.name}/${lib.head config.locations}"; + config.outputs.html = lib.mkForce (cfg.templates.html.article cfg config); + }; +} diff --git a/website/structure/content-types.nix b/website/structure/content-types.nix deleted file mode 100644 index ec30efc3..00000000 --- a/website/structure/content-types.nix +++ /dev/null @@ -1,151 +0,0 @@ -{ config, lib, options, ... }: -let - inherit (lib) - mkOption - types - ; - cfg = config; -in -{ - options = { - content-types = mkOption { - description = "Content types"; - type = with types; attrsOf deferredModule; - }; - }; - config.content-types = { - document = { name, config, link, ... }: { - config._module.args.link = config.link; - options = { - name = mkOption { - description = "Symbolic name, used as a human-readable identifier"; - type = types.str; - default = name; - }; - # TODO: reconsider using `page.outPath` and what to put into `locations`. - # maybe we can avoid having ".html" suffixes there. - # since templates can output multiple files, `html` is merely one of many things we *could* produce. - # TODO: make `apply` configurable so one can programmatically modify locations - locations = mkOption { - description = '' - List of historic output locations for the resulting file - - The first element is the canonical location. - All other elements are used to create redirects to the canonical location. - ''; - type = with types; nonEmptyListOf str; - }; - link = mkOption { - description = "Helper function for transparent linking to other pages"; - type = with types; functionTo str; - default = target: with lib; relativePath (head config.locations) (head target.locations); - }; - # TODO: may not need it when using `link`; could repurpose it to render the default template - outPath = mkOption { - description = '' - Location of the page, used for transparently creating links - ''; - type = types.str; - default = lib.head config.locations; - }; - outputs = mkOption { - description = '' - Representations of the document in different formats - ''; - type = with types; attrsOf str; - }; - }; - }; - page = { name, config, ... }: { - imports = [ cfg.content-types.document ]; - options = { - title = mkOption { - description = "Page title"; - type = types.str; - default = name; - }; - description = mkOption { - description = '' - One-sentence description of page contents - ''; - type = types.str; - }; - summary = mkOption { - description = '' - One-paragraph summary of page contents - ''; - type = types.str; - }; - body = mkOption { - description = '' - Page contents in CommonMark - ''; - type = types.str; - }; - }; - config.outputs.html = cfg.templates.html.page cfg config; - }; - - article = { config, collection, ... }: { - imports = [ cfg.content-types.page ]; - options = { - collection = mkOption { - description = "Collection this article belongs to"; - type = options.collections.type.nestedTypes.elemType; - default = collection; - }; - date = mkOption { - description = "Publication date"; - type = with types; str; - default = null; - }; - author = mkOption { - description = "Page author"; - type = with types; either str (nonEmptyListOf str); - default = null; - }; - }; - config.name = lib.slug config.title; - # TODO: this should be covered by the TBD `link` function instead, - # taking a historical list of collection names into account - config.outPath = "${collection.name}/${lib.head config.locations}"; - config.outputs.html = lib.mkForce (cfg.templates.html.article cfg config); - }; - - named-link = { ... }: { - options = { - label = mkOption { - description = "Link label"; - type = types.str; - }; - url = mkOption { - description = "Link URL"; - type = types.str; - }; - }; - }; - - navigation = { name, ... }: { - options = { - name = mkOption { - description = "Symbolic name, used as a human-readable identifier"; - type = types.str; - default = name; - }; - label = mkOption { - description = "Menu label"; - type = types.str; - default = name; - }; - items = mkOption { - description = "List of menu items"; - type = with types; listOf (attrTag { - menu = mkOption { type = submodule cfg.content-types.navigation; }; - page = mkOption { type = submodule cfg.content-types.page; }; - link = mkOption { type = submodule cfg.content-types.named-link; }; - }); - }; - }; - }; - }; -} diff --git a/website/structure/default.nix b/website/structure/default.nix index 70a473ff..4150f253 100644 --- a/website/structure/default.nix +++ b/website/structure/default.nix @@ -7,7 +7,12 @@ let cfg = config; in { - imports = [ ./content-types.nix ]; + imports = lib.nixFiles ./.; + + options.content-types = mkOption { + description = "Content types"; + type = with types; attrsOf deferredModule; + }; # TODO: enable i18n, e.g. via a nested attribute for language-specific content options.pages = mkOption { diff --git a/website/structure/document.nix b/website/structure/document.nix new file mode 100644 index 00000000..ba02c7fe --- /dev/null +++ b/website/structure/document.nix @@ -0,0 +1,51 @@ +{ lib, ... }: +let + inherit (lib) + mkOption + types + ; +in +{ + content-types.document = { name, config, link, ... }: { + config._module.args.link = config.link; + options = { + name = mkOption { + description = "Symbolic name, used as a human-readable identifier"; + type = types.str; + default = name; + }; + # TODO: reconsider using `page.outPath` and what to put into `locations`. + # maybe we can avoid having ".html" suffixes there. + # since templates can output multiple files, `html` is merely one of many things we *could* produce. + # TODO: make `apply` configurable so one can programmatically modify locations + locations = mkOption { + description = '' + List of historic output locations for the resulting file + + The first element is the canonical location. + All other elements are used to create redirects to the canonical location. + ''; + type = with types; nonEmptyListOf str; + }; + link = mkOption { + description = "Helper function for transparent linking to other pages"; + type = with types; functionTo str; + default = target: with lib; relativePath (head config.locations) (head target.locations); + }; + # TODO: may not need it when using `link`; could repurpose it to render the default template + outPath = mkOption { + description = '' + Location of the page, used for transparently creating links + ''; + type = types.str; + default = lib.head config.locations; + }; + outputs = mkOption { + description = '' + Representations of the document in different formats + ''; + type = with types; attrsOf str; + }; + }; + }; +} diff --git a/website/structure/navigation.nix b/website/structure/navigation.nix new file mode 100644 index 00000000..a642bcaa --- /dev/null +++ b/website/structure/navigation.nix @@ -0,0 +1,45 @@ +{ config, lib, ... }: +let + inherit (lib) + mkOption + types + ; + cfg = config; +in +{ + content-types.named-link = { ... }: { + options = { + label = mkOption { + description = "Link label"; + type = types.str; + }; + url = mkOption { + description = "Link URL"; + type = types.str; + }; + }; + }; + + content-types.navigation = { name, ... }: { + options = { + name = mkOption { + description = "Symbolic name, used as a human-readable identifier"; + type = types.str; + default = name; + }; + label = mkOption { + description = "Menu label"; + type = types.str; + default = name; + }; + items = mkOption { + description = "List of menu items"; + type = with types; listOf (attrTag { + menu = mkOption { type = submodule cfg.content-types.navigation; }; + page = mkOption { type = submodule cfg.content-types.page; }; + link = mkOption { type = submodule cfg.content-types.named-link; }; + }); + }; + }; + }; +} diff --git a/website/structure/page.nix b/website/structure/page.nix new file mode 100644 index 00000000..d76954e1 --- /dev/null +++ b/website/structure/page.nix @@ -0,0 +1,39 @@ +{ config, lib, ... }: +let + inherit (lib) + mkOption + types + ; + cfg = config; +in +{ + content-types.page = { name, config, ... }: { + imports = [ cfg.content-types.document ]; + options = { + title = mkOption { + description = "Page title"; + type = types.str; + default = name; + }; + description = mkOption { + description = '' + One-sentence description of page contents + ''; + type = types.str; + }; + summary = mkOption { + description = '' + One-paragraph summary of page contents + ''; + type = types.str; + }; + body = mkOption { + description = '' + Page contents in CommonMark + ''; + type = types.str; + }; + }; + config.outputs.html = cfg.templates.html.page cfg config; + }; +}