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);
|
imports = with lib.fileset; toList (difference (fileFilter ({ hasExt, ... }: hasExt "nix") ./.) ./default.nix);
|
||||||
|
|
||||||
|
collections.news.type = config.content-types.article;
|
||||||
|
|
||||||
pages.index = {
|
pages.index = {
|
||||||
title = "Fediversity";
|
title = "Fediversity";
|
||||||
locations = [
|
locations = [
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
, lib ? import "${sources.nixpkgs}/lib"
|
, lib ? import "${sources.nixpkgs}/lib"
|
||||||
}:
|
}:
|
||||||
let
|
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';
|
lib'' = lib.extend lib';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
44
lib.nix
44
lib.nix
|
@ -37,4 +37,48 @@ rec {
|
||||||
|
|
||||||
indent = prefix: s:
|
indent = prefix: s:
|
||||||
join "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines 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
|
types
|
||||||
;
|
;
|
||||||
cfg = config;
|
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
|
in
|
||||||
{
|
{
|
||||||
# TODO: split out:
|
imports = [ ./content-types.nix ];
|
||||||
# - 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;
|
|
||||||
|
|
||||||
options.pages = mkOption {
|
options.pages = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Collection of pages on the site
|
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
|
options.collections = mkOption
|
||||||
|
@ -115,7 +29,7 @@ in
|
||||||
};
|
};
|
||||||
entry = mkOption {
|
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.entry;
|
_module.args.collection = config.entry;
|
||||||
_module.args.collectionName = name;
|
_module.args.collectionName = name;
|
||||||
imports = [ config.type ];
|
imports = [ config.type ];
|
||||||
|
@ -222,7 +136,6 @@ in
|
||||||
in
|
in
|
||||||
pages // collections;
|
pages // collections;
|
||||||
|
|
||||||
|
|
||||||
options.build = mkOption {
|
options.build = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
The final output of the web site
|
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