From e76305f71a1301105951b046e4c5e8076e001860 Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 1 Jan 2024 12:42:18 +0000 Subject: [PATCH] reusable, extendable tags --- flake.nix | 17 ++++++------- nixite/html.nix | 38 +++++++++++++++------------- nixite/site.nix | 2 ++ nixite/style.nix | 19 ++++++-------- testing/html.test.nix | 8 +++++- testing/import.nix | 1 + testing/it.nix | 11 +++++--- testing/site.test.nix | 8 +++--- testing/style.test.nix | 57 +++++++++++++++++++++--------------------- 9 files changed, 85 insertions(+), 76 deletions(-) diff --git a/flake.nix b/flake.nix index c9aec85..c1ffeee 100644 --- a/flake.nix +++ b/flake.nix @@ -10,30 +10,29 @@ packages.${system} = { raw = nixite.mkSite (let readme = { - type = "link"; name = "readme"; content = nixite.md.mdToPage ./README.md; }; markup = { - "test" = with nixite.elems; + "index.html" = with nixite.elems; let - blue = nixite.style.tag "span" "blue" { + blue = nixite.style.component span "blue" { style = { color = "blue"; }; }; - underblue = nixite.style.extend blue "under" { + underblue = nixite.style.component blue "under" { style = { text-decoration = "underline"; }; }; in (Doc { } [ - [ (title { } "Nixite") ] - (main { } [ - (a { href = readme; } "Readme") + [ (title "Nixite") ] + (main [ + (a { href = nixite.site.link readme; } "Readme") (a "/blog" "blog") (List { } [ "item 1" "item 2" "item 3" ]) - (p { } [ + (p [ "check out my" (blue "blue span") "isn't it" - (underblue "great!") + (underblue { onclick = "alert(1)"; } "great!") ]) ]) ]); diff --git a/nixite/html.nix b/nixite/html.nix index 1161567..b6e04e2 100644 --- a/nixite/html.nix +++ b/nixite/html.nix @@ -28,27 +28,29 @@ in rec { else keyvalue key value) attrs))); - tag = tag: { - inherit tag; - __toString = self: toString (self { } ""); - __functor = self: attrs: - if !(builtins.isAttrs attrs) then - throw "HTML tag requires attribute set" + tag = t: { + tag = t; + attrs = {}; + __toString = self: toString (self ""); + __functor = self: child: + (if !(isTag child) then + (if isSet child then + self // ({attrs = self.attrs // child;}) + else + throw "tag child must be tag, list, or string, got ${ + builtins.typeOf child + }" + ) 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 ${ - builtins.typeOf child - }" - else { - inherit tag attrs child; - __toString = toHTML; - }; - }; + tag = t; + attrs = self.attrs; + inherit child; + __toString = toHTML; + }); }; + isSet = a: builtins.isAttrs a && !a ? __toString; + isTag = tag: (builtins.isString tag || builtins.isList tag || (tag ? __toString && builtins.isFunction tag.__toString)); diff --git a/nixite/site.nix b/nixite/site.nix index 72cfe1e..7f7b8ad 100644 --- a/nixite/site.nix +++ b/nixite/site.nix @@ -112,6 +112,8 @@ in rec { else [ ]); + link = {name, content}@page: page // {type = "link";}; + copyTo = prefix: site: builtins.toString (builtins.attrValues (builtins.mapAttrs (name: content: if builtins.isString content then '' diff --git a/nixite/style.nix b/nixite/style.nix index cac2195..36bfa28 100644 --- a/nixite/style.nix +++ b/nixite/style.nix @@ -1,5 +1,4 @@ let - html = import ./html.nix; styleToString = identifier: styles: if !builtins.isAttrs styles then @@ -21,7 +20,7 @@ let ({ ${element.attrs.__id} = element.attrs.style or { }; } // (if element.attrs ? __extends then { - ${element.attrs.__extends.attrs.__id} = + ${element.attrs.__extends.attrs.__id or element.attrs.__extends.tag} = element.attrs.__extends.attrs.style or { }; } else { })) @@ -42,10 +41,11 @@ let builtins.zipAttrsWith (name: value: builtins.elemAt value 0) (map getStyles elements); - mkProps = props: tag: class: + mkProps = tag: class: props: props // { - __id = "${tag}.${builtins.concatStringsSep "." class}"; - class = class ++ (props.class or [ ]); + __id = "${tag.tag}.${class}"; + __extends = tag; + class = ( tag.attrs.class or [] ) ++ [ class ] ++ (props.class or [ ]); }; stylesToString = styles: @@ -55,11 +55,6 @@ let in { inherit getStyle getStyles stylesToString; - extend = tag: class: props: - (html.tag tag.tag ((mkProps props tag.tag (tag.attrs.class ++ [ class ])) - // { - __extends = tag; - })); - - tag = tag: class: props: (html.tag tag (mkProps props tag [ class ])); + component = tag: class: props: + tag ( mkProps tag class props ); } diff --git a/testing/html.test.nix b/testing/html.test.nix index b3af048..ffd2425 100644 --- a/testing/html.test.nix +++ b/testing/html.test.nix @@ -9,7 +9,7 @@ in with html; [ expected = "p"; })) - (it "keeps attr info in the tag" (let p = tag "p" { class = ""; }; + (it "keeps attr info in the tag" (let p = tag "p" { class = ""; }; in { actual = p.attrs; expected = { class = ""; }; @@ -81,6 +81,12 @@ in with html; [ expected = ''

''; })) + (it "can take many sets of props" (let p = tag "p"; + in { + actual = toString (p { class = "foobar"; } { style = "a style"; }); + expected = ''

''; + })) + (it "works recursively" (let attrs = { style = { foo = "bar"; }; }; para = (tag "p" attrs); diff --git a/testing/import.nix b/testing/import.nix index 87aefe1..5bef664 100644 --- a/testing/import.nix +++ b/testing/import.nix @@ -1,4 +1,5 @@ path: +builtins.trace ( "testing " + builtins.baseNameOf path ) '' echo echo 'TEST: ${builtins.baseNameOf path}' diff --git a/testing/it.nix b/testing/it.nix index 4324a02..9071da6 100644 --- a/testing/it.nix +++ b/testing/it.nix @@ -4,7 +4,7 @@ msg: let preProcess = v: if removeDunders then - builtins.removeAttrs v [ "__toString" "__functor" ] + undunder v else if asString then toString v else if asJSON then @@ -15,11 +15,14 @@ let a = preProcess actual; e = preProcess expected; + undunder = v: if builtins.isAttrs v then builtins.removeAttrs v [ "__toString" "__functor" ] else v; + + out = (if safeToPrint then builtins.toJSON (undunder actual) else ''{"msg": "refusing to print"}''); + in if (a == e) then '' echo 'it ${msg}' '' else - builtins.trace "FAILED ${msg}" builtins.trace - (if safeToPrint then builtins.toJSON actual else actual) builtins.trace - (if safeToPrint then builtins.toJSON expected else expected) '' + builtins.trace "FAILED ${msg}" '' echo FAILED ${msg} + echo '${out}' | jq '.' '' diff --git a/testing/site.test.nix b/testing/site.test.nix index fdc38d8..3f46afe 100644 --- a/testing/site.test.nix +++ b/testing/site.test.nix @@ -85,13 +85,13 @@ in with site; [ }) (it "gets all styles" { - expected = { + expected = {"p"={};"div"={}; "p.class" = { color = "blue"; }; - "a.class2" = { color = "green"; }; + "div.class2" = { color = "green"; }; }; actual = getStyles (let - p = style.tag "p" "class" { style = { color = "blue"; }; }; - g = style.tag "a" "class2" { style = { color = "green"; }; }; + p = style.component elems.p "class" { style = { color = "blue"; }; }; + g = style.component elems.div "class2" { style = { color = "green"; }; }; in { "index.html" = p ""; blog = { "index.html" = g ""; }; diff --git a/testing/style.test.nix b/testing/style.test.nix index 329fed0..5deb192 100644 --- a/testing/style.test.nix +++ b/testing/style.test.nix @@ -1,26 +1,27 @@ let style = import ../nixite/style.nix; + elems = import ../nixite/elems.nix; it = import ./it.nix; in [ - (it "fetches empty style" (let para = (style.tag "p" "para" { }); + (it "fetches empty style" (let para = (style.component elems.p "para" { }); in { - expected = { "p.para" = { }; }; + expected = { "p" = {}; "p.para" = { }; }; actual = style.getStyle (para ""); })) (it "fetches style" (let attrs = { style = { foo = "bar"; }; }; - para = (style.tag "p" "para" attrs); + para = (style.component elems.p "para" attrs); in { - expected = { "p.para" = attrs.style; }; + expected = {"p" = {}; "p.para" = attrs.style; }; actual = style.getStyle (para ""); })) (it "appliess class" (let attrs = { style = { foo = "bar"; }; }; - para = (style.tag "p" "para" attrs); + para = (style.component elems.p "para" attrs); in { expected = [ "para" ]; actual = (para "").attrs.class; @@ -31,7 +32,7 @@ in [ style = { foo = "bar"; }; class = [ "other" "class" ]; }; - para = (style.tag "p" "para" attrs); + para = (style.component elems.p "para" attrs); in { expected = [ "para" "other" "class" ]; actual = (para "").attrs.class; @@ -39,32 +40,32 @@ in [ (it "fetches style for class" (let s = { foo = "bar"; }; - para = (style.tag "p" "para" { style = s; }); + para = (style.component elems.p "para" { style = s; }); in { - expected = { "p.para" = s; }; + expected = { "p" = {}; "p.para" = s; }; actual = style.getStyle (para ""); })) (it "fetches style recursively" (let - s = { + s = {"p" = {};"div" = {}; "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; + "div.link" = { this = "that"; }; }; - para = (style.tag "p" "para" { style = s."p.para"; }); - a = (style.tag "a" "link" { style = s."a.link"; }); + para = (style.component elems.p "para" { style = s."p.para"; }); + div = (style.component elems.div "link" { style = s."div.link"; }); in { expected = s; - actual = style.getStyles (para (a "hello")); + actual = style.getStyles (para (div "hello")); removeDunders = true; })) (it "fetches style recursively through lists" (let - s = { + s = {"p" = {};"div" = {}; "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; + "div.link" = { this = "that"; }; }; - para = (style.tag "p" "para" { style = s."p.para"; }); - a = (style.tag "a" "link" { style = s."a.link"; }); + para = (style.component elems.p "para" { style = s."p.para"; }); + a = (style.component elems.div "link" { style = s."div.link"; }); in { expected = s; actual = style.getStyles (para [ (a "hello") ]); @@ -72,12 +73,12 @@ in [ })) (it "fetches style recursively with repeats" (let - s = { + s = {"p" = {};"div" = {}; "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; + "div.link" = { this = "that"; }; }; - para = (style.tag "p" "para" { style = s."p.para"; }); - a = (style.tag "a" "link" { style = s."a.link"; }); + para = (style.component elems.p "para" { style = s."p.para"; }); + a = (style.component elems.div "link" { style = s."div.link"; }); in { expected = s; actual = style.getStyles (para [ (a "hello") (a "hello") ]); @@ -85,7 +86,7 @@ in [ })) (it "converts styles to string" (let - s = { + s = {"p" = {}; "p.para" = { foo = "bar"; }; "a.link" = { this = "that"; }; }; @@ -104,10 +105,10 @@ in [ (it "extends styled tags" (let s = { "p.para" = { foo = "bar"; }; - "p.para.oof" = { oof = "yes"; }; + "p.oof" = { oof = "yes"; }; }; - para = (style.tag "p" "para" { style = s."p.para"; }); - para2 = (style.extend para "oof" { style = s."p.para.oof"; }); + para = (style.component elems.p "para" { style = s."p.para"; }); + para2 = (style.component para "oof" { style = s."p.oof"; }); in { expected = s; actual = style.getStyles (para2 ""); @@ -115,12 +116,12 @@ in [ })) (it "extends styled tags classes" (let - s = { + s = {"p" = {}; "div" = {}; "p.para" = { foo = "bar"; }; "p.para.oof" = { oof = "yes"; }; }; - para = (style.tag "p" "para" { style = s."p.para"; }); - para2 = (style.extend para "oof" { style = s."p.para.oof"; }); + para = (style.component elems.p "para" { style = s."p.para"; }); + para2 = (style.component para "oof" { style = s."p.para.oof"; }); in { expected = [ "para" "oof" ]; actual = (para2 "").attrs.class;