diff --git a/cmd/oslstats/routes.go b/cmd/oslstats/routes.go index c19f6d0..9a577a9 100644 --- a/cmd/oslstats/routes.go +++ b/cmd/oslstats/routes.go @@ -56,6 +56,11 @@ func addRoutes( Methods: []hws.Method{hws.MethodGET, hws.MethodPOST}, Handler: auth.LoginReq(handlers.Logout(server, auth, conn, discordAPI)), }, + { + Path: "/test", + Methods: []hws.Method{hws.MethodGET, hws.MethodPOST}, + Handler: handlers.Test(server), + }, } htmxRoutes := []hws.Route{ diff --git a/internal/handlers/notifications.go b/internal/handlers/notifications.go new file mode 100644 index 0000000..3d17197 --- /dev/null +++ b/internal/handlers/notifications.go @@ -0,0 +1,141 @@ +package handlers + +import ( + "encoding/json" + "fmt" + "net/http" + + "git.haelnorr.com/h/golib/hws" +) + +// NotificationType defines the type of notification +type NotificationType string + +const ( + NotificationSuccess NotificationType = "success" + NotificationWarning NotificationType = "warning" + NotificationInfo NotificationType = "info" +) + +// Notification represents a toast notification (success, warning, info) +type Notification struct { + Type NotificationType `json:"type"` + Title string `json:"title"` + Message string `json:"message"` +} + +// ErrorModal represents a full-screen error modal (500, 503) +type ErrorModal struct { + Code int `json:"code"` + Title string `json:"title"` + Message string `json:"message"` + Details string `json:"details"` +} + +// setHXTrigger sets the HX-Trigger header with JSON-encoded data +func setHXTrigger(w http.ResponseWriter, event string, data any) { + payload := map[string]any{ + event: data, + } + + jsonData, err := json.Marshal(payload) + if err != nil { + // Fallback if JSON encoding fails + w.Header().Set("HX-Trigger", event) + return + } + + w.Header().Set("HX-Trigger", string(jsonData)) +} + +// formatErrorDetails extracts and formats error details from wrapped errors +func formatErrorDetails(err error) string { + if err == nil { + return "" + } + + // Use %+v format to get stack trace from github.com/pkg/errors + return fmt.Sprintf("%+v", err) +} + +// notifyToast sends a toast notification via HX-Trigger header +func notifyToast( + w http.ResponseWriter, + notifType NotificationType, + title string, + message string, +) { + notification := Notification{ + Type: notifType, + Title: title, + Message: message, + } + + setHXTrigger(w, "showNotification", notification) +} + +// notifyErrorModal sends a full-screen error modal via HX-Trigger header +func notifyErrorModal( + s *hws.Server, + w http.ResponseWriter, + statusCode int, + title string, + message string, + err error, +) { + modal := ErrorModal{ + Code: statusCode, + Title: title, + Message: message, + Details: formatErrorDetails(err), + } + + // Log the error + s.LogError(hws.HWSError{ + StatusCode: statusCode, + Message: message, + Error: err, + Level: hws.ErrorERROR, + }) + + // Set response status + w.WriteHeader(statusCode) + + // Send notification via HX-Trigger + setHXTrigger(w, "showErrorModal", modal) +} + +// notifySuccess sends a success toast notification +func notifySuccess(w http.ResponseWriter, title string, message string) { + notifyToast(w, NotificationSuccess, title, message) +} + +// notifyWarning sends a warning toast notification +func notifyWarning(w http.ResponseWriter, title string, message string) { + notifyToast(w, NotificationWarning, title, message) +} + +// notifyInfo sends an info toast notification +func notifyInfo(w http.ResponseWriter, title string, message string) { + notifyToast(w, NotificationInfo, title, message) +} + +// notifyInternalServiceError sends a 500 error modal +func notifyInternalServiceError( + s *hws.Server, + w http.ResponseWriter, + message string, + err error, +) { + notifyErrorModal(s, w, 500, "Internal Server Error", message, err) +} + +// notifyServiceUnavailable sends a 503 error modal +func notifyServiceUnavailable( + s *hws.Server, + w http.ResponseWriter, + message string, + err error, +) { + notifyErrorModal(s, w, 503, "Service Unavailable", message, err) +} diff --git a/internal/handlers/test.go b/internal/handlers/test.go new file mode 100644 index 0000000..efa3eb1 --- /dev/null +++ b/internal/handlers/test.go @@ -0,0 +1,42 @@ +package handlers + +import ( + "net/http" + + "git.haelnorr.com/h/oslstats/internal/view/page" + "github.com/pkg/errors" + + "git.haelnorr.com/h/golib/hws" +) + +// Handles responses to the / path. Also serves a 404 Page for paths that +// don't have explicit handlers +func Test(server *hws.Server) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + page.Test().Render(r.Context(), w) + } else { + r.ParseForm() + notifytype := r.Form.Get("type") + title := r.Form.Get("title") + message := r.Form.Get("message") + switch notifytype { + case "error": + err := errors.New(message) + notifyInternalServiceError(server, w, title, err) + return + case "warn": + notifyWarning(w, title, message) + return + case "info": + notifyInfo(w, title, message) + return + case "success": + notifySuccess(w, title, message) + return + } + } + }, + ) +} diff --git a/internal/view/component/popup/error503Popup.templ b/internal/view/component/popup/error503Popup.templ deleted file mode 100644 index 254659d..0000000 --- a/internal/view/component/popup/error503Popup.templ +++ /dev/null @@ -1,63 +0,0 @@ -package popup - -templ Error503Popup() { -
- -
-} diff --git a/internal/view/component/popup/errorModal.templ b/internal/view/component/popup/errorModal.templ new file mode 100644 index 0000000..5d67e49 --- /dev/null +++ b/internal/view/component/popup/errorModal.templ @@ -0,0 +1,126 @@ +package popup + +// ErrorModal displays a full-screen modal for critical errors (500, 503) +templ ErrorModal() { +
+ +
+ + +
+ + +} diff --git a/internal/view/component/popup/error500Popup.templ b/internal/view/component/popup/errorPopup.templ similarity index 98% rename from internal/view/component/popup/error500Popup.templ rename to internal/view/component/popup/errorPopup.templ index 45573e0..6f30390 100644 --- a/internal/view/component/popup/error500Popup.templ +++ b/internal/view/component/popup/errorPopup.templ @@ -1,6 +1,6 @@ package popup -templ Error500Popup() { +templ ErrorPopup() {
+ +
+} diff --git a/internal/view/component/popup/toastNotification.templ b/internal/view/component/popup/toastNotification.templ new file mode 100644 index 0000000..bcdcc14 --- /dev/null +++ b/internal/view/component/popup/toastNotification.templ @@ -0,0 +1,114 @@ +package popup + +// ToastNotification displays an individual toast notification +templ ToastNotification() { + +} diff --git a/internal/view/layout/global.templ b/internal/view/layout/global.templ index 8a77c6f..6a4d774 100644 --- a/internal/view/layout/global.templ +++ b/internal/view/layout/global.templ @@ -34,35 +34,139 @@ templ Global(title string) { htmx.logAll(); } - + + requestAnimationFrame(animate); + }, + + // Remove toast from stack + removeToast(id) { + this.toasts = this.toasts.filter(t => t.id !== id); + }, + + // Close error modal + closeErrorModal() { + this.errorModal.show = false; + } + }; + - - @popup.Error500Popup() - @popup.Error503Popup() + + @popup.ErrorModal() + @popup.ToastContainer()
+
+ +

+ Notification Test +

+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+
+
+ } +} diff --git a/oslstats b/oslstats new file mode 100755 index 0000000..5899776 Binary files /dev/null and b/oslstats differ diff --git a/pkg/embedfs/files/css/input.css b/pkg/embedfs/files/css/input.css index a673dd5..12af588 100644 --- a/pkg/embedfs/files/css/input.css +++ b/pkg/embedfs/files/css/input.css @@ -15,11 +15,14 @@ --color-maroon: var(--maroon); --color-peach: var(--peach); --color-yellow: var(--yellow); + --color-dark-yellow: var(--dark-yellow); --color-green: var(--green); + --color-dark-green: var(--dark-green); --color-teal: var(--teal); --color-sky: var(--sky); --color-sapphire: var(--sapphire); --color-blue: var(--blue); + --color-dark-blue: var(--dark-blue); --color-lavender: var(--lavender); --color-text: var(--text); --color-subtext1: var(--subtext1); @@ -45,11 +48,14 @@ --maroon: hsl(355, 76%, 59%); --peach: hsl(22, 99%, 52%); --yellow: hsl(35, 77%, 49%); + --dark-yellow: hsl(35, 50%, 85%); --green: hsl(109, 58%, 40%); + --dark-green: hsl(109, 35%, 85%); --teal: hsl(183, 74%, 35%); --sky: hsl(197, 97%, 46%); --sapphire: hsl(189, 70%, 42%); --blue: hsl(220, 91%, 54%); + --dark-blue: hsl(220, 50%, 85%); --lavender: hsl(231, 97%, 72%); --text: hsl(234, 16%, 35%); --subtext1: hsl(233, 13%, 41%); @@ -75,11 +81,14 @@ --maroon: hsl(350, 65%, 77%); --peach: hsl(23, 92%, 75%); --yellow: hsl(41, 86%, 83%); + --dark-yellow: hsl(41, 30%, 25%); --green: hsl(115, 54%, 76%); + --dark-green: hsl(115, 25%, 22%); --teal: hsl(170, 57%, 73%); --sky: hsl(189, 71%, 73%); --sapphire: hsl(199, 76%, 69%); --blue: hsl(217, 92%, 76%); + --dark-blue: hsl(217, 30%, 25%); --lavender: hsl(232, 97%, 85%); --text: hsl(226, 64%, 88%); --subtext1: hsl(227, 35%, 80%); diff --git a/pkg/embedfs/files/css/output.css b/pkg/embedfs/files/css/output.css index 4c9c53f..665506b 100644 --- a/pkg/embedfs/files/css/output.css +++ b/pkg/embedfs/files/css/output.css @@ -10,6 +10,7 @@ monospace; --spacing: 0.25rem; --breakpoint-xl: 80rem; + --container-sm: 24rem; --container-md: 28rem; --container-2xl: 42rem; --container-7xl: 80rem; @@ -39,10 +40,42 @@ --radius-sm: 0.25rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); --default-mono-font-family: var(--font-mono); + --color-rosewater: var(--rosewater); + --color-flamingo: var(--flamingo); + --color-pink: var(--pink); + --color-mauve: var(--mauve); + --color-red: var(--red); + --color-dark-red: var(--dark-red); + --color-maroon: var(--maroon); + --color-peach: var(--peach); + --color-yellow: var(--yellow); + --color-dark-yellow: var(--dark-yellow); + --color-green: var(--green); + --color-dark-green: var(--dark-green); + --color-teal: var(--teal); + --color-sky: var(--sky); + --color-sapphire: var(--sapphire); + --color-blue: var(--blue); + --color-dark-blue: var(--dark-blue); + --color-lavender: var(--lavender); + --color-text: var(--text); + --color-subtext1: var(--subtext1); + --color-subtext0: var(--subtext0); + --color-overlay2: var(--overlay2); + --color-overlay1: var(--overlay1); + --color-overlay0: var(--overlay0); + --color-surface2: var(--surface2); + --color-surface1: var(--surface1); + --color-surface0: var(--surface0); + --color-base: var(--base); + --color-mantle: var(--mantle); + --color-crust: var(--crust); } } @layer base { @@ -194,6 +227,15 @@ } } @layer utilities { + .pointer-events-auto { + pointer-events: auto; + } + .pointer-events-none { + pointer-events: none; + } + .collapse { + visibility: collapse; + } .visible { visibility: visible; } @@ -211,12 +253,18 @@ .absolute { position: absolute; } + .fixed { + position: fixed; + } .relative { position: relative; } .static { position: static; } + .inset-0 { + inset: calc(var(--spacing) * 0); + } .end-0 { inset-inline-end: calc(var(--spacing) * 0); } @@ -229,21 +277,57 @@ .top-4 { top: calc(var(--spacing) * 4); } + .top-20 { + top: calc(var(--spacing) * 20); + } .right-0 { right: calc(var(--spacing) * 0); } + .right-5 { + right: calc(var(--spacing) * 5); + } .bottom-0 { bottom: calc(var(--spacing) * 0); } .left-0 { left: calc(var(--spacing) * 0); } + .z-3 { + z-index: 3; + } .z-10 { z-index: 10; } + .z-40 { + z-index: 40; + } + .z-50 { + z-index: 50; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } .mx-auto { margin-inline: auto; } + .mt-1 { + margin-top: calc(var(--spacing) * 1); + } .mt-1\.5 { margin-top: calc(var(--spacing) * 1.5); } @@ -280,6 +364,9 @@ .mr-5 { margin-right: calc(var(--spacing) * 5); } + .mb-8 { + margin-bottom: calc(var(--spacing) * 8); + } .mb-auto { margin-bottom: auto; } @@ -321,6 +408,13 @@ width: calc(var(--spacing) * 6); height: calc(var(--spacing) * 6); } + .size-8 { + width: calc(var(--spacing) * 8); + height: calc(var(--spacing) * 8); + } + .h-1 { + height: calc(var(--spacing) * 1); + } .h-16 { height: calc(var(--spacing) * 16); } @@ -330,6 +424,15 @@ .h-screen { height: 100vh; } + .max-h-96 { + max-height: calc(var(--spacing) * 96); + } + .max-h-\[90vh\] { + max-height: 90vh; + } + .min-h-\[calc\(100vh-200px\)\] { + min-height: calc(100vh - 200px); + } .w-26 { width: calc(var(--spacing) * 26); } @@ -360,9 +463,30 @@ .max-w-screen-xl { max-width: var(--breakpoint-xl); } + .max-w-sm { + max-width: var(--container-sm); + } + .min-w-0 { + min-width: calc(var(--spacing) * 0); + } .flex-1 { flex: 1; } + .flex-shrink { + flex-shrink: 1; + } + .flex-shrink-0 { + flex-shrink: 0; + } + .flex-grow { + flex-grow: 1; + } + .grow { + flex-grow: 1; + } + .border-collapse { + border-collapse: collapse; + } .translate-x-0 { --tw-translate-x: calc(var(--spacing) * 0); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -371,12 +495,27 @@ --tw-translate-x: 100%; translate: var(--tw-translate-x) var(--tw-translate-y); } + .translate-x-full { + --tw-translate-x: 100%; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-y-0 { + --tw-translate-y: calc(var(--spacing) * 0); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-y-4 { + --tw-translate-y: calc(var(--spacing) * 4); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .transform { transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); } .cursor-pointer { cursor: pointer; } + .resize { + resize: both; + } .flex-col { flex-direction: column; } @@ -389,6 +528,9 @@ .items-center { align-items: center; } + .items-start { + align-items: flex-start; + } .justify-between { justify-content: space-between; } @@ -401,6 +543,12 @@ .gap-2 { gap: calc(var(--spacing) * 2); } + .gap-3 { + gap: calc(var(--spacing) * 3); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } .gap-6 { gap: calc(var(--spacing) * 6); } @@ -434,6 +582,11 @@ border-color: var(--surface2); } } + .truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } .overflow-hidden { overflow: hidden; } @@ -443,6 +596,9 @@ .overflow-x-hidden { overflow-x: hidden; } + .overflow-y-auto { + overflow-y: auto; + } .rounded { border-radius: 0.25rem; } @@ -466,6 +622,16 @@ border-style: var(--tw-border-style); border-width: 2px; } + .border-b { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 1px; + } + .border-blue { + border-color: var(--blue); + } + .border-dark-red { + border-color: var(--dark-red); + } .border-green { border-color: var(--green); } @@ -481,15 +647,36 @@ .border-transparent { border-color: transparent; } + .border-yellow { + border-color: var(--yellow); + } .bg-base { background-color: var(--base); } + .bg-blue { + background-color: var(--blue); + } .bg-crust { background-color: var(--crust); } + .bg-crust\/80 { + background-color: var(--crust); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--crust) 80%, transparent); + } + } + .bg-dark-blue { + background-color: var(--dark-blue); + } + .bg-dark-green { + background-color: var(--dark-green); + } .bg-dark-red { background-color: var(--dark-red); } + .bg-dark-yellow { + background-color: var(--dark-yellow); + } .bg-green { background-color: var(--green); } @@ -508,6 +695,9 @@ .bg-teal { background-color: var(--teal); } + .bg-yellow { + background-color: var(--yellow); + } .p-2 { padding: calc(var(--spacing) * 2); } @@ -517,6 +707,9 @@ .p-4 { padding: calc(var(--spacing) * 4); } + .p-6 { + padding: calc(var(--spacing) * 6); + } .px-2 { padding-inline: calc(var(--spacing) * 2); } @@ -529,6 +722,9 @@ .px-5 { padding-inline: calc(var(--spacing) * 5); } + .px-6 { + padding-inline: calc(var(--spacing) * 6); + } .py-1 { padding-block: calc(var(--spacing) * 1); } @@ -617,9 +813,15 @@ .whitespace-pre-wrap { white-space: pre-wrap; } + .text-blue { + color: var(--blue); + } .text-crust { color: var(--crust); } + .text-green { + color: var(--green); + } .text-mantle { color: var(--mantle); } @@ -638,6 +840,15 @@ .text-text { color: var(--text); } + .text-yellow { + color: var(--yellow); + } + .lowercase { + text-transform: lowercase; + } + .underline { + text-decoration-line: underline; + } .opacity-0 { opacity: 0%; } @@ -652,15 +863,46 @@ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .shadow-xl { + --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } + .filter { + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .delay-100 { + transition-delay: 100ms; + } .duration-200 { --tw-duration: 200ms; transition-duration: 200ms; } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; + } + .ease-in { + --tw-ease: var(--ease-in); + transition-timing-function: var(--ease-in); + } + .ease-out { + --tw-ease: var(--ease-out); + transition-timing-function: var(--ease-out); + } .outline-none { --tw-outline-style: none; outline-style: none; @@ -786,6 +1028,23 @@ border-color: var(--red); } } + .focus\:ring-2 { + &:focus { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + .focus\:ring-mauve { + &:focus { + --tw-ring-color: var(--mauve); + } + } + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; + } + } .disabled\:pointer-events-none { &:disabled { pointer-events: none; @@ -940,11 +1199,14 @@ --maroon: hsl(355, 76%, 59%); --peach: hsl(22, 99%, 52%); --yellow: hsl(35, 77%, 49%); + --dark-yellow: hsl(35, 50%, 85%); --green: hsl(109, 58%, 40%); + --dark-green: hsl(109, 35%, 85%); --teal: hsl(183, 74%, 35%); --sky: hsl(197, 97%, 46%); --sapphire: hsl(189, 70%, 42%); --blue: hsl(220, 91%, 54%); + --dark-blue: hsl(220, 50%, 85%); --lavender: hsl(231, 97%, 72%); --text: hsl(234, 16%, 35%); --subtext1: hsl(233, 13%, 41%); @@ -969,11 +1231,14 @@ --maroon: hsl(350, 65%, 77%); --peach: hsl(23, 92%, 75%); --yellow: hsl(41, 86%, 83%); + --dark-yellow: hsl(41, 30%, 25%); --green: hsl(115, 54%, 76%); + --dark-green: hsl(115, 25%, 22%); --teal: hsl(170, 57%, 73%); --sky: hsl(189, 71%, 73%); --sapphire: hsl(199, 76%, 69%); --blue: hsl(217, 92%, 76%); + --dark-blue: hsl(217, 30%, 25%); --lavender: hsl(232, 97%, 85%); --text: hsl(226, 64%, 88%); --subtext1: hsl(227, 35%, 80%); @@ -1135,10 +1400,72 @@ inherits: false; initial-value: 0 0 #0000; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-blur { + syntax: "*"; + inherits: false; +} +@property --tw-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-invert { + syntax: "*"; + inherits: false; +} +@property --tw-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-drop-shadow-size { + syntax: "*"; + inherits: false; +} @property --tw-duration { syntax: "*"; inherits: false; } +@property --tw-ease { + syntax: "*"; + inherits: false; +} @layer properties { @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { *, ::before, ::after, ::backdrop { @@ -1170,7 +1497,22 @@ --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; + --tw-outline-style: solid; + --tw-blur: initial; + --tw-brightness: initial; + --tw-contrast: initial; + --tw-grayscale: initial; + --tw-hue-rotate: initial; + --tw-invert: initial; + --tw-opacity: initial; + --tw-saturate: initial; + --tw-sepia: initial; + --tw-drop-shadow: initial; + --tw-drop-shadow-color: initial; + --tw-drop-shadow-alpha: 100%; + --tw-drop-shadow-size: initial; --tw-duration: initial; + --tw-ease: initial; } } }