nixite/nixite/html.nix

87 lines
2 KiB
Nix

let
keyvalue = key: value:
assert builtins.isString key;
if builtins.isAttrs value
then builtins.trace "Skipping ${key} as it is a set" ""
else if value == "" || value == [] || value == false
then ""
else if value == true
then key
else ''${key}="${toString value}"'';
in rec {
toHTML = elem:
if builtins.isString elem
then elem
else if builtins.isList elem
then builtins.toString (map toHTML elem)
else "<${elem.tag} ${writeAttrs elem.attrs or {}}>${
toHTML elem.child or ""
}</${elem.tag}>";
writeAttrs = attrs:
toString (builtins.filter (value: value != "") (builtins.attrValues
(builtins.mapAttrs (key: value:
if (builtins.isPath value)
then keyvalue key (baseNameOf value)
else if (builtins.substring 0 2 key) == "__"
then ""
else keyvalue key value)
attrs)));
tag = t: ({
tag = t;
attrs = {};
}
// baseTag);
baseTag = {
__toString = self: toString (self "");
__functor = self: child: (
if !(isTag child)
then
(
if isSet child
then incorporateAttrs self child
else
throw "tag child must be tag, list, or string, got ${
builtins.typeOf child
}"
)
else
self
// {
inherit child;
__toString = toHTML;
}
);
};
incorporateAttrs = self: attrs: self // {attrs = self.attrs // attrs;};
isSet = a: builtins.isAttrs a && !a ? __toString;
isTag = tag: (builtins.isString tag
|| builtins.isList tag
|| (tag ? __toString && builtins.isFunction tag.__toString));
addToHead = doc: heads:
doc
// {
head = doc.head ++ heads;
};
document = {
head ? [],
body ? [],
attrs ? {},
}: {
inherit head body attrs;
__toString = self: ''
<!DOCTYPE html>
${(tag "html" [
(tag "head" self.head)
(tag "body" self.body)
])}
'';
};
}