diff --git a/framework/h/tag.go b/framework/h/tag.go index 23fd3b4..611fc55 100644 --- a/framework/h/tag.go +++ b/framework/h/tag.go @@ -182,6 +182,10 @@ func Input(inputType string, children ...Ren) *Element { } } +func TextArea(children ...Ren) *Element { + return Tag("textarea", children...) +} + func TextInput(children ...Ren) *Element { return Input("text", children...) } @@ -462,6 +466,10 @@ func THead(children ...Ren) *Element { return Tag("thead", children...) } +func I(children ...Ren) *Element { + return Tag("i", children...) +} + func TFoot(children ...Ren) *Element { return Tag("tfoot", children...) } diff --git a/htmgo-site/go.mod b/htmgo-site/go.mod index 35bad92..a71ecf1 100644 --- a/htmgo-site/go.mod +++ b/htmgo-site/go.mod @@ -10,7 +10,10 @@ require ( ) require ( - github.com/alecthomas/chroma/v2 v2.2.0 // indirect - github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/alecthomas/chroma/v2 v2.14.0 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/maddalax/htmgo/tools/html-to-htmgo v0.0.0-20241011152834-980afbc5ac5b // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/text v0.19.0 // indirect ) diff --git a/htmgo-site/go.sum b/htmgo-site/go.sum index 61c08ee..904edc3 100644 --- a/htmgo-site/go.sum +++ b/htmgo-site/go.sum @@ -1,19 +1,26 @@ github.com/alecthomas/chroma/v2 v2.2.0 h1:Aten8jfQwUqEdadVFFjNyjx7HTexhKP0XuqBG67mRDY= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae h1:zzGwJfFlFGD94CyyYwCJeSuD32Gj9GTaSi5y9hoVzdY= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/maddalax/htmgo/framework v0.0.0-20241011141133-d0c272e1e516 h1:7nky9p/TVkRZOgu0xQ/t+Z23ZeRLGjZc9PpH9xJgEjo= github.com/maddalax/htmgo/framework v0.0.0-20241011141133-d0c272e1e516/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80= +github.com/maddalax/htmgo/tools/html-to-htmgo v0.0.0-20241011152834-980afbc5ac5b h1:326OAhrxyoDbq51MBB0DmN0JYPcCFcg0nAkeHuS1uws= +github.com/maddalax/htmgo/tools/html-to-htmgo v0.0.0-20241011152834-980afbc5ac5b/go.mod h1:hpDNkFnNT0FIgmQsVjMeQOzLuPxaqmkbNuws3zh4gWs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -27,6 +34,10 @@ github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+ github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/htmgo-site/pages/html-to-go.go b/htmgo-site/pages/html-to-go.go new file mode 100644 index 0000000..0a9231a --- /dev/null +++ b/htmgo-site/pages/html-to-go.go @@ -0,0 +1,26 @@ +package pages + +import ( + "github.com/maddalax/htmgo/framework/h" + "htmgo-site/pages/base" + "htmgo-site/partials" +) + +func HtmlToGoPage(ctx *h.RequestContext) *h.Page { + return h.NewPage( + base.RootPage(ctx, + h.Div( + h.Class("flex flex-col h-full items-center justify-center w-full pt-6"), + h.H3( + h.Text("Convert raw html to htmgo code"), + h.Class("text-2xl font-bold"), + ), + h.Div( + h.Class("h-full w-full flex gap-4 p-8"), + partials.HtmlInput(), + partials.GoOutput(""), + ), + ), + ), + ) +} diff --git a/htmgo-site/partials/html-to-go.go b/htmgo-site/partials/html-to-go.go new file mode 100644 index 0000000..0d6a844 --- /dev/null +++ b/htmgo-site/partials/html-to-go.go @@ -0,0 +1,56 @@ +package partials + +import ( + "bytes" + "github.com/alecthomas/chroma/v2" + "github.com/alecthomas/chroma/v2/formatters/html" + "github.com/alecthomas/chroma/v2/lexers" + "github.com/alecthomas/chroma/v2/styles" + "github.com/maddalax/htmgo/framework/h" + "github.com/maddalax/htmgo/tools/html-to-htmgo/htmltogo" +) + +func ConvertHtmlToGo(ctx *h.RequestContext) *h.Partial { + value := ctx.FormValue("html-input") + parsed := htmltogo.Parse([]byte(value)) + + var buf bytes.Buffer + + lexer := lexers.Get("go") + style := styles.Get("github") + formatter := html.New(html.WithCustomCSS(map[chroma.TokenType]string{ + chroma.PreWrapper: "padding: 12px; height: 100%; overflow: auto;", + })) + iterator, err := lexer.Tokenise(nil, string(parsed)) + err = formatter.Format(&buf, style, iterator) + + if err != nil { + return h.SwapPartial(ctx, GoOutput(string(parsed))) + } + + return h.SwapPartial(ctx, GoOutput(buf.String())) +} + +func HtmlInput() *h.Element { + return h.Div( + h.Class("h-[90%] w-1/2 min-w-1/2"), + h.TextArea( + h.Name("html-input"), + h.PostPartial(ConvertHtmlToGo, "keyup delay:300ms"), + h.Class("h-[90%] w-full p-4 rounded border border-slate-200"), + h.Placeholder("Paste your HTML here"), + h.Rows(10), + ), + ) +} + +func GoOutput(content string) *h.Element { + return h.Div( + h.Class("h-[90%] w-1/2 min-w-1/2"), + h.Id("go-output"), + h.Div( + h.Class("h-[90%] w-full rounded border border-slate-200"), + h.UnsafeRaw(content), + ), + ) +} diff --git a/tools/html-to-htmgo/main.go b/tools/html-to-htmgo/htmltogo/main.go similarity index 96% rename from tools/html-to-htmgo/main.go rename to tools/html-to-htmgo/htmltogo/main.go index 8e51ab7..ce382c1 100644 --- a/tools/html-to-htmgo/main.go +++ b/tools/html-to-htmgo/htmltogo/main.go @@ -1,6 +1,6 @@ // Forked from https://github.com/PiotrKowalski/html-to-gomponents -package main +package htmltogo import ( serviceformatter "github.com/maddalax/htmgo/tools/html-to-htmgo/internal/adapters/services/formatter" diff --git a/tools/html-to-htmgo/internal/domain/node.go b/tools/html-to-htmgo/internal/domain/node.go index d0fdfa4..29464a0 100644 --- a/tools/html-to-htmgo/internal/domain/node.go +++ b/tools/html-to-htmgo/internal/domain/node.go @@ -20,6 +20,8 @@ type CustomNode struct { func (n *CustomNode) SetType(in string) { switch in { + case "textarea": + n.Type = "h.TextArea" case "head": n.Type = "h.Head" case "thead": @@ -61,6 +63,8 @@ func (n *CustomNode) AddAttr(key, value string) { } switch { + case key == "autocomplete": + n.Attrs = append(n.Attrs, Attr{key: "h.AutoComplete", value: value}) case key == "id": n.Attrs = append(n.Attrs, Attr{key: "h.Id", value: value}) case key == "tabindex": @@ -88,6 +92,42 @@ func (n *CustomNode) String() string { str += n.Type + "(" } + if str == "h.Input(" { + if len(n.Attrs) > 0 { + for i, attr := range n.Attrs { + if attr.key == "h.Type" { + str = str + fmt.Sprintf(`"%s"`, attr.value) + "," + n.Attrs = append(n.Attrs[:i], n.Attrs[i+1:]...) + } + } + } + } + + booleanAttributes := []string{ + "h.AllowFullscreen", + "h.Async", + "h.Autofocus", + "h.Autoplay", + "h.Checked", + "h.Controls", + "h.Default", + "h.Defer", + "h.Disabled", + "h.FormNoValidate", + "h.Hidden", + "h.IsMap", + "h.Loop", + "h.Multiple", + "h.Muted", + "h.NoModule", + "h.NoValidate", + "h.Open", + "h.ReadOnly", + "h.Required", + "h.Reversed", + "h.Selected", + } + if len(n.Attrs) > 0 { for _, v := range n.Attrs { switch { @@ -101,7 +141,7 @@ func (n *CustomNode) String() string { } else { str = fmt.Sprintf("%s%s(\"%s\"),", str, v.key, v.value) } - case v.value == "": + case v.value == "" && !slices.Contains(booleanAttributes, v.key): str = fmt.Sprintf("%s%s(\"\"),", str, v.key) default: str = fmt.Sprintf("%s%s(),", str, v.key)