{ config, options, lib, ... }: let inherit (lib) mkOption types ; cfg = config; subtype = baseModule: types.submodule [ baseModule { _module.freeformType = types.attrs; # XXX: this is supposed to be used with a finished value, # and we don't want to process locations again. process-locations = lib.mkForce lib.id; } ]; in { options.menus = mkOption { description = '' Collection navigation menus ''; type = with types; attrsOf (submodule config.content-types.navigation); }; config.content-types.named-link = { ... }: { options = { label = mkOption { description = "Link label"; type = types.str; }; url = mkOption { description = "Link URL"; type = types.str; }; }; }; config.content-types.navigation = { name, config, ... }: { 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 = subtype cfg.content-types.page; }; link = mkOption { type = submodule cfg.content-types.named-link; }; }); }; outputs = mkOption { description = '' Representations of the navigation structure in different formats It must be a function that takes the page on which the navigation is to be shown, such that relative links get computed correctly. ''; type = with types; attrsOf (functionTo str); default.html = page: cfg.templates.html.nav { menu = config; inherit page; }; }; }; }; }