From 53943dd1839f4751aab4208968e722fc757ca3f3 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Sat, 26 Jul 2025 22:36:48 -0700 Subject: [PATCH] (FEAT): Implemented recipe of the week! And image placeholder. Still having the stupid ass nil dereferences, I think I might need to migrate to using success returns instead of pointers. Because they're fucked. And even more so now. --- internal/app/handlers/page_handler.go | 26 +++++- internal/app/service/recipe_service.go | 10 +++ internal/domain/recipe/repository.go | 3 + internal/domain/recipe/service.go | 7 +- .../database/repository/recipe_repository.go | 85 ++++++++++++++++++ internal/templates/components/cards.templ | 82 ++++++++--------- internal/templates/components/cards_templ.go | 31 ++++--- internal/templates/pages/favorites.templ | 2 +- internal/templates/pages/favorites_templ.go | 2 +- internal/templates/pages/home.templ | 8 +- internal/templates/pages/home_templ.go | 8 +- internal/templates/pages/recipe.templ | 2 +- internal/templates/pages/recipe_templ.go | 2 +- internal/templates/pages/search.templ | 2 +- internal/templates/pages/search_templ.go | 2 +- web/static/css/tailwind.css | 50 +---------- web/static/img/recipe_placeholder.png | Bin 0 -> 1072 bytes web/static/img/recipe_placeholder_wide.jpg | Bin 0 -> 7930 bytes 18 files changed, 199 insertions(+), 123 deletions(-) create mode 100644 web/static/img/recipe_placeholder.png create mode 100644 web/static/img/recipe_placeholder_wide.jpg diff --git a/internal/app/handlers/page_handler.go b/internal/app/handlers/page_handler.go index 61dfe22..ae28e7b 100644 --- a/internal/app/handlers/page_handler.go +++ b/internal/app/handlers/page_handler.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "strconv" + "time" "github.com/a-h/templ" "github.com/gin-gonic/gin" @@ -28,6 +29,7 @@ func HomePage(ctx *gin.Context) { loggedIn := domain.IsLoggedIn(ctx) + var page templ.Component if loggedIn { userId := ctx.MustGet("userId").(int) @@ -48,9 +50,29 @@ func HomePage(ctx *gin.Context) { return } - page = templates.HomePage(true, viewedRecipes, madeRecipes) + // Get the recipe of the week + recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(&userId, time.Now()) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{ + "status": http.StatusInternalServerError, + "message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()), + }) + return + } + + page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek) } else { - page = templates.HomePage(false, nil, nil) + // Get the recipe of the week + recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(nil, time.Now()) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{ + "status": http.StatusInternalServerError, + "message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()), + }) + return + } + + page = templates.HomePage(false, nil, nil, recipeOfTheWeek) } title := "Potion - Home" diff --git a/internal/app/service/recipe_service.go b/internal/app/service/recipe_service.go index e9d48d6..1d3f231 100644 --- a/internal/app/service/recipe_service.go +++ b/internal/app/service/recipe_service.go @@ -174,6 +174,9 @@ func (s *RecipeService) GetUserFavoriteRecipes(id int) ([]domain.Recipe, error) return s.recipeRepository.GetUserFavoriteRecipes(id) } +// GetUserViewedRecipes returns a list of the most recent x (limit) recipes viewed by a user, from +// the provided userId. This will return a list of size 'limit'. Any errors will be bubbled up to +// the caller. func (s *RecipeService) GetUserViewedRecipes(userId, limit int) ([]domain.Recipe, error) { engagement, err := s.engagementRepository.GetUserEngagementFiltered(userId, limit, domainEngagement.EngagementViewed) if err != nil { @@ -188,6 +191,9 @@ func (s *RecipeService) GetUserViewedRecipes(userId, limit int) ([]domain.Recipe return s.recipeRepository.GetRecipes(ids, &userId) } +// GetUserMadeRecipes returns a list of the most recent x (limit) recipes made by a user, from the +// provided userId. This will return a list of size 'limit'. Any errors will be bubbled up to the +// caller. func (s *RecipeService) GetUserMadeRecipes(userId, limit int) ([]domain.Recipe, error) { engagement, err := s.engagementRepository.GetUserEngagementFiltered(userId, limit, domainEngagement.EngagementMade) if err != nil { @@ -201,3 +207,7 @@ func (s *RecipeService) GetUserMadeRecipes(userId, limit int) ([]domain.Recipe, return s.recipeRepository.GetRecipes(ids, &userId) } + +func (s *RecipeService) GetRecipeOfTheWeek(userId *int, date time.Time) (*domain.Recipe, error) { + return s.recipeRepository.GetRecipeOfTheWeek(userId, date) +} diff --git a/internal/domain/recipe/repository.go b/internal/domain/recipe/repository.go index 761aa2e..55db598 100644 --- a/internal/domain/recipe/repository.go +++ b/internal/domain/recipe/repository.go @@ -1,5 +1,7 @@ package domain +import "time" + type RecipeRepository interface { CreateRecipe(recipe *Recipe) error GetRecipe(id int, userId *int) (*Recipe, error) @@ -10,4 +12,5 @@ type RecipeRepository interface { GetUserFavoriteRecipes(id int) ([]Recipe, error) GetRecipeTags(recipe *Recipe) error GetRecipeFavorite(recipe *Recipe, userId int) error + GetRecipeOfTheWeek(userId *int, date time.Time) (*Recipe, error) } diff --git a/internal/domain/recipe/service.go b/internal/domain/recipe/service.go index 373d417..33b83ef 100644 --- a/internal/domain/recipe/service.go +++ b/internal/domain/recipe/service.go @@ -1,6 +1,10 @@ package domain -import "github.com/gin-gonic/gin" +import ( + "time" + + "github.com/gin-gonic/gin" +) type RecipeService interface { CreateRecipe(ctx *gin.Context) (*Recipe, error) @@ -10,4 +14,5 @@ type RecipeService interface { GetUserFavoriteRecipes(id int) ([]Recipe, error) GetUserViewedRecipes(userId, limit int) ([]Recipe, error) GetUserMadeRecipes(userId, limit int) ([]Recipe, error) + GetRecipeOfTheWeek(userId *int, date time.Time) (*Recipe, error) } diff --git a/internal/infrastructure/database/repository/recipe_repository.go b/internal/infrastructure/database/repository/recipe_repository.go index f043102..960abee 100644 --- a/internal/infrastructure/database/repository/recipe_repository.go +++ b/internal/infrastructure/database/repository/recipe_repository.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strings" + "time" domain "github.com/haydenhargreaves/Potion/internal/domain/recipe" "github.com/lib/pq" @@ -832,3 +833,87 @@ func (r *RecipeRepository) GetRecipeFavorite(recipe *domain.Recipe, userId int) return nil } + +func (r *RecipeRepository) GetRecipeOfTheWeek(userId *int, date time.Time) (*domain.Recipe, error) { + tx, err := r.db.Begin() + if err != nil { + tx.Rollback() + return nil, err + } + + query := ` + SELECT + r.id, r.title, r.description, r.instructions, r.serves, r.difficulty, r.duration, r.category, + r.ingredients, r.userid, r.modified, r.created + FROM recipes r + JOIN recipeoftheweek rw ON rw.recipeid = r.id + ORDER BY created DESC + LIMIT 1; + ` + + var durationBytes []byte + var ingredientBytes []byte + + var recipe domain.Recipe + if err := tx.QueryRow(query).Scan( + &recipe.Id, + &recipe.Title, + &recipe.Description, + pq.Array(&recipe.Instructions), + &recipe.Serves, + &recipe.Difficulty, + &durationBytes, + &recipe.Category, + &ingredientBytes, + &recipe.UserId, + &recipe.Modified, + &recipe.Created, + ); err != nil { + return nil, fmt.Errorf("Failed to location recipe in database: %s", err.Error()) + } + + // Parse duration + if len(durationBytes) > 0 { + var duration domain.RecipeDuration + if err := json.Unmarshal(durationBytes, &duration); err != nil { + return nil, fmt.Errorf("Failed to parse duration from database: %s", err.Error()) + } + + recipe.Duration = duration + } else { + recipe.Duration = domain.RecipeDuration{} + } + + // Parse ingredient + if len(ingredientBytes) > 0 { + var ingredients []domain.RecipeIngredient + if err := json.Unmarshal(ingredientBytes, &ingredients); err != nil { + return nil, fmt.Errorf("Failed to parse ingredients from database: %s", err.Error()) + } + + recipe.Ingredients = ingredients + } else { + recipe.Ingredients = []domain.RecipeIngredient{} + } + + // Add tags + if err := r.GetRecipeTags(&recipe); err != nil { + fmt.Printf("ERROR getting recipe tags. %s\n", err.Error()) + } + + // Get favorite status, if user id is provided + if userId != nil { + if err := r.GetRecipeFavorite(&recipe, *userId); err != nil { + fmt.Printf("ERROR getting recipe favorite status. %s\n", err.Error()) + } + } else { + recipe.Favorite = false + } + + if err := tx.Commit(); err != nil { + tx.Rollback() + return nil, err + } + + return &recipe, nil +} diff --git a/internal/templates/components/cards.templ b/internal/templates/components/cards.templ index 7378274..ced3d84 100644 --- a/internal/templates/components/cards.templ +++ b/internal/templates/components/cards.templ @@ -5,20 +5,18 @@ import "github.com/haydenhargreaves/Potion/internal/domain/recipe" import domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" templ likeButton() { - + + + } templ RecipeCardSmall(recipe domain.Recipe) {
- -
+ +

{ recipe.Title }

@@ -55,41 +53,39 @@ templ ContentCardSmall(content, target string) {
} -// TODO: Implement this using a recipe type parameter! templ RecipeCardLarge(recipe *domain.Recipe) { - if recipe != nil { -
- -
-

- { recipe.Title } -

-

- Serves { recipe.Serves } -

-

- { recipe.Description } -

- -
-

- { recipe.Category } - { recipe.Duration.Total } mins + if recipe != nil { +

+ +
+

+ { recipe.Title } +

+

+ Serves { recipe.Serves }

- if recipe.Favorite { - @likeButton() - } +

+ { recipe.Description } +

+
+

+ { recipe.Category } - { recipe.Duration.Total } mins +

+ if recipe.Favorite { + @likeButton() + } +
+
-
-
- } else { -

Coming soon!

- } + } else { +

Coming soon!

+ } } diff --git a/internal/templates/components/cards_templ.go b/internal/templates/components/cards_templ.go index 4a817ad..65fb91b 100644 --- a/internal/templates/components/cards_templ.go +++ b/internal/templates/components/cards_templ.go @@ -33,7 +33,7 @@ func likeButton() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -62,14 +62,14 @@ func RecipeCardSmall(recipe domain.Recipe) templ.Component { templ_7745c5c3_Var2 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 23, Col: 18} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 21, Col: 18} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -82,7 +82,7 @@ func RecipeCardSmall(recipe domain.Recipe) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Serves) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 26, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 24, Col: 26} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -95,7 +95,7 @@ func RecipeCardSmall(recipe domain.Recipe) templ.Component { var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 30, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 28, Col: 22} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -108,7 +108,7 @@ func RecipeCardSmall(recipe domain.Recipe) templ.Component { var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 30, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 28, Col: 50} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -131,7 +131,7 @@ func RecipeCardSmall(recipe domain.Recipe) templ.Component { var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(domainServer.API_ENGAGEMENT_VIEW, recipe.Id)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 37, Col: 70} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 35, Col: 70} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -182,7 +182,7 @@ func ContentCardSmall(content, target string) templ.Component { var templ_7745c5c3_Var10 string templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(content) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 52, Col: 32} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 50, Col: 32} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { @@ -196,7 +196,6 @@ func ContentCardSmall(content, target string) templ.Component { }) } -// TODO: Implement this using a recipe type parameter! func RecipeCardLarge(recipe *domain.Recipe) 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 @@ -219,14 +218,14 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { } ctx = templ.ClearChildren(ctx) if recipe != nil { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 65, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 62, Col: 19} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { @@ -239,7 +238,7 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Serves) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 68, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 65, Col: 27} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -252,7 +251,7 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 71, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 68, Col: 25} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { @@ -265,7 +264,7 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 76, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 72, Col: 23} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { @@ -278,7 +277,7 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { var templ_7745c5c3_Var16 string templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 76, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 72, Col: 51} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) if templ_7745c5c3_Err != nil { @@ -301,7 +300,7 @@ func RecipeCardLarge(recipe *domain.Recipe) templ.Component { var templ_7745c5c3_Var17 string templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(domainServer.API_ENGAGEMENT_VIEW, recipe.Id)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 83, Col: 70} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/cards.templ`, Line: 79, Col: 71} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) if templ_7745c5c3_Err != nil { diff --git a/internal/templates/pages/favorites.templ b/internal/templates/pages/favorites.templ index 7ddc99e..0f8f808 100644 --- a/internal/templates/pages/favorites.templ +++ b/internal/templates/pages/favorites.templ @@ -25,7 +25,7 @@ templ favoriteResult(recipe domain.Recipe) { hx-swap="none" class="w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer" > - +
diff --git a/internal/templates/pages/favorites_templ.go b/internal/templates/pages/favorites_templ.go index 790cfd8..a16e478 100644 --- a/internal/templates/pages/favorites_templ.go +++ b/internal/templates/pages/favorites_templ.go @@ -97,7 +97,7 @@ func favoriteResult(recipe domain.Recipe) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer\">

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer\">

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/templates/pages/home.templ b/internal/templates/pages/home.templ index 87f80d4..8c9b49b 100644 --- a/internal/templates/pages/home.templ +++ b/internal/templates/pages/home.templ @@ -36,7 +36,7 @@ templ searchSection() { } -templ highlightSection(liked bool) { +templ highlightSection(recipeOfTheWeek *domainRecipe.Recipe) {
@components.BannerText("Recipe of the Week!")

@@ -47,7 +47,7 @@ templ highlightSection(liked bool) { resonate with our users!

- @components.RecipeCardLarge(nil) + @components.RecipeCardLarge(recipeOfTheWeek)
} @@ -122,13 +122,13 @@ templ ctaSection() { } -templ HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe) { +templ HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe, recipeOfTheWeek *domainRecipe.Recipe) { @components.Navbar("home")
@introSection() @searchSection() - @highlightSection(false) + @highlightSection(recipeOfTheWeek) @listsSection(loggedIn, viewed, made) @ctaSection()
diff --git a/internal/templates/pages/home_templ.go b/internal/templates/pages/home_templ.go index d49bc7e..4dca9af 100644 --- a/internal/templates/pages/home_templ.go +++ b/internal/templates/pages/home_templ.go @@ -86,7 +86,7 @@ func searchSection() templ.Component { }) } -func highlightSection(liked bool) templ.Component { +func highlightSection(recipeOfTheWeek *domainRecipe.Recipe) 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 { @@ -119,7 +119,7 @@ func highlightSection(liked bool) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = components.RecipeCardLarge(nil).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = components.RecipeCardLarge(recipeOfTheWeek).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -304,7 +304,7 @@ func ctaSection() templ.Component { }) } -func HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe) templ.Component { +func HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe, recipeOfTheWeek *domainRecipe.Recipe) 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 { @@ -341,7 +341,7 @@ func HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe) templ.Component if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = highlightSection(false).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = highlightSection(recipeOfTheWeek).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/templates/pages/recipe.templ b/internal/templates/pages/recipe.templ index 44b6b8c..69d6c02 100644 --- a/internal/templates/pages/recipe.templ +++ b/internal/templates/pages/recipe.templ @@ -295,7 +295,7 @@ templ RecipePage(recipe domain.Recipe, user domainUser.User, loggedIn bool, doma @components.Navbar("")
- +

{ recipe.Title }

Author: { user.Name }

diff --git a/internal/templates/pages/recipe_templ.go b/internal/templates/pages/recipe_templ.go index b68c36a..10be9fc 100644 --- a/internal/templates/pages/recipe_templ.go +++ b/internal/templates/pages/recipe_templ.go @@ -803,7 +803,7 @@ func RecipePage(recipe domain.Recipe, user domainUser.User, loggedIn bool, domai if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "
\"\"

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/templates/pages/search.templ b/internal/templates/pages/search.templ index e5acc11..faab3d1 100644 --- a/internal/templates/pages/search.templ +++ b/internal/templates/pages/search.templ @@ -43,7 +43,7 @@ templ searchResult(recipe domain.Recipe) { hx-swap="none" class="w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer" > - +
diff --git a/internal/templates/pages/search_templ.go b/internal/templates/pages/search_templ.go index c3bec1a..7280f63 100644 --- a/internal/templates/pages/search_templ.go +++ b/internal/templates/pages/search_templ.go @@ -153,7 +153,7 @@ func searchResult(recipe domain.Recipe) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer\">

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer\">

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/web/static/css/tailwind.css b/web/static/css/tailwind.css index 2c0d983..080b507 100644 --- a/web/static/css/tailwind.css +++ b/web/static/css/tailwind.css @@ -8,7 +8,6 @@ --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); @@ -335,9 +334,6 @@ .mb-16 { margin-bottom: calc(var(--spacing) * 16); } - .\[display\:-webkit-box\] { - display: -webkit-box; - } .block { display: block; } @@ -379,14 +375,6 @@ width: calc(var(--spacing) * 56); height: calc(var(--spacing) * 56); } - .size-64 { - width: calc(var(--spacing) * 64); - height: calc(var(--spacing) * 64); - } - .size-72 { - width: calc(var(--spacing) * 72); - height: calc(var(--spacing) * 72); - } .size-80 { width: calc(var(--spacing) * 80); height: calc(var(--spacing) * 80); @@ -424,6 +412,9 @@ .h-screen { height: 100vh; } + .min-h-72 { + min-height: calc(var(--spacing) * 72); + } .min-h-screen { min-height: 100vh; } @@ -454,12 +445,6 @@ .w-52 { width: calc(var(--spacing) * 52); } - .w-64 { - width: calc(var(--spacing) * 64); - } - .w-72 { - width: calc(var(--spacing) * 72); - } .w-80 { width: calc(var(--spacing) * 80); } @@ -472,9 +457,6 @@ .max-w-2xl { max-width: var(--container-2xl); } - .min-w-full { - min-width: 100%; - } .flex-shrink-0 { flex-shrink: 0; } @@ -644,9 +626,6 @@ .border-green-500 { border-color: var(--color-green-500); } - .border-red-200 { - border-color: var(--color-red-200); - } .border-red-500 { border-color: var(--color-red-500); } @@ -994,12 +973,6 @@ -webkit-user-select: none; user-select: none; } - .\[-webkit-box-orient\:vertical\] { - -webkit-box-orient: vertical; - } - .\[-webkit-line-clamp\:4\] { - -webkit-line-clamp: 4; - } .peer-checked\:border-blue-600 { &:is(:where(.peer):checked ~ *) { border-color: var(--color-blue-600); @@ -1330,18 +1303,6 @@ height: calc(var(--spacing) * 48); } } - .md\:size-64 { - @media (width >= 48rem) { - width: calc(var(--spacing) * 64); - height: calc(var(--spacing) * 64); - } - } - .md\:size-80 { - @media (width >= 48rem) { - width: calc(var(--spacing) * 80); - height: calc(var(--spacing) * 80); - } - } .md\:h-24 { @media (width >= 48rem) { height: calc(var(--spacing) * 24); @@ -1362,11 +1323,6 @@ width: calc(1/4 * 100%); } } - .md\:w-2\/5 { - @media (width >= 48rem) { - width: calc(2/5 * 100%); - } - } .md\:w-3\/4 { @media (width >= 48rem) { width: calc(3/4 * 100%); diff --git a/web/static/img/recipe_placeholder.png b/web/static/img/recipe_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..c8664d907a793d90bb47a2859139e80e55b5d63a GIT binary patch literal 1072 zcmV-01kd}4P)-QZS*000BK zNkl{m?5P;!Txp*1%{ol4L1Ma3hX}gLmn*U3hY?FpCFkA%scmMzZ00000 z00000000000000000000031vn?)m4woblFLZ`|1xIf!(&in?3&qnI_o%FcHT@zsM% zh|Ss6Ie-t5`PPR>{rx&IbfN7;bU5Cx6Qy6ms+XRVc?oeoyGFUmwB)8P6K?t0-Yrd~ zUBZfgxo3p^Yw!(AmiBjxP-mJc{PbbYIk`UBiGLw9-iO!YZ%X8Zm8Q=2ix{?{pk8s`{yV9AU{@LWH5gH zXZ^RUxQleJ&T0NOlgMM}ulV8b+Ei=v@8lCVU#%OZ@v+9{{}uvyr1K4biP0#v{dn?_ zG4{H>K&GzeO`p{@ja+L=4^edDu(5f-*6CDD-W{edF;7RmS$d=kid|c1P58~L>LE0X(XD|g=3}*>~I%X&;?w$R$5y8HR0@~S+T#I zOd1f zgl~Z*)NC(-x^f=fXlsYSy2)odfN*L0I-mGMMocJn|K1@7cgzk;Q=^El#IPD3Z~!W$fo=kf8q*x{Wj0x)MBo)3s=L_JfHirU)K9< zn_ZPkK6g>9zTn&?;~Np4yZ`Qv%hI*vbH5VPjoQ=7PMONfAijm^#w?S}7$0R66kyuh zWL+odfdkGtRHK)_b$>TDfO```h2y_ndw2O|m$=I0nd= zMbLZzz|vA35CDF+#W?^@3?=*T0zd!{7ghj(#W9HX&X5oW4uzt#v`Cbo9aJrHP#`LT z#6W3lp;5s4jS&nI*`FGM+(GrF(T$bnFa4~9q*08OT(CB18-^)$C(U9vlj^wJ)``5^ zpKM4`+PDF^J^~jJ$Oxo{kdP690dy8F!dPip9LF6m!6+r{Sc$MSE7H}*4rv<1 zq$06edYWXko<36FP)i%Dudl1W4yl9I#-h*|6b7xSgTd*dak@Il&!)tkjY;vrIS|c1 z&&BnOl|EloczC#0I7Tao>5I}fG&Dq^bx=Awnp}n^YZpC)6ro9HDSuHQQdwjsjS)f% zq9d0SNjriC=j`P;W*k~*JARQdY^MCe_e~| zU*@8?#h{k9_Yd3s1>*M5((t$Da4|9X3b>@WxTFM}dmtpFq$Ch)5eRt%Vl7%(fosZW4J{QF6)g=c7LCSY z@%W8@lvr#A-~tdNPdNmn1c2cn2pqK70;F+oeh3Hz;+Fo!zz`k~FCQ2CBghScz%T#| z1|a-Aza@aUE)33tMB90bufX6L+7gONI#J~*a4s3b`$r<62-gO~2=>9zOJvef9Y%$? z580_V>AF1R7;OKtz1|674CD*!&Wy><9rV$m1>-<*Xe zEQC@9wFW(n-_?m!&uddD;rJtBv+IDV(n^p2tJ8n z2>B;JE)4()YwUDQ;#;eKSxOo(Pf-PcBt!%yJcWM`+}BUK3q5paAGXT&yovV@slv|G z*B`wH@cV4NR3M_Gv)S(YU7_C5Hf^b$*EvyK1x~i?nCdj;3GC%ep+ znSb{I62AQ$FG%$8Ayp)Y77)AO(@TBGJlSR&5bNUwzK{>BHh*Iq1poq#)u;F}r-}K1 z?$lt2-QQ_0$As&P)M4BaKNUndi;!(gBb}?`t09!8_)`#XQg`|y_N3B$5VEcB&v?iP z5|>iaicz^s=f5}S0PFnkFu?D~>feFCg>;yVsBbX<;JL2!9rRnCkouMQZ!zxcKhPb@ z`)Bx12)wImHRDexAmUaXjsG+JEdtTY6pH;81b{6z(o5U*Pi7EyNr}3&8DASHzoRqx z2Ob#?F7(ag7A09($glIcUifj{L#K~&jCr^IV;%h3v};g}=>})r$Gv~j0nda;3AKXP zT;!{~iT_jdYk<#Bvltk~q0UoAEG?qGjsbvw@r+4`Y%D6j&o%ek*f%~z6Ia=|@@~vk za(40Ap{q(Wr=z}NKx$5G_ua`LWi!Atq0&NM#lGVh9^A)A0=8^be2npO;L&KHCij?| zvr{z__#-~EalwX?sH2(gyX`6cAOy6s2>{*gzmNZp*4Gf_T%>Cex6?-WK0c_dF3KQh z1K{=SQtxx=LM}qmhg^jA>@4*@NC5!GOs(__O`l>vu4Z-7F_y(Oa%A-anbN*H3)u4iJQ28Rb5|{@Fww zBbu(iY@r z(4Dmi+#h)!x2NItf`{82RcGSprQW1ToecW(45r1z-q&Npy{xo(q z5Z7D0Y78=au+D9_aP45^;SI)FJ-(RbaLy$|YmSGkHOK4C;pJ%{pQfqSU-m$sytJ!+ z8oZjD791T~R=+-R(P7V;;@8bN(iNPyu`Vvd1A9qZ4olTkYXk=DJJ??*qao?dlJUEO zE^Ix}~rs&HbhyX+B4GGXJeda|Jz7WN%@Jqu-9!fU3s!*4y`T)j0)V1 zm@{A-%Ntpv&qO+q)xtchZ0!XBkz{tZq6s(ccV}C$O4!#k`7{=@uY-sut=c z_+q^y6D0dEf*sSZGvRiIQJI2tYM1~$nFWmnE=mX}0{C*3&hEy&~93>}2Ro_P3}3c2XrzfGrA*#r`A1hIjH^PQvTPRgR$!hos znRrA3qO%c_{zP`8M3K+?ric%<1(1a)X!~rd>Z&rdE5=sM^_pR9;t_EOrh98*PJ$CA zaz{gC#0kiYZkNQq1UnsDuh&s=@HSdY3gswUb#nCS433-~fxcE7lQ=43|6%8)bgWcJ z$*r6oY2loB2h3jVCjC^8!G=l;(C{TI(XC?<4|RpzsC82C^3>)>yu@2 z^q2{gXNu9M7y7)d=;Lrd>pXhKD_LQq_9m+?Tj%kDjThJX?PX7UJv%V)=<0OYy3j4J z+ifN$lk7e`Ggs|w8iK0v!3bk`asM+~>zX8oFOdsY{k+c4MR&Nk&rMjy+X?NbxYbis zGE)<#Y9H;LKWcN3Y+a|aPA6`wLutkKQn&L1YbOHOR(7i@b%$x_gSKk z+4h`jIH-Bwg>aiEKJ%b!{h`}nfjbmo)wr;8*_n?>DkR^b6|=qPeTOi!8LztEzL-rI zb{n=FInNCXti{tU0loa{BSm4c$1j>~_e~ez*=}iC%M)LJm}k3P%-cksRqhtB`*umi z@MEcVFC+_R_<9zvIsRPTm8n5r=Z?PxHq6c+a!Iaxl|Sla*$6Gsjli zA9SR}jfyUmZeWeG0}4Ei0}kHw@pZJFJbsDtbi`<|=T+76AkCJOkz;1Kz*h)nL+bAD_!_ClbBK*wz3z{>n-*H%vTqqUrx zqyqSbg?Q(K=Y-m{PW4G!DfPL(xK>;xnpq{9dX-adYLhQX`dO$=C=g96LDQ@eel3z) zjrSvE{7ZVSJI)Slxa>IVvZ0#w>0`;Qa*`ZG0zY+a`t)i8^KAtDff zPFk)=xv;`;6`{?mFVGN58@wGjcy}Ma>`yiqCNv8@Xcs*~U&>QI==G)4WCwEY1`gc_ zPJcOSYqFFYdeQ6Oq%GWLO7)dq7%i=TE2>`5aj76hykSoF>H%<`MS@9|rtW=aG)xh1 zXmWCX>Rpc&P}T6!xzU$(Eyx&fx0?bJ@pb=7=4t*_u>UH8X>_JJ4JCYkHm*2p?CNl|LR&cTHUq z<<+S!*kyB{)V#xFhfr_@(@zR>q`m@oJJJ8IeQBi1bXtffPLHa&VD-LHj&u zO6K|Fi<6iquNmsn+XDzO5fTp$7?&ks8b;*~KG=K4teW}QI52)L`^Z@1V<*u*8MSuZ z@yeri!Z;5gZ{NEG*3Atuw?ZcSZZ5bs?TckP#?f+qK@v^g);8he=^vf9?4Cds^%vp- zlFPczkZY+1Q&}oJYTR|IPp7mA<~r`LY^t!&Xb+uOA;6(b8AYKd$1m@28fZ0eIoIDm zl;XIuzdcm@u66itgDv3mPtQNigm$Q%JvT68hE+cuvU|cGWSkfCilgkC1_g{9BjoNmaAKK2zI8jtQD&fi4v-$q?t86L*3n7 zTHD@;t#~^czawXEBkf~halE$NS!qY0b>) z#DcqQ0CxL}ZB4s2sd%}QGs(iK zmdShAX@z(3X!(ZON#f5vuZq>j*;}j_P8~OQ@lF_VjD|Ei!aWJr*(<=ACm0$;*mGiHPnlA~q30SMWy*JVDNI`b`hH8%;H2!p5gmN3eO|q! zP^>|K8r;70EiZ62;{nkmiEpKrt(;u#X1=ybMECA(xjg)OR{XFl9AhY|Tsis!L1T_| z1D9&6l68tr>6Rh`I!=S-HXtWov3G7x5C&5GQ$dsF4k*nx1N@#1G2rkmszc*<7H zoktX&E8ilXd364