From df9b26c33930f20250d8716e50921108b8b8dec1 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Wed, 30 Jul 2025 14:00:18 +0200 Subject: [PATCH] init --- .gitignore | 2 + README.md | 12 +++ controller/template.go | 190 +++++++++++++++++++++++++++++++++++++++++ form/contact.go | 82 ++++++++++++++++++ form/theme.go | 39 +++++++++ go.mod | 11 +++ go.sum | 18 ++++ main.go | 14 +++ 8 files changed, 368 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 controller/template.go create mode 100644 form/contact.go create mode 100644 form/theme.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1d89c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/go-form-demo +/vendor diff --git a/README.md b/README.md new file mode 100644 index 0000000..9597461 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Demo of [deblan/go-form](https://gitnet.fr/deblan/go-form) + +## Usage + +```sh +git clone https://gitnet.fr/deblan/go-form-demo +go mod tidy +go build -o demo +./demo +``` + +Then browse http://127.0.0.1:1324. diff --git a/controller/template.go b/controller/template.go new file mode 100644 index 0000000..8c5e89d --- /dev/null +++ b/controller/template.go @@ -0,0 +1,190 @@ +package controller + +import ( + "html/template" + "net/http" + + "github.com/yassinebenaid/godump" + "gitnet.fr/deblan/go-form-demo/form" + "gitnet.fr/deblan/go-form/theme" +) + +func UsingTemplate(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + + var dumped any + + // New instances of datas + themeValue := form.NewTheme() + contactValue := form.Contact{} + + // Theme form handler + themeSelectorForm := form.CreateThemeSelectorForm() + themeSelectorForm.HandleRequest(r) + if themeSelectorForm.IsSubmitted() && themeSelectorForm.IsValid() { + themeSelectorForm.Bind(themeValue) + } + + // Contact form handler + contactForm := form.CreateContactForm(themeValue.Value == "Bootstrap5") + if r.Method == contactForm.Method { + contactForm.HandleRequest(r) + + if contactForm.IsSubmitted() && contactForm.IsValid() { + contactForm.Bind(&contactValue) + + // For debugging + var dump godump.Dumper + dump.Theme = godump.Theme{} + dumped = dump.Sprint(contactValue) + } + } + + render := theme.NewRenderer(themes[themeValue.Value]) + + tpl, _ := template.New("page"). + Funcs(render.FuncMap()). + Parse(pageTemplates[themeValue.Value]) + + tpl.Execute(w, map[string]any{ + "ContactForm": contactForm, + "ThemeSelectorForm": themeSelectorForm, + "IsSent": dumped != nil, + "Dump": dumped, + }) +} + +var pageTemplates = map[string]string{ + "Html5": ` + + + + Form + + + +
+ {{ if .IsSent }} +

+ OK! +

{{ .Dump }}
+

+ {{ else }} + {{ form .ThemeSelectorForm }} + +

Contact form

+ + {{ form .ContactForm }} + {{ end }} +
+ +`, + "Bootstrap5": ` + + + + + Form + + + +
+ {{ if .IsSent }} +
+ OK! +
{{ .Dump }}
+
+ {{ else }} + {{ form .ThemeSelectorForm }} + +

Contact form

+ + {{ form .ContactForm }} + {{ end }} +
+ +`, +} + +var themes = map[string]map[string]theme.RenderFunc{ + "Html5": theme.Html5, + "Bootstrap5": theme.Bootstrap5, +} diff --git a/form/contact.go b/form/contact.go new file mode 100644 index 0000000..d3d1b2f --- /dev/null +++ b/form/contact.go @@ -0,0 +1,82 @@ +package form + +import ( + "net/http" + + "gitnet.fr/deblan/go-form/form" + "gitnet.fr/deblan/go-form/validation" +) + +type Contact struct { + Name string + Email string + Topic string + Message string +} + +func CreateContactForm(isBoostrap bool) *form.Form { + var rowAttr form.Attrs + var btnAttr form.Attrs + + formAttr := form.Attrs{"id": "contact-form"} + + if isBoostrap { + rowAttr = form.Attrs{"class": "col-12"} + formAttr["class"] = "row" + btnAttr = form.Attrs{"class": "btn-primary"} + } + + topics := form.NewChoices([]string{"I have a question", "Report a bug"}). + WithLabelBuilder(func(key int, item any) string { + return item.(string) + }) + + return form.NewForm( + form.NewFieldText("Name"). + WithOptions( + form.NewOption("label", "Your name"), + form.NewOption("required", true), + form.NewOption("row_attr", rowAttr), + form.NewOption("label_attr", form.Attrs{"class": "required"}), + ). + WithConstraints(validation.NewNotBlank()), + form.NewFieldMail("Email"). + WithOptions( + form.NewOption("label", "Your e-mail"), + form.NewOption("required", true), + form.NewOption("row_attr", rowAttr), + form.NewOption("label_attr", form.Attrs{"class": "required"}), + ). + WithConstraints( + validation.NewNotBlank(), + validation.NewMail(), + ), + form.NewFieldChoice("Topic"). + WithOptions( + form.NewOption("label", "Topic"), + form.NewOption("empty_choice_label", ""), + form.NewOption("choices", topics), + ), + form.NewFieldTextarea("Message"). + WithOptions( + form.NewOption("label", "Message"), + form.NewOption("required", true), + form.NewOption("row_attr", rowAttr), + form.NewOption("label_attr", form.Attrs{"class": "required"}), + form.NewOption("attr", form.Attrs{"rows": "10"}), + form.NewOption("help_attr", form.Attrs{"class": "help"}), + form.NewOption("help", "Minimum 10 chars"), + ). + WithConstraints( + validation.NewNotBlank(), + validation.NewLength().WithMin(10), + ), + form.NewSubmit(""). + WithData("Send"). + WithOptions(form.NewOption("attr", btnAttr)), + ). + End(). + WithOptions(form.NewOption("attr", formAttr)). + WithName("contact"). + WithMethod(http.MethodPost) +} diff --git a/form/theme.go b/form/theme.go new file mode 100644 index 0000000..d6a6cce --- /dev/null +++ b/form/theme.go @@ -0,0 +1,39 @@ +package form + +import ( + "net/http" + + "gitnet.fr/deblan/go-form/form" + "gitnet.fr/deblan/go-form/validation" +) + +type Theme struct { + Value string +} + +func NewTheme() *Theme { + return &Theme{Value: "Html5"} +} + +func CreateThemeSelectorForm() *form.Form { + choices := form.NewChoices([]string{"Html5", "Bootstrap5"}) + choices.LabelBuilder = func(key int, item any) string { return item.(string) } + choices.ValueBuilder = func(key int, item any) string { return item.(string) } + + return form.NewForm( + form.NewFieldChoice("Value"). + WithOptions( + form.NewOption("choices", choices), + form.NewOption("label", "Select a theme"), + form.NewOption("required", true), + ). + WithConstraints(validation.NewNotBlank()), + form.NewSubmit(""). + WithData("Change"). + WithOptions(form.NewOption("attr", form.Attrs{"class": "btn-primary"})), + ). + End(). + WithName(""). + WithOptions(form.NewOption("attr", form.Attrs{"id": "theme-form"})). + WithMethod(http.MethodGet) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a37cb29 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module gitnet.fr/deblan/go-form-demo + +go 1.23.0 + +require ( + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/spf13/cast v1.9.2 // indirect + github.com/yassinebenaid/godump v0.11.1 // indirect + gitnet.fr/deblan/go-form v1.1.6 // indirect + maragu.dev/gomponents v1.1.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4cd72c1 --- /dev/null +++ b/go.sum @@ -0,0 +1,18 @@ +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= +github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/yassinebenaid/godump v0.11.1 h1:SPujx/XaYqGDfmNh7JI3dOyCUVrG0bG2duhO3Eh2EhI= +github.com/yassinebenaid/godump v0.11.1/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44= +gitnet.fr/deblan/go-form v1.1.2 h1:3jXPgJvgFGFfD3KFrp/l49luDTp6SNObdadVDxgsxvQ= +gitnet.fr/deblan/go-form v1.1.2/go.mod h1:b+mDJlGUnFKnym06Mys5uHUskgo6uSlr1NMaQPwmJKY= +gitnet.fr/deblan/go-form v1.1.3 h1:BvwYv1vb2wpvz2frUe+V6b4o2PXtzfdhYnV7+dRTtAM= +gitnet.fr/deblan/go-form v1.1.3/go.mod h1:b+mDJlGUnFKnym06Mys5uHUskgo6uSlr1NMaQPwmJKY= +gitnet.fr/deblan/go-form v1.1.4 h1:ULwjrmGPmvZNc/YwmNRLNKjweNGjozu2A5Z0D8Ol2XQ= +gitnet.fr/deblan/go-form v1.1.4/go.mod h1:b+mDJlGUnFKnym06Mys5uHUskgo6uSlr1NMaQPwmJKY= +gitnet.fr/deblan/go-form v1.1.5 h1:ad4StmMErs5Qrt8pzHOCLcaZyXjTupQtjZ9zsNH/qLQ= +gitnet.fr/deblan/go-form v1.1.5/go.mod h1:b+mDJlGUnFKnym06Mys5uHUskgo6uSlr1NMaQPwmJKY= +gitnet.fr/deblan/go-form v1.1.6 h1:ckT3jktWLnododHhiq0/rRLQQ66ccH+vofGfiCVslW8= +gitnet.fr/deblan/go-form v1.1.6/go.mod h1:b+mDJlGUnFKnym06Mys5uHUskgo6uSlr1NMaQPwmJKY= +maragu.dev/gomponents v1.1.0 h1:iCybZZChHr1eSlvkWp/JP3CrZGzctLudQ/JI3sBcO4U= +maragu.dev/gomponents v1.1.0/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..6fa1b26 --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "log" + "net/http" + + "gitnet.fr/deblan/go-form-demo/controller" +) + +func main() { + http.HandleFunc("/", controller.UsingTemplate) + + log.Fatal(http.ListenAndServe(":1324", nil)) +}