REFACTOR: add 'toast' helper response handler to produce toasts
This commit is contained in:
parent
e12f347650
commit
39c2250719
@ -34,7 +34,7 @@ func (app *Application) recoverPanic(next http.Handler) http.Handler {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
w.Header().Set("Connection", "close")
|
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)
|
next.ServeHTTP(w, r)
|
||||||
|
@ -28,24 +28,27 @@ func (app *Application) error_404(w http.ResponseWriter) {
|
|||||||
http.Error(w, "Not Found", 404)
|
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())
|
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
|
||||||
err2 := app.ErrorLog.Output(2, trace) // Magic
|
err2 := app.ErrorLog.Output(2, trace) // Magic
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
panic(err2)
|
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
|
// Reset the HTMX response to return an error toast and put it in the
|
||||||
w.Header().Set("HX-Reswap", "beforeend")
|
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")
|
w.Header().Set("HX-Push-Url", "false")
|
||||||
|
|
||||||
r := renderer{
|
app.buffered_render_htmx(w, "toast", PageGlobalData{}, t)
|
||||||
Filenames: []string{get_filepath("tpl/http_500.tpl")},
|
}
|
||||||
TplName: "error-toast",
|
|
||||||
Data: struct {
|
type Toast struct {
|
||||||
ErrorMsg string
|
Title string
|
||||||
}{err.Error()},
|
Message string
|
||||||
}
|
Type string
|
||||||
r.BufferedRender(w)
|
AutoCloseDelay int64
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,31 @@ main {
|
|||||||
/**
|
/**
|
||||||
* Toast notification popup that gets sent on HTTP 500
|
* 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;
|
position: fixed;
|
||||||
left: var(--width-body-margins);
|
left: var(--width-body-margins);
|
||||||
top: 10em;
|
top: 10em;
|
||||||
@ -301,18 +325,6 @@ main {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
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 {
|
.text {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 0.4em;
|
margin-bottom: 0.5em;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
/* Prevent empty paragraphs from being collapsed into each other (i.e., `margin-bottom`s overlapping) */
|
||||||
|
padding-bottom: 0.1em;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -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}}
|
|
@ -43,7 +43,7 @@
|
|||||||
<a class="button image-carousel__close-button" onclick="image_carousel.close()">X</a>
|
<a class="button image-carousel__close-button" onclick="image_carousel.close()">X</a>
|
||||||
<img class="image-carousel__active-image" src="">
|
<img class="image-carousel__active-image" src="">
|
||||||
</dialog>
|
</dialog>
|
||||||
<div class="error-messages" id="errorMessages">
|
<div class="toasts" id="toasts">
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
13
internal/webserver/tpl/includes/toast.tpl
Normal file
13
internal/webserver/tpl/includes/toast.tpl
Normal 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}}
|
Loading…
x
Reference in New Issue
Block a user