REFACTOR: add 'toast' helper response handler to produce toasts

This commit is contained in:
Alessio 2024-05-10 22:02:20 -07:00
parent e12f347650
commit 39c2250719
6 changed files with 56 additions and 32 deletions

View File

@ -34,7 +34,7 @@ func (app *Application) recoverPanic(next http.Handler) http.Handler {
defer func() {
if err := recover(); err != nil {
w.Header().Set("Connection", "close")
app.error_500(w, fmt.Errorf("%s", err))
app.error_500(w, r, fmt.Errorf("%s", err))
}
}()
next.ServeHTTP(w, r)

View File

@ -28,24 +28,27 @@ func (app *Application) error_404(w http.ResponseWriter) {
http.Error(w, "Not Found", 404)
}
func (app *Application) error_500(w http.ResponseWriter, err error) {
func (app *Application) error_500(w http.ResponseWriter, r *http.Request, err error) {
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
err2 := app.ErrorLog.Output(2, trace) // Magic
if err2 != nil {
panic(err2)
}
app.toast(w, r, Toast{Title: "Server error", Message: err.Error(), Type: "error"})
}
func (app *Application) toast(w http.ResponseWriter, r *http.Request, t Toast) {
// Reset the HTMX response to return an error toast and put it in the
w.Header().Set("HX-Reswap", "beforeend")
w.Header().Set("HX-Retarget", "#errorMessages")
w.Header().Set("HX-Retarget", "#toasts")
w.Header().Set("HX-Push-Url", "false")
r := renderer{
Filenames: []string{get_filepath("tpl/http_500.tpl")},
TplName: "error-toast",
Data: struct {
ErrorMsg string
}{err.Error()},
}
r.BufferedRender(w)
app.buffered_render_htmx(w, "toast", PageGlobalData{}, t)
}
type Toast struct {
Title string
Message string
Type string
AutoCloseDelay int64
}

View File

@ -293,7 +293,31 @@ main {
/**
* Toast notification popup that gets sent on HTTP 500
*/
.error-messages {
.toast {
border-radius: 1em;
padding: 1em;
text-align: center;
word-wrap: break-word;
margin: 1em;
width: 90%;
/* Default: use "success" toast */
background-color: #efe;
border: 1px solid green;
color: green;
&.toast--error {
color: red;
background-color: #fee;
border-color: red;
}
&.toast--warning {
color: hsl(50.59deg 75% 40%);
background-color: #ffe;
border-color: hsl(50.59deg 75% 40%);
}
}
.toasts {
position: fixed;
left: var(--width-body-margins);
top: 10em;
@ -301,18 +325,6 @@ main {
display: flex;
flex-direction: column;
align-items: center;
.error-messages__msg {
background-color: #fee;
border: 1px solid red;
border-radius: 1em;
padding: 1em;
color: red;
text-align: center;
word-wrap: break-word;
margin: 1em;
width: 90%;
}
}
/**
@ -440,10 +452,12 @@ main {
*/
.text {
display: block;
margin-bottom: 0.4em;
margin-bottom: 0.5em;
margin-top: 0;
overflow-wrap: anywhere;
cursor: text;
/* Prevent empty paragraphs from being collapsed into each other (i.e., `margin-bottom`s overlapping) */
padding-bottom: 0.1em;
&:last-child {
margin-bottom: 0;

View File

@ -1,6 +0,0 @@
{{define "error-toast"}}
<div class="error-messages__msg" open>
<span>{{.ErrorMsg}}</span>
<button class="suicide" onclick="htmx.remove('.error-messages__msg')">X</button>
</div>
{{end}}

View File

@ -43,7 +43,7 @@
<a class="button image-carousel__close-button" onclick="image_carousel.close()">X</a>
<img class="image-carousel__active-image" src="">
</dialog>
<div class="error-messages" id="errorMessages">
<div class="toasts" id="toasts">
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
{{define "toast"}}
<div
class="toast toast--{{.Type}}"
{{if .AutoCloseDelay}}
hx-on::load="setTimeout(() => this.remove(), {{.AutoCloseDelay}} + 2000); setTimeout(() => this.classList.add('disappearing'), {{.AutoCloseDelay}})"
{{end}}
>
<span class="toast__message">{{.Message}}</span>
{{if not .AutoCloseDelay}}
<button class="suicide" onclick="this.parentElement.remove()">X</button>
{{end}}
</div>
{{end}}