lyrics

lyrics
git clone git://brookjeynes.dev/bjeynes/lyrics.git
Log | Files | Refs

commit dedabec83aec63d8171ad04a667d530dd8381fd8
parent 817f63eaad17ed22317eec173382fb73c1c94ce9
Author: brookjeynes <me@brookjeynes.dev>
Date:   Sun,  7 Jun 2026 17:40:05 +1000

refactor: simplify toast component

Signed-off-by: brookjeynes <me@brookjeynes.dev>

Diffstat:
Minternal/server/htmx/htmx.go | 11+++++++----
Minternal/server/toast/toast.css | 68++++++++++++++++++++++++++++++++++----------------------------------
Minternal/server/toast/toast.go | 17+----------------
Minternal/server/toast/toast.js | 50++++++++++++++++++++++++--------------------------
Minternal/server/ui/layouts/base/base.templ | 7+------
5 files changed, 67 insertions(+), 86 deletions(-)

diff --git a/internal/server/htmx/htmx.go b/internal/server/htmx/htmx.go @@ -6,13 +6,16 @@ import ( ) func HxError(w http.ResponseWriter, status int, msg string) { - toast := toast.Error(msg) - toastJSON, err := toast.Marshal() + t := toast.Toast{ + Type: toast.ToastTypeError, + Body: msg, + } + json, err := t.Marshal() if err != nil { - toastJSON = []byte(`{"HXToast":{"type":"error","body":"An error occurred"}}`) + json = []byte(`{"HXToast":{"type":"error","body":"An error occurred"}}`) } - w.Header().Set("HX-Trigger", string(toastJSON)) + w.Header().Set("HX-Trigger", string(json)) w.Header().Set("HX-Reswap", "none") w.WriteHeader(status) _, _ = w.Write([]byte(msg)) diff --git a/internal/server/toast/toast.css b/internal/server/toast/toast.css @@ -1,43 +1,43 @@ -#toast-container { - position: fixed; - right: 1rem; - top: 1rem; - display: flex; - flex-direction: column; - gap: 0.5rem; +.toast-container { + position: fixed; + right: 1rem; + top: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; } -.toast { - background-color: white; - border: 1px solid black; - padding: 0.2rem 0.5rem; - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem; - opacity: 0; - transform: translateY(8px); - animation: toast-in 0.2s ease-out forwards; +.toast-box { + background-color: white; + border: 1px solid black; + padding: 0.2rem 0.5rem; + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + opacity: 0; + transform: translateY(8px); + animation: toast-in 0.2s ease-out forwards; } -.toast button { - background: none; - border: none; - cursor: pointer; - padding: 0; - font: inherit; - line-height: 1; - flex-shrink: 0; +.toast-box > .dismiss-button { + background: none; + border: none; + cursor: pointer; + padding: 0; + font: inherit; + line-height: 1; + flex-shrink: 0; } @keyframes toast-in { - from { - opacity: 0; - transform: translateY(8px); - } + from { + opacity: 0; + transform: translateY(8px); + } - to { - opacity: 1; - transform: none; - } + to { + opacity: 1; + transform: none; + } } diff --git a/internal/server/toast/toast.go b/internal/server/toast/toast.go @@ -5,8 +5,7 @@ import "encoding/json" type ToastType = string const ( - ToastTypeError ToastType = "error" - ToastTypeSuccess ToastType = "success" + ToastTypeError ToastType = "error" ) type Toast struct { @@ -14,20 +13,6 @@ type Toast struct { Body string } -func Error(body string) Toast { - return Toast{ - Type: ToastTypeError, - Body: body, - } -} - -func Success(body string) Toast { - return Toast{ - Type: ToastTypeSuccess, - Body: body, - } -} - func (t *Toast) Marshal() ([]byte, error) { trigger := map[string]any{ "HXToast": map[string]string{ diff --git a/internal/server/toast/toast.js b/internal/server/toast/toast.js @@ -1,33 +1,31 @@ -class Toast { - constructor(type, body) { - this.type = type; - this.body = body; - } +function makeToast(type, body) { + const isError = type === "error"; - make() { - const isError = this.type === "error"; + const container = document.createElement("div"); + container.classList.add("toast-box", `toast-${type}`); + container.setAttribute("role", isError ? "alert" : "status"); - const container = document.createElement("div"); - container.classList.add("toast", `toast-${this.type}`); - container.setAttribute("role", isError ? "alert" : "status"); + const message = document.createElement("span"); + message.textContent = body; - const message = document.createElement("span"); - message.textContent = this.body; + const dismiss = document.createElement("button"); + dismiss.classList.add("dismiss-button"); + dismiss.setAttribute("type", "button"); + dismiss.setAttribute("aria-label", "Dismiss"); + dismiss.textContent = "x"; + dismiss.addEventListener("click", () => container.remove()); - const dismiss = document.createElement("button"); - dismiss.setAttribute("type", "button"); - dismiss.setAttribute("aria-label", "Dismiss"); - dismiss.textContent = "x"; - dismiss.addEventListener("click", () => container.remove()); + container.appendChild(message); + container.appendChild(dismiss); - container.appendChild(message); - container.appendChild(dismiss); - - return container; - } + return container; +} - show() { - const toastContainer = document.querySelector("#toast-container"); - toastContainer.appendChild(this.make()); - } +function showToast(type, body) { + const toastContainer = document.querySelector(".toast-container"); + toastContainer.appendChild(makeToast(type, body)); } + +document.body.addEventListener("HXToast", (evt) => { + showToast(evt.detail.type, evt.detail.body); +}); diff --git a/internal/server/ui/layouts/base/base.templ b/internal/server/ui/layouts/base/base.templ @@ -19,17 +19,12 @@ templ Base(params BaseParams) { </head> <body> <main> - <section id="toast-container"></section> + <section class="toast-container"></section> { children... } </main> </body> <script> initLucideIcons(); - - document.body.addEventListener("HXToast", (evt) => { - const toast = new Toast(evt.detail.type, evt.detail.body); - toast.show(); - }); </script> </html> }