Last active
February 16, 2025 11:49
-
-
Save 17twenty/60f501a4556a6ed006283a4d0e7ca890 to your computer and use it in GitHub Desktop.
Golang Flash demo using cookies - recreate the Flask Flash library using Golang and HTMX and make life easier.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script src="https://unpkg.com/[email protected]"></script> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<title>Template Fragment Example</title> | |
</head> | |
<body> | |
<div hx-get="/notifications" hx-trigger="load" hx-swap="outerHTML"><!-- I GET REPLACED --></div> | |
<h1>Template Fragment Example</h1> | |
<p> | |
This page demonstrates how to create and serve | |
<a href="https://htmx.org/essays/template-fragments/" | |
>template fragments</a | |
> | |
using the | |
<a href="https://pkg.go.dev/text/template">built-in template package</a> | |
in Go. | |
</p> | |
<p> | |
This is accomplished by using the "block" action in the template, which | |
lets you define and execute a sub-template in a single step. | |
</p> | |
<!-- Here's the fragment. We can target it by executing the "buttonOnly" template. --> | |
{{block "buttonOnly" .}} | |
<button | |
hx-get="/?counter={{.next}}&template=buttonOnly" | |
hx-swap="outerHTML" | |
> | |
This Button Has Been Clicked {{.counter}} Times | |
</button> | |
{{end}} | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/base64" | |
"encoding/gob" | |
"log" | |
"net/http" | |
"time" | |
) | |
type Flash struct { | |
Type string // Warning | Success | Info | |
Title string | |
Content string | |
} | |
func init() { | |
gob.Register(&Flash{}) | |
} | |
func SetFlash(w http.ResponseWriter, flashType string, title string, content string) { | |
// Initialize a buffer to hold the gob data. | |
var buf bytes.Buffer | |
f := Flash{ | |
Type: flashType, | |
Title: title, | |
Content: content, | |
} | |
err := gob.NewEncoder(&buf).Encode(&f) | |
if err != nil { | |
log.Println(err) | |
http.Error(w, "Internal Server Error", http.StatusInternalServerError) | |
return | |
} | |
enc := base64.URLEncoding.EncodeToString(buf.Bytes()) | |
c := &http.Cookie{Name: "flash", Value: enc} | |
http.SetCookie(w, c) | |
} | |
func GetFlash(w http.ResponseWriter, r *http.Request) (Flash, error) { | |
var f Flash | |
c, err := r.Cookie("flash") | |
if err != nil { | |
switch err { | |
case http.ErrNoCookie: | |
return f, nil | |
default: | |
return f, err | |
} | |
} | |
// No point worrying about bad data. Just move on past. | |
uDec, _ := base64.URLEncoding.DecodeString(c.Value) | |
if err := gob.NewDecoder(bytes.NewReader(uDec)).Decode(&f); err != nil { | |
log.Println(err) | |
http.Error(w, "Internal Server Error", http.StatusInternalServerError) | |
return Flash{}, err | |
} | |
// "Delete" by setting expired cookie | |
http.SetCookie(w, &http.Cookie{Name: "flash", MaxAge: -1, Expires: time.Unix(1, 0)}) | |
return f, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div | |
class="fixed top-0 z-10 flex w-full flex-col items-center justify-center space-y-2" | |
> | |
{{ if eq .Type "Warning" }} | |
<div | |
class="border-l-8 border-orange-500 bg-orange-100 p-4 text-sm text-orange-700 shadow-lg" | |
role="alert" | |
style="cursor: pointer" | |
onclick="this.remove()" | |
> | |
<p class="font-bold">{{ .Title }}</p> | |
<p>{{ .Content }}</p> | |
</div> | |
{{end}} {{ if eq .Type "Success" }} | |
<div | |
class="border-l-8 border-green-500 bg-green-100 p-4 text-sm text-green-600 shadow-lg" | |
role="alert" | |
style="cursor: pointer" | |
onclick="this.remove()" | |
> | |
<p class="font-bold">{{ .Title }}</p> | |
<p>{{ .Content }}</p> | |
</div> | |
{{end}} {{ if eq .Type "Info" }} | |
<div | |
class="border-l-8 border-blue-500 bg-blue-100 p-4 text-sm text-blue-600 shadow-lg" | |
role="alert" | |
style="cursor: pointer" | |
onclick="this.remove()" | |
> | |
<p class="font-bold">{{ .Title }}</p> | |
<p>{{ .Content }}</p> | |
</div> | |
{{end}} | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
// Flash demo | |
unprotectedRouter.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) { | |
var tpl = template.Must(template.ParseFiles("templates/flash.tmpl.html")) | |
f, err := GetFlash(w, r) | |
if err != nil { | |
log.Println("Error received", err) | |
} | |
tpl.Execute(w, f) | |
}) | |
unprotectedRouter.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) { | |
var tpl = template.Must(template.ParseFiles("templates/login.tmpl.html")) | |
SetFlash(w, "Warning", "This is a warning", "This is the contents - i was set via Flash()") | |
tpl.Execute(w, nil) | |
}) | |
unprotectedRouter.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) { | |
var tpl = template.Must(template.ParseFiles("templates/demo.tmpl.html")) | |
tpl.Execute(w, nil) | |
}) | |
... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gist.github.com/17twenty/60f501a4556a6ed006283a4d0e7ca890#file-main-go-L15 this could either be a simple template setting the flash OR you set the flash and redirect to another and have the flash show on that page.