allow prefixing output paths of collection items

This commit is contained in:
Valentin Gagarin 2024-11-13 15:24:41 +01:00 committed by Valentin Gagarin
parent 3505539499
commit 7efd5b8317
10 changed files with 54 additions and 46 deletions

View file

@ -5,7 +5,10 @@ in
{ {
imports = lib.nixFiles ./.; imports = lib.nixFiles ./.;
collections.news.type = config.content-types.article; collections.news = {
type = config.content-types.article;
prefixes = [ "news" ];
};
pages.index = { link, ... }: { pages.index = { link, ... }: {
title = "Fediversity"; title = "Fediversity";

View file

@ -18,9 +18,7 @@ in
in in
map map
(page: { (page: {
page = lib.recursiveUpdate page { page = lib.recursiveUpdate page { title = "${page.date}: ${page.title}"; };
title = "${page.date}: ${page.title}";
};
}) })
(lib.take 3 sorted); (lib.take 3 sorted);
} }

View file

@ -1,6 +1,6 @@
{ ... }: { config, lib, ... }:
{ {
collections.news.entry = { collections.news.entry = { link, ... }: {
title = "Fediversity project publicly announced"; title = "Fediversity project publicly announced";
description = "The Fediversity project has officially been announced"; description = "The Fediversity project has officially been announced";
date = "2024-01-01"; date = "2024-01-01";

View file

@ -52,16 +52,17 @@ rec {
inherit (lib) lists; inherit (lib) lists;
path1 = subpath.components path1'; path1 = subpath.components path1';
prefix1 = with lib; take (length path1 - 1) path1;
path2 = subpath.components path2'; path2 = subpath.components path2';
prefix2 = with lib; take (length path1 - 1) path2;
commonPrefixLength = with lists; commonPrefixLength = with lists;
findFirstIndex (i: i.fst != i.snd) findFirstIndex (i: i.fst != i.snd)
{ fst = null; snd = null; } (length prefix1)
(zipLists path1 path2); (zipLists prefix1 prefix2);
relativeComponents = with lists; relativeComponents = with lists;
[ "." ] ++ (replicate (length path1 - commonPrefixLength - 1) "..") ++ [ "." ] ++ (replicate (length prefix1 - commonPrefixLength) "..") ++ (drop commonPrefixLength path2);
(drop commonPrefixLength path2);
in in
join "/" relativeComponents; join "/" relativeComponents;
@ -98,13 +99,7 @@ rec {
merge = loc: defs: merge = loc: defs:
map map
(def: (def:
let elemType.merge (loc ++ [ "[definition ${toString def.file}]" ]) [{ inherit (def) file; value = def.value; }]
merged = lib.mergeDefinitions
(loc ++ [ "[definition ${toString def.file}]" ])
elemType
[{ inherit (def) file; value = def.value; }];
in
if merged ? mergedValue then merged.mergedValue else merged.value
) )
defs; defs;
check = elemType.check; check = elemType.check;

View file

@ -41,7 +41,7 @@ in
<link rel="canonical" href="${page.outPath}" /> <link rel="canonical" href="${page.outPath}" />
''; '';
body = '' body = ''
${templates.nav { menu = { menu = config.menus.main; }; }} ${templates.nav { inherit page; menu = { menu = config.menus.main; }; }}
${builtins.readFile (commonmark page.name page.body)} ${builtins.readFile (commonmark page.name page.body)}
''; '';
}); });
@ -55,7 +55,7 @@ in
} }
''; '';
body = '' body = ''
${templates.nav { menu = { menu = config.menus.main; }; }} ${templates.nav { inherit page; menu = { menu = config.menus.main; }; }}
${builtins.readFile (commonmark page.name page.body)} ${builtins.readFile (commonmark page.name page.body)}
''; '';
}); });
@ -76,20 +76,13 @@ in
let let
pages = lib.attrValues config.pages; pages = lib.attrValues config.pages;
collections = with lib; concatMap (collection: collection.entry) (attrValues config.collections); collections = with lib; concatMap (collection: collection.entry) (attrValues config.collections);
collections' = with lib; map
(
entry: recursiveUpdate entry {
locations = map (l: "${entry.collection.name}/${l}") entry.locations;
}
)
collections;
in in
with lib; foldl with lib; foldl
(acc: elem: acc // { (acc: elem: acc // {
"${head elem.locations}" = builtins.toFile "${elem.name}.html" elem.outputs.html; "${head elem.locations}" = builtins.toFile "${elem.name}.html" elem.outputs.html;
}) })
{ } { }
(pages ++ collections'); (pages ++ collections);
options.build = mkOption { options.build = mkOption {
description = '' description = ''

View file

@ -14,16 +14,16 @@ rec {
<body> <body>
</html> </html>
''; '';
nav = { menu }: nav = { page, menu }:
let let
render-item = item: render-item = item:
if item ? menu then if item ? menu then
'' ''
<li>${item.menu.label} <li>${item.menu.label}
${lib.indent " " (nav { menu = item; })} ${lib.indent " " (nav { inherit page; menu = item; })}
'' ''
else else
if item ? page then ''<li><a href="${item.page}">${item.page.title}</a></li>'' 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>'' else ''<li><a href="${item.link.url}">${item.link.label}</a></li>''
; ;
in in

View file

@ -27,9 +27,6 @@ in
}; };
}; };
config.name = lib.slug config.title; 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); config.outputs.html = lib.mkForce (cfg.templates.html.article cfg config);
}; };
} }

View file

@ -52,11 +52,23 @@ in
type = types.str; type = types.str;
default = name; default = name;
}; };
entry = mkOption { prefixes = mkOption {
description = ''
List of historic output locations for files in the collection
The first element is the canonical location.
All other elements are used to create redirects to the canonical location.
'';
type = with types; nonEmptyListOf str;
example = [ "." ];
};
entry = mkOption
{
description = "An entry in the collection"; description = "An entry in the collection";
type = types.collection (types.submodule ({ type = types.collection (types.submodule ({
_module.args.collection = config;
imports = [ config.type ]; imports = [ config.type ];
_module.args.collection = config;
process-locations = ls: with lib; concatMap (l: map (p: "${p}/${l}") config.prefixes) ls;
})); }));
}; };
}; };

View file

@ -6,7 +6,7 @@ let
; ;
in in
{ {
content-types.document = { name, config, link, ... }: { content-types.document = { name, config, options, link, ... }: {
config._module.args.link = config.link; config._module.args.link = config.link;
options = { options = {
name = mkOption { name = mkOption {
@ -17,7 +17,6 @@ in
# TODO: reconsider using `page.outPath` and what to put into `locations`. # TODO: reconsider using `page.outPath` and what to put into `locations`.
# maybe we can avoid having ".html" suffixes there. # maybe we can avoid having ".html" suffixes there.
# since templates can output multiple files, `html` is merely one of many things we *could* produce. # 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 { locations = mkOption {
description = '' description = ''
List of historic output locations for the resulting file List of historic output locations for the resulting file
@ -26,11 +25,17 @@ in
All other elements are used to create redirects to the canonical location. All other elements are used to create redirects to the canonical location.
''; '';
type = with types; nonEmptyListOf str; type = with types; nonEmptyListOf str;
apply = config.process-locations;
};
process-locations = mkOption {
description = "Function to post-process the output locations of contained document";
type = types.functionTo options.locations.type;
default = lib.id;
}; };
link = mkOption { link = mkOption {
description = "Helper function for transparent linking to other pages"; description = "Helper function for transparent linking to other pages";
type = with types; functionTo str; type = with types; functionTo str;
default = target: with lib; relativePath (head config.locations) (head target.locations); default = target: with lib; relativePath config.outPath target.outPath;
}; };
# TODO: may not need it when using `link`; could repurpose it to render the default template # TODO: may not need it when using `link`; could repurpose it to render the default template
outPath = mkOption { outPath = mkOption {

View file

@ -1,4 +1,4 @@
{ config, lib, ... }: { config, options, lib, ... }:
let let
inherit (lib) inherit (lib)
mkOption mkOption
@ -7,7 +7,12 @@ let
cfg = config; cfg = config;
subtype = baseModule: types.submodule [ subtype = baseModule: types.submodule [
baseModule baseModule
{ _module.freeformType = types.attrs; } {
_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 in
{ {