diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..37bd484 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONY: test tidy + +tidy: + @echo "Tidying up module..." + go mod tidy + +test: + @echo "Running tests..." + go test ./... \ No newline at end of file diff --git a/elem.go b/elem.go new file mode 100644 index 0000000..a4adbdf --- /dev/null +++ b/elem.go @@ -0,0 +1,49 @@ +package elem + +import ( + "sort" +) + +type Element struct { + Tag string + Props map[string]string + Children []interface{} // Can be either string (for text) or another Element +} + +func NewElement(tag string, props Props, children ...interface{}) *Element { + return &Element{ + Tag: tag, + Props: props, + Children: children, + } +} + +func (e *Element) Render() string { + // Sort the keys for consistent order + keys := make([]string, 0, len(e.Props)) + for k := range e.Props { + keys = append(keys, k) + } + sort.Strings(keys) + + props := "" + for _, k := range keys { + props += ` ` + k + `="` + e.Props[k] + `"` + } + + content := "" + for _, child := range e.Children { + switch c := child.(type) { + case string: + content += c + case *Element: + content += c.Render() + } + } + + if content == "" { + return `<` + e.Tag + props + ` />` // Self-closing tag + } + + return `<` + e.Tag + props + `>` + content + `` + e.Tag + `>` +} diff --git a/elements.go b/elements.go new file mode 100644 index 0000000..6b4e9e0 --- /dev/null +++ b/elements.go @@ -0,0 +1,45 @@ +package elem + +func Div(props Props, children ...interface{}) *Element { + return NewElement("div", props, children...) +} + +func H1(props Props, children ...interface{}) *Element { + return NewElement("h1", props, children...) +} + +func H2(props Props, children ...interface{}) *Element { + return NewElement("h2", props, children...) +} + +func H3(props Props, children ...interface{}) *Element { + return NewElement("h3", props, children...) +} + +func P(props Props, children ...interface{}) *Element { + return NewElement("p", props, children...) +} + +func A(props Props, children ...interface{}) *Element { + return NewElement("a", props, children...) +} + +func Span(props Props, children ...interface{}) *Element { + return NewElement("span", props, children...) +} + +func Ul(props Props, children ...interface{}) *Element { + return NewElement("ul", props, children...) +} + +func Li(props Props, children ...interface{}) *Element { + return NewElement("li", props, children...) +} + +func Img(props Props) *Element { + return NewElement("img", props) +} + +func Text(content string) string { + return content +} diff --git a/elements_test.go b/elements_test.go new file mode 100644 index 0000000..70798e7 --- /dev/null +++ b/elements_test.go @@ -0,0 +1,66 @@ +package elem + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestA(t *testing.T) { + expected := `Visit Example` + el := A(Props{Href: "https://example.com"}, Text("Visit Example")) + assert.Equal(t, expected, el.Render()) +} + +func TestDiv(t *testing.T) { + expected := `
Hello, Elem!
` + el := P(nil, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestSpan(t *testing.T) { + expected := `Hello, Elem!` + el := Span(Props{Class: "highlight"}, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestUl(t *testing.T) { + expected := `