mirror of
https://github.com/acaloiaro/hugo-htmx-go-template
synced 2026-07-21 10:12:25 +00:00
feat: templ templates
This commit is contained in:
parent
9e3c6c2efa
commit
e918ba6850
8 changed files with 261 additions and 60 deletions
|
|
@ -10,7 +10,7 @@ Every time `Click Me!` is clicked, a request is sent to fetch static template `/
|
|||
|
||||
{{< html.inline >}}
|
||||
<button
|
||||
hx-get="/goodbyeworld.html"
|
||||
hx-get="{{ .Site.Params.apiBaseUrl }}/goodbyeworld.html"
|
||||
hx-trigger="click"
|
||||
hx-target="#goodbye"
|
||||
hx-swap="beforeend">
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -1,3 +1,5 @@
|
|||
module github.com/acaloiaro/hugo-htmx-go-template
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/a-h/templ v0.2.304
|
||||
|
|
|
|||
2
go.sum
Normal file
2
go.sum
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
github.com/a-h/templ v0.2.304 h1:vIgCNazkW6NiYifFIGYNRfBkoBzOMZMO1NibIayzihE=
|
||||
github.com/a-h/templ v0.2.304/go.mod h1:3oc37WS5rpDvFGi6yeknvTKt50xCu67ywQsM43Wr4PU=
|
||||
|
|
@ -1 +0,0 @@
|
|||
<p>Goodbye, World!</p>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<div>
|
||||
<p>This content is coming from our API server. It's a standard <strong>text/html</strong> template:
|
||||
<strong>partials/helloworld.html</strong>. The template has a single variable named
|
||||
<strong>Name</strong>, which it greets below.</p>
|
||||
</div>
|
||||
|
||||
<p>If you set the <strong>name</strong> URL param, it greets you by name, e.g.
|
||||
<a href="/posts/hello-world/?name=foobar">/posts/hello-world/?name=foobar</a></p>
|
||||
|
||||
<h3>Greeting: Hello, {{ .Name }}!</h3>
|
||||
18
partials/templates.templ
Normal file
18
partials/templates.templ
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package partials
|
||||
|
||||
templ HelloWorld(name string) {
|
||||
<div>
|
||||
<p>This content is coming from our API server. It's a standard <strong>text/html</strong>template: <strong>partials/helloworld.html</strong>. The template has a single variable named <strong>Name</strong>, which it greets below.</p>
|
||||
</div>
|
||||
<p>If you set the <strong>name</strong>URL param, it greets you by name, e.g. <a href="/posts/hello-world/?name=foobar">/posts/hello-world/?name=foobar</a></p>
|
||||
@HelloWorldGreeting(name)
|
||||
}
|
||||
|
||||
templ HelloWorldGreeting(name string) {
|
||||
<h3>Greeting: Hello, { name }!</h3>
|
||||
}
|
||||
|
||||
templ GoodbyeWorld() {
|
||||
<p>Goodbye, World!</p>
|
||||
}
|
||||
|
||||
213
partials/templates_templ.go
Normal file
213
partials/templates_templ.go
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
// Code generated by templ@(devel) DO NOT EDIT.
|
||||
|
||||
package partials
|
||||
|
||||
//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"
|
||||
|
||||
func HelloWorld(name 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)
|
||||
_, err = templBuffer.WriteString("<div><p>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_2 := `This content is coming from our API server. It's a standard `
|
||||
_, err = templBuffer.WriteString(var_2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("<strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_3 := `text/html`
|
||||
_, err = templBuffer.WriteString(var_3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_4 := `template: `
|
||||
_, err = templBuffer.WriteString(var_4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("<strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_5 := `partials/helloworld.html`
|
||||
_, err = templBuffer.WriteString(var_5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_6 := `. The template has a single variable named `
|
||||
_, err = templBuffer.WriteString(var_6)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("<strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_7 := `Name`
|
||||
_, err = templBuffer.WriteString(var_7)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_8 := `, which it greets below.`
|
||||
_, err = templBuffer.WriteString(var_8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</p></div><p>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_9 := `If you set the `
|
||||
_, err = templBuffer.WriteString(var_9)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("<strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_10 := `name`
|
||||
_, err = templBuffer.WriteString(var_10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</strong>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_11 := `URL param, it greets you by name, e.g. `
|
||||
_, err = templBuffer.WriteString(var_11)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("<a href=\"/posts/hello-world/?name=foobar\">")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_12 := `/posts/hello-world/?name=foobar`
|
||||
_, err = templBuffer.WriteString(var_12)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</a></p>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = HelloWorldGreeting(name).Render(ctx, templBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !templIsBuffer {
|
||||
_, err = io.Copy(w, templBuffer)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func HelloWorldGreeting(name 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_13 := templ.GetChildren(ctx)
|
||||
if var_13 == nil {
|
||||
var_13 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, err = templBuffer.WriteString("<h3>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_14 := `Greeting: Hello, `
|
||||
_, err = templBuffer.WriteString(var_14)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var var_15 string = name
|
||||
_, err = templBuffer.WriteString(templ.EscapeString(var_15))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_16 := `!`
|
||||
_, err = templBuffer.WriteString(var_16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</h3>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !templIsBuffer {
|
||||
_, err = io.Copy(w, templBuffer)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func GoodbyeWorld() 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_17 := templ.GetChildren(ctx)
|
||||
if var_17 == nil {
|
||||
var_17 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, err = templBuffer.WriteString("<p>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var_18 := `Goodbye, World!`
|
||||
_, err = templBuffer.WriteString(var_18)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = templBuffer.WriteString("</p>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !templIsBuffer {
|
||||
_, err = io.Copy(w, templBuffer)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
73
server.go
73
server.go
|
|
@ -1,13 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/acaloiaro/hugo-htmx-go-template/partials"
|
||||
)
|
||||
|
||||
//go:embed all:public
|
||||
|
|
@ -20,9 +21,25 @@ func main() {
|
|||
// Serve all hugo content (the 'public' directory) at the root url
|
||||
mux.Handle("/", http.FileServer(http.FS(serverRoot)))
|
||||
|
||||
cors := func(h http.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// in development, the Origin is the the Hugo server, i.e. http://localhost:1313
|
||||
// but in production, it is the domain name where one's site is deployed
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, hx-target, hx-current-url, hx-request")
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Add any number of handlers for custom endpoints here
|
||||
mux.HandleFunc("/hello_world", helloWorld)
|
||||
mux.HandleFunc("/hello_world_form", helloWorldForm)
|
||||
mux.HandleFunc("/goodbyeworld.html", cors(templ.Handler(partials.GoodbyeWorld())))
|
||||
mux.HandleFunc("/hello_world", cors(http.HandlerFunc(helloWorld)))
|
||||
mux.HandleFunc("/hello_world_form", cors(http.HandlerFunc(helloWorldForm)))
|
||||
|
||||
fmt.Printf("Starting API server on port 1314\n")
|
||||
if err := http.ListenAndServe("0.0.0.0:1314", mux); err != nil {
|
||||
|
|
@ -36,30 +53,15 @@ func main() {
|
|||
//
|
||||
// It responds with the the HTML partial `partials/helloworld.html`
|
||||
func helloWorld(w http.ResponseWriter, r *http.Request) {
|
||||
// in development, the Origin is the the Hugo server, i.e. http://localhost:1313
|
||||
// but in production, it is the domain name where one's site is deployed
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if name == "null" || name == "" {
|
||||
name = "World"
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.ParseFiles("partials/helloworld.html"))
|
||||
var buff = bytes.NewBufferString("")
|
||||
err := tmpl.Execute(buff, map[string]string{"Name": name})
|
||||
if err != nil {
|
||||
ise(err, w)
|
||||
if err := partials.HelloWorld(name).Render(r.Context(), w); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(buff.Bytes())
|
||||
}
|
||||
|
||||
// this handler accepts POST requests to /hello_world_form
|
||||
|
|
@ -68,18 +70,6 @@ func helloWorld(w http.ResponseWriter, r *http.Request) {
|
|||
//
|
||||
// It responds with a simple greeting HTML partial
|
||||
func helloWorldForm(w http.ResponseWriter, r *http.Request) {
|
||||
// in development, the Origin is the the Hugo server, i.e. http://localhost:1313
|
||||
// but in production, it is the domain name where one's site is deployed
|
||||
// for this demo, we're using `*` to keep things simple
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.Header().Set("Access-Control-Allow-Methods", "POST")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, hx-current-url, hx-request")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
name := "World"
|
||||
// The name is not in the query param, let's see if it was submitted as a form
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
|
@ -88,23 +78,10 @@ func helloWorldForm(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
name = r.FormValue("name")
|
||||
// we're dealing with a really simple template; let's use an inline string instead of a whole separate file for this
|
||||
// one
|
||||
tmpl, err := template.New("form_response").Parse("<h3>Greeting: Hello, {{ .Name }}!</h3>")
|
||||
if err != nil {
|
||||
ise(err, w)
|
||||
if err := partials.HelloWorldGreeting(name).Render(r.Context(), w); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var buff = bytes.NewBufferString("")
|
||||
err = tmpl.Execute(buff, map[string]string{"Name": name})
|
||||
if err != nil {
|
||||
ise(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(buff.Bytes())
|
||||
}
|
||||
|
||||
func ise(err error, w http.ResponseWriter) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue