diff --git a/internal/ui/app.ts b/internal/ui/app.ts
index 9575ab3..44745db 100644
--- a/internal/ui/app.ts
+++ b/internal/ui/app.ts
@@ -1,6 +1,9 @@
import "htmx.org";
import Alpine from "alpinejs";
+import initToastComponent from "./components/toast/toast";
window.Alpine = Alpine;
+initToastComponent();
+
Alpine.start();
diff --git a/internal/ui/components/toast/toast.templ b/internal/ui/components/toast/toast.templ
index 48f1540..38e88e3 100644
--- a/internal/ui/components/toast/toast.templ
+++ b/internal/ui/components/toast/toast.templ
@@ -3,52 +3,37 @@ package toast
const toastContainerID = "toast-container"
templ Container() {
-
+
}
-templ toast() {
-
-
+templ toast(toastType string) {
+
+
{ children... }
-
+
}
templ success(msg string) {
- @toast() {
-
- { msg }
-
+ @toast("success") {
+
{ msg }
}
}
templ info(msg string) {
- @toast() {
-
- { msg }
-
+ @toast("info") {
+
{ msg }
}
}
templ warning(msg string) {
- @toast() {
-
- { msg }
-
+ @toast("warning") {
+
{ msg }
}
}
templ err(msg string) {
- @toast() {
-
- { msg }
-
+ @toast("error") {
+
{ msg }
}
}
diff --git a/internal/ui/components/toast/toast.ts b/internal/ui/components/toast/toast.ts
index 3cde401..813a76e 100644
--- a/internal/ui/components/toast/toast.ts
+++ b/internal/ui/components/toast/toast.ts
@@ -1,23 +1,201 @@
+const ALERT_TYPE_CLASSES: Record
= {
+ "success": "alert-success",
+ "info": "alert-info",
+ "warning": "alert-warning",
+ "error": "alert-error",
+}
+
+const DEFAULT_TOAST_DURATION = 5000;
+const TOAST_SWIPE_VELOCITY_THRESHOLD = window.screen.availWidth / 2; // px / s
+
+// recreating:
+// x-data="{
+// timeoutId: 0,
+// close() { $el.remove();}
+// }"
+// x-init="timeoutId = setTimeout(() => { close() }, 5000);"
+// @click="clearTimeout(timeoutId); close();"
+//
+// additional features: progress bar, pause on hover, swiping away on mobile
+
class Toast extends HTMLElement {
- constructor() {
- super();
- this.attachShadow({ mode: "open" });
+ constructor() {
+ super();
+ this.#children = Array.from(this.children).map(el=>el.cloneNode(true));
+ }
+
+ #progressAnimation: Animation | undefined;
+ #lastTouchEvent: TouchEvent | undefined;
+ // [px, timestamp]
+ #lastTouchChanges: number[][] = [];
+ #children: Node[];
+
+ #getAlertElement = (): HTMLElement => {
+ return this.children[0];
+ }
+
+ #parseLeft = (): number => {
+ const currentLeft = this.#getAlertElement().style.left;
+ if(currentLeft !== ""){
+ return parseInt(currentLeft.slice(0, -2))
+ }
+ return 0;
+ }
+
+ connectedCallback() {
+ this.render();
+
+ const durationAttr = this.getAttribute("duration") || "";
+ let toastDuration = parseInt(durationAttr);
+ if (Number.isNaN(toastDuration)) {
+ toastDuration = DEFAULT_TOAST_DURATION;
+ }
+
+ this.#progressAnimation = this.querySelector(".toast-alert-progress")!.animate([
+ {
+ width: "0%"
+ },
+ {
+ width: "100%"
+ }
+ ], {
+ duration: toastDuration,
+ fill: "forwards"
+ });
+
+ this.#progressAnimation?.addEventListener("finish", ()=>this.triggerClose(0));
+
+ this.addEventListener("mouseenter", this.onMouseEnter);
+ this.addEventListener("mouseleave", this.onMouseLeave);
+ this.addEventListener("click", ()=>this.triggerClose(0));
+ this.addEventListener("touchstart", this.onTouchStart);
+ this.addEventListener("touchmove", this.onTouchMove);
+ this.addEventListener("touchend", this.onTouchEnd);
+ }
+
+ disconnectedCallback(){
+ this.removeEventListener("mouseenter", this.onMouseEnter);
+ this.removeEventListener("mouseleave", this.onMouseLeave);
+ this.removeEventListener("click", ()=>this.triggerClose(0));
+ this.removeEventListener("touchstart", this.onTouchStart);
+ this.removeEventListener("touchmove", this.onTouchMove);
+ this.removeEventListener("touchend", this.onTouchEnd);
+ }
+
+ onMouseEnter = () => {
+ this.#progressAnimation?.pause();
+ }
+
+ onMouseLeave = () => {
+ this.#progressAnimation?.play();
+ }
+
+ onTouchStart = (e: TouchEvent) => {
+ this.#lastTouchEvent = e;
+ this.#lastTouchChanges = [];
+ this.#progressAnimation?.pause();
+ }
+
+ onTouchMove = (e: TouchEvent) => {
+ let diffX = e.changedTouches[0].clientX - this.#lastTouchEvent!.changedTouches[0].clientX;
+
+ // reset lastTouchChanges when the direction changes so that swiping in one direction and then another still closes
+ // the toast
+ if(this.#lastTouchChanges.length > 0 && this.#lastTouchChanges[this.#lastTouchChanges.length - 1][0] * diffX < 0){
+ this.#lastTouchChanges = [];
}
- connectedCallback() {
- this.render();
+ // saving x traveled and current timestamp for velocity calculations
+ this.#lastTouchChanges.push([diffX, performance.now()]);
+
+ this.#lastTouchEvent = e;
+ this.#lastTouchChanges = this.#lastTouchChanges.slice(-5);
+ this.#getAlertElement().style.left = `${diffX + this.#parseLeft()}px`;
+ }
+
+ onTouchEnd = () => {
+ const left = this.#parseLeft();
+ if(this.#lastTouchChanges.length > 0){
+ // calculate total x movement
+ const x = this.#lastTouchChanges.reduce((cur, prev) => cur + prev[0], 0);
+ // calculate timespan
+ const t = performance.now() - this.#lastTouchChanges[0][1];
+ // calculate velocity
+ const v = x / t;
+
+ if(Math.abs(v * 1000) >= TOAST_SWIPE_VELOCITY_THRESHOLD) return this.triggerClose(v);
}
- render() {
- this.shadowRoot.innerHTML = `
-
-
-
-
- `;
+ this.#progressAnimation?.play();
+ this.#getAlertElement().style.left = "";
+ this.#getAlertElement().animate([
+ {
+ left: `${left}px`
+ },
+ {
+ left: `0px`
+ }
+ ], 250);
+ }
+
+ triggerClose = (velocity: number) => {
+ if(!this.#progressAnimation) return;
+
+ // we dont want to close the toast if there is text selected
+ const sel = window.getSelection();
+ if(sel && sel.rangeCount > 0 && sel.type === "Range"){
+ if(this.contains(sel?.focusNode)) return;
+ for(let i = 0; i < sel.rangeCount; i++){
+ if(this.contains(sel.getRangeAt(i).startContainer)) return;
+ }
}
+
+ this.#progressAnimation = undefined;
+
+ const left = this.#parseLeft();
+ const animationDuration = 250;
+
+ this.#getAlertElement().animate([
+ {
+ left: `${left}px`
+ },
+ {
+ // velocity is in px per ms
+ left: `${left + (velocity * animationDuration)}px`
+ }
+ ], {
+ duration: animationDuration,
+ fill: "forwards"
+ });
+ this.animate([
+ {
+ scale: 1,
+ opacity: 1
+ },
+ {
+ scale: 0.9,
+ opacity: 0
+ }
+ ], {
+ duration: animationDuration,
+ easing: "ease-out",
+ fill: "forwards"
+ }).addEventListener("finish", () => {
+ this.remove();
+ });
+ }
+
+ render() {
+ const alertType = this.getAttribute('type') || "";
+ this.innerHTML = `
+
+ `;
+ this.#getAlertElement().prepend(...this.#children);
+ }
}
-customElements.define("toast-container", Toast);
+export default function initToastComponent() {
+ customElements.define("toast-element", Toast);
+}
diff --git a/internal/ui/components/toast/toast_templ.go b/internal/ui/components/toast/toast_templ.go
index bd780a6..6da5ab8 100644
--- a/internal/ui/components/toast/toast_templ.go
+++ b/internal/ui/components/toast/toast_templ.go
@@ -44,7 +44,7 @@ func Container() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" class=\"toast toast-top toast-center\"> ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -52,7 +52,7 @@ func Container() templ.Component {
})
}
-func toast() templ.Component {
+func toast(toastType string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -86,7 +86,20 @@ func toast() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" hx-swap-oob=\"afterbegin\">")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" class=\"toast-container\" hx-swap-oob=\"afterbegin\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -94,7 +107,7 @@ func toast() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -118,12 +131,12 @@ func success(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var5 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var5 == nil {
- templ_7745c5c3_Var5 = templ.NopComponent
+ templ_7745c5c3_Var6 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var6 == nil {
+ templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -135,26 +148,26 @@ func success(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var7 string
- templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
+ var templ_7745c5c3_Var8 string
+ templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 27, Col: 14}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 19, Col: 19}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = toast().Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = toast("success").Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -178,12 +191,12 @@ func info(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var8 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var8 == nil {
- templ_7745c5c3_Var8 = templ.NopComponent
+ templ_7745c5c3_Var9 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var9 == nil {
+ templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var10 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -195,26 +208,26 @@ func info(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var10 string
- templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
+ var templ_7745c5c3_Var11 string
+ templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 35, Col: 14}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 25, Col: 19}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = toast().Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = toast("info").Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -238,12 +251,12 @@ func warning(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var11 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var11 == nil {
- templ_7745c5c3_Var11 = templ.NopComponent
+ templ_7745c5c3_Var12 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var12 == nil {
+ templ_7745c5c3_Var12 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var12 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var13 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -255,26 +268,26 @@ func warning(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var13 string
- templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
+ var templ_7745c5c3_Var14 string
+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 43, Col: 14}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 31, Col: 19}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = toast().Render(templ.WithChildren(ctx, templ_7745c5c3_Var12), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = toast("warning").Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -298,12 +311,12 @@ func err(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var14 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var14 == nil {
- templ_7745c5c3_Var14 = templ.NopComponent
+ templ_7745c5c3_Var15 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var15 == nil {
+ templ_7745c5c3_Var15 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var15 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var16 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -315,26 +328,26 @@ func err(msg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var16 string
- templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
+ var templ_7745c5c3_Var17 string
+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(msg)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 51, Col: 14}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/components/toast/toast.templ`, Line: 37, Col: 19}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = toast().Render(templ.WithChildren(ctx, templ_7745c5c3_Var15), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = toast("error").Render(templ.WithChildren(ctx, templ_7745c5c3_Var16), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/internal/ui/styles.css b/internal/ui/styles.css
index e4f365c..b0af83b 100644
--- a/internal/ui/styles.css
+++ b/internal/ui/styles.css
@@ -3,6 +3,33 @@
themes: light --default, dark --prefersdark;
}
+/*alert-[status] isn't found in source very easily, so best to force add to css*/
+/*reference: https://tailwindcss.com/docs/detecting-classes-in-source-files#safelisting-specific-utilities*/
+@source inline("alert-success");
+@source inline("alert-warning");
+@source inline("alert-error");
+@source inline("alert-info");
+
[x-cloak] {
display: none !important;
}
+
+@layer components{
+ .toast-alert{
+ @apply alert alert-vertical sm:alert-horizontal relative overflow-hidden;
+ }
+
+ .toast-alert-progress{
+ @apply h-0.5 absolute;
+
+
+ bottom: 0;
+ left: 0;
+ z-index: 10;
+ background: currentColor;
+ }
+
+ #toast-container{
+ @apply toast sm:toast-top flex-col-reverse sm:flex-col toast-center z-50;
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index d73caac..585c6ab 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
"@tailwindcss/cli": "^4.1.12",
"@types/alpinejs": "^3.13.11",
"bun": "^1.2.21",
- "daisyui": "^5.0.51",
+ "daisyui": "^5.4.4",
"tailwindcss": "^4.1.12"
}
},
@@ -923,9 +923,9 @@
}
},
"node_modules/daisyui": {
- "version": "5.0.51",
- "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.0.51.tgz",
- "integrity": "sha512-lhB0BBOjt43/t5S1my0XChMy3ClXfmGlDU/XmSlx+N0h2y7cyWF+cnheeemguxNHb9TjqI66mxKI9qiFsOU3mA==",
+ "version": "5.4.4",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.4.4.tgz",
+ "integrity": "sha512-FEfdwmGdb3ZbtYN3OqaZn/RMarlZTPOv6mWpGUo7KX42RkcBanEZk5tgYp2ZgirKl7QvH8pCiwpuy55wi2dHyQ==",
"dev": true,
"license": "MIT",
"funding": {
diff --git a/package.json b/package.json
index f1c911c..54c66bb 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"@tailwindcss/cli": "^4.1.12",
"@types/alpinejs": "^3.13.11",
"bun": "^1.2.21",
- "daisyui": "^5.0.51",
+ "daisyui": "^5.4.4",
"tailwindcss": "^4.1.12"
},
"dependencies": {
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..76c0e8b
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "commonjs",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "skipLibCheck": true
+ }
+}