Compare commits

..

2 Commits

Author SHA1 Message Date
46b3656161
write new templater 2023-04-06 05:43:25 +03:00
ea64bc70fc
a 2023-04-06 01:43:12 +03:00
17 changed files with 752 additions and 482 deletions

52
css.nix
View File

@ -1,19 +1,43 @@
{utils}: let {lib, ...}: let
inherit (utils) mapAttrsToList concatStringsSep isList toString map; l = lib // builtins;
t = l.types;
evalCssValue = value: evalCssValue = value:
if isList value if l.isList value
then concatStringsSep ", " (map toString value) then l.concatStringsSep ", " (l.map toString value)
else toString value; else l.toString value;
evalInner = inner: concatStringsSep " " (mapAttrsToList (name: value: "${name}: ${evalCssValue value};") inner); evalInner = inner:
css = maybeAttrs: l.concatStringsSep
if isList maybeAttrs " "
then concatStringsSep " " maybeAttrs (
else concatStringsSep " " (mapAttrsToList (name: inner: "${name} { ${evalInner inner} }") maybeAttrs); l.mapAttrsToList
in { (name: value: "${name}: ${evalCssValue value};")
inherit css; 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: inner: ''
@media (${rule}) { ${css inner} } @media (${rule}) { ${eval inner} }
''; '';
};
in {
options = {
html-nix.lib.css = l.mkOption {
type = t.raw;
};
};
config = {
html-nix.lib.css = css;
};
} }

8
default.nix Normal file
View File

@ -0,0 +1,8 @@
{
imports = [
./html.nix
./css.nix
./pkgs-lib.nix
./templaters
];
}

3
examples/default.nix Normal file
View File

@ -0,0 +1,3 @@
{
imports = [./site.nix];
}

View File

@ -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

View File

@ -1,12 +1,12 @@
{ topArgs: {
pkgs, perSystem = {config, ...}: let
lib, html-nix = config.html-nix.lib;
}: let siteServe = html-nix.mkServeFromSite (html-nix.mkSiteFrom {
inherit (pkgs) htmlNix;
src = ./site; src = ./site;
in templater = topArgs.config.html-nix.lib.templaters.simple;
htmlNix.mkServeFromSite (htmlNix.mkSiteFrom {
inherit src;
templater = lib.templaters.basic;
local = true; local = true;
}) });
in {
apps.site.program = "${siteServe}/bin/serve";
};
}

View File

@ -6,4 +6,6 @@ fn main() {
} }
``` ```
AAAAAAAAAAa `rust` `test` aaaaaaaaaaaa
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur condimentum felis risus, ac tempor eros mollis ac. Curabitur dictum justo magna, a tristique nibh euismod at. Nullam at laoreet quam, a facilisis massa. Vestibulum iaculis euismod lorem non consequat. Quisque elementum pharetra egestas. Mauris in enim facilisis, pretium lacus vitae, accumsan diam. Praesent ut finibus mauris, eget iaculis lorem. Cras pharetra lectus varius, volutpat odio sit amet, pulvinar lectus. Aliquam malesuada erat a enim rutrum viverra. Nullam blandit nec enim eu egestas. Duis venenatis aliquet cursus. Phasellus non posuere lectus, sed rhoncus mi. Quisque ut ornare dui. Ut eget elit ac leo aliquam aliquam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur condimentum felis risus, ac tempor eros mollis ac. Curabitur dictum justo magna, a tristique nibh euismod at. Nullam at laoreet quam, a facilisis massa. Vestibulum iaculis euismod lorem non consequat. Quisque elementum pharetra egestas. Mauris in enim facilisis, pretium lacus vitae, accumsan diam. Praesent ut finibus mauris, eget iaculis lorem. Cras pharetra lectus varius, volutpat odio sit amet, pulvinar lectus. Aliquam malesuada erat a enim rutrum viverra. Nullam blandit nec enim eu egestas. Duis venenatis aliquet cursus. Phasellus non posuere lectus, sed rhoncus mi. Quisque ut ornare dui. Ut eget elit ac leo aliquam aliquam.

View File

@ -1,8 +0,0 @@
tags:
with tags;
html [
(body [
(p "Hello,")
(p "world!")
])
]

View File

@ -1,27 +1,12 @@
{ {
"nodes": { "nodes": {
"flakeUtils": {
"locked": {
"lastModified": 1644229661,
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1644972330, "lastModified": 1680668850,
"narHash": "sha256-6V2JFpTUzB9G+KcqtUR1yl7f6rd9495YrFECslEmbGw=", "narHash": "sha256-mQMg13yRsS0LXVzaeoSPwqgPO6yhkGzGewPgMSqXSv8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "19574af0af3ffaf7c9e359744ed32556f34536bd", "rev": "4a65e9f64e53fdca6eed31adba836717a11247d2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -31,10 +16,46 @@
"type": "github" "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"
}
},
"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"
}
},
"root": { "root": {
"inputs": { "inputs": {
"flakeUtils": "flakeUtils", "nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs" "parts": "parts"
} }
} }
}, },

View File

@ -1,57 +1,19 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flakeUtils.url = "github:numtide/flake-utils"; parts.url = "github:hercules-ci/flake-parts";
}; };
outputs = { outputs = inp:
self, inp.parts.lib.mkFlake {inputs = inp;} {
flakeUtils, debug = true;
nixpkgs, systems = ["x86_64-linux"];
}: let imports = [
utils = import ./utils.nix; ./default.nix
./examples
lib = { ];
# Convert Nix expressions to HTML flake = {
tags = import ./tags.nix {inherit utils;}; flakeModule = ./default.nix;
# 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 = 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
View 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${l.toString n}") (l.range 1 6))
++ ["ul" "li" "html" "head" "body" "div" "p"]
++ ["a" "title" "code" "pre" "nav" "article" "script"];
tags = l.genAttrs tagsToGen tag;
noChildrenTagsToGen = ["link" "meta" "hr"];
noChildrenTags = l.genAttrs noChildrenTagsToGen noChildrenTag;
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;
};
};
};
}

View File

@ -1,7 +1,46 @@
{ {
utils, lib,
pkgs, flake-parts-lib,
...
}: let }: let
l = lib // builtins;
recursiveAttrPaths = set: let
flattenIfHasList = x:
if (l.isList x) && (l.any l.isList x)
then l.concatMap flattenIfHasList x
else [x];
recurse = path: set: let
g = name: value:
if l.isAttrs value
then recurse (path ++ [name]) value
else path ++ [name];
in
l.mapAttrsToList g set;
in
flattenIfHasList (recurse [] set);
in {
options = {
perSystem =
flake-parts-lib.mkPerSystemOption
({...}: {
options = {
html-nix.lib = {
mkServeFromSite = l.mkOption {
type = with l.types; functionTo package;
};
mkSiteFrom = l.mkOption {
type = with l.types; functionTo attrs;
};
mkSitePathFrom = l.mkOption {
type = l.types.raw;
};
};
};
});
};
config = {
perSystem = {pkgs, ...}: let
pkgBin = name: "${pkgs.${name}}/bin/${name}"; pkgBin = name: "${pkgs.${name}}/bin/${name}";
mkServePathScript = path: mkServePathScript = path:
@ -10,55 +49,60 @@
''; '';
mkSitePath = site: let mkSitePath = site: let
inherit (utils) recursiveAttrPaths concatStringsSep map;
inherit (pkgs.lib) mapAttrsRecursive init last getAttrFromPath;
convertToPath = path: value: convertToPath = path: value:
if builtins.isPath value if builtins.isPath value
then value then value
else pkgs.writeText (concatStringsSep "-" path) value; else pkgs.writeText (l.concatStringsSep "-" path) value;
fileAttrPaths = recursiveAttrPaths site; fileAttrPaths = recursiveAttrPaths site;
texts = mapAttrsRecursive convertToPath site; texts = l.mapAttrsRecursive convertToPath site;
mkCreateFileCmd = path: value: let p = concatStringsSep "/" (init path); in "mkdir -p \"$out/${p}\" && ln -s \"${value}\" \"$out/${p}/${last path}\""; mkCreateFileCmd = path: value: let
createFileCmds = map (path: mkCreateFileCmd path (getAttrFromPath path texts)) fileAttrPaths; 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 in
pkgs.runCommandLocal "site-path" {} '' pkgs.runCommandLocal "site-path" {} ''
mkdir -p $out mkdir -p $out
${concatStringsSep "\n" createFileCmds} ${l.concatStringsSep "\n" createFileCmds}
''; '';
parseMarkdown = name: contents: parseMarkdown = name: contents:
pkgs.runCommandLocal name {} '' pkgs.runCommandLocal name {} ''
printf ${pkgs.lib.escapeShellArg contents} | ${pkgBin "pandoc"} -f gfm > $out printf ${l.escapeShellArg contents} | ${pkgBin "pandoc"} -f gfm > $out
''; '';
in { in {
inherit mkServePathScript mkSitePath parseMarkdown; html-nix.lib = {
mkSitePathFrom = mkSitePath;
mkServeFromSite = site: mkServePathScript (mkSitePath site); mkServeFromSite = site: mkServePathScript (mkSitePath site);
mkSiteFrom = { mkSiteFrom = {
src, src,
templater, templater,
local ? false, local ? false,
}: let }: let
inherit (utils) readDir readFile fromTOML mapAttrsToList sort elemAt;
inherit (pkgs.lib) nameValuePair head splitString pipe removeSuffix mapAttrs';
postsRendered = let postsRendered = let
path = src + "/posts"; path = src + "/posts";
in in
pipe (readDir path) [ l.pipe (l.readDir path) [
(mapAttrsToList ( (l.mapAttrsToList (
name: _: name: _: let
nameValuePair __displayName = l.head (l.splitString "." name);
(head (splitString "." name)) _displayName = l.splitString "_" __displayName;
(readFile (parseMarkdown name (readFile (path + "/${name}")))) id = l.replaceStrings [" "] ["_"] __displayName;
in {
inherit id;
displayName = l.last _displayName;
date = l.head _displayName;
content = l.readFile (parseMarkdown id (l.readFile (path + "/${name}")));
}
)) ))
(sort ( (l.sort (
p: op: let p: op: let
extractDate = name: splitString "-" (head (splitString "_" name)); extractDate = date: l.splitString "-" date;
getPart = name: el: removeSuffix "0" (elemAt (extractDate name) el); getPart = date: el: l.removeSuffix "0" (l.elemAt (extractDate date) el);
d = getPart p.name; d = getPart p.date;
od = getPart op.name; od = getPart op.date;
in in
!(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2))) !(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2)))
)) ))
@ -66,22 +110,23 @@ in {
pagesRendered = let pagesRendered = let
path = src + "/pages"; path = src + "/pages";
in in
mapAttrs' l.mapAttrsToList
( (
name: _: name: _: rec {
nameValuePair displayName = l.head (l.splitString "." name);
(head (splitString "." name)) id = l.replaceStrings [" "] ["_"] displayName;
(readFile (parseMarkdown name (readFile (path + "/${name}")))) content = l.readFile (parseMarkdown id (l.readFile (path + "/${name}")));
}
) )
(readDir path); (l.readDir path);
siteConfig = fromTOML (readFile (src + "/config.toml")); siteConfig = l.fromTOML (l.readFile (src + "/config.toml"));
baseurl = baseurl =
if local if local
then "http://localhost:8080" then "http://localhost:8080"
else siteConfig.baseurl or (throw "Need baseurl"); else siteConfig.baseurl or (throw "Need baseurl");
context = { context = {
inherit utils pkgs baseurl; inherit lib baseurl;
config = siteConfig; config = siteConfig;
posts = postsRendered; posts = postsRendered;
pages = pagesRendered; pages = pagesRendered;
@ -94,4 +139,7 @@ in {
}; };
in in
(templater context).site; (templater context).site;
};
};
};
} }

View File

@ -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;
};
}

View File

@ -1,27 +1,23 @@
{ {
utils,
posts,
pkgs,
config, config,
pages, lib,
site,
baseurl,
... ...
} @ context: let }: let
inherit (utils) readFile mapAttrsToList mapAttrs tags fetchGit map elemAt foldl' concatStrings genAttrs toString; l = lib // builtins;
inherit (pkgs.lib) optionalString optionalAttrs optional length splitString nameValuePair toInt range mapAttrs' singleton; t = l.types;
inherit (builtins) listToAttrs; inherit (config.html-nix.lib) html css;
stylesheets = map tags.mkStylesheet [ func = ctx: let
"https://unpkg.com/purecss@2.0.6/build/pure-min.css" stylesheets = l.map html.mkStylesheet [
"https://unpkg.com/purecss@2.0.6/build/grids-responsive-min.css" "https://unpkg.com/purecss@3.0.0/build/pure-min.css"
"${baseurl}/site.css" "https://unpkg.com/purecss@3.0.0/build/grids-responsive-min.css"
"${ctx.baseurl}/site.css"
]; ];
parsePostName = name: let parsePostName = name: let
parts = splitString "_" name; parts = l.splitString "_" name;
id = elemAt parts 1; id = l.elemAt parts 1;
date = elemAt parts 0; date = l.elemAt parts 0;
in { in {
inherit id date; inherit id date;
formatted = "${date} - ${id}"; formatted = "${date} - ${id}";
@ -34,7 +30,7 @@
parsed = parsePostName name; parsed = parsePostName name;
inherit (parsed) id date; inherit (parsed) id date;
in in
with tags; with html;
article [ article [
(a { (a {
href = "#${id}"; href = "#${id}";
@ -44,45 +40,43 @@
value value
]; ];
pagesSection = pagesSection = with html;
[ [
(tags.div {class = "pure-u-1";} (tags.a { (div {class = "pure-u-1";} (a {
href = "${baseurl}/"; href = "${ctx.baseurl}/";
class = "pagelink"; class = "pagelink";
} "home")) } "home"))
] ]
++ (map ++ (l.map
(name: (name:
tags.div {class = "pure-u-1";} (tags.a { div {class = "pure-u-1";} (a {
href = "${baseurl}/${name}/"; href = "${ctx.baseurl}/${name}/";
class = "pagelink"; class = "pagelink";
} }
name)) name))
(mapAttrsToList (name: _: name) pages)) (l.mapAttrsToList (name: _: name) ctx.pages))
++ [ ++ [
(tags.div {class = "pure-u-1";} (tags.a { (div {class = "pure-u-1";} (a {
href = "${baseurl}/posts/"; href = "${ctx.baseurl}/posts/";
class = "pagelink"; class = "pagelink";
} "posts")) } "posts"))
]; ];
postsRendered = map renderPost posts; postsLinks = with html;
l.singleton
postsLinks = with tags;
singleton
(ul ( (ul (
map l.map
( (
post: post:
li ( li (
a {href = "${baseurl}/${post.name}";} a {href = "${ctx.baseurl}/${post.name}";}
(parsePostName post.name).formatted (parsePostName post.name).formatted
) )
) )
posts ctx.posts
)); ));
postsSectionContent = with tags; postsSectionContent = with html;
[ [
(a { (a {
href = "#posts"; href = "#posts";
@ -91,20 +85,20 @@
] ]
++ postsLinks; ++ postsLinks;
sidebarSection = optionalString ((length pagesSection) > 0) ( sidebarSection = l.optionalString ((l.length pagesSection) > 0) (
with tags; with html;
nav {class = "sidebar";} [ nav {class = "sidebar";} [
(div {class = "pure-g";} pagesSection) (div {class = "pure-g";} pagesSection)
] ]
); );
mkPage = content: mkPage = content:
with tags; '' with html; ''
<!DOCTYPE html> <!DOCTYPE html>
${html [ ${html.html [
(head (stylesheets (head (stylesheets
++ [ ++ [
(title config.title) (title ctx.config.title)
(meta { (meta {
name = "viewport"; name = "viewport";
content = "width=device-width, initial-scale=1"; content = "width=device-width, initial-scale=1";
@ -118,15 +112,15 @@
]} ]}
''; '';
indexPage = mkPage (context.indexContent or postsSectionContent); indexPage = mkPage (ctx.indexContent or postsSectionContent);
pagesAndPosts = pagesAndPosts =
pages ctx.pages
// listToAttrs ( // l.listToAttrs (
map (post: nameValuePair post.name (renderPost post)) posts map (post: l.nameValuePair post.name (renderPost post)) ctx.posts
); );
stylesheet = with utils.css; let stylesheet = let
marginMobile = { marginMobile = {
margin-left = "3%"; margin-left = "3%";
margin-right = "3%"; margin-right = "3%";
@ -135,9 +129,20 @@
css [ css [
(css ( (css (
( (
mapAttrs' l.mapAttrs'
(name: value: nameValuePair value {content = "\"${concatStrings (map (_: "#") (range 1 (toInt name)))} \"";}) (
(genAttrs (n: "h${toString n}:before") (map toString (range 1 6))) name: value:
l.nameValuePair
value
{
content = "\"${l.concatStrings (l.map (_: "#") (l.range 1 (l.toInt name)))} \"";
}
)
(
l.genAttrs
(l.map l.toString (l.range 1 6))
(n: "h${l.toString n}:before")
)
) )
// { // {
body = { body = {
@ -177,7 +182,7 @@
}; };
} }
)) ))
(media "max-width: 48em" { (css.media "max-width: 48em" {
"nav.sidebar" = "nav.sidebar" =
{ {
position = "relative"; position = "relative";
@ -191,17 +196,27 @@
// marginMobile; // marginMobile;
}) })
]; ];
in { in {
inherit stylesheets sidebarSection mkPage stylesheet; inherit stylesheets sidebarSection mkPage stylesheet;
site = site =
site ctx.site
// { // {
"index.html" = indexPage; "index.html" = indexPage;
"posts"."index.html" = mkPage postsSectionContent; "posts"."index.html" = mkPage postsSectionContent;
"404.html" = mkPage (tags.h1 "No such page"); "404.html" = mkPage (html.h1 "No such page");
"site.css" = stylesheet; "site.css" = stylesheet;
} }
// (mapAttrs (name: value: {"index.html" = mkPage value;}) pagesAndPosts) // (l.mapAttrs (name: value: {"index.html" = mkPage value;}) pagesAndPosts)
// optionalAttrs (context ? resources) {inherit (context) resources;}; // 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;
};
} }

6
templaters/default.nix Normal file
View File

@ -0,0 +1,6 @@
{
imports = [
./basic.nix
./simple
];
}

View File

@ -0,0 +1,151 @@
{
config,
lib,
...
}: let
l = lib // builtins;
t = l.types;
inherit (config.html-nix.lib) html css;
func = ctx: let
stylesheets = l.map html.mkStylesheet ["${ctx.baseurl}/site.css"];
stylesheet = import ./stylesheet.nix {inherit css l;};
renderPost = post:
with html;
article [
(h1 {inherit (post) id;} post.displayName)
(h4 {class = "nohashtag";} ("date: " + post.date))
post.content
];
mkPage = {
content,
titleStr ? ctx.config.title,
}:
with html; ''
<!DOCTYPE html>
${html.html [
(head (stylesheets
++ [
(title titleStr)
(meta {
name = "viewport";
content = "width=device-width, initial-scale=1";
})
]))
(body ''
${script "0"}
${div (l.flatten [
navBar
(hr {})
content
])}
'')
]}
'';
navBar = with html;
nav (
[
(a {
href = "${ctx.baseurl}/";
class = "novisited";
} "home")
]
++ (
l.map
(
page:
" "
+ (
a {
href = "${ctx.baseurl}/${page.id}/";
class = "novisited";
}
page.displayName
)
)
ctx.pages
)
);
postsLinks = with html;
l.singleton
(ul (
l.map
(
post:
li (
a {href = "${ctx.baseurl}/${post.id}";}
"${post.date} - ${post.displayName}"
)
)
ctx.posts
));
postsSectionContent = [(html.h1 "posts")] ++ postsLinks;
postsRendered = l.listToAttrs (
l.map
(post:
l.nameValuePair post.id {
content = renderPost post;
name = post.displayName;
})
ctx.posts
);
pagesRendered = l.listToAttrs (
l.map
(page:
l.nameValuePair page.id {
content = page.content;
name = page.displayName;
})
ctx.pages
);
indexPage = mkPage {
content = ctx.indexContent or postsSectionContent;
};
in {
inherit stylesheets mkPage stylesheet;
site =
ctx.site
// {
"index.html" = indexPage;
"posts"."index.html" = mkPage {
content = postsSectionContent;
titleStr = "posts - ${ctx.config.title}";
};
"404.html" = mkPage {
content = html.h1 {class = "nohashtag";} "page not found";
titleStr = "page not found - ${ctx.config.title}";
};
"site.css" = stylesheet;
}
// (
l.mapAttrs
(
name: value: {
"index.html" = mkPage {
content = value.content;
titleStr = "${value.name} - ${ctx.config.title}";
};
}
)
(pagesRendered // postsRendered)
)
// l.optionalAttrs (ctx ? resources) {inherit (ctx) resources;};
};
in {
options = {
html-nix.lib.templaters.simple = l.mkOption {
type = t.uniq (t.functionTo t.attrs);
};
};
config = {
html-nix.lib.templaters.simple = func;
};
}

View File

@ -0,0 +1,88 @@
{
css,
l,
...
}: let
colors = {
light = rec {
fg = "#000";
bg = "#faf9f6";
code-bg = fg;
code-fg = bg;
link = "#1f51ff";
link-visited = "#9d00ff";
};
dark = rec {
fg = "#eee";
bg = "#111";
code-bg = "#333";
code-fg = fg;
link = "#007fff";
link-visited = "#bf40bf";
};
};
headers = extra:
l.genAttrs
(l.map l.toString (l.range 1 6))
(n: "h${l.toString n}${extra}");
in
css [
(css (
l.mapAttrs'
(
name: value:
l.nameValuePair
value
{
content = ''"${l.concatStrings (l.map (_: "#") (l.range 1 (l.toInt name)))} "'';
}
)
(headers ":before")
))
(css (
l.mapAttrs'
(_: value: l.nameValuePair value {content = ''""'';})
(headers ".nohashtag:before")
))
(css {
body = {
font-family = ["sans-serif"];
color = colors.light.fg;
background = colors.light.bg;
max-width = "650px";
margin = "40px auto";
};
"pre,code" = {
font-family = ["monospace"];
background = colors.light.code-bg;
color = colors.light.code-fg;
padding = "4px";
border-radius = "4px";
};
"pre code" = {
padding = 0;
border-radius = 0;
};
a = {
color = colors.light.link;
text-decoration = "none";
};
"a:hover".text-decoration = "underline";
"a:visited".color = colors.light.link-visited;
"a.novisited:visited".color = colors.light.link;
"h1,h2,h3".line-height = "1.2";
})
(css.media "prefers-color-scheme: dark" {
body = {
color = colors.dark.fg;
background = colors.dark.bg;
};
"pre,code" = {
color = colors.dark.code-fg;
background = colors.dark.code-bg;
};
a.color = colors.dark.link;
"a:visited".color = colors.dark.link-visited;
"a.novisited:visited".color = colors.dark.link;
})
]

View File

@ -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