From 003100e691b59e12ab2d726dad9780f484773ce8 Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 1 Jan 2024 04:41:56 +0000 Subject: [PATCH] WIP better style management --- nixite/html.nix | 4 +- nixite/style.nix | 16 ++++ testing/html.test.nix | 59 ++++++++++++++ testing/style.test.nix | 171 ++++++++++++++++++++++++++++++++++------- 4 files changed, 221 insertions(+), 29 deletions(-) diff --git a/nixite/html.nix b/nixite/html.nix index 6945a7a..b5ced54 100644 --- a/nixite/html.nix +++ b/nixite/html.nix @@ -34,7 +34,7 @@ in rec { if !(builtins.isAttrs attrs) then throw "HTML tag requires attribute set" else { - inherit attrs; + inherit tag attrs; __functor = self: child: if !(isTag child) then throw "tag child must be tag, list, or string" @@ -47,7 +47,7 @@ in rec { isTag = tag: (builtins.isString tag || builtins.isList tag - || (tag ? toString && builtins.isFunction tag.toString)); + || (tag ? __toString && builtins.isFunction tag.__toString)); addToHead = page: heads: page // { diff --git a/nixite/style.nix b/nixite/style.nix index 7efab3b..555cc1e 100644 --- a/nixite/style.nix +++ b/nixite/style.nix @@ -36,7 +36,23 @@ let "${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 {};} 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 diff --git a/testing/html.test.nix b/testing/html.test.nix index 009055b..98048c6 100644 --- a/testing/html.test.nix +++ b/testing/html.test.nix @@ -15,6 +15,12 @@ in with html; [ expected = { class = ""; }; })) + (it "keeps tag after setting attrs" (let p = tag "p" { class = ""; }; + in { + actual = p.tag; + expected = "p"; + })) + (it "makes a p tag" { actual = tag "p" { } "Hello"; expected = { @@ -25,6 +31,59 @@ in with html; [ }; }) + (it "makes element" + (let para = (tag "p" {}); + in { + expected = "p"; + actual = para.tag; + })) + + (it "keeps attrs on element" + (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" 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 "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 "works recursively" + (let + attrs = { style = { foo = "bar"; }; }; + para = (tag "p" attrs); + a = (tag "a" {}); + in { + expected = "

hello

"; + actual = toString ( para (a "hello") ); + })) + (it "concatinates classes" { actual = toString (tag "p" { class = [ "class1" "class2" ]; } "Hello"); expected = ''

Hello

''; diff --git a/testing/style.test.nix b/testing/style.test.nix index 950e42f..a5a1296 100644 --- a/testing/style.test.nix +++ b/testing/style.test.nix @@ -3,21 +3,6 @@ let html = import ../nixite/html.nix; it = import ./it.nix; - 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 [ (it "makes a p component" (let @@ -55,45 +40,94 @@ in [ actual = my.classless { } "yes"; asString = true; })) - (it "does not error without attrs" { + + (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" { + })) + + (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" { + })) + + (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" { + })) + (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" { + })) + (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" { + })) + (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 { @@ -136,4 +170,87 @@ in [ actual = removeAttrs my.style [ "__toString" ]; })) + (it "fetches empty style" + (let + para = (style.tag "p" "para" {}); + in { + expected = {"p.para" = {};}; + 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 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" + (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 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 "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 "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; + })) + ]