diff --git a/flake.nix b/flake.nix index 727a8d3..269b8ad 100644 --- a/flake.nix +++ b/flake.nix @@ -9,7 +9,7 @@ in nixite // { packages.${system} = { raw = nixite.mkSite (let - site = (nixite.site.extractPaths { + markup = { "test" = with nixite.elems; let blue = nixite.style.tag "span" "blue" { @@ -19,14 +19,7 @@ style = { text-decoration = "underline"; }; }; in (Doc { } [ - [ - (title { } "Nixite") - (link { - rel = "shortcut icon"; - type = "image/png"; - href = ./testing/src/favicon.png; - } "") - ] + [ (title { } "Nixite") ] (main { } [ (a "/readme" "Readme") (a "/blog" "blog") @@ -41,10 +34,11 @@ ]); blog = nixite.md.readDir ./testing/blog; "index.html" = nixite.md.mdToPage ./README.md; - }); - styles = # nixite.site.getStyles site; - nixite.style.getStyles site.test; - in nixite.site.applyStyle styles site); + }; + styles = nixite.site.getStyles markup; + site = (nixite.site.extractPaths (nixite.site.applyStyle styles + (nixite.site.applyFavicon ./testing/src/favicon.png markup))); + in site); default = nixite.serve self.packages.${system}.raw; diff --git a/nixite/html.nix b/nixite/html.nix index 4acaf6d..1161567 100644 --- a/nixite/html.nix +++ b/nixite/html.nix @@ -14,8 +14,8 @@ in rec { else if builtins.isList elem then builtins.toString (map toHTML elem) else - "<${elem.tag} ${writeAttrs elem.attrs}>${ - toHTML elem.child + "<${elem.tag} ${writeAttrs elem.attrs or { }}>${ + toHTML elem.child or "" }${elem.tag}>"; writeAttrs = attrs: @@ -30,11 +30,13 @@ in rec { tag = tag: { inherit tag; + __toString = self: toString (self { } ""); __functor = self: attrs: if !(builtins.isAttrs attrs) then throw "HTML tag requires attribute set" else { inherit tag attrs; + __toString = self: toString (self ""); __functor = self: child: if !(isTag child) then throw "tag child must be tag, list, or string, got ${ diff --git a/nixite/site.nix b/nixite/site.nix index e7e7b36..4d137f9 100644 --- a/nixite/site.nix +++ b/nixite/site.nix @@ -1,24 +1,45 @@ let html = import ./html.nix; elems = import ./elems.nix; + style = import ./style.nix; in rec { + getStyles = site: + builtins.zipAttrsWith (name: value: builtins.elemAt value 0) + (map style.getStyles ( flatten site )); + + flatten = site: map ( + page: if builtins.isAttrs page && page ? "__toString" then + page + else if builtins.isAttrs page then + flatten page + else + page + ) (builtins.attrValues site); + applyStyle = style: site: (linkStyle site) // { "style.css" = style; }; - getStyles = site: '' - .blue { - color: blue; - } - ''; - linkStyle = site: + eachPage site + (content: html.addToHead content [ (elems.Stylesheet "/style.css") ]); + + eachPage = site: callback: (builtins.mapAttrs (name: content: if builtins.isAttrs content && content ? "__toString" then - html.addToHead content [ (elems.Stylesheet "/style.css") ] + callback content else if builtins.isAttrs content then - linkStyle content + eachPage content callback else content) site); + applyFavicon = icon: site: + eachPage site (content: + html.addToHead content [ + (elems.link { + rel = "shortcut icon"; + href = icon; + }) + ]); + extractPaths = content: switchPaths content // { static = getPaths content; }; switchPaths = content: diff --git a/testing/html.test.nix b/testing/html.test.nix index 4215e18..b3af048 100644 --- a/testing/html.test.nix +++ b/testing/html.test.nix @@ -69,6 +69,18 @@ in with html; [ actual = (para "").attrs.style; })) + (it "needs no args to make string" (let p = tag "p"; + in { + actual = toString p; + expected = "
"; + })) + + (it "needs no content to make string" (let p = tag "p"; + in { + actual = toString (p { class = "foobar"; }); + expected = ''''; + })) + (it "works recursively" (let attrs = { style = { foo = "bar"; }; }; para = (tag "p" attrs); diff --git a/testing/it.nix b/testing/it.nix index 98f05d1..7936006 100644 --- a/testing/it.nix +++ b/testing/it.nix @@ -1,15 +1,24 @@ msg: { actual, expected, asString ? false, asJSON ? false, removeDunders ? false, }: -if (if asString then - toString actual == toString expected -else if asJSON then - builtins.toJSON actual == builtins.toJSON expected -else if removeDunders then - builtins.removeAttrs actual [ "__toString" "__functor" ] == expected -else - actual == expected) then '' +let + preProcess = v: + if removeDunders then + builtins.removeAttrs v [ "__toString" "__functor" ] + else if asString then + toString v + else if asJSON then + builtins.toJSON v + else v; + + a = preProcess actual; + e = preProcess expected; + +in +if (a == e) then '' echo 'it ${msg}' - '' else '' + '' +else + '' echo 'FAILED: ${msg}' echo '${builtins.toJSON expected}' echo '${builtins.toJSON actual}' diff --git a/testing/site.test.nix b/testing/site.test.nix index e12a7a4..0839c37 100644 --- a/testing/site.test.nix +++ b/testing/site.test.nix @@ -2,6 +2,7 @@ let html = import ../nixite/html.nix; elems = import ../nixite/elems.nix; site = import ../nixite/site.nix; + style = import ../nixite/style.nix; it = import ./it.nix; in with site; [ (it "applies a style" { @@ -42,6 +43,64 @@ in with site; [ }; asJSON = true; }) + + (it "applies a favicon" { + expected = { + "index.html" = elems.html { } [ + (elems.head { } [ + (elems.title { } "foobar") + (elems.link { + rel = "shortcut icon"; + href = ./src/favicon.png; + }) + ]) + (elems.main { } "something") + ]; + blog = { + "index.html" = elems.html { } [ + (elems.head { } [ + (elems.title { } "foobar") + (elems.link { + rel = "shortcut icon"; + href = ./src/favicon.png; + }) + ]) + (elems.main { } "something") + ]; + }; + }; + actual = applyFavicon ./src/favicon.png { + "index.html" = elems.html { } [ + (elems.head { } [ (elems.title { } "foobar") ]) + (elems.main { } "something") + ]; + blog = { + "index.html" = elems.html { } [ + (elems.head { } [ (elems.title { } "foobar") ]) + (elems.main { } "something") + ]; + }; + }; + asJSON = true; + }) + + (it "extracts all styles" { + expected = { + "p.class" = {color = "blue";}; + "a.class2" = {color = "green";}; + }; + actual = getStyles (let + p = style.tag "p" "class" {style = {color = "blue";};}; + g = style.tag "a" "class2" {style = {color = "green";};}; + in { + "index.html" = p ""; + blog = { + "index.html" = g ""; + }; + }); + removeDunders = true; + }) + (it "extracts top level paths" { actual = getPaths { something = "";