Skip to content

Commit

Permalink
Add first working version of the library :)
Browse files Browse the repository at this point in the history
  • Loading branch information
andre-dasilva committed May 20, 2024
1 parent 5ea4101 commit 956e790
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 12 deletions.
9 changes: 9 additions & 0 deletions src/document.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import elements.{type HtmlAttribute, type HtmlElement}

pub fn document(
attrs: List(HtmlAttribute),
head: List(HtmlElement),
body: List(HtmlElement),
) -> HtmlElement {
elements.html(attrs, [elements.head([], head), elements.body([], body)])
}
118 changes: 118 additions & 0 deletions src/elements.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
pub type HtmlAttribute {
HtmlAttribute(key: String, value: String)
}

pub type HtmlElement {
HtmlElement(
tag: String,
attrs: List(HtmlAttribute),
children: List(HtmlElement),
)
Text(String)
}

pub fn attr(key: String, value: String) -> HtmlAttribute {
HtmlAttribute(key, value)
}

pub fn text(value: String) -> HtmlElement {
Text(value)
}

pub fn element(
tag: String,
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
HtmlElement(tag: tag, attrs: attrs, children: children)
}

pub fn element_self_closing(tag: String, attrs: List(HtmlAttribute)) {
element(tag, attrs, [])
}

pub fn html(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("html", attrs, children)
}

pub fn head(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("head", attrs, children)
}

pub fn title(title: String) -> HtmlElement {
element("title", [], [text(title)])
}

pub fn meta(attrs: List(HtmlAttribute)) -> HtmlElement {
element_self_closing("meta", attrs)
}

pub fn body(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("body", attrs, children)
}

pub fn p(attrs: List(HtmlAttribute), children: List(HtmlElement)) -> HtmlElement {
element("p", attrs, children)
}

pub fn h1(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("h1", attrs, children)
}

pub fn h2(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("h2", attrs, children)
}

pub fn h3(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("h3", attrs, children)
}

pub fn h4(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("h4", attrs, children)
}

pub fn h5(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("h5", attrs, children)
}

pub fn a(attrs: List(HtmlAttribute), children: List(HtmlElement)) -> HtmlElement {
element("a", attrs, children)
}

pub fn span(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("span", attrs, children)
}

pub fn div(
attrs: List(HtmlAttribute),
children: List(HtmlElement),
) -> HtmlElement {
element("div", attrs, children)
}
5 changes: 0 additions & 5 deletions src/html_components.gleam

This file was deleted.

53 changes: 53 additions & 0 deletions src/render.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import elements
import gleam/list
import gleam/string

fn attributes_to_list(attributes: List(elements.HtmlAttribute)) -> String {
attributes
|> list.map(fn(attr) { attr.key <> "=" <> "\"" <> attr.value <> "\"" })
|> string.join(" ")
}

fn append_if(text, predicate, value_func) -> String {
case predicate() {
True -> string.append(text, value_func())
False -> text
}
}

pub fn render_element(element: elements.HtmlElement) -> String {
case element {
elements.HtmlElement(tag, attributes, children) -> {
let html =
"<"
|> append_if(fn() { tag == "html" }, fn() { "!DOCTYPE html><" })
|> string.append(tag)
|> append_if(fn() { list.length(attributes) > 0 }, fn() {
" " <> attributes_to_list(attributes)
})

case children {
[] -> {
html
|> string.append(" />")
}
_ -> {
let html_childen =
children
|> list.map(render_element)
|> string.join("")
|> string.append("</")
|> string.append(tag)
|> string.append(">")

html
|> string.append(">")
|> string.append(html_childen)
}
}
}
elements.Text(value) -> {
value
}
}
}
7 changes: 0 additions & 7 deletions test/html_components_test.gleam
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import gleeunit
import gleeunit/should

pub fn main() {
gleeunit.main()
}

// gleeunit test functions end in `_test`
pub fn hello_world_test() {
1
|> should.equal(1)
}
65 changes: 65 additions & 0 deletions test/render_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import elements
import gleeunit/should
import render

fn paragraph(text: String) {
elements.p([], [elements.text(text)])
}

fn meta() {
elements.meta([
elements.attr("name", "author"),
elements.attr("content", "André da Silva"),
])
}

pub fn render_single_paragraph_test() {
let input = paragraph("Hello")

let expected = "<p>Hello</p>"

render.render_element(input)
|> should.equal(expected)
}

pub fn render_single_meta_test() {
let input = meta()

let expected = "<meta name=\"author\" content=\"André da Silva\" />"

render.render_element(input)
|> should.equal(expected)
}

pub fn render_multiple_paragraph_test() {
let input =
elements.html([elements.attr("lang", "en")], [
paragraph("Hello"),
paragraph("World"),
])

let expected =
"<!DOCTYPE html><html lang=\"en\"><p>Hello</p><p>World</p></html>"

render.render_element(input)
|> should.equal(expected)
}

pub fn render_nested_elements_test() {
let input =
elements.html([elements.attr("lang", "en")], [
elements.head([], [elements.title("Nested")]),
elements.body([], [
elements.h1([], [elements.text("Hello")]),
elements.div([elements.attr("class", "text-2xl")], [
elements.p([], [elements.text("What a nice library")]),
]),
]),
])

let expected =
"<!DOCTYPE html><html lang=\"en\"><head><title>Nested</title></head><body><h1>Hello</h1><div class=\"text-2xl\"><p>What a nice library</p></div></body></html>"

render.render_element(input)
|> should.equal(expected)
}

0 comments on commit 956e790

Please sign in to comment.