forked from Fediversity/fediversity.eu
Compare commits
2 commits
72fe2e9639
...
61709abeb5
Author | SHA1 | Date | |
---|---|---|---|
61709abeb5 | |||
2d1fa43c67 |
|
@ -5,6 +5,8 @@ in
|
|||
{
|
||||
imports = with lib.fileset; toList (difference (fileFilter ({ hasExt, ... }: hasExt "nix") ./.) ./default.nix);
|
||||
|
||||
collections.news.type = config.content-types.article;
|
||||
|
||||
pages.index = {
|
||||
title = "Fediversity";
|
||||
locations = [
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
, lib ? import "${sources.nixpkgs}/lib"
|
||||
}:
|
||||
let
|
||||
lib' = final: prev: import ./lib.nix { lib = final; };
|
||||
lib' = final: prev:
|
||||
let
|
||||
new = import ./lib.nix { lib = final; };
|
||||
in
|
||||
new // { types = prev.recursiveUpdate prev.types new.types; };
|
||||
lib'' = lib.extend lib';
|
||||
in
|
||||
{
|
||||
|
|
44
lib.nix
44
lib.nix
|
@ -37,4 +37,48 @@ rec {
|
|||
|
||||
indent = prefix: s:
|
||||
join "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s));
|
||||
|
||||
types = rec {
|
||||
collection = elemType:
|
||||
let
|
||||
unparenthesize = class: class == "noun";
|
||||
desc = type:
|
||||
types.optionDescriptionPhrase unparenthesize type;
|
||||
desc' = type:
|
||||
let
|
||||
typeDesc = lib.types.optionDescriptionPhrase unparenthesize type;
|
||||
in
|
||||
if type.descriptionClass == "noun"
|
||||
then
|
||||
typeDesc + "s"
|
||||
else
|
||||
"many instances of ${typeDesc}";
|
||||
in
|
||||
lib.types.mkOptionType {
|
||||
name = "collection";
|
||||
description = "separately specified ${desc elemType} for a collection of ${desc' elemType}";
|
||||
merge = loc: defs:
|
||||
map
|
||||
(def:
|
||||
let
|
||||
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;
|
||||
check = elemType.check;
|
||||
getSubOptions = elemType.getSubOptions;
|
||||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: collection (elemType.substSubModules m);
|
||||
functor = (lib.defaultFunctor "collection") // {
|
||||
type = collection;
|
||||
wrapped = elemType;
|
||||
payload = { };
|
||||
};
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
97
structure/content-types.nix
Normal file
97
structure/content-types.nix
Normal file
|
@ -0,0 +1,97 @@
|
|||
{ 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 = {
|
||||
page = { name, config, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "Symbolic name for the page, used as a human-readable identifier";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
title = mkOption {
|
||||
description = "Page title";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
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: "TODO: compute the relative path based on `locations`";
|
||||
};
|
||||
outPath = mkOption {
|
||||
description = ''
|
||||
Location of the page, used for transparently creating links
|
||||
'';
|
||||
type = types.str;
|
||||
default = lib.head config.locations;
|
||||
};
|
||||
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;
|
||||
};
|
||||
template = mkOption {
|
||||
description = ''
|
||||
Function that converts the page contents to files
|
||||
'';
|
||||
type = with types; functionTo (functionTo options.files.type);
|
||||
default = cfg.templates.page;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
article = { config, collectionName, ... }: {
|
||||
imports = [ cfg.content-types.page ];
|
||||
options = {
|
||||
date = mkOption {
|
||||
description = "Publication date";
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
author = mkOption {
|
||||
description = "Page author";
|
||||
type = with types; nullOr (either str (listOf str));
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
config.name = lib.slug config.title;
|
||||
config.outPath = "${collectionName}/${lib.head config.locations}";
|
||||
config.template = cfg.templates.article;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -5,101 +5,15 @@ let
|
|||
types
|
||||
;
|
||||
cfg = config;
|
||||
types' = import ./types.nix { inherit lib; } // {
|
||||
article = { config, collectionName, ... }: {
|
||||
imports = [ types'.page ];
|
||||
options = {
|
||||
date = mkOption {
|
||||
description = "Publication date";
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
author = mkOption {
|
||||
description = "Page author";
|
||||
type = with types; nullOr (either str (listOf str));
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
config.name = lib.slug config.title;
|
||||
config.outPath = "${collectionName}/${lib.head config.locations}";
|
||||
config.template = cfg.templates.article;
|
||||
};
|
||||
|
||||
page = { name, config, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "Symbolic name for the page, used as a human-readable identifier";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
title = mkOption {
|
||||
description = "Page title";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
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: "TODO: compute the relative path based on `locations`";
|
||||
};
|
||||
outPath = mkOption {
|
||||
description = ''
|
||||
Location of the page, used for transparently creating links
|
||||
'';
|
||||
type = types.str;
|
||||
default = lib.head config.locations;
|
||||
};
|
||||
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;
|
||||
};
|
||||
template = mkOption
|
||||
{
|
||||
description = ''
|
||||
Function that converts the page contents to files
|
||||
'';
|
||||
type = with types; functionTo (functionTo options.files.type);
|
||||
default = cfg.templates.page;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
# TODO: split out:
|
||||
# - extra module system types into lib'
|
||||
# - page and article types into their own module values under structure/${page,article}.nix
|
||||
# yes, actually. those types should probably be configurable
|
||||
config.collections.news.type = types'.article;
|
||||
imports = [ ./content-types.nix ];
|
||||
|
||||
options.pages = mkOption {
|
||||
description = ''
|
||||
Collection of pages on the site
|
||||
'';
|
||||
type = with types; attrsOf (submodule types'.page);
|
||||
type = with types; attrsOf (submodule config.content-types.page);
|
||||
};
|
||||
|
||||
options.collections = mkOption
|
||||
|
@ -115,7 +29,7 @@ in
|
|||
};
|
||||
entry = mkOption {
|
||||
description = "An entry in the collection";
|
||||
type = types'.collection (types.submodule ({
|
||||
type = types.collection (types.submodule ({
|
||||
_module.args.collection = config.entry;
|
||||
_module.args.collectionName = name;
|
||||
imports = [ config.type ];
|
||||
|
@ -222,7 +136,6 @@ in
|
|||
in
|
||||
pages // collections;
|
||||
|
||||
|
||||
options.build = mkOption {
|
||||
description = ''
|
||||
The final output of the web site
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) types;
|
||||
in
|
||||
rec {
|
||||
collection = elemType:
|
||||
let
|
||||
unparenthesize = class: class == "noun";
|
||||
desc = type:
|
||||
types.optionDescriptionPhrase unparenthesize type;
|
||||
desc' = type:
|
||||
let
|
||||
typeDesc = types.optionDescriptionPhrase unparenthesize type;
|
||||
in
|
||||
if type.descriptionClass == "noun"
|
||||
then
|
||||
typeDesc + "s"
|
||||
else
|
||||
"many instances of ${typeDesc}";
|
||||
in
|
||||
types.mkOptionType {
|
||||
name = "collection";
|
||||
description = "separately specified ${desc elemType} for a collection of ${desc' elemType}";
|
||||
merge = loc: defs:
|
||||
map
|
||||
(def:
|
||||
let
|
||||
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;
|
||||
check = elemType.check;
|
||||
getSubOptions = elemType.getSubOptions;
|
||||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: collection (elemType.substSubModules m);
|
||||
functor = (lib.defaultFunctor "collection") // {
|
||||
type = collection;
|
||||
wrapped = elemType;
|
||||
payload = { };
|
||||
};
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
}
|
Reference in a new issue