diff --git a/flake.nix b/flake.nix index faf8ced..727a8d3 100644 --- a/flake.nix +++ b/flake.nix @@ -8,36 +8,52 @@ nixite = import ./nixite/. { inherit pkgs; }; in nixite // { packages.${system} = { - raw = nixite.mkSite (nixite.site.applyStyle ./testing/src/style.css - (nixite.site.extractPaths { + raw = nixite.mkSite (let + site = (nixite.site.extractPaths { "test" = with nixite.elems; - (Doc [ + let + blue = nixite.style.tag "span" "blue" { + style = { color = "blue"; }; + }; + underblue = nixite.style.extend blue "under" { + style = { text-decoration = "underline"; }; + }; + in (Doc { } [ [ - (title "Nixite") - (nixite.html.tag "link" { + (title { } "Nixite") + (link { rel = "shortcut icon"; type = "image/png"; href = ./testing/src/favicon.png; } "") - (a "/readme" "Readme") ] - (main [ + (main { } [ + (a "/readme" "Readme") (a "/blog" "blog") - (List [ "item 1" "item 2" "item 3" ]) + (List { } [ "item 1" "item 2" "item 3" ]) + (p { } [ + "check out my" + (blue "blue span") + "isn't it" + (underblue "great!") + ]) ]) ]); 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); default = nixite.serve self.packages.${system}.raw; test = let run = import ./testing/run.nix pkgs; in run [ - #./testing/md.test.nix + ./testing/md.test.nix ./testing/html.test.nix - #./testing/elems.test.nix - #./testing/site.test.nix + ./testing/elems.test.nix + ./testing/site.test.nix ./testing/style.test.nix ]; }; diff --git a/nixite/elems.nix b/nixite/elems.nix index 6f79372..49ef8c2 100644 --- a/nixite/elems.nix +++ b/nixite/elems.nix @@ -1,60 +1,143 @@ -let - html = import ./html.nix; - s = import ./style.nix; - base = tag: (s.styled tag tag { class = [ ]; }); -in (base "html") (base "head") (base "title") (base "base") (base "link") -(base "meta") -# (base "style" ) # borks styled coponents -(base "body") (base "article") (base "section") (base "nav") (base "aside") -(base "h1") (base "h2") (base "h3") (base "h4") (base "h5") (base "h6") -(base "hgroup") (base "header") (base "footer") (base "address") (base "p") -(base "hr") (base "pre") (base "blockquote") (base "ol") (base "ul") -(base "menu") (base "li") (base "dl") (base "dt") (base "dd") (base "figure") -(base "figcaption") (base "main") (base "div") (base "a") (base "em") -(base "strong") (base "small") (base "s") (base "cite") (base "q") (base "dfn") -(base "abbr") (base "ruby") (base "rt") (base "rp") (base "data") (base "time") -(base "code") (base "var") (base "samp") (base "kbd") (base "sub") (base "sup") -(base "i") (base "b") (base "u") (base "mark") (base "bdi") (base "bdo") -(base "span") (base "br") (base "wbr") (base "ins") (base "del") -(base "picture") (base "source") (base "img") (base "iframe") (base "embed") -(base "object") (base "param") (base "video") (base "audio") (base "track") -(base "map") (base "area") (base "table") (base "caption") (base "colgroup") -(base "col") (base "tbody") (base "thead") (base "tfoot") (base "tr") -(base "td") (base "th") (base "form") (base "label") (base "input") -(base "button") (base "select") (base "datalist") (base "optgroup") -(base "option") (base "textarea") (base "output") (base "progress") -(base "meter") (base "fieldset") (base "legend") (base "details") -(base "summary") (base "dialog") (base "script") (base "noscript") -(base "template") (base "slot") (base "canvas") - -(s.styled "List" "ul" { - __child = child: +let html = import ./html.nix; +in { + html = html.tag "html"; + # Document metadata + head = html.tag "head"; + title = html.tag "title"; + base = html.tag "base"; + link = html.tag "link"; + meta = html.tag "meta"; + style = html.tag "style"; + # Sections + body = html.tag "body"; + article = html.tag "article"; + section = html.tag "section"; + nav = html.tag "nav"; + aside = html.tag "aside"; + h1 = html.tag "h1"; + h2 = html.tag "h2"; + h3 = html.tag "h3"; + h4 = html.tag "h4"; + h5 = html.tag "h5"; + h6 = html.tag "h6"; + hgroup = html.tag "hgroup"; + header = html.tag "header"; + footer = html.tag "footer"; + address = html.tag "address"; + # Grouping content + p = html.tag "p"; + hr = html.tag "hr"; + pre = html.tag "pre"; + blockquote = html.tag "blockquote"; + ol = html.tag "ol"; + ul = html.tag "ul"; + menu = html.tag "menu"; + li = html.tag "li"; + dl = html.tag "dl"; + dt = html.tag "dt"; + dd = html.tag "dd"; + figure = html.tag "figure"; + figcaption = html.tag "figcaption"; + main = html.tag "main"; + div = html.tag "div"; + # Text-level semantics + a = params: + html.tag "a" + (if builtins.isString params then { href = params; } else params); + em = html.tag "em"; + strong = html.tag "strong"; + small = html.tag "small"; + s = html.tag "s"; + cite = html.tag "cite"; + q = html.tag "q"; + dfn = html.tag "dfn"; + abbr = html.tag "abbr"; + ruby = html.tag "ruby"; + rt = html.tag "rt"; + rp = html.tag "rp"; + data = html.tag "data"; + time = html.tag "time"; + code = html.tag "code"; + var = html.tag "var"; + samp = html.tag "samp"; + kbd = html.tag "kbd"; + sub = html.tag "sub"; + sup = html.tag "sup"; + i = html.tag "i"; + b = html.tag "b"; + u = html.tag "u"; + mark = html.tag "mark"; + bdi = html.tag "bdi"; + bdo = html.tag "bdo"; + span = html.tag "span"; + br = html.tag "br"; + wbr = html.tag "wbr"; + # Edits + ins = html.tag "ins"; + del = html.tag "del"; + # Embedded content + picture = html.tag "picture"; + source = html.tag "source"; + img = html.tag "img"; + iframe = html.tag "iframe"; + embed = html.tag "embed"; + object = html.tag "object"; + param = html.tag "param"; + video = html.tag "video"; + audio = html.tag "audio"; + track = html.tag "track"; + map = html.tag "map"; + area = html.tag "area"; + # Tabular data + table = html.tag "table"; + caption = html.tag "caption"; + colgroup = html.tag "colgroup"; + col = html.tag "col"; + tbody = html.tag "tbody"; + thead = html.tag "thead"; + tfoot = html.tag "tfoot"; + tr = html.tag "tr"; + td = html.tag "td"; + th = html.tag "th"; + # Forms + form = html.tag "form"; + label = html.tag "label"; + input = html.tag "input"; + button = html.tag "button"; + select = html.tag "select"; + datalist = html.tag "datalist"; + optgroup = html.tag "optgroup"; + option = html.tag "option"; + textarea = html.tag "textarea"; + output = html.tag "output"; + progress = html.tag "progress"; + meter = html.tag "meter"; + fieldset = html.tag "fieldset"; + legend = html.tag "legend"; + # Interactive elements + details = html.tag "details"; + summary = html.tag "summary"; + dialog = html.tag "dialog"; + # Scripting + script = html.tag "script"; + noscript = html.tag "noscript"; + template = html.tag "template"; + slot = html.tag "slot"; + canvas = html.tag "canvas"; + # custom + List = params: child: assert builtins.isList child; - (map (html.tag "li" { }) child); -}) (s.styled "Doc" "html" { - __child = child: + html.tag "ul" { } (map (html.tag "li" { }) child); + Doc = params: child: assert builtins.isList child; assert builtins.length child == 2; - assert builtins.isList (builtins.elemAt child 0); [ + assert builtins.isList (builtins.elemAt child 0); + html.tag "html" ({ lang = "en"; } // params) [ (html.tag "head" { } (builtins.elemAt child 0)) (html.tag "body" { } (builtins.elemAt child 1)) ]; - lang = "en"; - class = [ ]; -}) (s.styled "a" "a" { - __self = self: attrs: child: - if builtins.isString attrs then - self { href = attrs; } child - else - self attrs child; -}) (s.styled "Stylesheet" "link" { - rel = "stylesheet"; - class = [ ]; - __self = self: attrs: - if builtins.isString attrs then - self { href = attrs; } "" - else - self attrs ""; -}) // { - H = v: child: html.tag "h${toString v}" { } child; + Stylesheet = params: + html.tag "link" ({ + rel = "stylesheet"; + } // (if builtins.isString params then { href = params; } else params)) ""; } diff --git a/nixite/html.nix b/nixite/html.nix index b5ced54..4acaf6d 100644 --- a/nixite/html.nix +++ b/nixite/html.nix @@ -1,9 +1,9 @@ let keyvalue = key: value: assert builtins.isString key; - if builtins.isAttrs value then - builtins.trace "Skipping ${key} as it is a set" "" else - if value == "" || value == [ ] then + if builtins.isAttrs value then + builtins.trace "Skipping ${key} as it is a set" "" + else if value == "" || value == [ ] then "" else ''${key}="${toString value}"''; @@ -37,7 +37,9 @@ in rec { inherit tag attrs; __functor = self: child: if !(isTag child) then - throw "tag child must be tag, list, or string" + throw "tag child must be tag, list, or string, got ${ + builtins.typeOf child + }" else { inherit tag attrs child; __toString = toHTML; diff --git a/nixite/md.nix b/nixite/md.nix index 64701e4..3f1740f 100644 --- a/nixite/md.nix +++ b/nixite/md.nix @@ -1,4 +1,15 @@ -let elems = import ./elems.nix; +let + elems = import ./elems.nix; + html = import ./html.nix; + H = n: + let + v = if n < 1 then + builtins.trace "attempted to make heading size ${n} (min is 1)" 1 + else if n > 6 then + builtins.trace "attempted to make heading size ${n} (max is 6)" 6 + else + n; + in html.tag "h${toString v}" { }; in rec { readMd = md: if builtins.isPath md then @@ -30,13 +41,14 @@ in rec { readDir = root: recFixAppendix (recReadMd root); - mdToPage = md: elems.Doc [ [ (elems.title "markdown file") ] (readMd md) ]; + mdToPage = md: + elems.Doc { } [ [ (elems.title { } "markdown file") ] (readMd md) ]; 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); + in if m == null then elems.p { } block else H h (builtins.elemAt m 1); heading = block: builtins.match "(#+) (.*)" block; } diff --git a/nixite/site.nix b/nixite/site.nix index 0303697..e7e7b36 100644 --- a/nixite/site.nix +++ b/nixite/site.nix @@ -4,6 +4,12 @@ let in rec { applyStyle = style: site: (linkStyle site) // { "style.css" = style; }; + getStyles = site: '' + .blue { + color: blue; + } + ''; + linkStyle = site: (builtins.mapAttrs (name: content: if builtins.isAttrs content && content ? "__toString" then diff --git a/nixite/style.nix b/nixite/style.nix index 555cc1e..cac2195 100644 --- a/nixite/style.nix +++ b/nixite/style.nix @@ -1,16 +1,6 @@ let html = import ./html.nix; - join = { - __functor = self: new: self // new // { style = self.style // new.style; }; - }; - - mkStyle = identifier: styles: { - ${identifier} = styles; - __toString = self: - toString (builtins.attrValues (builtins.mapAttrs styleToString self)); - }; - styleToString = identifier: styles: if !builtins.isAttrs styles then "" @@ -26,76 +16,50 @@ let } ''; - mkIdentifier = name: tag: - assert builtins.isString name; - let - elem = if builtins.isString tag then tag else tag.tag or ""; - inheritClass = - if builtins.isString tag then [ ] else tag.attrs.class or [ ]; - in { class ? [ name ] ++ inheritClass, id ? "", ... }: - "${elem}" + builtins.concatStringsSep "" (map (c: "." + c) class) - + (if id != "" then "#" else "") + id; + getStyle = element: + if builtins.isAttrs element && element.attrs ? __id then + ({ + ${element.attrs.__id} = element.attrs.style or { }; + } // (if element.attrs ? __extends then { + ${element.attrs.__extends.attrs.__id} = + element.attrs.__extends.attrs.style or { }; + } else + { })) + else + { }; - - getStyle = element: if builtins.isAttrs element && element.attrs ? __id - then {${element.attrs.__id} = element.attrs.style or {};} else {}; - - getStyles = element: ( getStyle element ) // - (if builtins.isList element then getStylesFromList element else - if element ? child then getStyles element.child else {}); - - getStylesFromList = elements: builtins.zipAttrsWith (name: value: builtins.elemAt value 0) (map getStyles elements); - -in { - inherit getStyle getStyles; - - stylesToString = styles: builtins.concatStringsSep "" ( builtins.attrValues ( builtins.mapAttrs (styleToString) styles ) ); - - tag = tag: class: props: (html.tag tag (props // {__id = "${tag}.${class}";})); - - styled = name: tag: cprops: - assert builtins.isString name; - let - __child = cprops.__child or (child: child); - - joinProps = (cprops // { - __functor = prev: next: - prev // next // { - class = prev.class ++ next.class or [ ]; - }; - class = if cprops ? class then - if cprops.class == [ ] then [ ] else [ name ] ++ cprops.class - else - [ name ]; - }); - - self = if tag ? __functor && builtins.isFunction tag.__functor then - props: tag (joinProps props) - else if builtins.isString tag then - props: html.tag tag (joinProps props) - else - throw "You may only style a tag (string) or element, got ${ - builtins.typeOf tag - }"; - - __self = (cprops.__self or (self: props: - if builtins.isAttrs props then - (child: (self props (__child child))) - else if builtins.isString props || builtins.isList props then - (self { } (__child props)) - else - throw "Call element with attributes and child.")) self; - - in { - ${name} = { - tag = (if builtins.isString tag then tag else tag.tag); - attrs = - joinProps (if builtins.isString tag then { } else tag.attrs or { }); - __functor = self: __self; + getStyles = element: + (getStyle element) // (if builtins.isList element then + getStylesFromList element + else if element ? child then + getStyles element.child + else + { }) // { + __toString = stylesToString; }; - style = mkStyle (mkIdentifier name tag cprops) (cprops.style or { }); - } // join; + getStylesFromList = elements: + builtins.zipAttrsWith (name: value: builtins.elemAt value 0) + (map getStyles elements); - style = identifier: styles: { style = mkStyle identifier styles; } // join; + mkProps = props: tag: class: + props // { + __id = "${tag}.${builtins.concatStringsSep "." class}"; + class = class ++ (props.class or [ ]); + }; + + stylesToString = styles: + builtins.concatStringsSep "" + (builtins.attrValues (builtins.mapAttrs (styleToString) styles)); + +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 ])); } diff --git a/testing/elems.test.nix b/testing/elems.test.nix index 48e66a7..7272476 100644 --- a/testing/elems.test.nix +++ b/testing/elems.test.nix @@ -28,26 +28,13 @@ in with elems; [ actual = main { } [ "yeet" ]; asString = true; }) - (it "makes an h1 tag" { - expected = html.tag "h1" { } "foobar"; - actual = H 1 "foobar"; - asString = true; - }) - (it "makes an h2 tag" { - expected = html.tag "h2" { } "foobar"; - actual = H 2 "foobar"; - asString = true; - }) (it "makes a title tag" { expected = html.tag "title" { } "foobar"; actual = title { } "foobar"; asString = true; }) (it "makes an a tag" { - expected = html.tag "a" { - class = [ "a" ]; - href = "https://example.com"; - } "example"; + expected = html.tag "a" { href = "https://example.com"; } "example"; actual = a "https://example.com" "example"; asString = true; }) @@ -60,10 +47,7 @@ in with elems; [ asString = true; }) (it "makes a list" { - expected = html.tag "ul" { - __ = ""; - class = [ "List" ]; - } [ + expected = html.tag "ul" { __ = ""; } [ (html.tag "li" { } "foo") (html.tag "li" { } "bar") (html.tag "li" { } "baz") diff --git a/testing/html.test.nix b/testing/html.test.nix index 98048c6..4215e18 100644 --- a/testing/html.test.nix +++ b/testing/html.test.nix @@ -31,58 +31,52 @@ in with html; [ }; }) - (it "makes element" - (let para = (tag "p" {}); - in { - expected = "p"; - actual = para.tag; - })) + (it "makes element" (let para = (tag "p" { }); + in { + expected = "p"; + actual = para.tag; + })) - (it "keeps attrs on element" - (let + (it "keeps attrs on element" (let attrs = { style = { foo = "bar"; }; }; para = (tag "p" attrs); - in { - expected = attrs; - actual = para.attrs; - })) + in { + expected = attrs; + actual = para.attrs; + })) - (it "makes renderable element" - (let - attrs = { style = { foo = "bar"; }; }; - para = (tag "p" attrs); - in { - expected = "
"; - actual = toString ( para "" ); - })) + (it "makes renderable element" (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" attrs); + in { + expected = ""; + actual = toString (para ""); + })) - (it "keeps tag" - (let - attrs = { style = { foo = "bar"; }; }; - para = (tag "p" attrs); - in { - expected = "p"; - actual = ( para "" ).tag; - })) + (it "keeps tag" (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" attrs); + in { + expected = "p"; + actual = (para "").tag; + })) - (it "keeps style" - (let - attrs = { style = { foo = "bar"; }; }; - para = (tag "p" attrs); - in { - expected = { foo = "bar"; }; - actual = ( para "" ).attrs.style; - })) + (it "keeps style" (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" attrs); + in { + expected = { foo = "bar"; }; + actual = (para "").attrs.style; + })) - (it "works recursively" - (let - attrs = { style = { foo = "bar"; }; }; - para = (tag "p" attrs); - a = (tag "a" {}); - in { - expected = ""; - actual = toString ( para (a "hello") ); - })) + (it "works recursively" (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" attrs); + a = (tag "a" { }); + in { + expected = ""; + actual = toString (para (a "hello")); + })) (it "concatinates classes" { actual = toString (tag "p" { class = [ "class1" "class2" ]; } "Hello"); diff --git a/testing/it.nix b/testing/it.nix index 90d7cbd..98f05d1 100644 --- a/testing/it.nix +++ b/testing/it.nix @@ -1,9 +1,11 @@ msg: -{ actual, expected, asString ? false, asJSON ? false, }: +{ 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 '' echo 'it ${msg}' diff --git a/testing/md.test.nix b/testing/md.test.nix index 98de59a..72a2023 100644 --- a/testing/md.test.nix +++ b/testing/md.test.nix @@ -19,7 +19,7 @@ in with md; [ lorem ipsum ''; expected = [ - (elems.H 1 "foo bar") + (elems.h1 { } "foo bar") "" (elems.p { } '' lorem ipsum @@ -33,6 +33,14 @@ in with md; [ expected = "index.html"; }) + (it "converts markdown to a page" { + actual = mdToPage ./blog/index.md; + expected = '' +ye
&
''; + asString = true; + }) + (it "recursively reads dir" { actual = recReadMd ./blog; expected = { diff --git a/testing/style.test.nix b/testing/style.test.nix index a5a1296..329fed0 100644 --- a/testing/style.test.nix +++ b/testing/style.test.nix @@ -1,256 +1,129 @@ let style = import ../nixite/style.nix; - html = import ../nixite/html.nix; it = import ./it.nix; in [ - (it "makes a p component" (let - my = (style.styled "para" "p" { style = { some-style = "some value"; }; }); + (it "fetches empty style" (let para = (style.tag "p" "para" { }); in { - expected = html.tag "p" { class = [ "para" ]; } "yes"; - actual = my.para { } "yes"; - asString = true; + expected = { "p.para" = { }; }; + actual = style.getStyle (para ""); })) - (it "extends existing components" (let - my = (style.styled "generic" "p" { - foo = "bar"; - forgetme = "nothing"; - }); - this = (style.styled "quote" my.generic { - baz = "baz"; - forgetme = "forgotten"; - }); + (it "fetches style" (let + attrs = { style = { foo = "bar"; }; }; + para = (style.tag "p" "para" attrs); in { - expected = html.tag "p" { - forgetme = "forgotten"; - baz = "baz"; - foo = "bar"; - class = [ "generic" "quote" ]; - } "yes"; - actual = this.quote { } "yes"; - asString = true; + expected = { "p.para" = attrs.style; }; + actual = style.getStyle (para ""); })) - (it "makes a component with no class" - (let my = (style.styled "classless" "div" { class = [ ]; }); - in { - expected = html.tag "div" { class = [ ]; } "yes"; - actual = my.classless { } "yes"; - asString = true; - })) - - (it "does not error without attrs" (let - my = (style.styled "div" "div" { - class = [ "something" ]; - style = { this = "that"; }; - }); - in{ - expected = html.tag "div" { class = [ "div" "something" ]; } "yes"; - actual = my.div "yes"; - asString = true; - })) - - (it "makes a component" (let - my = (style.styled "div" "div" { - class = [ "something" ]; - style = { this = "that"; }; - }); - in{ - expected = html.tag "div" { class = [ "div" "something" ]; } "foobar"; - actual = my.div { } "foobar"; - asString = true; - })) - - (it "makes special components" (let - - my = (style.styled "s" "div" { - id = "s"; - class = [ "something" ]; - style = { s = "yes"; }; - }); - in{ - expected = html.tag "div" { - id = "s"; - class = [ "s" "something" ]; - } "foobar"; - actual = my.s { } "foobar"; - asString = true; - })) - (it "works on many classes" (let - my = (style.styled "foobar" "div" { - class = [ "foo" "bar" ]; - style = { something = "something"; }; - }); - in{ - expected = html.tag "div" { class = [ "foobar" "foo" "bar" ]; } "foobar"; - actual = my.foobar { } "foobar"; - asString = true; - })) - (it "does custom behavour" (let - - my = (style.styled "list" "ul" { - __child = child: - assert builtins.isList child; - (map (html.tag "li" { }) child); - }); - in { - expected = html.tag "ul" { - __ = ""; - class = [ "list" ]; - } [ (html.tag "li" { } "1") (html.tag "li" { } "2") ]; - actual = my.list { } [ "1" "2" ]; - asString = true; - })) - (it "combines attrs" (let - - my = (style.styled "div" "div" { - class = [ "something" ]; - style = { this = "that"; }; - }) (style.styled "s" "div" { - id = "s"; - class = [ "something" ]; - style = { s = "yes"; }; - }) (style.styled "foobar" "div" { - class = [ "foo" "bar" ]; - style = { something = "something"; }; - }) (style.style "body" { foo = "bar"; }) (style.styled "list" "ul" { - __child = child: - assert builtins.isList child; - (map (html.tag "li" { }) child); - }); - in { - expected = html.tag "div" { - id = "foo"; - class = [ "div" "something" ]; - } "foobar"; - actual = my.div { id = "foo"; } "foobar"; - asString = true; - })) - (it "makes a style" - (let my = (style.styled "para" "p" { style = { foo = "bar"; }; }); - in { - expected = { "p.para" = { foo = "bar"; }; }; - actual = removeAttrs my.style [ "__toString" ]; - })) - - (it "retains tag" - (let p = (style.styled "para" "p" { style = { foo = "bar"; }; }); - in { - expected = "p"; - actual = p.para.tag; - })) - - (it "retains attrs" - (let p = (style.styled "para" "p" { style = { foo = "bar"; }; }); - in { - expected = { foo = "bar"; }; - actual = p.para.attrs.style; - })) - - (it "retains class" (let p = (style.styled "para" "p" { }); + (it "appliess class" (let + attrs = { style = { foo = "bar"; }; }; + para = (style.tag "p" "para" attrs); in { expected = [ "para" ]; - actual = p.para.attrs.class; + actual = (para "").attrs.class; })) - (it "merges styles" (let - p = (style.styled "para" "p" { style = { foo = "bar"; }; }); - d = (style.styled "para2" p.para { style = { baz = "bar"; }; }); - my = p d; - in { - expected = { - "p.para" = { foo = "bar"; }; - "p.para2.para" = { - foo = "bar"; - baz = "bar"; - }; + (it "applies classes from props" (let + attrs = { + style = { foo = "bar"; }; + class = [ "other" "class" ]; }; - actual = removeAttrs my.style [ "__toString" ]; + para = (style.tag "p" "para" attrs); + in { + expected = [ "para" "other" "class" ]; + actual = (para "").attrs.class; })) - (it "fetches empty style" - (let - para = (style.tag "p" "para" {}); - in { - expected = {"p.para" = {};}; - actual = style.getStyle ( para "" ); - })) + (it "fetches style for class" (let + s = { foo = "bar"; }; + para = (style.tag "p" "para" { style = s; }); + in { + expected = { "p.para" = s; }; + actual = style.getStyle (para ""); + })) - (it "fetches style" - (let - attrs = { style = { foo = "bar"; }; }; - para = (style.tag "p" "para" attrs); - in { - expected = {"p.para" = attrs.style;}; - actual = style.getStyle ( para "" ); - })) + (it "fetches style recursively" (let + s = { + "p.para" = { foo = "bar"; }; + "a.link" = { this = "that"; }; + }; + para = (style.tag "p" "para" { style = s."p.para"; }); + a = (style.tag "a" "link" { style = s."a.link"; }); + in { + expected = s; + actual = style.getStyles (para (a "hello")); + removeDunders = true; + })) - (it "fetches style for class" - (let - s = { foo = "bar"; }; - para = (style.tag "p" "para" {style = s;}); - in { - expected = {"p.para" = s;}; - actual = style.getStyle ( para "" ); - })) + (it "fetches style recursively through lists" (let + s = { + "p.para" = { foo = "bar"; }; + "a.link" = { this = "that"; }; + }; + para = (style.tag "p" "para" { style = s."p.para"; }); + a = (style.tag "a" "link" { style = s."a.link"; }); + in { + expected = s; + actual = style.getStyles (para [ (a "hello") ]); + removeDunders = true; + })) - (it "fetches style recursively" - (let - s = { - "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; - }; - para = (style.tag "p" "para" {style = s."p.para";}); - a = (style.tag "a" "link" {style = s."a.link";}); - in { - expected = s; - actual = style.getStyles ( para (a "hello") ); - })) + (it "fetches style recursively with repeats" (let + s = { + "p.para" = { foo = "bar"; }; + "a.link" = { this = "that"; }; + }; + para = (style.tag "p" "para" { style = s."p.para"; }); + a = (style.tag "a" "link" { style = s."a.link"; }); + in { + expected = s; + actual = style.getStyles (para [ (a "hello") (a "hello") ]); + removeDunders = true; + })) - (it "fetches style recursively through lists" - (let - s = { - "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; - }; - para = (style.tag "p" "para" {style = s."p.para";}); - a = (style.tag "a" "link" {style = s."a.link";}); - in { - expected = s; - actual = style.getStyles ( para [(a "hello")] ); - })) + (it "converts styles to string" (let + s = { + "p.para" = { foo = "bar"; }; + "a.link" = { this = "that"; }; + }; + in { + expected = '' + a.link { + this: that; + } + p.para { + foo: bar; + } + ''; + actual = style.stylesToString s; + })) - (it "fetches style recursively with repeats" - (let - s = { - "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; - }; - para = (style.tag "p" "para" {style = s."p.para";}); - a = (style.tag "a" "link" {style = s."a.link";}); - in { - expected = s; - actual = style.getStyles ( para [(a "hello") (a "hello")] ); - })) + (it "extends styled tags" (let + s = { + "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"; }); + in { + expected = s; + actual = style.getStyles (para2 ""); + removeDunders = true; + })) - (it "converts styles to string" - (let - s = { - "p.para" = { foo = "bar"; }; - "a.link" = { this = "that"; }; - }; - in { - expected = '' - a.link { - this: that; - } - p.para { - foo: bar; - } - ''; - actual = style.stylesToString s; - })) + (it "extends styled tags classes" (let + s = { + "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"; }); + in { + expected = [ "para" "oof" ]; + actual = (para2 "").attrs.class; + })) ]