From 60d3a869d2df7b1362015b8e704f581f4f5de418 Mon Sep 17 00:00:00 2001 From: joerdav Date: Tue, 18 Apr 2023 10:23:18 +0100 Subject: [PATCH] feat: bulk update and click to edit --- README.md | 13 + bulkupdate/handlers.go | 64 +++ bulkupdate/templates.templ | 91 ++++ bulkupdate/templates_templ.go | 853 +++++++++++++++++++++++++++++ clicktoedit/handlers.go | 53 ++ clicktoedit/templates.templ | 60 +++ clicktoedit/templates_templ.go | 952 +++++++++++++++++++++++++++++++++ go.mod | 10 + go.sum | 8 + home.templ | 23 + home_templ.go | 227 ++++++++ main.go | 47 ++ shared/layout.templ | 50 ++ shared/layout_templ.go | 389 ++++++++++++++ shared/shared.go | 25 + 15 files changed, 2865 insertions(+) create mode 100644 README.md create mode 100644 bulkupdate/handlers.go create mode 100644 bulkupdate/templates.templ create mode 100644 bulkupdate/templates_templ.go create mode 100644 clicktoedit/handlers.go create mode 100644 clicktoedit/templates.templ create mode 100644 clicktoedit/templates_templ.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 home.templ create mode 100644 home_templ.go create mode 100644 main.go create mode 100644 shared/layout.templ create mode 100644 shared/layout_templ.go create mode 100644 shared/shared.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..5595d60 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Go HTMX Examples + + implemented in Go and templ. + +## Tasks + +### run + +Runs the app and looks for changes. + +``` +reflex -r '.*\.(go|templ)' -R '.*_templ\.go' -s -- sh -c 'templ generate && go run .' +``` diff --git a/bulkupdate/handlers.go b/bulkupdate/handlers.go new file mode 100644 index 0000000..2f41171 --- /dev/null +++ b/bulkupdate/handlers.go @@ -0,0 +1,64 @@ +package bulkupdate + +import ( + "log" + "net/http" + "strconv" +) + +type user struct { + name, email string + active bool +} + +var inMemDB []user = []user{ + {"Joe Smith", "joe@smith.org", true}, + {"Angie MacDowell", "angie@macdowell.org", true}, + {"Fuqua Tarketon", "fuqua@tarketon.org", true}, + {"Kim Yee", "kim@yee.org", false}, +} + +func Handlers(prefix string, mux *http.ServeMux) { + mux.HandleFunc(prefix+"/", index) + mux.HandleFunc(prefix+"/activate", putActivate) + mux.HandleFunc(prefix+"/deactivate", putDeactivate) +} + +func index(w http.ResponseWriter, r *http.Request) { + // Load users + Index(inMemDB).Render(r.Context(), w) +} + +func putActivate(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + log.Println(err) + w.WriteHeader(500) + return + } + ids := map[int]bool{} + for _, i := range r.Form["ids"] { + id, _ := strconv.Atoi(i) + user := inMemDB[id] + user.active = true + inMemDB[id] = user + ids[id] = true + } + tbody(inMemDB, ids).Render(r.Context(), w) +} + +func putDeactivate(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + log.Println(err) + w.WriteHeader(500) + return + } + ids := map[int]bool{} + for _, i := range r.Form["ids"] { + id, _ := strconv.Atoi(i) + user := inMemDB[id] + user.active = false + inMemDB[id] = user + ids[id] = true + } + tbody(inMemDB, ids).Render(r.Context(), w) +} diff --git a/bulkupdate/templates.templ b/bulkupdate/templates.templ new file mode 100644 index 0000000..fa9f324 --- /dev/null +++ b/bulkupdate/templates.templ @@ -0,0 +1,91 @@ +package bulkupdate + +import ( + "fmt" + + "examples/shared" +) + +templ demo(users []user) { +

Select Rows And Activate Or Deactivate Below

+
+ + + + + + + + + + @tbody(users, map[int]bool{}) +
NameEmailStatus
+
+ + +} + +templ tbody(users []user, modified map[int]bool) { + + for k, u := range users { + + + { u.name } + { u.email } + + if u.active { + Active + } else { + Inactive + } + + + } + +} + +templ Index(users []user) { + @shared.Layout("Bulk Update") { +

Bulk Update

+

This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is accomplished by putting a form around a table, with checkboxes in the table, and then including the checked values in PUT’s to two different endpoints: activateand deactivate:

+

+	@shared.Raw() {
+		@demo(users)
+	}
+
+

The server will either activate or deactivate the checked users and then rerender the tbodytag with updated rows. It will apply the class activateor deactivateto rows that have been mutated. This allows us to use a bit of CSS to flash a color helping the user see what happened:

+
{ `.htmx-settling tr.deactivate td { 
+    background: lightcoral;
+} 
+.htmx-settling tr.activate td { 
+    background: darkseagreen;
+}
+tr td { 
+    transition: all 1.2s;
+}` }
+

Demo

+ @demo(users) + } +} + diff --git a/bulkupdate/templates_templ.go b/bulkupdate/templates_templ.go new file mode 100644 index 0000000..bf0d439 --- /dev/null +++ b/bulkupdate/templates_templ.go @@ -0,0 +1,853 @@ +// Code generated by templ@(devel) DO NOT EDIT. + +package bulkupdate + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +// GoExpression +import ( + "fmt" + + "examples/shared" +) + +func demo(users []user) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_1 := templ.GetChildren(ctx) + if var_1 == nil { + var_1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_2 := `Select Rows And Activate Or Deactivate Below` + _, err = templBuffer.WriteString(var_2) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_3 := `Name` + _, err = templBuffer.WriteString(var_3) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_4 := `Email` + _, err = templBuffer.WriteString(var_4) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_5 := `Status` + _, err = templBuffer.WriteString(var_5) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // TemplElement + err = tbody(users, map[int]bool{}).Render(ctx, templBuffer) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_6 := `Activate` + _, err = templBuffer.WriteString(var_6) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_7 := `Deactivate` + _, err = templBuffer.WriteString(var_7) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + +func tbody(users []user, modified map[int]bool) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_9 := templ.GetChildren(ctx) + if var_9 == nil { + var_9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // For + for k, u := range users { + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // StringExpression + var var_10 string = u.name + _, err = templBuffer.WriteString(templ.EscapeString(var_10)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // StringExpression + var var_11 string = u.email + _, err = templBuffer.WriteString(templ.EscapeString(var_11)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // If + if u.active { + // Text + var_12 := `Active` + _, err = templBuffer.WriteString(var_12) + if err != nil { + return err + } + } else { + // Text + var_13 := `Inactive` + _, err = templBuffer.WriteString(var_13) + if err != nil { + return err + } + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + +func Index(users []user) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_14 := templ.GetChildren(ctx) + if var_14 == nil { + var_14 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // TemplElement + var_15 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_16 := `Bulk Update` + _, err = templBuffer.WriteString(var_16) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Text + var_17 := `This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is accomplished by putting a form around a table, with checkboxes in the table, and then including the checked values in ` + _, err = templBuffer.WriteString(var_17) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_18 := `PUT` + _, err = templBuffer.WriteString(var_18) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_19 := `’s to two different endpoints: ` + _, err = templBuffer.WriteString(var_19) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_20 := `activate` + _, err = templBuffer.WriteString(var_20) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_21 := `and ` + _, err = templBuffer.WriteString(var_21) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_22 := `deactivate` + _, err = templBuffer.WriteString(var_22) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_23 := `:` + _, err = templBuffer.WriteString(var_23) + if err != nil { + return err + } + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
")
+			if err != nil {
+				return err
+			}
+			// Element (standard)
+			_, err = templBuffer.WriteString("")
+			if err != nil {
+				return err
+			}
+			// TemplElement
+			var_24 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
+				templBuffer, templIsBuffer := w.(*bytes.Buffer)
+				if !templIsBuffer {
+					templBuffer = templ.GetBuffer()
+					defer templ.ReleaseBuffer(templBuffer)
+				}
+				// TemplElement
+				err = demo(users).Render(ctx, templBuffer)
+				if err != nil {
+					return err
+				}
+				if !templIsBuffer {
+					_, err = io.Copy(w, templBuffer)
+				}
+				return err
+			})
+			err = shared.Raw().Render(templ.WithChildren(ctx, var_24), templBuffer)
+			if err != nil {
+				return err
+			}
+			_, err = templBuffer.WriteString("")
+			if err != nil {
+				return err
+			}
+			_, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Text + var_25 := `The server will either activate or deactivate the checked users and then rerender the ` + _, err = templBuffer.WriteString(var_25) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_26 := `tbody` + _, err = templBuffer.WriteString(var_26) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_27 := `tag with updated rows. It will apply the class ` + _, err = templBuffer.WriteString(var_27) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_28 := `activate` + _, err = templBuffer.WriteString(var_28) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_29 := `or ` + _, err = templBuffer.WriteString(var_29) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_30 := `deactivate` + _, err = templBuffer.WriteString(var_30) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_31 := `to rows that have been mutated. This allows us to use a bit of CSS to flash a color helping the user see what happened:` + _, err = templBuffer.WriteString(var_31) + if err != nil { + return err + } + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
")
+			if err != nil {
+				return err
+			}
+			// Element (standard)
+			_, err = templBuffer.WriteString("")
+			if err != nil {
+				return err
+			}
+			// StringExpression
+			var var_32 string = `.htmx-settling tr.deactivate td { 
+    background: lightcoral;
+} 
+.htmx-settling tr.activate td { 
+    background: darkseagreen;
+}
+tr td { 
+    transition: all 1.2s;
+}`
+			_, err = templBuffer.WriteString(templ.EscapeString(var_32))
+			if err != nil {
+				return err
+			}
+			_, err = templBuffer.WriteString("")
+			if err != nil {
+				return err
+			}
+			_, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_33 := `Demo` + _, err = templBuffer.WriteString(var_33) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // TemplElement + err = demo(users).Render(ctx, templBuffer) + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) + err = shared.Layout("Bulk Update").Render(templ.WithChildren(ctx, var_15), templBuffer) + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + diff --git a/clicktoedit/handlers.go b/clicktoedit/handlers.go new file mode 100644 index 0000000..a9e7541 --- /dev/null +++ b/clicktoedit/handlers.go @@ -0,0 +1,53 @@ +package clicktoedit + +import ( + "log" + "net/http" +) + +type user struct { + firstName, lastName, email string +} + +var demoUser user = user{ + firstName: "Joe", + lastName: "Blow", + email: "joe@blow.com", +} + +func Handlers(prefix string, mux *http.ServeMux) { + mux.HandleFunc(prefix+"/", index) + mux.HandleFunc(prefix+"/contact/1", putUser) + mux.HandleFunc(prefix+"/contact/1/edit", editForm) +} + +func index(w http.ResponseWriter, r *http.Request) { + // Load user + user := demoUser + if r.Header.Get("HX-Request") == "true" { + Display(user).Render(r.Context(), w) + return + } + Index(user).Render(r.Context(), w) +} + +func editForm(w http.ResponseWriter, r *http.Request) { + // Load user + user := demoUser + Form(user).Render(r.Context(), w) +} + +func putUser(w http.ResponseWriter, r *http.Request) { + // Load user + if err := r.ParseForm(); err != nil { + log.Println(err) + w.WriteHeader(500) + return + } + demoUser = user{ + firstName: r.FormValue("firstName"), + lastName: r.FormValue("lastName"), + email: r.FormValue("email"), + } + Display(demoUser).Render(r.Context(), w) +} diff --git a/clicktoedit/templates.templ b/clicktoedit/templates.templ new file mode 100644 index 0000000..14d7b78 --- /dev/null +++ b/clicktoedit/templates.templ @@ -0,0 +1,60 @@ +package clicktoedit + +import "examples/shared" + +templ Display(u user) { +
+
: { u.firstName }
+
: { u.lastName }
+
: { u.email }
+ +
+} + +templ Form(u user) { +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+} + +templ Index(u user) { + @shared.Layout("Click to Edit") { +

Click to Edit

+

The click to edit pattern provides a way to offer inline editing of all or part of a record without a page refresh.

+
    +
  • + This pattern starts with a UI that shows the details of a contact. The div has a button that will get the editing UI for the contact from + /contacts/1/edit +
    
    +	@shared.Raw() {
    +		@Display(u)
    +	}
    +
    +
  • +
  • + This returns a form that can be used to edit the contact +
    
    +	@shared.Raw() {
    +		@Form(u)
    +	}
    +
    +
  • +
  • The form issues a PUTback to /contacts/1, following the usual REST-ful pattern.
  • +
+

Demo

+ @Display(u) + } +} + diff --git a/clicktoedit/templates_templ.go b/clicktoedit/templates_templ.go new file mode 100644 index 0000000..e024433 --- /dev/null +++ b/clicktoedit/templates_templ.go @@ -0,0 +1,952 @@ +// Code generated by templ@(devel) DO NOT EDIT. + +package clicktoedit + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +// GoExpression +import "examples/shared" + +func Display(u user) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_1 := templ.GetChildren(ctx) + if var_1 == nil { + var_1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_3 := `: ` + _, err = templBuffer.WriteString(var_3) + if err != nil { + return err + } + // StringExpression + var var_4 string = u.firstName + _, err = templBuffer.WriteString(templ.EscapeString(var_4)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_6 := `: ` + _, err = templBuffer.WriteString(var_6) + if err != nil { + return err + } + // StringExpression + var var_7 string = u.lastName + _, err = templBuffer.WriteString(templ.EscapeString(var_7)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_9 := `: ` + _, err = templBuffer.WriteString(var_9) + if err != nil { + return err + } + // StringExpression + var var_10 string = u.email + _, err = templBuffer.WriteString(templ.EscapeString(var_10)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_11 := `Click To Edit` + _, err = templBuffer.WriteString(var_11) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + +func Form(u user) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_12 := templ.GetChildren(ctx) + if var_12 == nil { + var_12 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_16 := `Submit` + _, err = templBuffer.WriteString(var_16) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_17 := `Cancel` + _, err = templBuffer.WriteString(var_17) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + +func Index(u user) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_18 := templ.GetChildren(ctx) + if var_18 == nil { + var_18 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // TemplElement + var_19 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_20 := `Click to Edit` + _, err = templBuffer.WriteString(var_20) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Text + var_21 := `The click to edit pattern provides a way to offer inline editing of all or part of a record without a page refresh.` + _, err = templBuffer.WriteString(var_21) + if err != nil { + return err + } + _, err = templBuffer.WriteString("

") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
    ") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + // Text + var_22 := `This pattern starts with a UI that shows the details of a contact. The div has a button that will get the editing UI for the contact from ` + _, err = templBuffer.WriteString(var_22) + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_23 := `/contacts/1/edit` + _, err = templBuffer.WriteString(var_23) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
    ")
    +			if err != nil {
    +				return err
    +			}
    +			// Element (standard)
    +			_, err = templBuffer.WriteString("")
    +			if err != nil {
    +				return err
    +			}
    +			// TemplElement
    +			var_24 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
    +				templBuffer, templIsBuffer := w.(*bytes.Buffer)
    +				if !templIsBuffer {
    +					templBuffer = templ.GetBuffer()
    +					defer templ.ReleaseBuffer(templBuffer)
    +				}
    +				// TemplElement
    +				err = Display(u).Render(ctx, templBuffer)
    +				if err != nil {
    +					return err
    +				}
    +				if !templIsBuffer {
    +					_, err = io.Copy(w, templBuffer)
    +				}
    +				return err
    +			})
    +			err = shared.Raw().Render(templ.WithChildren(ctx, var_24), templBuffer)
    +			if err != nil {
    +				return err
    +			}
    +			_, err = templBuffer.WriteString("")
    +			if err != nil {
    +				return err
    +			}
    +			_, err = templBuffer.WriteString("
    ") + if err != nil { + return err + } + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + // Text + var_25 := `This returns a form that can be used to edit the contact` + _, err = templBuffer.WriteString(var_25) + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
    ")
    +			if err != nil {
    +				return err
    +			}
    +			// Element (standard)
    +			_, err = templBuffer.WriteString("")
    +			if err != nil {
    +				return err
    +			}
    +			// TemplElement
    +			var_26 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
    +				templBuffer, templIsBuffer := w.(*bytes.Buffer)
    +				if !templIsBuffer {
    +					templBuffer = templ.GetBuffer()
    +					defer templ.ReleaseBuffer(templBuffer)
    +				}
    +				// TemplElement
    +				err = Form(u).Render(ctx, templBuffer)
    +				if err != nil {
    +					return err
    +				}
    +				if !templIsBuffer {
    +					_, err = io.Copy(w, templBuffer)
    +				}
    +				return err
    +			})
    +			err = shared.Raw().Render(templ.WithChildren(ctx, var_26), templBuffer)
    +			if err != nil {
    +				return err
    +			}
    +			_, err = templBuffer.WriteString("")
    +			if err != nil {
    +				return err
    +			}
    +			_, err = templBuffer.WriteString("
    ") + if err != nil { + return err + } + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + // Text + var_27 := `The form issues a ` + _, err = templBuffer.WriteString(var_27) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_28 := `PUT` + _, err = templBuffer.WriteString(var_28) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_29 := `back to ` + _, err = templBuffer.WriteString(var_29) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_30 := `/contacts/1` + _, err = templBuffer.WriteString(var_30) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_31 := `, following the usual REST-ful pattern.` + _, err = templBuffer.WriteString(var_31) + if err != nil { + return err + } + _, err = templBuffer.WriteString("
  • ") + if err != nil { + return err + } + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_32 := `Demo` + _, err = templBuffer.WriteString(var_32) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // TemplElement + err = Display(u).Render(ctx, templBuffer) + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) + err = shared.Layout("Click to Edit").Render(templ.WithChildren(ctx, var_19), templBuffer) + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8e2c193 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module examples + +go 1.21 + +require github.com/a-h/templ v0.2.234-0.20230416205859-20293271f3c5 + +require ( + github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 // indirect + golang.org/x/net v0.9.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..482aab9 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/a-h/templ v0.2.233 h1:EnZqZmtV0YICqWG6MtLNmTcWuFkl2ImyQ63SIpWaM2Y= +github.com/a-h/templ v0.2.233/go.mod h1:h1DdzFMWVApvTcZBNmM6+mD6EPq6uYkncMNF7zdLj9I= +github.com/a-h/templ v0.2.234-0.20230416205859-20293271f3c5 h1:NeF/iw7KU9W7CYYJimd5x7ooOXCLrfo8FcHdFPUU+2w= +github.com/a-h/templ v0.2.234-0.20230416205859-20293271f3c5/go.mod h1:nqma2qb9ViAJOP4MBucyH+SPbOyNDZaRQyusfpK4PjY= +github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts= +github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= diff --git a/home.templ b/home.templ new file mode 100644 index 0000000..f90a478 --- /dev/null +++ b/home.templ @@ -0,0 +1,23 @@ +package main + +import "examples/shared" + +templ Home(examples []Example) { + @shared.Layout("Home") { +

Examples:

+ + + + + + + for _, e := range examples { + + + + + } +
PatternDescription
{ e.Name }{ e.Desc }
+ } +} + diff --git a/home_templ.go b/home_templ.go new file mode 100644 index 0000000..715da7f --- /dev/null +++ b/home_templ.go @@ -0,0 +1,227 @@ +// Code generated by templ@(devel) DO NOT EDIT. + +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +// GoExpression +import "examples/shared" + +func Home(examples []Example) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_1 := templ.GetChildren(ctx) + if var_1 == nil { + var_1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // TemplElement + var_2 := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_3 := `Examples:` + _, err = templBuffer.WriteString(var_3) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Whitespace (normalised) + _, err = templBuffer.WriteString(` `) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_4 := `Pattern` + _, err = templBuffer.WriteString(var_4) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_5 := `Description` + _, err = templBuffer.WriteString(var_5) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // For + for _, e := range examples { + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // StringExpression + var var_7 string = e.Name + _, err = templBuffer.WriteString(templ.EscapeString(var_7)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // StringExpression + var var_8 string = e.Desc + _, err = templBuffer.WriteString(templ.EscapeString(var_8)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) + err = shared.Layout("Home").Render(templ.WithChildren(ctx, var_2), templBuffer) + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + diff --git a/main.go b/main.go new file mode 100644 index 0000000..aaccedc --- /dev/null +++ b/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "examples/bulkupdate" + "examples/clicktoedit" + "log" + "net/http" + + "github.com/a-h/templ" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +func run() error { + r := http.NewServeMux() + r.Handle("/", templ.Handler(Home(examples))) + for _, e := range examples { + log.Printf("Serving %q on /%s", e.Name, e.Slug) + e.Handlers("/"+e.Slug, r) + } + log.Println("Listening on localhost:2468") + return http.ListenAndServe("localhost:2468", r) +} + +type Example struct { + Name, Desc, Slug string + Handlers func(string, *http.ServeMux) +} + +var examples = []Example{ + { + Name: "Click To Edit", + Desc: "Demonstrates inline editing of a data object", + Slug: "click-to-edit", + Handlers: clicktoedit.Handlers, + }, + { + Name: "Bulk Update", + Desc: "Demonstrates bulk updating of multiple rows of data", + Slug: "bulk-update", + Handlers: bulkupdate.Handlers, + }, +} diff --git a/shared/layout.templ b/shared/layout.templ new file mode 100644 index 0000000..db3a5a0 --- /dev/null +++ b/shared/layout.templ @@ -0,0 +1,50 @@ +package shared + +import "os" + +templ Layout(title string) { + + + + + + Go htmx examples - { title } + + if os.Getenv("DEBUG") == "true" { + + } + + + @Nav() +
+ { children... } +
+ + + + +} + +templ Nav() { + +} + diff --git a/shared/layout_templ.go b/shared/layout_templ.go new file mode 100644 index 0000000..ca0981c --- /dev/null +++ b/shared/layout_templ.go @@ -0,0 +1,389 @@ +// Code generated by templ@(devel) DO NOT EDIT. + +package shared + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +// GoExpression +import "os" + +func Layout(title string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_1 := templ.GetChildren(ctx) + if var_1 == nil { + var_1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (void) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_3 := `Go htmx examples - ` + _, err = templBuffer.WriteString(var_3) + if err != nil { + return err + } + // StringExpression + var var_4 string = title + _, err = templBuffer.WriteString(templ.EscapeString(var_4)) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// Text +var_5 := `` +_, err = templBuffer.WriteString(var_5) +if err != nil { + return err +} + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // If + if os.Getenv("DEBUG") == "true" { +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // TemplElement + err = Nav().Render(ctx, templBuffer) + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Children + err = var_1.Render(ctx, templBuffer) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// Text +var_7 := `` +_, err = templBuffer.WriteString(var_7) +if err != nil { + return err +} + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// RawElement + _, err = templBuffer.WriteString("") + if err != nil { + return err + } +// Text +var_8 := `` +_, err = templBuffer.WriteString(var_8) +if err != nil { + return err +} + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + +func Nav() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_9 := templ.GetChildren(ctx) + if var_9 == nil { + var_9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Element (standard) + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + // Text + var_10 := `Go HTMX Examples` + _, err = templBuffer.WriteString(var_10) + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + _, err = templBuffer.WriteString("") + if err != nil { + return err + } + if !templIsBuffer { + _, err = io.Copy(w, templBuffer) + } + return err + }) +} + diff --git a/shared/shared.go b/shared/shared.go new file mode 100644 index 0000000..4453ede --- /dev/null +++ b/shared/shared.go @@ -0,0 +1,25 @@ +package shared + +import ( + "bytes" + "context" + "io" + + "github.com/a-h/templ" + "github.com/yosssi/gohtml" +) + +func Raw() templ.ComponentFunc { + return func(ctx context.Context, w io.Writer) error { + b := new(bytes.Buffer) + if err := templ.GetChildren(ctx).Render(ctx, b); err != nil { + return err + } + gohtml.Condense = true + str := templ.EscapeString(gohtml.Format(b.String())) + if _, err := w.Write([]byte(str)); err != nil { + return err + } + return nil + } +}