(FEAT): Errors can now be displayed using the RenderErrorBanner fx.
This is found in the components domain. Make sure only HTMX routes call it. Although, I think I put this into the page handlers WHICH IS WRONG. However, it does work, ish. But it does not load into the DOM properly. But it seems to display just fine.
This commit is contained in:
parent
05ecea56db
commit
47b8386844
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
func EngagementViewRecipe(ctx *gin.Context) {
|
||||
@ -101,6 +102,7 @@ func EngagementFavoriteRecipe(ctx *gin.Context) {
|
||||
recipeId, _ := strconv.Atoi(id)
|
||||
|
||||
if _, err := deps.EngagementService.UserFavoriteRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Something went wrong. %s.", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
domainServer "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts"
|
||||
pages "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
@ -41,6 +42,7 @@ func HomePage(ctx *gin.Context) {
|
||||
userId := ctx.MustGet("userId").(int)
|
||||
madeRecipes, err := deps.RecipeService.GetUserMadeRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting made recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
@ -49,9 +51,10 @@ func HomePage(ctx *gin.Context) {
|
||||
}
|
||||
viewedRecipes, err := deps.RecipeService.GetUserViewedRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
"message": fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -59,9 +62,10 @@ func HomePage(ctx *gin.Context) {
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(&userId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -82,9 +86,10 @@ func HomePage(ctx *gin.Context) {
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(nil)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -178,6 +183,7 @@ func ProfilePage(ctx *gin.Context) {
|
||||
|
||||
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
|
||||
@ -187,9 +193,10 @@ func ProfilePage(ctx *gin.Context) {
|
||||
|
||||
favorites, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
|
||||
"message": fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -197,6 +204,7 @@ func ProfilePage(ctx *gin.Context) {
|
||||
// Get the engagement data, not sure what will happen when errors occur
|
||||
engagements, err := deps.EngagementService.GetUserEngagement(user.Id, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting user engagements. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
|
||||
@ -217,7 +225,6 @@ func ListPage(ctx *gin.Context) {
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
// TODO: Figure out how to handle errors, think we just need a simple display.
|
||||
func RecipePage(ctx *gin.Context) {
|
||||
// Call recipe service to get via ID
|
||||
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
@ -226,7 +233,7 @@ func RecipePage(ctx *gin.Context) {
|
||||
// Parse ID
|
||||
parsed, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
@ -251,7 +258,7 @@ func RecipePage(ctx *gin.Context) {
|
||||
// Get recipe
|
||||
recipe, err := deps.RecipeService.GetRecipe(parsed, userId)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
@ -259,7 +266,7 @@ func RecipePage(ctx *gin.Context) {
|
||||
// Get user (owner)
|
||||
user, err := deps.UserService.GetUser(recipe.UserId)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
58
internal/templates/components/error.templ
Normal file
58
internal/templates/components/error.templ
Normal file
@ -0,0 +1,58 @@
|
||||
package components
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
templ errorIcon() {
|
||||
<svg class="h-6 text-red-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 16.99V17M12 7V14M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>
|
||||
</svg>
|
||||
}
|
||||
|
||||
templ closeButton() {
|
||||
<button
|
||||
onclick="hideError();"
|
||||
class="text-red-500 ml-auto hover:bg-red-200 p-1 rounded-sm transition-all duration-300 cursor-pointer"
|
||||
>
|
||||
<svg class="h-4" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M19.207 6.207a1 1 0 0 0-1.414-1.414L12 10.586 6.207 4.793a1 1 0 0 0-1.414 1.414L10.586 12l-5.793 5.793a1 1 0 1 0 1.414 1.414L12 13.414l5.793 5.793a1 1 0 0 0 1.414-1.414L13.414 12l5.793-5.793z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
}
|
||||
|
||||
templ errorBanner(message string) {
|
||||
<div
|
||||
id="error-toast"
|
||||
hx-swap-oob="outerHTML"
|
||||
class="fixed z-20 border border-red-500 rounded-sm right-0 top-0 m-4 p-4 bg-red-100 shadow shadow-red-200 transition-all duration-300 text-sm md:w-1/3"
|
||||
>
|
||||
<div class="flex items-center gap-x-2 pb-1">
|
||||
@errorIcon()
|
||||
<h1 class="text-red-500 font-semibold">Error</h1>
|
||||
@closeButton()
|
||||
</div>
|
||||
<div class="ml-8">
|
||||
<p class="text-red-500 text-sm">
|
||||
{ message }
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// RenderErrorBanner renders the error banner. However, this function must ONLY be called by an
|
||||
// HTMX route. Otherwise, there is no promise it will work (may result in undefined behavior).
|
||||
// Just writes a piece of content to the response.
|
||||
func RenderErrorBanner(ctx *gin.Context, message string) {
|
||||
ctx.Writer.Header().Set("Content-Type", "text/html")
|
||||
errorBanner(message).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
137
internal/templates/components/error_templ.go
Normal file
137
internal/templates/components/error_templ.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.3.937
|
||||
package components
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func errorIcon() 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 {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<svg class=\"h-6 text-red-500\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12 16.99V17M12 7V14M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></svg>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func closeButton() 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 {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var2 == nil {
|
||||
templ_7745c5c3_Var2 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<button onclick=\"hideError();\" class=\"text-red-500 ml-auto hover:bg-red-200 p-1 rounded-sm transition-all duration-300 cursor-pointer\"><svg class=\"h-4\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M19.207 6.207a1 1 0 0 0-1.414-1.414L12 10.586 6.207 4.793a1 1 0 0 0-1.414 1.414L10.586 12l-5.793 5.793a1 1 0 1 0 1.414 1.414L12 13.414l5.793 5.793a1 1 0 0 0 1.414-1.414L13.414 12l5.793-5.793z\" fill=\"currentColor\"></path></svg></button>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func errorBanner(message 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 {
|
||||
return templ_7745c5c3_CtxErr
|
||||
}
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
defer func() {
|
||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err == nil {
|
||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var3 == nil {
|
||||
templ_7745c5c3_Var3 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div id=\"error-toast\" hx-swap-oob=\"outerHTML\" class=\"fixed z-20 border border-red-500 rounded-sm right-0 top-0 m-4 p-4 bg-red-100 shadow shadow-red-200 transition-all duration-300 text-sm md:w-1/3\"><div class=\"flex items-center gap-x-2 pb-1\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = errorIcon().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<h1 class=\"text-red-500 font-semibold\">Error</h1>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = closeButton().Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div><div class=\"ml-8\"><p class=\"text-red-500 text-sm\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(message)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/error.templ`, Line: 46, Col: 13}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</p></div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// RenderErrorBanner renders the error banner. However, this function must ONLY be called by an
|
||||
// HTMX route. Otherwise, there is no promise it will work (may result in undefined behavior).
|
||||
// Just writes a piece of content to the response.
|
||||
func RenderErrorBanner(ctx *gin.Context, message string) {
|
||||
ctx.Writer.Header().Set("Content-Type", "text/html")
|
||||
errorBanner(message).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
|
||||
var _ = templruntime.GeneratedTemplate
|
||||
@ -3,20 +3,24 @@ package templates
|
||||
// AppLayout is the main application layout, this does not contain any content other than
|
||||
// meta data, links, scripts and whatever is passed into it as a component.
|
||||
templ AppLayout(title string, child templ.Component) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{ title }</title>
|
||||
<link rel="stylesheet" href="/v1/web/static/css/tailwind.css" />
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-100">
|
||||
@child
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>{ title }</title>
|
||||
<link rel="stylesheet" href="/v1/web/static/css/tailwind.css"/>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
<div id="error-toast"></div>
|
||||
@child
|
||||
<script>
|
||||
function hideError() {
|
||||
const err = document.getElementById("error-toast");
|
||||
err.classList.add("hidden");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
@ -38,13 +38,13 @@ func AppLayout(title string, child templ.Component) templ.Component {
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/layouts/app_layout.templ`, Line: 12, Col: 16}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/layouts/app_layout.templ`, Line: 11, Col: 17}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><link rel=\"stylesheet\" href=\"/v1/web/static/css/tailwind.css\"><script src=\"https://unpkg.com/htmx.org@2.0.4\"></script></head><body class=\"bg-gray-100\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><link rel=\"stylesheet\" href=\"/v1/web/static/css/tailwind.css\"><script src=\"https://unpkg.com/htmx.org@2.0.4\"></script></head><body class=\"bg-gray-100\"><div id=\"error-toast\"></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@ -52,7 +52,7 @@ func AppLayout(title string, child templ.Component) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</body></html>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<script>\n function hideError() {\n const err = document.getElementById(\"error-toast\");\n err.classList.add(\"hidden\");\n }\n </script></body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||
monospace;
|
||||
--color-red-100: oklch(93.6% 0.032 17.717);
|
||||
--color-red-200: oklch(88.5% 0.062 18.334);
|
||||
--color-red-500: oklch(63.7% 0.237 25.331);
|
||||
--color-green-500: oklch(72.3% 0.219 149.579);
|
||||
--color-blue-50: oklch(97% 0.014 254.604);
|
||||
@ -235,18 +236,27 @@
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
.top-0 {
|
||||
top: calc(var(--spacing) * 0);
|
||||
}
|
||||
.top-1\/2 {
|
||||
top: calc(1/2 * 100%);
|
||||
}
|
||||
.top-\[100\%\] {
|
||||
top: 100%;
|
||||
}
|
||||
.right-0 {
|
||||
right: calc(var(--spacing) * 0);
|
||||
}
|
||||
.left-0 {
|
||||
left: calc(var(--spacing) * 0);
|
||||
}
|
||||
@ -262,6 +272,9 @@
|
||||
.z-20 {
|
||||
z-index: 20;
|
||||
}
|
||||
.m-4 {
|
||||
margin: calc(var(--spacing) * 4);
|
||||
}
|
||||
.mx-2 {
|
||||
margin-inline: calc(var(--spacing) * 2);
|
||||
}
|
||||
@ -337,6 +350,12 @@
|
||||
.mb-16 {
|
||||
margin-bottom: calc(var(--spacing) * 16);
|
||||
}
|
||||
.ml-8 {
|
||||
margin-left: calc(var(--spacing) * 8);
|
||||
}
|
||||
.ml-auto {
|
||||
margin-left: auto;
|
||||
}
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
@ -694,6 +713,9 @@
|
||||
--tw-gradient-to: var(--color-purple-200);
|
||||
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
||||
}
|
||||
.p-1 {
|
||||
padding: calc(var(--spacing) * 1);
|
||||
}
|
||||
.p-2 {
|
||||
padding: calc(var(--spacing) * 2);
|
||||
}
|
||||
@ -939,6 +961,12 @@
|
||||
--tw-shadow-color: color-mix(in oklab, var(--color-gray-300) var(--tw-shadow-alpha), transparent);
|
||||
}
|
||||
}
|
||||
.shadow-red-200 {
|
||||
--tw-shadow-color: oklch(88.5% 0.062 18.334);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--tw-shadow-color: color-mix(in oklab, var(--color-red-200) var(--tw-shadow-alpha), transparent);
|
||||
}
|
||||
}
|
||||
.outline {
|
||||
outline-style: var(--tw-outline-style);
|
||||
outline-width: 1px;
|
||||
@ -1141,6 +1169,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:bg-red-200 {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
background-color: var(--color-red-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:text-blue-400 {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user