diff --git a/flake.nix b/flake.nix index a1edc88..0027951 100644 --- a/flake.nix +++ b/flake.nix @@ -11,25 +11,47 @@ }; nixite = import ./nixite/. {inherit pkgs;}; in { - packages.${system} = with nixite; { - # default = nixite.mkSite (nixite.layout (nixite.md.readMd ./src/index.md)); - default = nixite.mkSite { - index = - html.toHTML - ( - elems.doc + packages.${system} = { + default = with nixite; + mkSite (site.applyStyle ./testing/src/style.css { + "index.html" = with elems; (doc [ - (elems.title "Nixite") + (title "Nixite") ] - [ - (elems.h 1 "Nixite") - (elems.main - (elems.p "hello")) - ] - ); - }; + (main [ + (md.readMd ./testing/src/index.md) + (link "/blog" "blog") + (list [ + "item 1" + "item 2" + "item 3" + ]) + ])); + blog = { + "index.html" = with elems; (doc + [ + (title "A post") + ] + (main [ + (p '' + This is a post + '') + (link "/" "Home") + ])); + }; + }); serve = nixite.serve self.packages.${system}.default; + + test = let + test = import ./testing/import.nix; + in + pkgs.writeShellScriptBin "test" '' + ${test ./testing/md.test.nix} + ${test ./testing/html.test.nix} + ${test ./testing/elems.test.nix} + ${test ./testing/site.test.nix} + ''; }; }; } diff --git a/nixite/default.nix b/nixite/default.nix index e4d3fec..bd111bf 100644 --- a/nixite/default.nix +++ b/nixite/default.nix @@ -1,9 +1,10 @@ {pkgs, ...}: { - mkSite = import ./site.nix {inherit pkgs;}; + mkSite = import ./make-site.nix {inherit pkgs;}; serve = site: (pkgs.writeShellScriptBin "serve" '' ${pkgs.caddy}/bin/caddy file-server --root ${site} ''); md = import ./md.nix; html = import ./html.nix; elems = import ./elems.nix; + site = import ./site.nix; } diff --git a/nixite/elems.nix b/nixite/elems.nix index 9d01a0f..acd6c66 100644 --- a/nixite/elems.nix +++ b/nixite/elems.nix @@ -1,13 +1,33 @@ let html = import ./html.nix; in { - p = child: html.tag "p" child; - main = child: html.tag "main" child; - h = v: child: html.tag "h${toString v}" child; - title = child: html.tag "title" child; + p = child: + html.tag "p" {} child; + + main = child: + html.tag "main" {} child; + + h = v: child: + html.tag "h${toString v}" {} child; + + title = child: + html.tag "title" {} child; + + link = href: child: + html.tag "a" {inherit href;} child; + + stylesheet = path: + html.tag "link" { + rel = "stylesheet"; + href = path; + } ""; + + list = elems: html.tag "ul" {} (map (e: html.tag "li" {} e) elems); + doc = head: body: - html.tag "html" [ - (html.tag "head" head) - (html.tag "body" body) - ]; + assert builtins.isList head; + html.tag "html" {lang = "en";} [ + (html.tag "head" {} head) + (html.tag "body" {} body) + ]; } diff --git a/nixite/html.nix b/nixite/html.nix index 42452d9..79b52d4 100644 --- a/nixite/html.nix +++ b/nixite/html.nix @@ -4,15 +4,33 @@ rec { then elem else if builtins.typeOf elem == "list" then builtins.toString (map toHTML elem) - else ''<${elem.tag}>${toHTML elem.child}${elem.tag}>''; + else ''<${elem.tag} ${writeAttrs elem.attrs}>${toHTML elem.child}${elem.tag}>''; writeAttrs = attrs: - toString builtins.attrValues ( + toString (builtins.attrValues ( builtins.mapAttrs (key: value: ''${key}="${value}"'') attrs - ); + )); - tag = tag: child: { - inherit tag child; + tag = tag: attrs: child: { + inherit tag child attrs; __toString = toHTML; }; + + addToHead = page: heads: + page + // { + child = + map + ( + e: + if e.tag == "head" + then + e + // { + child = e.child ++ heads; + } + else e + ) + page.child; + }; } diff --git a/nixite/make-site.nix b/nixite/make-site.nix new file mode 100644 index 0000000..914cabf --- /dev/null +++ b/nixite/make-site.nix @@ -0,0 +1,16 @@ +{pkgs, ...}: raw: let + site = import ./site.nix; +in + pkgs.stdenv.mkDerivation { + name = "site"; + src = ./.; + buildPhase = '' + mkdir dist + + ${site.copyTo "dist" raw} + + ''; + installPhase = '' + cp -r dist $out + ''; + } diff --git a/nixite/md.nix b/nixite/md.nix index 04eb345..a23cab1 100644 --- a/nixite/md.nix +++ b/nixite/md.nix @@ -1,26 +1,25 @@ -rec { - readMd = path: processMd (builtins.readFile path); - processMd = md: { - title = "idk"; - content = toString (map (c: - if builtins.typeOf c == "string" - then processMdBlock c - else null) (builtins.split "\n\n" md)); - }; +let + elems = import ./elems.nix; +in rec { + readMd = md: + if builtins.isPath md + then processMd (builtins.readFile md) + else processMd md; + processMd = md: (map (c: + if builtins.isString c + then mdBlock c + else "") (builtins.split "\n\n" md)); - processMdBlock = block: p block; + mdBlock = block: let + m = heading block; + h = + if m == null + then 0 + else builtins.stringLength (builtins.elemAt m 0); + in + if m == null + then elems.p block + else elems.h h (builtins.elemAt m 1); - isHeading = block: builtins.match "#+ .*" block; - - h = content: '' -
- ${toString content} -
- ''; + heading = block: builtins.match "(#+) (.*)" block; } diff --git a/nixite/site.nix b/nixite/site.nix index 570737b..be0ef17 100644 --- a/nixite/site.nix +++ b/nixite/site.nix @@ -1,12 +1,44 @@ -{pkgs, ...}: site: -pkgs.stdenv.mkDerivation { - name = "site"; - src = ./.; - buildPhase = '' - mkdir dist - echo "${toString site.index}" > dist/index.html - ''; - installPhase = '' - cp -r dist $out - ''; +let + html = import ./html.nix; + elems = import ./elems.nix; +in rec { + applyStyle = style: site: (linkStyle site) // {"style.css" = style;}; + + linkStyle = site: (builtins.mapAttrs ( + name: content: + if builtins.isAttrs content && content ? "__toString" + then html.addToHead content [(elems.stylesheet "/style.css")] + else if builtins.isAttrs content + then linkStyle content + else content + ) + site); + + copyTo = prefix: site: + builtins.toString ( + builtins.attrValues ( + builtins.mapAttrs ( + name: content: + if builtins.isString content + then '' + cp ${builtins.toFile name content} ${prefix}/${name} + '' + else if builtins.isPath content + then '' + cp ${content} ${prefix}/${name} + '' + else if builtins.isAttrs content && content ? "__toString" + then '' + cp ${builtins.toFile name (toString content)} ${prefix}/${name} + '' + else if builtins.isAttrs content + then '' + mkdir -p ${prefix}/${name} + ${copyTo "${prefix}/${name}" content} + '' + else throw "Site page must be string, path or attrset" + ) + site + ) + ); } diff --git a/src/index.md b/src/index.md deleted file mode 100644 index 795bbef..0000000 --- a/src/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Hello World - -Making a website in Nix? That sounds dumb. diff --git a/testing/elems.test.nix b/testing/elems.test.nix new file mode 100644 index 0000000..ba70564 --- /dev/null +++ b/testing/elems.test.nix @@ -0,0 +1,53 @@ +let + elems = import ../nixite/elems.nix; + html = import ../nixite/html.nix; + it = import ./it.nix; +in + with elems; [ + (it "makes a p tag" { + expected = html.tag "p" {} "foobar"; + actual = p "foobar"; + }) + (it "makes a main tag" { + expected = html.tag "main" {} ["yeet"]; + actual = main ["yeet"]; + }) + (it "makes an h1 tag" { + expected = html.tag "h1" {} "foobar"; + actual = h 1 "foobar"; + }) + (it "makes an h2 tag" { + expected = html.tag "h2" {} "foobar"; + actual = h 2 "foobar"; + }) + (it "makes a title tag" { + expected = html.tag "title" {} "foobar"; + actual = title "foobar"; + }) + (it "makes an a tag" { + expected = html.tag "a" {href = "https://example.com";} "example"; + actual = link "https://example.com" "example"; + }) + (it "makes a stylesheet link" { + expected = html.tag "link" { + href = "/style"; + rel = "stylesheet"; + } ""; + actual = stylesheet "/style"; + }) + (it "makes a list" { + expected = html.tag "ul" {} [ + (html.tag "li" {} "foo") + (html.tag "li" {} "bar") + (html.tag "li" {} "baz") + ]; + actual = list ["foo" "bar" "baz"]; + }) + (it "makes an html doc" { + expected = html.tag "html" {lang = "en";} [ + (html.tag "head" {} ["foo"]) + (html.tag "body" {} "bar") + ]; + actual = doc ["foo"] "bar"; + }) + ] diff --git a/testing/html.test.nix b/testing/html.test.nix new file mode 100644 index 0000000..e4b2448 --- /dev/null +++ b/testing/html.test.nix @@ -0,0 +1,27 @@ +let + html = import ../nixite/html.nix; + it = import ./it.nix; +in + with html; [ + (it "makes a p tag" { + actual = tag "p" {} "Hello"; + expected = { + tag = "p"; + attrs = {}; + child = "Hello"; + __toString = toHTML; + }; + }) + + (it "applies style" (let + page = tag "html" {} [(tag "head" {} ["foo"])]; + in { + actual = addToHead page ["bar"]; + expected = { + tag = "html"; + attrs = {}; + child = [(tag "head" {} ["foo" "bar"])]; + __toString = toHTML; + }; + })) + ] diff --git a/testing/import.nix b/testing/import.nix new file mode 100644 index 0000000..d5beccc --- /dev/null +++ b/testing/import.nix @@ -0,0 +1,5 @@ +path: +toString (map (v: '' + echo '${builtins.baseNameOf path} :: ${v}' + '') + (import path)) diff --git a/testing/it.nix b/testing/it.nix new file mode 100644 index 0000000..ee93698 --- /dev/null +++ b/testing/it.nix @@ -0,0 +1,11 @@ +msg: { + actual, + expected, +}: +if actual == expected +then msg +else + throw + (builtins.toJSON { + inherit actual expected msg; + }) diff --git a/testing/md.test.nix b/testing/md.test.nix new file mode 100644 index 0000000..016afc4 --- /dev/null +++ b/testing/md.test.nix @@ -0,0 +1,27 @@ +let + md = import ../nixite/md.nix; + elems = import ../nixite/elems.nix; + it = import ./it.nix; +in + with md; [ + (assert heading "# heading 1" == ["#" "heading 1"]; "gets heading 1") + (assert heading "## subheading" == ["##" "subheading"]; "gets heading 2") + (assert heading "some paragraph" == null; "paragraph is heading 0") + + (assert mdBlock "# heading 1" == elems.h 1 "heading 1"; "makes h1 tag") + (assert mdBlock "## subheading" == elems.h 2 "subheading"; "makes h2 tag") + (assert mdBlock "some paragraph" == elems.p "some paragraph"; "makes p tag") + + (it "processes md block" { + actual = readMd '' + # foo bar + + lorem ipsum + ''; + expected = [ + (elems.h 1 "foo bar") + "" + (elems.p "lorem ipsum\n") + ]; + }) + ] diff --git a/testing/site.test.nix b/testing/site.test.nix new file mode 100644 index 0000000..2e66bf8 --- /dev/null +++ b/testing/site.test.nix @@ -0,0 +1,27 @@ +let + elems = import ../nixite/elems.nix; + site = import ../nixite/site.nix; + it = import ./it.nix; +in + with site; [ + (it "applies a style" { + expected = { + "index.html" = with elems; (doc [(title "foobar") (stylesheet "/style.css")] [(main "something")]); + blog = { + "index.html" = with elems; (doc [(title "foobar") (stylesheet "/style.css")] [(main "blogy blog")]); + }; + "style.css" = '' + this is a stylesheet + ''; + }; + actual = + applyStyle '' + this is a stylesheet + '' { + "index.html" = with elems; (doc [(title "foobar")] [(main "something")]); + blog = { + "index.html" = with elems; (doc [(title "foobar")] [(main "blogy blog")]); + }; + }; + }) + ] diff --git a/testing/src/index.md b/testing/src/index.md new file mode 100644 index 0000000..0443389 --- /dev/null +++ b/testing/src/index.md @@ -0,0 +1,11 @@ +# Hello World + +Making a website in Nix? That sounds dumb. + +## but why? + +great question! + +### you are dumb. + +yes I am. diff --git a/testing/src/style.css b/testing/src/style.css new file mode 100644 index 0000000..26603f5 --- /dev/null +++ b/testing/src/style.css @@ -0,0 +1,3 @@ +p { + padding: 1rem; +};