Compare commits

..

No commits in common. "46b3656161aab4fe38b7aba089341648c2d91b85" and "d30b07841100278a1d7901001ecec038c5448be2" have entirely different histories.

17 changed files with 479 additions and 749 deletions

54
css.nix
View File

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

View File

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

View File

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

27
examples/serve.nix Normal file
View File

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

View File

@ -6,6 +6,4 @@ 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.

8
examples/tags.nix Normal file
View File

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

View File

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

View File

@ -1,19 +1,57 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
parts.url = "github:hercules-ci/flake-parts"; flakeUtils.url = "github:numtide/flake-utils";
}; };
outputs = inp: outputs = {
inp.parts.lib.mkFlake {inputs = inp;} { self,
debug = true; flakeUtils,
systems = ["x86_64-linux"]; nixpkgs,
imports = [ }: let
./default.nix utils = import ./utils.nix;
./examples
]; lib = {
flake = { # Convert Nix expressions to HTML
flakeModule = ./default.nix; 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 = 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;};
} }

View File

@ -1,49 +0,0 @@
{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,145 +1,97 @@
{ {
lib, utils,
flake-parts-lib, pkgs,
...
}: let }: let
l = lib // builtins; pkgBin = name: "${pkgs.${name}}/bin/${name}";
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 mkServePathScript = path:
g = name: value: pkgs.writeScriptBin "serve" ''
if l.isAttrs value ${pkgs.nodePackages.http-server}/bin/http-server -c-1 ${path}
then recurse (path ++ [name]) value '';
else path ++ [name];
in mkSitePath = site: let
l.mapAttrsToList g set; 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 in
flattenIfHasList (recurse [] set); 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
'';
in { in {
options = { inherit mkServePathScript mkSitePath parseMarkdown;
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}";
mkServePathScript = path: mkServeFromSite = site: mkServePathScript (mkSitePath site);
pkgs.writeScriptBin "serve" '' mkSiteFrom = {
${pkgs.nodePackages.http-server}/bin/http-server -c-1 ${path} src,
''; templater,
local ? false,
}: let
inherit (utils) readDir readFile fromTOML mapAttrsToList sort elemAt;
inherit (pkgs.lib) nameValuePair head splitString pipe removeSuffix mapAttrs';
mkSitePath = site: let postsRendered = let
convertToPath = path: value: path = src + "/posts";
if builtins.isPath value in
then value pipe (readDir path) [
else pkgs.writeText (l.concatStringsSep "-" path) value; (mapAttrsToList (
fileAttrPaths = recursiveAttrPaths site; name: _:
texts = l.mapAttrsRecursive convertToPath site; nameValuePair
mkCreateFileCmd = path: value: let (head (splitString "." name))
p = l.concatStringsSep "/" (l.init path); (readFile (parseMarkdown name (readFile (path + "/${name}"))))
in "mkdir -p \"$out/${p}\" && ln -s \"${value}\" \"$out/${p}/${l.last path}\""; ))
createFileCmds = (sort (
l.map p: op: let
(path: mkCreateFileCmd path (l.getAttrFromPath path texts)) extractDate = name: splitString "-" (head (splitString "_" name));
fileAttrPaths; getPart = name: el: removeSuffix "0" (elemAt (extractDate name) el);
in d = getPart p.name;
pkgs.runCommandLocal "site-path" {} '' od = getPart op.name;
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 = {
mkSitePathFrom = mkSitePath;
mkServeFromSite = site: mkServePathScript (mkSitePath site);
mkSiteFrom = {
src,
templater,
local ? false,
}: let
postsRendered = let
path = src + "/posts";
in in
l.pipe (l.readDir path) [ !(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2)))
(l.mapAttrsToList ( ))
name: _: let ];
__displayName = l.head (l.splitString "." name); pagesRendered = let
_displayName = l.splitString "_" __displayName; path = src + "/pages";
id = l.replaceStrings [" "] ["_"] __displayName; in
in { mapAttrs'
inherit id; (
displayName = l.last _displayName; name: _:
date = l.head _displayName; nameValuePair
content = l.readFile (parseMarkdown id (l.readFile (path + "/${name}"))); (head (splitString "." name))
} (readFile (parseMarkdown name (readFile (path + "/${name}"))))
)) )
(l.sort ( (readDir path);
p: op: let siteConfig = fromTOML (readFile (src + "/config.toml"));
extractDate = date: l.splitString "-" date; baseurl =
getPart = date: el: l.removeSuffix "0" (l.elemAt (extractDate date) el); if local
d = getPart p.date; then "http://localhost:8080"
od = getPart op.date; else siteConfig.baseurl or (throw "Need baseurl");
in
!(((d 0) > (od 0)) && ((d 1) > (od 1)) && ((d 2) > (od 2)))
))
];
pagesRendered = let
path = src + "/pages";
in
l.mapAttrsToList
(
name: _: rec {
displayName = l.head (l.splitString "." name);
id = l.replaceStrings [" "] ["_"] displayName;
content = l.readFile (parseMarkdown id (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 = { context = {
inherit lib baseurl; inherit utils pkgs baseurl;
config = siteConfig; config = siteConfig;
posts = postsRendered; posts = postsRendered;
pages = pagesRendered; pages = pagesRendered;
site = { site = {
"robots.txt" = '' "robots.txt" = ''
User-agent: * User-agent: *
Allow: / Allow: /
''; '';
};
};
in
(templater context).site;
}; };
}; };
}; in
(templater context).site;
} }

34
tags.nix Normal file
View File

@ -0,0 +1,34 @@
{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,222 +1,207 @@
{ {
utils,
posts,
pkgs,
config, config,
lib, pages,
site,
baseurl,
... ...
}: let } @ context: let
l = lib // builtins; inherit (utils) readFile mapAttrsToList mapAttrs tags fetchGit map elemAt foldl' concatStrings genAttrs toString;
t = l.types; inherit (pkgs.lib) optionalString optionalAttrs optional length splitString nameValuePair toInt range mapAttrs' singleton;
inherit (config.html-nix.lib) html css; inherit (builtins) listToAttrs;
func = ctx: let stylesheets = map tags.mkStylesheet [
stylesheets = l.map html.mkStylesheet [ "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
"https://unpkg.com/purecss@3.0.0/build/pure-min.css" "https://unpkg.com/purecss@2.0.6/build/grids-responsive-min.css"
"https://unpkg.com/purecss@3.0.0/build/grids-responsive-min.css" "${baseurl}/site.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}";
};
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
];
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"))
]; ];
parsePostName = name: let postsRendered = map renderPost posts;
parts = l.splitString "_" name;
id = l.elemAt parts 1;
date = l.elemAt parts 0;
in {
inherit id date;
formatted = "${date} - ${id}";
};
renderPost = { postsLinks = with tags;
name, singleton
value, (ul (
}: let map
parsed = parsePostName name; (
inherit (parsed) id date; post:
in li (
with html; a {href = "${baseurl}/${post.name}";}
article [ (parsePostName post.name).formatted
(a { )
href = "#${id}"; )
class = "postheader"; posts
} (h2 {inherit id;} id)) ));
(h3 ("date: " + date))
value
];
pagesSection = with html; postsSectionContent = with tags;
[ [
(div {class = "pure-u-1";} (a { (a {
href = "${ctx.baseurl}/"; href = "#posts";
class = "pagelink"; class = "postheader";
} "home")) } (h1 "posts"))
]
++ postsLinks;
sidebarSection = optionalString ((length pagesSection) > 0) (
with tags;
nav {class = "sidebar";} [
(div {class = "pure-g";} pagesSection)
] ]
++ (l.map );
(name:
div {class = "pure-u-1";} (a {
href = "${ctx.baseurl}/${name}/";
class = "pagelink";
}
name))
(l.mapAttrsToList (name: _: name) ctx.pages))
++ [
(div {class = "pure-u-1";} (a {
href = "${ctx.baseurl}/posts/";
class = "pagelink";
} "posts"))
];
postsLinks = with html; mkPage = content:
l.singleton with tags; ''
(ul ( <!DOCTYPE html>
l.map ${html [
( (head (stylesheets
post: ++ [
li ( (title config.title)
a {href = "${ctx.baseurl}/${post.name}";} (meta {
(parsePostName post.name).formatted name = "viewport";
) content = "width=device-width, initial-scale=1";
) })
ctx.posts ]))
)); (body ''
${script "0"}
${sidebarSection}
${div {class = "content";} content}
'')
]}
'';
postsSectionContent = with html; indexPage = mkPage (context.indexContent or postsSectionContent);
[
(a {
href = "#posts";
class = "postheader";
} (h1 "posts"))
]
++ postsLinks;
sidebarSection = l.optionalString ((l.length pagesSection) > 0) ( pagesAndPosts =
with html; pages
nav {class = "sidebar";} [ // listToAttrs (
(div {class = "pure-g";} pagesSection) map (post: nameValuePair post.name (renderPost post)) posts
]
); );
mkPage = content: stylesheet = with utils.css; let
with html; '' marginMobile = {
<!DOCTYPE html> margin-left = "3%";
${html.html [ margin-right = "3%";
(head (stylesheets
++ [
(title ctx.config.title)
(meta {
name = "viewport";
content = "width=device-width, initial-scale=1";
})
]))
(body ''
${script "0"}
${sidebarSection}
${div {class = "content";} content}
'')
]}
'';
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
(l.map l.toString (l.range 1 6))
(n: "h${l.toString n}:before")
)
)
// {
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;
}; };
}; in
config = { css [
html-nix.lib.templaters.basic = func; (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;
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;};
} }

View File

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

View File

@ -1,151 +0,0 @@
{
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

@ -1,88 +0,0 @@
{
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;
})
]

38
utils.nix Normal file
View File

@ -0,0 +1,38 @@
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