a
This commit is contained in:
parent
d30b078411
commit
ea64bc70fc
54
css.nix
54
css.nix
@ -1,19 +1,43 @@
|
||||
{utils}: let
|
||||
inherit (utils) mapAttrsToList concatStringsSep isList toString map;
|
||||
{lib, ...}: let
|
||||
l = lib // builtins;
|
||||
t = l.types;
|
||||
|
||||
evalCssValue = value:
|
||||
if isList value
|
||||
then concatStringsSep ", " (map toString value)
|
||||
else toString value;
|
||||
evalInner = inner: concatStringsSep " " (mapAttrsToList (name: value: "${name}: ${evalCssValue value};") inner);
|
||||
css = maybeAttrs:
|
||||
if isList maybeAttrs
|
||||
then concatStringsSep " " maybeAttrs
|
||||
else concatStringsSep " " (mapAttrsToList (name: inner: "${name} { ${evalInner inner} }") maybeAttrs);
|
||||
if l.isList value
|
||||
then l.concatStringsSep ", " (l.map toString value)
|
||||
else l.toString value;
|
||||
evalInner = inner:
|
||||
l.concatStringsSep
|
||||
" "
|
||||
(
|
||||
l.mapAttrsToList
|
||||
(name: value: "${name}: ${evalCssValue value};")
|
||||
inner
|
||||
);
|
||||
eval = maybeAttrs:
|
||||
if l.isList maybeAttrs
|
||||
then l.concatStringsSep " " maybeAttrs
|
||||
else
|
||||
l.concatStringsSep
|
||||
" "
|
||||
(
|
||||
l.mapAttrsToList
|
||||
(name: inner: "${name} { ${evalInner inner} }")
|
||||
maybeAttrs
|
||||
);
|
||||
css = {
|
||||
__functor = self: arg: eval arg;
|
||||
media = rule: inner: ''
|
||||
@media (${rule}) { ${eval inner} }
|
||||
'';
|
||||
};
|
||||
in {
|
||||
inherit css;
|
||||
|
||||
media = rule: inner: ''
|
||||
@media (${rule}) { ${css inner} }
|
||||
'';
|
||||
options = {
|
||||
html-nix.lib.css = l.mkOption {
|
||||
type = t.functionTo t.str;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
html-nix.lib.css = css;
|
||||
};
|
||||
}
|
||||
|
8
default.nix
Normal file
8
default.nix
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
imports = [
|
||||
./html.nix
|
||||
./css.nix
|
||||
./pkgs-lib.nix
|
||||
./templaters/default.nix
|
||||
];
|
||||
}
|
15
examples/flake.nix
Normal file
15
examples/flake.nix
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
parts.url = "github:hercules-ci/flake-parts";
|
||||
};
|
||||
|
||||
outputs = inp:
|
||||
inp.parts.lib.mkFlake {inputs = inp;} {
|
||||
systems = ["x86_64-linux"];
|
||||
imports = [
|
||||
../default.nix
|
||||
./site.nix
|
||||
];
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
tags,
|
||||
pkgs,
|
||||
}:
|
||||
with pkgs.htmlNix; let
|
||||
index = with tags;
|
||||
html [
|
||||
(body [
|
||||
(p "Hello world!")
|
||||
(mkLink "./ex.html" "say bye")
|
||||
])
|
||||
];
|
||||
|
||||
ex = with tags;
|
||||
html [
|
||||
(body [
|
||||
(p "Bye world!")
|
||||
(mkLink "./index.html" "go back")
|
||||
])
|
||||
];
|
||||
|
||||
site = {
|
||||
"index.html" = index;
|
||||
"ex.html" = ex;
|
||||
};
|
||||
in
|
||||
mkServeFromSite site
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
}: let
|
||||
inherit (pkgs) htmlNix;
|
||||
src = ./site;
|
||||
in
|
||||
htmlNix.mkServeFromSite (htmlNix.mkSiteFrom {
|
||||
inherit src;
|
||||
templater = lib.templaters.basic;
|
||||
local = true;
|
||||
})
|
||||
perSystem = {config, ...}: let
|
||||
html-nix = config.html-nix;
|
||||
siteServe = html-nix.mkServeFromSite (html-nix.mkSiteFrom {
|
||||
src = ./site;
|
||||
templater = html-nix.lib.templaters.basic;
|
||||
local = true;
|
||||
});
|
||||
in {
|
||||
apps.site.program = "${siteServe}/bin/serve";
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
tags:
|
||||
with tags;
|
||||
html [
|
||||
(body [
|
||||
(p "Hello,")
|
||||
(p "world!")
|
||||
])
|
||||
]
|
120
flake.lock
120
flake.lock
@ -1,27 +1,28 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flakeUtils": {
|
||||
"examples": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"parts": "parts"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1644229661,
|
||||
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
|
||||
"type": "github"
|
||||
"lastModified": 1,
|
||||
"narHash": "sha256-agjsV0F6nVUimGUciKlOSF35XvTOQKKEez0xZ8X0JBI=",
|
||||
"path": "./examples",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
"path": "./examples",
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1644972330,
|
||||
"narHash": "sha256-6V2JFpTUzB9G+KcqtUR1yl7f6rd9495YrFECslEmbGw=",
|
||||
"lastModified": 1680668850,
|
||||
"narHash": "sha256-mQMg13yRsS0LXVzaeoSPwqgPO6yhkGzGewPgMSqXSv8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "19574af0af3ffaf7c9e359744ed32556f34536bd",
|
||||
"rev": "4a65e9f64e53fdca6eed31adba836717a11247d2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -31,10 +32,99 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1680213900,
|
||||
"narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e3652e0735fbec227f342712f180f4f21f0594f2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib_2": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1680213900,
|
||||
"narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e3652e0735fbec227f342712f180f4f21f0594f2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1680668850,
|
||||
"narHash": "sha256-mQMg13yRsS0LXVzaeoSPwqgPO6yhkGzGewPgMSqXSv8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4a65e9f64e53fdca6eed31adba836717a11247d2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680392223,
|
||||
"narHash": "sha256-n3g7QFr85lDODKt250rkZj2IFS3i4/8HBU2yKHO3tqw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "dcc36e45d054d7bb554c9cdab69093debd91a0b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680392223,
|
||||
"narHash": "sha256-n3g7QFr85lDODKt250rkZj2IFS3i4/8HBU2yKHO3tqw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "dcc36e45d054d7bb554c9cdab69093debd91a0b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flakeUtils": "flakeUtils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"examples": "examples",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"parts": "parts_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
58
flake.nix
58
flake.nix
@ -1,57 +1,17 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
flakeUtils.url = "github:numtide/flake-utils";
|
||||
parts.url = "github:hercules-ci/flake-parts";
|
||||
examples.url = "path:./examples";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
flakeUtils,
|
||||
nixpkgs,
|
||||
}: let
|
||||
utils = import ./utils.nix;
|
||||
|
||||
lib = {
|
||||
# Convert Nix expressions to HTML
|
||||
tags = import ./tags.nix {inherit utils;};
|
||||
# Convert Nix expressions to CSS
|
||||
css = import ./css.nix {inherit utils;};
|
||||
|
||||
# Various site templaters
|
||||
templaters = {
|
||||
# Basic templater with purecss, mobile responsive layout and supports posts
|
||||
basic = import ./templaters/basic.nix;
|
||||
outputs = inp:
|
||||
inp.parts.lib.mkFlake {inputs = inp;} {
|
||||
debug = true;
|
||||
systems = ["x86_64-linux"];
|
||||
flake = {
|
||||
flakeModule = ./default.nix;
|
||||
inherit (inp.examples) apps;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = flakeUtils.lib.eachDefaultSystem (system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in {
|
||||
lib = {
|
||||
pkgsLib = import ./pkgs-lib.nix {
|
||||
inherit pkgs;
|
||||
utils = utils // {inherit (lib) tags css;};
|
||||
};
|
||||
};
|
||||
|
||||
apps = with flakeUtils.lib; {
|
||||
site = mkApp {
|
||||
drv = import ./examples/site.nix {inherit lib pkgs;};
|
||||
name = "serve";
|
||||
};
|
||||
basicServe = mkApp {
|
||||
drv = import ./examples/serve.nix {
|
||||
inherit (lib) tags;
|
||||
inherit pkgs;
|
||||
};
|
||||
name = "serve";
|
||||
};
|
||||
};
|
||||
|
||||
examples = {
|
||||
tags = import ./examples/tags.nix lib.tags;
|
||||
};
|
||||
});
|
||||
in
|
||||
outputs // {lib = outputs.lib // lib;};
|
||||
}
|
||||
|
49
html.nix
Normal file
49
html.nix
Normal file
@ -0,0 +1,49 @@
|
||||
{lib, ...}: let
|
||||
l = lib // builtins;
|
||||
|
||||
evalAttrs = attrs:
|
||||
l.concatStrings
|
||||
(
|
||||
l.mapAttrsToList
|
||||
(name: value: " ${name}=\"${value}\"")
|
||||
attrs
|
||||
);
|
||||
evalChildren = children:
|
||||
if l.isList children
|
||||
then l.concatStrings children
|
||||
else children;
|
||||
tag = name: maybeAttrs:
|
||||
if l.isAttrs maybeAttrs
|
||||
then (children: "<${name}${evalAttrs maybeAttrs}>${evalChildren children}</${name}>")
|
||||
else tag name {} maybeAttrs;
|
||||
noChildrenTag = name: attrs: "<${name} ${evalAttrs attrs}>";
|
||||
|
||||
tagsToGen =
|
||||
(l.map (n: "h${toString n}") (l.range 1 6))
|
||||
++ ["ul" "li" "html" "head" "body" "div" "p"]
|
||||
++ ["a" "title" "code" "pre" "nav" "article" "script"];
|
||||
tags = l.genAttrs tag tagsToGen;
|
||||
|
||||
noChildrenTagsToGen = ["link" "meta"];
|
||||
noChildrenTags = l.genAttrs noChildrenTag noChildrenTagsToGen;
|
||||
in {
|
||||
options = {
|
||||
html-nix.lib.html = l.mkOption {
|
||||
type = l.types.raw;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
html-nix.lib.html =
|
||||
tags
|
||||
// noChildrenTags
|
||||
// {
|
||||
inherit tag;
|
||||
mkLink = url: tags.a {href = url;};
|
||||
mkStylesheet = url:
|
||||
noChildrenTags.link {
|
||||
rel = "stylesheet";
|
||||
href = url;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
198
pkgs-lib.nix
198
pkgs-lib.nix
@ -1,97 +1,117 @@
|
||||
{
|
||||
utils,
|
||||
pkgs,
|
||||
lib,
|
||||
flake-parts-lib,
|
||||
...
|
||||
}: let
|
||||
pkgBin = name: "${pkgs.${name}}/bin/${name}";
|
||||
|
||||
mkServePathScript = path:
|
||||
pkgs.writeScriptBin "serve" ''
|
||||
${pkgs.nodePackages.http-server}/bin/http-server -c-1 ${path}
|
||||
'';
|
||||
|
||||
mkSitePath = site: let
|
||||
inherit (utils) recursiveAttrPaths concatStringsSep map;
|
||||
inherit (pkgs.lib) mapAttrsRecursive init last getAttrFromPath;
|
||||
|
||||
convertToPath = path: value:
|
||||
if builtins.isPath value
|
||||
then value
|
||||
else pkgs.writeText (concatStringsSep "-" path) value;
|
||||
fileAttrPaths = recursiveAttrPaths site;
|
||||
texts = mapAttrsRecursive convertToPath site;
|
||||
mkCreateFileCmd = path: value: let p = concatStringsSep "/" (init path); in "mkdir -p \"$out/${p}\" && ln -s \"${value}\" \"$out/${p}/${last path}\"";
|
||||
createFileCmds = map (path: mkCreateFileCmd path (getAttrFromPath path texts)) fileAttrPaths;
|
||||
in
|
||||
pkgs.runCommandLocal "site-path" {} ''
|
||||
mkdir -p $out
|
||||
${concatStringsSep "\n" createFileCmds}
|
||||
'';
|
||||
|
||||
parseMarkdown = name: contents:
|
||||
pkgs.runCommandLocal name {} ''
|
||||
printf ${pkgs.lib.escapeShellArg contents} | ${pkgBin "pandoc"} -f gfm > $out
|
||||
'';
|
||||
l = lib // builtins;
|
||||
in {
|
||||
inherit mkServePathScript mkSitePath parseMarkdown;
|
||||
options = {
|
||||
perSystem =
|
||||
flake-parts-lib.mkPerSystemOption
|
||||
({...}: {
|
||||
html-nix.lib = {
|
||||
mkServeFromSite = l.mkOption {
|
||||
type = with l.types; functionTo package;
|
||||
};
|
||||
mkSiteFrom = l.mkOption {
|
||||
type = with l.types; functionTo attrs;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
config = {
|
||||
perSystem = {pkgs, ...}: let
|
||||
pkgBin = name: "${pkgs.${name}}/bin/${name}";
|
||||
|
||||
mkServeFromSite = site: mkServePathScript (mkSitePath site);
|
||||
mkSiteFrom = {
|
||||
src,
|
||||
templater,
|
||||
local ? false,
|
||||
}: let
|
||||
inherit (utils) readDir readFile fromTOML mapAttrsToList sort elemAt;
|
||||
inherit (pkgs.lib) nameValuePair head splitString pipe removeSuffix mapAttrs';
|
||||
|
||||
postsRendered = let
|
||||
path = src + "/posts";
|
||||
in
|
||||
pipe (readDir path) [
|
||||
(mapAttrsToList (
|
||||
name: _:
|
||||
nameValuePair
|
||||
(head (splitString "." name))
|
||||
(readFile (parseMarkdown name (readFile (path + "/${name}"))))
|
||||
))
|
||||
(sort (
|
||||
p: op: let
|
||||
extractDate = name: splitString "-" (head (splitString "_" name));
|
||||
getPart = name: el: removeSuffix "0" (elemAt (extractDate name) el);
|
||||
d = getPart p.name;
|
||||
od = getPart op.name;
|
||||
in
|
||||
!(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2)))
|
||||
))
|
||||
];
|
||||
pagesRendered = let
|
||||
path = src + "/pages";
|
||||
in
|
||||
mapAttrs'
|
||||
(
|
||||
name: _:
|
||||
nameValuePair
|
||||
(head (splitString "." name))
|
||||
(readFile (parseMarkdown name (readFile (path + "/${name}"))))
|
||||
)
|
||||
(readDir path);
|
||||
siteConfig = fromTOML (readFile (src + "/config.toml"));
|
||||
baseurl =
|
||||
if local
|
||||
then "http://localhost:8080"
|
||||
else siteConfig.baseurl or (throw "Need baseurl");
|
||||
|
||||
context = {
|
||||
inherit utils pkgs baseurl;
|
||||
config = siteConfig;
|
||||
posts = postsRendered;
|
||||
pages = pagesRendered;
|
||||
site = {
|
||||
"robots.txt" = ''
|
||||
User-agent: *
|
||||
Allow: /
|
||||
mkServePathScript = path:
|
||||
pkgs.writeScriptBin "serve" ''
|
||||
${pkgs.nodePackages.http-server}/bin/http-server -c-1 ${path}
|
||||
'';
|
||||
|
||||
mkSitePath = site: let
|
||||
convertToPath = path: value:
|
||||
if builtins.isPath value
|
||||
then value
|
||||
else pkgs.writeText (l.concatStringsSep "-" path) value;
|
||||
fileAttrPaths = l.recursiveAttrPaths site;
|
||||
texts = l.mapAttrsRecursive convertToPath site;
|
||||
mkCreateFileCmd = path: value: let
|
||||
p = l.concatStringsSep "/" (l.init path);
|
||||
in "mkdir -p \"$out/${p}\" && ln -s \"${value}\" \"$out/${p}/${l.last path}\"";
|
||||
createFileCmds =
|
||||
l.map
|
||||
(path: mkCreateFileCmd path (l.getAttrFromPath path texts))
|
||||
fileAttrPaths;
|
||||
in
|
||||
pkgs.runCommandLocal "site-path" {} ''
|
||||
mkdir -p $out
|
||||
${l.concatStringsSep "\n" createFileCmds}
|
||||
'';
|
||||
|
||||
parseMarkdown = name: contents:
|
||||
pkgs.runCommandLocal name {} ''
|
||||
printf ${l.escapeShellArg contents} | ${pkgBin "pandoc"} -f gfm > $out
|
||||
'';
|
||||
in {
|
||||
html-nix.lib = {
|
||||
mkServeFromSite = site: mkServePathScript (mkSitePath site);
|
||||
mkSiteFrom = {
|
||||
src,
|
||||
templater,
|
||||
local ? false,
|
||||
}: let
|
||||
postsRendered = let
|
||||
path = src + "/posts";
|
||||
in
|
||||
l.pipe (l.readDir path) [
|
||||
(l.mapAttrsToList (
|
||||
name: _:
|
||||
l.nameValuePair
|
||||
(l.head (l.splitString "." name))
|
||||
(l.readFile (parseMarkdown name (l.readFile (path + "/${name}"))))
|
||||
))
|
||||
(l.sort (
|
||||
p: op: let
|
||||
extractDate = name: l.splitString "-" (l.head (l.splitString "_" name));
|
||||
getPart = name: el: l.removeSuffix "0" (l.elemAt (extractDate name) el);
|
||||
d = getPart p.name;
|
||||
od = getPart op.name;
|
||||
in
|
||||
!(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2)))
|
||||
))
|
||||
];
|
||||
pagesRendered = let
|
||||
path = src + "/pages";
|
||||
in
|
||||
l.mapAttrs'
|
||||
(
|
||||
name: _:
|
||||
l.nameValuePair
|
||||
(l.head (l.splitString "." name))
|
||||
(l.readFile (parseMarkdown name (l.readFile (path + "/${name}"))))
|
||||
)
|
||||
(l.readDir path);
|
||||
siteConfig = l.fromTOML (l.readFile (src + "/config.toml"));
|
||||
baseurl =
|
||||
if local
|
||||
then "http://localhost:8080"
|
||||
else siteConfig.baseurl or (throw "Need baseurl");
|
||||
|
||||
context = {
|
||||
inherit lib baseurl;
|
||||
config = siteConfig;
|
||||
posts = postsRendered;
|
||||
pages = pagesRendered;
|
||||
site = {
|
||||
"robots.txt" = ''
|
||||
User-agent: *
|
||||
Allow: /
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
(templater context).site;
|
||||
};
|
||||
};
|
||||
in
|
||||
(templater context).site;
|
||||
};
|
||||
}
|
||||
|
34
tags.nix
34
tags.nix
@ -1,34 +0,0 @@
|
||||
{utils}: let
|
||||
inherit (utils) concatStrings mapAttrsToList genAttrs isAttrs isList range toString;
|
||||
|
||||
evalAttrs = attrs: concatStrings (mapAttrsToList (name: value: " ${name}=\"${value}\"") attrs);
|
||||
evalChildren = children:
|
||||
if isList children
|
||||
then concatStrings children
|
||||
else children;
|
||||
tag = name: maybeAttrs:
|
||||
if isAttrs maybeAttrs
|
||||
then (children: "<${name}${evalAttrs maybeAttrs}>${evalChildren children}</${name}>")
|
||||
else tag name {} maybeAttrs;
|
||||
noChildrenTag = name: attrs: "<${name} ${evalAttrs attrs}>";
|
||||
|
||||
tagsToGen =
|
||||
(map (n: "h${toString n}") (range 1 6))
|
||||
++ ["ul" "li" "html" "head" "body" "div" "p"]
|
||||
++ ["a" "title" "code" "pre" "nav" "article" "script"];
|
||||
tags = genAttrs tag tagsToGen;
|
||||
|
||||
noChildrenTagsToGen = ["link" "meta"];
|
||||
noChildrenTags = genAttrs noChildrenTag noChildrenTagsToGen;
|
||||
in
|
||||
tags
|
||||
// noChildrenTags
|
||||
// {
|
||||
inherit tag;
|
||||
mkLink = url: tags.a {href = url;};
|
||||
mkStylesheet = url:
|
||||
noChildrenTags.link {
|
||||
rel = "stylesheet";
|
||||
href = url;
|
||||
};
|
||||
}
|
@ -1,207 +1,222 @@
|
||||
{
|
||||
utils,
|
||||
posts,
|
||||
pkgs,
|
||||
config,
|
||||
pages,
|
||||
site,
|
||||
baseurl,
|
||||
lib,
|
||||
...
|
||||
} @ context: let
|
||||
inherit (utils) readFile mapAttrsToList mapAttrs tags fetchGit map elemAt foldl' concatStrings genAttrs toString;
|
||||
inherit (pkgs.lib) optionalString optionalAttrs optional length splitString nameValuePair toInt range mapAttrs' singleton;
|
||||
inherit (builtins) listToAttrs;
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
t = l.types;
|
||||
inherit (config.html-nix.lib) html css;
|
||||
|
||||
stylesheets = map tags.mkStylesheet [
|
||||
"https://unpkg.com/purecss@2.0.6/build/pure-min.css"
|
||||
"https://unpkg.com/purecss@2.0.6/build/grids-responsive-min.css"
|
||||
"${baseurl}/site.css"
|
||||
];
|
||||
func = ctx: let
|
||||
stylesheets = l.map html.mkStylesheet [
|
||||
"https://unpkg.com/purecss@3.0.0/build/pure-min.css"
|
||||
"https://unpkg.com/purecss@3.0.0/build/grids-responsive-min.css"
|
||||
"${ctx.baseurl}/site.css"
|
||||
];
|
||||
|
||||
parsePostName = name: let
|
||||
parts = splitString "_" name;
|
||||
id = elemAt parts 1;
|
||||
date = elemAt parts 0;
|
||||
in {
|
||||
inherit id date;
|
||||
formatted = "${date} - ${id}";
|
||||
};
|
||||
parsePostName = name: let
|
||||
parts = l.splitString "_" name;
|
||||
id = l.elemAt parts 1;
|
||||
date = l.elemAt parts 0;
|
||||
in {
|
||||
inherit id date;
|
||||
formatted = "${date} - ${id}";
|
||||
};
|
||||
|
||||
renderPost = {
|
||||
name,
|
||||
value,
|
||||
}: let
|
||||
parsed = parsePostName name;
|
||||
inherit (parsed) id date;
|
||||
in
|
||||
with tags;
|
||||
article [
|
||||
(a {
|
||||
href = "#${id}";
|
||||
class = "postheader";
|
||||
} (h2 {inherit id;} id))
|
||||
(h3 ("date: " + date))
|
||||
value
|
||||
renderPost = {
|
||||
name,
|
||||
value,
|
||||
}: let
|
||||
parsed = parsePostName name;
|
||||
inherit (parsed) id date;
|
||||
in
|
||||
with html;
|
||||
article [
|
||||
(a {
|
||||
href = "#${id}";
|
||||
class = "postheader";
|
||||
} (h2 {inherit id;} id))
|
||||
(h3 ("date: " + date))
|
||||
value
|
||||
];
|
||||
|
||||
pagesSection = with html;
|
||||
[
|
||||
(div {class = "pure-u-1";} (a {
|
||||
href = "${ctx.baseurl}/";
|
||||
class = "pagelink";
|
||||
} "home"))
|
||||
]
|
||||
++ (l.map
|
||||
(name:
|
||||
div {class = "pure-u-1";} (a {
|
||||
href = "${ctx.baseurl}/${name}/";
|
||||
class = "pagelink";
|
||||
}
|
||||
name))
|
||||
(l.mapAttrsToList (name: _: name) pages))
|
||||
++ [
|
||||
(div {class = "pure-u-1";} (a {
|
||||
href = "${ctx.baseurl}/posts/";
|
||||
class = "pagelink";
|
||||
} "posts"))
|
||||
];
|
||||
|
||||
pagesSection =
|
||||
[
|
||||
(tags.div {class = "pure-u-1";} (tags.a {
|
||||
href = "${baseurl}/";
|
||||
class = "pagelink";
|
||||
} "home"))
|
||||
]
|
||||
++ (map
|
||||
(name:
|
||||
tags.div {class = "pure-u-1";} (tags.a {
|
||||
href = "${baseurl}/${name}/";
|
||||
class = "pagelink";
|
||||
}
|
||||
name))
|
||||
(mapAttrsToList (name: _: name) pages))
|
||||
++ [
|
||||
(tags.div {class = "pure-u-1";} (tags.a {
|
||||
href = "${baseurl}/posts/";
|
||||
class = "pagelink";
|
||||
} "posts"))
|
||||
];
|
||||
postsLinks = with html;
|
||||
singleton
|
||||
(ul (
|
||||
l.map
|
||||
(
|
||||
post:
|
||||
li (
|
||||
a {href = "${ctx.baseurl}/${post.name}";}
|
||||
(parsePostName post.name).formatted
|
||||
)
|
||||
)
|
||||
posts
|
||||
));
|
||||
|
||||
postsRendered = map renderPost posts;
|
||||
|
||||
postsLinks = with tags;
|
||||
singleton
|
||||
(ul (
|
||||
map
|
||||
(
|
||||
post:
|
||||
li (
|
||||
a {href = "${baseurl}/${post.name}";}
|
||||
(parsePostName post.name).formatted
|
||||
)
|
||||
)
|
||||
posts
|
||||
));
|
||||
|
||||
postsSectionContent = with tags;
|
||||
[
|
||||
(a {
|
||||
href = "#posts";
|
||||
class = "postheader";
|
||||
} (h1 "posts"))
|
||||
]
|
||||
++ postsLinks;
|
||||
|
||||
sidebarSection = optionalString ((length pagesSection) > 0) (
|
||||
with tags;
|
||||
nav {class = "sidebar";} [
|
||||
(div {class = "pure-g";} pagesSection)
|
||||
postsSectionContent = with html;
|
||||
[
|
||||
(a {
|
||||
href = "#posts";
|
||||
class = "postheader";
|
||||
} (h1 "posts"))
|
||||
]
|
||||
);
|
||||
++ postsLinks;
|
||||
|
||||
mkPage = content:
|
||||
with tags; ''
|
||||
<!DOCTYPE html>
|
||||
${html [
|
||||
(head (stylesheets
|
||||
++ [
|
||||
(title config.title)
|
||||
(meta {
|
||||
name = "viewport";
|
||||
content = "width=device-width, initial-scale=1";
|
||||
})
|
||||
]))
|
||||
(body ''
|
||||
${script "0"}
|
||||
${sidebarSection}
|
||||
${div {class = "content";} content}
|
||||
'')
|
||||
]}
|
||||
'';
|
||||
|
||||
indexPage = mkPage (context.indexContent or postsSectionContent);
|
||||
|
||||
pagesAndPosts =
|
||||
pages
|
||||
// listToAttrs (
|
||||
map (post: nameValuePair post.name (renderPost post)) posts
|
||||
sidebarSection = l.optionalString ((l.length pagesSection) > 0) (
|
||||
with html;
|
||||
nav {class = "sidebar";} [
|
||||
(div {class = "pure-g";} pagesSection)
|
||||
]
|
||||
);
|
||||
|
||||
stylesheet = with utils.css; let
|
||||
marginMobile = {
|
||||
margin-left = "3%";
|
||||
margin-right = "3%";
|
||||
};
|
||||
in
|
||||
css [
|
||||
(css (
|
||||
(
|
||||
mapAttrs'
|
||||
(name: value: nameValuePair value {content = "\"${concatStrings (map (_: "#") (range 1 (toInt name)))} \"";})
|
||||
(genAttrs (n: "h${toString n}:before") (map toString (range 1 6)))
|
||||
)
|
||||
// {
|
||||
body = {
|
||||
font-family = ["Raleway" "Helvetica" "Arial" "sans-serif"];
|
||||
background = "#111111";
|
||||
color = "#eeeeee";
|
||||
};
|
||||
pre = {
|
||||
font-family = ["Iosevka Term" "Iosevka" "monospace"];
|
||||
background = "#171A21";
|
||||
color = "#eeeeee";
|
||||
};
|
||||
"a,a:hover" = {
|
||||
color = "#ffd814";
|
||||
text-decoration = "none";
|
||||
};
|
||||
"a:hover" = {
|
||||
text-decoration = "underline";
|
||||
};
|
||||
"a.postheader,a.postheader:hover" = {
|
||||
color = "#fc6711";
|
||||
};
|
||||
"a.pagelink,a.pagelink:hover" = {
|
||||
color = "#ffd814";
|
||||
};
|
||||
"div.content" = {
|
||||
margin-top = "5%";
|
||||
margin-bottom = "5%";
|
||||
margin-left = "20%";
|
||||
margin-right = "25%";
|
||||
};
|
||||
"nav.sidebar" = {
|
||||
position = "fixed";
|
||||
margin-left = "3%";
|
||||
padding-top = 0;
|
||||
z-index = 1000;
|
||||
};
|
||||
}
|
||||
))
|
||||
(media "max-width: 48em" {
|
||||
"nav.sidebar" =
|
||||
{
|
||||
position = "relative";
|
||||
margin-top = "5%";
|
||||
}
|
||||
// marginMobile;
|
||||
"div.content" =
|
||||
{
|
||||
margin-top = 0;
|
||||
}
|
||||
// marginMobile;
|
||||
})
|
||||
];
|
||||
in {
|
||||
inherit stylesheets sidebarSection mkPage stylesheet;
|
||||
mkPage = content:
|
||||
with html; ''
|
||||
<!DOCTYPE html>
|
||||
${html [
|
||||
(head (stylesheets
|
||||
++ [
|
||||
(title ctx.config.title)
|
||||
(meta {
|
||||
name = "viewport";
|
||||
content = "width=device-width, initial-scale=1";
|
||||
})
|
||||
]))
|
||||
(body ''
|
||||
${script "0"}
|
||||
${sidebarSection}
|
||||
${div {class = "content";} content}
|
||||
'')
|
||||
]}
|
||||
'';
|
||||
|
||||
site =
|
||||
site
|
||||
// {
|
||||
"index.html" = indexPage;
|
||||
"posts"."index.html" = mkPage postsSectionContent;
|
||||
"404.html" = mkPage (tags.h1 "No such page");
|
||||
"site.css" = stylesheet;
|
||||
}
|
||||
// (mapAttrs (name: value: {"index.html" = mkPage value;}) pagesAndPosts)
|
||||
// optionalAttrs (context ? resources) {inherit (context) resources;};
|
||||
indexPage = mkPage (ctx.indexContent or postsSectionContent);
|
||||
|
||||
pagesAndPosts =
|
||||
ctx.pages
|
||||
// l.listToAttrs (
|
||||
map (post: l.nameValuePair post.name (renderPost post)) ctx.posts
|
||||
);
|
||||
|
||||
stylesheet = let
|
||||
marginMobile = {
|
||||
margin-left = "3%";
|
||||
margin-right = "3%";
|
||||
};
|
||||
in
|
||||
css [
|
||||
(css (
|
||||
(
|
||||
l.mapAttrs'
|
||||
(
|
||||
name: value:
|
||||
l.nameValuePair
|
||||
value
|
||||
{
|
||||
content = "\"${l.concatStrings (l.map (_: "#") (l.range 1 (l.toInt name)))} \"";
|
||||
}
|
||||
)
|
||||
(
|
||||
l.genAttrs
|
||||
(n: "h${l.toString n}:before")
|
||||
(l.map l.toString (l.range 1 6))
|
||||
)
|
||||
)
|
||||
// {
|
||||
body = {
|
||||
font-family = ["Raleway" "Helvetica" "Arial" "sans-serif"];
|
||||
background = "#111111";
|
||||
color = "#eeeeee";
|
||||
};
|
||||
pre = {
|
||||
font-family = ["Iosevka Term" "Iosevka" "monospace"];
|
||||
background = "#171A21";
|
||||
color = "#eeeeee";
|
||||
};
|
||||
"a,a:hover" = {
|
||||
color = "#ffd814";
|
||||
text-decoration = "none";
|
||||
};
|
||||
"a:hover" = {
|
||||
text-decoration = "underline";
|
||||
};
|
||||
"a.postheader,a.postheader:hover" = {
|
||||
color = "#fc6711";
|
||||
};
|
||||
"a.pagelink,a.pagelink:hover" = {
|
||||
color = "#ffd814";
|
||||
};
|
||||
"div.content" = {
|
||||
margin-top = "5%";
|
||||
margin-bottom = "5%";
|
||||
margin-left = "20%";
|
||||
margin-right = "25%";
|
||||
};
|
||||
"nav.sidebar" = {
|
||||
position = "fixed";
|
||||
margin-left = "3%";
|
||||
padding-top = 0;
|
||||
z-index = 1000;
|
||||
};
|
||||
}
|
||||
))
|
||||
(css.media "max-width: 48em" {
|
||||
"nav.sidebar" =
|
||||
{
|
||||
position = "relative";
|
||||
margin-top = "5%";
|
||||
}
|
||||
// marginMobile;
|
||||
"div.content" =
|
||||
{
|
||||
margin-top = 0;
|
||||
}
|
||||
// marginMobile;
|
||||
})
|
||||
];
|
||||
in {
|
||||
inherit stylesheets sidebarSection mkPage stylesheet;
|
||||
|
||||
site =
|
||||
ctx.site
|
||||
// {
|
||||
"index.html" = indexPage;
|
||||
"posts"."index.html" = mkPage postsSectionContent;
|
||||
"404.html" = mkPage (html.h1 "No such page");
|
||||
"site.css" = stylesheet;
|
||||
}
|
||||
// (l.mapAttrs (name: value: {"index.html" = mkPage value;}) pagesAndPosts)
|
||||
// l.optionalAttrs (ctx ? resources) {inherit (ctx) resources;};
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
html-nix.lib.templaters.basic = l.mkOption {
|
||||
type = t.functionTo t.attrs;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
html-nix.lib.templaters.basic = func;
|
||||
};
|
||||
}
|
||||
|
5
templaters/default.nix
Normal file
5
templaters/default.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
imports = [
|
||||
./basic.nix
|
||||
];
|
||||
}
|
38
utils.nix
38
utils.nix
@ -1,38 +0,0 @@
|
||||
let
|
||||
inherit (builtins) isAttrs isList map any concatMap concatStringsSep listToAttrs genList;
|
||||
|
||||
mapAttrsToList = f: attrs: map (name: f name attrs.${name}) (builtins.attrNames attrs);
|
||||
in
|
||||
{
|
||||
inherit mapAttrsToList;
|
||||
|
||||
recursiveAttrPaths = set: let
|
||||
flattenIfHasList = x:
|
||||
if (isList x) && (any isList x)
|
||||
then concatMap flattenIfHasList x
|
||||
else [x];
|
||||
|
||||
recurse = path: set: let
|
||||
g = name: value:
|
||||
if isAttrs value
|
||||
then recurse (path ++ [name]) value
|
||||
else path ++ [name];
|
||||
in
|
||||
mapAttrsToList g set;
|
||||
in
|
||||
flattenIfHasList (recurse [] set);
|
||||
|
||||
concatStrings = concatStringsSep "";
|
||||
genAttrs = f: names:
|
||||
listToAttrs (map (n: {
|
||||
name = n;
|
||||
value = f n;
|
||||
})
|
||||
names);
|
||||
|
||||
range = first: last:
|
||||
if first > last
|
||||
then []
|
||||
else genList (n: first + n) (last - first + 1);
|
||||
}
|
||||
// builtins
|
Loading…
Reference in New Issue
Block a user