diff --git a/internal/webserver/middlewares.go b/internal/webserver/middlewares.go index 1b06fcc..5f41ed2 100644 --- a/internal/webserver/middlewares.go +++ b/internal/webserver/middlewares.go @@ -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) diff --git a/internal/webserver/response_helpers.go b/internal/webserver/response_helpers.go index 9a58e81..f489c10 100644 --- a/internal/webserver/response_helpers.go +++ b/internal/webserver/response_helpers.go @@ -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 } diff --git a/internal/webserver/static/styles.css b/internal/webserver/static/styles.css index 0ca62b6..4ae79d5 100644 --- a/internal/webserver/static/styles.css +++ b/internal/webserver/static/styles.css @@ -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; diff --git a/internal/webserver/tpl/http_500.tpl b/internal/webserver/tpl/http_500.tpl deleted file mode 100644 index ea136d1..0000000 --- a/internal/webserver/tpl/http_500.tpl +++ /dev/null @@ -1,6 +0,0 @@ -{{define "error-toast"}} -
-{{end}} diff --git a/internal/webserver/tpl/includes/base.tpl b/internal/webserver/tpl/includes/base.tpl index 02ae3e9..d11c302 100644 --- a/internal/webserver/tpl/includes/base.tpl +++ b/internal/webserver/tpl/includes/base.tpl @@ -43,7 +43,7 @@ X