diff options
-rw-r--r-- | .github/FUNDING.yml | 2 | ||||
-rw-r--r-- | README.md | 46 | ||||
-rw-r--r-- | components/components.go | 4 | ||||
-rw-r--r-- | components/components_test.go | 39 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | gomponents_test.go | 4 | ||||
-rw-r--r-- | html/attributes.go | 4 | ||||
-rw-r--r-- | html/attributes_test.go | 12 | ||||
-rw-r--r-- | html/elements.go | 2 | ||||
-rw-r--r-- | html/elements_test.go | 6 | ||||
-rw-r--r-- | http/handler.go | 2 | ||||
-rw-r--r-- | http/handler_test.go | 31 | ||||
-rw-r--r-- | internal/assert/assert.go | 2 | ||||
-rw-r--r-- | internal/examples/app/go.mod | 2 | ||||
-rw-r--r-- | internal/examples/app/go.sum | 4 | ||||
-rw-r--r-- | internal/examples/app/go.work.sum | 2 | ||||
-rw-r--r-- | internal/examples/app/html/about.go | 13 | ||||
-rw-r--r-- | internal/examples/app/html/components.go | 9 | ||||
-rw-r--r-- | internal/examples/app/html/home.go | 13 | ||||
-rw-r--r-- | internal/examples/app/http/pages.go | 4 | ||||
-rw-r--r-- | internal/import/import_test.go | 23 |
21 files changed, 119 insertions, 107 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index c8ba47b..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom: - - "https://maragu.gumroad.com/l/gomponents" diff --git a/README.md b/README.md index f272f3b..5516a7b 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ <img src="logo.png" alt="Logo" width="300" align="right"> -[](https://pkg.go.dev/maragu.dev/gomponents) -[](https://github.com/maragudk/gomponents/actions/workflows/ci.yml) -[](https://codecov.io/gh/maragudk/gomponents) -[](https://goreportcard.com/report/maragu.dev/gomponents) +[](https://pkg.go.dev/go.alanpearce.eu/gomponents) +[](https://github.com/alanpearce/gomponents/actions/workflows/ci.yml) +[](https://codecov.io/gh/alanpearce/gomponents) +[](https://goreportcard.com/report/go.alanpearce.eu/gomponents) Try HTML components in pure Go. @@ -14,12 +14,15 @@ They render to HTML 5, and make it easy for you to build reusable components. So you can focus on building your app instead of learning yet another templating language. ```shell -go get maragu.dev/gomponents +go get go.alanpearce.eu/gomponents ``` -Made with ✨sparkles✨ by [maragu](https://www.maragu.dev/). +Made with ✨sparkles✨ by [maragu](https://www.maragu.dev/), forked by [alanpearce](https://alanpearce.eu) to add helpers. -Does your company depend on this project? [Contact me at markus@maragu.dk](mailto:markus@maragu.dk?Subject=Supporting%20your%20project) to discuss options for a one-time or recurring invoice to ensure its continued thriving. +## Fork changes + +- `MapWithIndex` and `MapMap` for mapping over slices and maps respectively +- `If` and `Iff` take an extra argument to render a fallback component when the condition is false ## Features @@ -43,16 +46,16 @@ Check out [www.gomponents.com](https://www.gomponents.com) for an introduction. ## Usage ```shell -go get maragu.dev/gomponents +go get go.alanpearce.eu/gomponents ``` ```go package main import ( - . "maragu.dev/gomponents" - . "maragu.dev/gomponents/components" - . "maragu.dev/gomponents/html" + . "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/components" + . "go.alanpearce.eu/gomponents/html" ) func Navbar(authenticated bool, currentPath string) Node { @@ -121,27 +124,6 @@ I accept code contributions, especially with new HTML elements and attributes. I always welcome issues discussing interesting aspects of gomponents, and obviously bug reports and the like. But otherwise, I consider gomponents pretty much feature complete. -New features to the core library are unlikely to be merged, since I like keeping it simple and the API small. -In particular, new functions around collections (similar to `Map`) or flow control (`IfElse`/`Else`) will not be added. -`Map` was introduced before generics where a thing, and I think it's better to start using generic functions -from the stdlib or other libraries, instead of adding gomponents-specific variations of them to this library. - -If there's something missing that you need, I would recommend to keep small helper functions around in your own projects. -And if all else fails, you can always use an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE): - -```go -func list(ordered bool) Node { - return func() Node { - // Do whatever you need to do, imperatively - if ordered { - return Ol() - } else { - return Ul() - } - }() -} -``` - ### What's up with the specially named elements and attributes? Unfortunately, there are some name clashes in HTML elements and attributes, so they need an `El` or `Attr` suffix, diff --git a/components/components.go b/components/components.go index d37ccf4..2a36e1f 100644 --- a/components/components.go +++ b/components/components.go @@ -6,8 +6,8 @@ import ( "sort" "strings" - g "maragu.dev/gomponents" - . "maragu.dev/gomponents/html" + g "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/html" ) // HTML5Props for [HTML5]. diff --git a/components/components_test.go b/components/components_test.go index 75e8bb0..52265f4 100644 --- a/components/components_test.go +++ b/components/components_test.go @@ -4,10 +4,10 @@ import ( "os" "testing" - g "maragu.dev/gomponents" - . "maragu.dev/gomponents/components" - . "maragu.dev/gomponents/html" - "maragu.dev/gomponents/internal/assert" + g "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/components" + . "go.alanpearce.eu/gomponents/html" + "go.alanpearce.eu/gomponents/internal/assert" ) func TestHTML5(t *testing.T) { @@ -20,16 +20,27 @@ func TestHTML5(t *testing.T) { Body: []g.Node{Div()}, }) - assert.Equal(t, `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title><meta name="description" content="Love hats."><link rel="stylesheet" href="/hat.css"></head><body><div></div></body></html>`, e) + assert.Equal( + t, + `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title><meta name="description" content="Love hats."><link rel="stylesheet" href="/hat.css"></head><body><div></div></body></html>`, + e, + ) }) - t.Run("returns no language, description, and extra head/body elements if empty", func(t *testing.T) { - e := HTML5(HTML5Props{ - Title: "Hat", - }) + t.Run( + "returns no language, description, and extra head/body elements if empty", + func(t *testing.T) { + e := HTML5(HTML5Props{ + Title: "Hat", + }) - assert.Equal(t, `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title></head><body></body></html>`, e) - }) + assert.Equal( + t, + `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title></head><body></body></html>`, + e, + ) + }, + ) t.Run("returns an html5 document template with additional HTML attributes", func(t *testing.T) { e := HTML5(HTML5Props{ @@ -41,7 +52,11 @@ func TestHTML5(t *testing.T) { HTMLAttrs: []g.Node{Class("h-full"), ID("htmlid")}, }) - assert.Equal(t, `<!doctype html><html lang="en" class="h-full" id="htmlid"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title><meta name="description" content="Love hats."><link rel="stylesheet" href="/hat.css"></head><body><div></div></body></html>`, e) + assert.Equal( + t, + `<!doctype html><html lang="en" class="h-full" id="htmlid"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Hat</title><meta name="description" content="Love hats."><link rel="stylesheet" href="/hat.css"></head><body><div></div></body></html>`, + e, + ) }) } diff --git a/go.mod b/go.mod index 659200a..8a7823b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module "maragu.dev/gomponents" +module go.alanpearce.eu/gomponents go 1.18 diff --git a/gomponents_test.go b/gomponents_test.go index f3cb1b8..7ea31c0 100644 --- a/gomponents_test.go +++ b/gomponents_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - g "maragu.dev/gomponents" - "maragu.dev/gomponents/internal/assert" + g "go.alanpearce.eu/gomponents" + "go.alanpearce.eu/gomponents/internal/assert" ) func TestNodeFunc(t *testing.T) { diff --git a/html/attributes.go b/html/attributes.go index e9a0b6d..1a62e8a 100644 --- a/html/attributes.go +++ b/html/attributes.go @@ -1,7 +1,7 @@ package html import ( - g "maragu.dev/gomponents" + g "go.alanpearce.eu/gomponents" ) func Async() g.Node { @@ -138,7 +138,7 @@ func DataAttr(name, v string) g.Node { } func SlotAttr(v string) g.Node { - return g.Attr("slot", v) + return g.Attr("slot", v) } func For(v string) g.Node { diff --git a/html/attributes_test.go b/html/attributes_test.go index 6a01e03..1cdabd9 100644 --- a/html/attributes_test.go +++ b/html/attributes_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" - g "maragu.dev/gomponents" - . "maragu.dev/gomponents/html" - "maragu.dev/gomponents/internal/assert" + g "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/html" + "go.alanpearce.eu/gomponents/internal/assert" ) func TestBooleanAttributes(t *testing.T) { @@ -126,17 +126,17 @@ func TestVariadicAttributes(t *testing.T) { } for _, test := range tests { - t.Run(test.Name + "(no args)", func(t *testing.T) { + t.Run(test.Name+"(no args)", func(t *testing.T) { n := g.El("div", test.Func()) assert.Equal(t, fmt.Sprintf(`<div %v></div>`, test.Name), n) }) - t.Run(test.Name +"(one arg)", func(t *testing.T) { + t.Run(test.Name+"(one arg)", func(t *testing.T) { n := g.El("div", test.Func("hat")) assert.Equal(t, fmt.Sprintf(`<div %v="hat"></div>`, test.Name), n) }) - t.Run(test.Name + "(two args panics)", func(t *testing.T) { + t.Run(test.Name+"(two args panics)", func(t *testing.T) { defer func() { if r := recover(); r == nil { t.Errorf("expected a panic") diff --git a/html/elements.go b/html/elements.go index bf747a1..ad3f19f 100644 --- a/html/elements.go +++ b/html/elements.go @@ -8,7 +8,7 @@ package html import ( "io" - g "maragu.dev/gomponents" + g "go.alanpearce.eu/gomponents" ) // Doctype returns a special kind of [g.Node] that prefixes its sibling with the string "<!doctype html>". diff --git a/html/elements_test.go b/html/elements_test.go index 7670af5..de8413f 100644 --- a/html/elements_test.go +++ b/html/elements_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - g "maragu.dev/gomponents" - . "maragu.dev/gomponents/html" - "maragu.dev/gomponents/internal/assert" + g "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/html" + "go.alanpearce.eu/gomponents/internal/assert" ) type erroringWriter struct{} diff --git a/http/handler.go b/http/handler.go index 1de6b8c..47a6e37 100644 --- a/http/handler.go +++ b/http/handler.go @@ -4,7 +4,7 @@ package http import ( "net/http" - g "maragu.dev/gomponents" + g "go.alanpearce.eu/gomponents" ) // Handler is like [http.Handler] but returns a [g.Node] and an error. diff --git a/http/handler_test.go b/http/handler_test.go index 453e3e7..6f3aa7c 100644 --- a/http/handler_test.go +++ b/http/handler_test.go @@ -7,8 +7,8 @@ import ( "net/http/httptest" "testing" - g "maragu.dev/gomponents" - ghttp "maragu.dev/gomponents/http" + g "go.alanpearce.eu/gomponents" + ghttp "go.alanpearce.eu/gomponents/http" ) func TestAdapt(t *testing.T) { @@ -51,18 +51,21 @@ func TestAdapt(t *testing.T) { } }) - t.Run("errors with status code if error implements StatusCode method and renders node", func(t *testing.T) { - h := ghttp.Adapt(func(w http.ResponseWriter, r *http.Request) (g.Node, error) { - return g.El("div"), statusCodeError{http.StatusTeapot} - }) - code, body := get(t, h) - if code != http.StatusTeapot { - t.Fatal("status code is", code) - } - if body != "<div></div>" { - t.Fatal(`body is`, body) - } - }) + t.Run( + "errors with status code if error implements StatusCode method and renders node", + func(t *testing.T) { + h := ghttp.Adapt(func(w http.ResponseWriter, r *http.Request) (g.Node, error) { + return g.El("div"), statusCodeError{http.StatusTeapot} + }) + code, body := get(t, h) + if code != http.StatusTeapot { + t.Fatal("status code is", code) + } + if body != "<div></div>" { + t.Fatal(`body is`, body) + } + }, + ) t.Run("errors with 500 if other error and renders node", func(t *testing.T) { h := ghttp.Adapt(func(w http.ResponseWriter, r *http.Request) (g.Node, error) { diff --git a/internal/assert/assert.go b/internal/assert/assert.go index 102a435..26479b2 100644 --- a/internal/assert/assert.go +++ b/internal/assert/assert.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - g "maragu.dev/gomponents" + g "go.alanpearce.eu/gomponents" ) // Equal checks for equality between the given expected string and the rendered Node string. diff --git a/internal/examples/app/go.mod b/internal/examples/app/go.mod index 83e51cf..ad86ed3 100644 --- a/internal/examples/app/go.mod +++ b/internal/examples/app/go.mod @@ -2,4 +2,4 @@ module app go 1.23.2 -require maragu.dev/gomponents v1.0.0-beta1 +require go.alanpearce.eu/gomponents v1.0.0-beta1 diff --git a/internal/examples/app/go.sum b/internal/examples/app/go.sum index d3b1274..0df2e94 100644 --- a/internal/examples/app/go.sum +++ b/internal/examples/app/go.sum @@ -1,2 +1,2 @@ -maragu.dev/gomponents v1.0.0-beta1 h1:I51NqKfrtQC4GxuWShqW5CT5BrfToMEueLD76IhdSXs= -maragu.dev/gomponents v1.0.0-beta1/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= +go.alanpearce.eu/gomponents v1.0.0-beta1 h1:I51NqKfrtQC4GxuWShqW5CT5BrfToMEueLD76IhdSXs= +go.alanpearce.eu/gomponents v1.0.0-beta1/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= diff --git a/internal/examples/app/go.work.sum b/internal/examples/app/go.work.sum index 5c5a195..bca4022 100644 --- a/internal/examples/app/go.work.sum +++ b/internal/examples/app/go.work.sum @@ -1 +1 @@ -maragu.dev/gomponents v1.0.0-beta1/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= +go.alanpearce.eu/gomponents v1.0.0-beta1/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= diff --git a/internal/examples/app/html/about.go b/internal/examples/app/html/about.go index 61a5001..1a0517d 100644 --- a/internal/examples/app/html/about.go +++ b/internal/examples/app/html/about.go @@ -3,14 +3,15 @@ package html import ( "time" - . "maragu.dev/gomponents" - . "maragu.dev/gomponents/html" + . "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/html" ) func AboutPage() Node { now := time.Now() - return page("About", + return page( + "About", H1(Text("About")), P(Textf("Built with gomponents and rendered at %v.", now.Format(time.TimeOnly))), @@ -20,6 +21,10 @@ func AboutPage() Node { If(now.Second()%2 != 0, Text("It's an odd second!")), ), - Img(Class("max-w-sm"), Src("https://www.gomponents.com/images/logo.png"), Alt("gomponents logo")), + Img( + Class("max-w-sm"), + Src("https://www.gomponents.com/images/logo.png"), + Alt("gomponents logo"), + ), ) } diff --git a/internal/examples/app/html/components.go b/internal/examples/app/html/components.go index ad5d582..78079d2 100644 --- a/internal/examples/app/html/components.go +++ b/internal/examples/app/html/components.go @@ -1,9 +1,9 @@ package html import ( - . "maragu.dev/gomponents" - . "maragu.dev/gomponents/components" - . "maragu.dev/gomponents/html" + . "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/components" + . "go.alanpearce.eu/gomponents/html" ) func page(title string, children ...Node) Node { @@ -56,7 +56,8 @@ func container(padY bool, children ...Node) Node { } func footer() Node { - return Div(Class("bg-gray-900 text-white shadow text-center h-16 flex items-center justify-center"), + return Div( + Class("bg-gray-900 text-white shadow text-center h-16 flex items-center justify-center"), A(Href("https://www.gomponents.com"), Text("gomponents")), ) } diff --git a/internal/examples/app/html/home.go b/internal/examples/app/html/home.go index 5743d38..fdd48dc 100644 --- a/internal/examples/app/html/home.go +++ b/internal/examples/app/html/home.go @@ -1,17 +1,22 @@ package html import ( - . "maragu.dev/gomponents" - . "maragu.dev/gomponents/html" + . "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/html" ) func HomePage(items []string) Node { - return page("Home", + return page( + "Home", H1(Text("Home")), P(Text("This is a gomponents example app!")), - P(Raw(`Have a look at the <a href="https:/github.com/maragudk/gomponents/tree/main/internal/examples/app">source code</a> to see how it’s structured.`)), + P( + Raw( + `Have a look at the <a href="https:/github.com/alanpearce/gomponents/tree/main/internal/examples/app">source code</a> to see how it’s structured.`, + ), + ), Ul(Map(items, func(s string) Node { return Li(Text(s)) diff --git a/internal/examples/app/http/pages.go b/internal/examples/app/http/pages.go index b09589b..a8756f7 100644 --- a/internal/examples/app/http/pages.go +++ b/internal/examples/app/http/pages.go @@ -3,8 +3,8 @@ package http import ( "net/http" - . "maragu.dev/gomponents" - ghttp "maragu.dev/gomponents/http" + . "go.alanpearce.eu/gomponents" + ghttp "go.alanpearce.eu/gomponents/http" "app/html" ) diff --git a/internal/import/import_test.go b/internal/import/import_test.go index e505e46..d81b967 100644 --- a/internal/import/import_test.go +++ b/internal/import/import_test.go @@ -3,17 +3,20 @@ package import_test import ( "testing" - . "maragu.dev/gomponents" - . "maragu.dev/gomponents/components" - . "maragu.dev/gomponents/html" - . "maragu.dev/gomponents/http" + . "go.alanpearce.eu/gomponents" + . "go.alanpearce.eu/gomponents/components" + . "go.alanpearce.eu/gomponents/html" + . "go.alanpearce.eu/gomponents/http" ) func TestImports(t *testing.T) { - t.Run("this is just a test that does nothing, but I need the dot imports above", func(t *testing.T) { - _ = El("div") - _ = A() - _ = HTML5(HTML5Props{}) - _ = Adapt(nil) - }) + t.Run( + "this is just a test that does nothing, but I need the dot imports above", + func(t *testing.T) { + _ = El("div") + _ = A() + _ = HTML5(HTML5Props{}) + _ = Adapt(nil) + }, + ) } |