From 4614b4ef37c5c35a7cb224b2320a54d3ee9e671c Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Fri, 25 Jul 2025 16:53:31 -0700 Subject: [PATCH] (UI): Implemented the UI for the recipe of the week. --- internal/templates/components/cards.templ | 43 ++++---- internal/templates/components/cards_templ.go | 107 +++++++++++++++++-- internal/templates/pages/home.templ | 24 +++-- internal/templates/pages/home_templ.go | 74 ++++++++----- web/static/css/tailwind.css | 37 ++++++- 5 files changed, 217 insertions(+), 68 deletions(-) diff --git a/internal/templates/components/cards.templ b/internal/templates/components/cards.templ index 58a8f20..7378274 100644 --- a/internal/templates/components/cards.templ +++ b/internal/templates/components/cards.templ @@ -56,35 +56,40 @@ templ ContentCardSmall(content, target string) { } // TODO: Implement this using a recipe type parameter! -templ RecipeCardLarge(liked bool) { -
- -
-

Avocado Toast

+templ RecipeCardLarge(recipe *domain.Recipe) { + if recipe != nil { +
+ +
+

+ { recipe.Title } +

- Hayden Hargreaves + Serves { recipe.Serves }

-

- Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to - make the BEST avocado toast with this recipe, plus fun variations. - Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to - make the BEST avocado toast with this recipe, plus fun variations. - Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to - make the BEST avocado toast with this recipe, plus fun variations. -

-
-

- Breakfast - 15 min +

+ { recipe.Description } +

+ +
+

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

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

Coming soon!

+ } } diff --git a/internal/templates/components/cards_templ.go b/internal/templates/components/cards_templ.go index f4c2b96..4a817ad 100644 --- a/internal/templates/components/cards_templ.go +++ b/internal/templates/components/cards_templ.go @@ -197,7 +197,7 @@ func ContentCardSmall(content, target string) templ.Component { } // TODO: Implement this using a recipe type parameter! -func RecipeCardLarge(liked bool) templ.Component { +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 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -218,19 +218,104 @@ func RecipeCardLarge(liked bool) templ.Component { templ_7745c5c3_Var11 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

Avocado Toast

Hayden Hargreaves

Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to make the BEST avocado toast with this recipe, plus fun variations. Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to make the BEST avocado toast with this recipe, plus fun variations. Avocado toast is a delicious and simple breakfast, snack or light meal! Learn how to make the BEST avocado toast with this recipe, plus fun variations.

Breakfast - 15 min

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if liked { - templ_7745c5c3_Err = likeButton().Render(ctx, templ_7745c5c3_Buffer) + if recipe != nil { + 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} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

Serves ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + 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} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + 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} + } + _, 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, 15, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + 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} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + 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} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " mins

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if recipe.Favorite { + templ_7745c5c3_Err = likeButton().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Coming soon!

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err } return nil }) diff --git a/internal/templates/pages/home.templ b/internal/templates/pages/home.templ index 657caf9..87f80d4 100644 --- a/internal/templates/pages/home.templ +++ b/internal/templates/pages/home.templ @@ -47,7 +47,7 @@ templ highlightSection(liked bool) { resonate with our users!

- @components.RecipeCardLarge(false) + @components.RecipeCardLarge(nil)
} @@ -59,10 +59,14 @@ templ listsSection(loggedIn bool, viewed, made []domainRecipe.Recipe) {

Recently viewed

if loggedIn {
- for _, recipe := range viewed { - @components.RecipeCardSmall(recipe) + if len(viewed) > 0 { + for _, recipe := range viewed { + @components.RecipeCardSmall(recipe) + } + @components.ContentCardSmall("View full history...", "/v1/web/history") + } else { +

You have not viewed any recipes. There is nothing to show.

} - @components.ContentCardSmall("View full history...", "/v1/web/history")
} else {
@@ -74,10 +78,14 @@ templ listsSection(loggedIn bool, viewed, made []domainRecipe.Recipe) {

Make again

if loggedIn {
- for _, recipe := range made { - @components.RecipeCardSmall(recipe) - } - @components.ContentCardSmall("View full history...", "/v1/web/history") + if len(made) > 0 { + for _, recipe := range made { + @components.RecipeCardSmall(recipe) + } + @components.ContentCardSmall("View full history...", "/v1/web/history") + } else { +

You have not made any recipes. There is nothing to show.

+ }
} else {
diff --git a/internal/templates/pages/home_templ.go b/internal/templates/pages/home_templ.go index e66f94c..d49bc7e 100644 --- a/internal/templates/pages/home_templ.go +++ b/internal/templates/pages/home_templ.go @@ -119,7 +119,7 @@ func highlightSection(liked bool) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = components.RecipeCardLarge(false).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = components.RecipeCardLarge(nil).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -169,22 +169,33 @@ func listsSection(loggedIn bool, viewed, made []domainRecipe.Recipe) templ.Compo if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for _, recipe := range viewed { - templ_7745c5c3_Err = components.RecipeCardSmall(recipe).Render(ctx, templ_7745c5c3_Buffer) + if len(viewed) > 0 { + for _, recipe := range viewed { + templ_7745c5c3_Err = components.RecipeCardSmall(recipe).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.ContentCardSmall("View full history...", "/v1/web/history").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

You have not viewed any recipes. There is nothing to show.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = components.ContentCardSmall("View full history...", "/v1/web/history").Render(ctx, templ_7745c5c3_Buffer) - 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, 13, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">

Log in to view metrics.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

Make again

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

Make again

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if loggedIn { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for _, recipe := range made { - templ_7745c5c3_Err = components.RecipeCardSmall(recipe).Render(ctx, templ_7745c5c3_Buffer) + if len(made) > 0 { + for _, recipe := range made { + templ_7745c5c3_Err = components.RecipeCardSmall(recipe).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.ContentCardSmall("View full history...", "/v1/web/history").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "

You have not made any recipes. There is nothing to show.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = components.ContentCardSmall("View full history...", "/v1/web/history").Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">

Log in to view metrics.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -265,7 +287,7 @@ func ctaSection() templ.Component { templ_7745c5c3_Var7 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Unleash Your Inner Chef!

Have a unique recipe idea? Want to share your culinary masterpiece with the world? It's time to bring your creations to life!

Unleash Your Inner Chef!

Have a unique recipe idea? Want to share your culinary masterpiece with the world? It's time to bring your creations to life!

Create Your Recipe!
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\" class=\"flex items-center justify-center\n bg-gradient-to-r from-blue-400 to-blue-600 text-white\n px-12 py-5 rounded-full shadow-sm hover:shadow-md\n transition-all duration-300 ease-in-out shadow-blue-700\n text-lg md:text-2xl font-bold uppercase tracking-wide\">Create Your Recipe!") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -307,7 +329,7 @@ func HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe) templ.Component if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -331,7 +353,7 @@ func HomePage(loggedIn bool, viewed, made []domainRecipe.Recipe) templ.Component if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/web/static/css/tailwind.css b/web/static/css/tailwind.css index a1d4d52..2c0d983 100644 --- a/web/static/css/tailwind.css +++ b/web/static/css/tailwind.css @@ -8,8 +8,8 @@ --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-red-800: oklch(44.4% 0.177 26.899); --color-green-500: oklch(72.3% 0.219 149.579); --color-blue-50: oklch(97% 0.014 254.604); --color-blue-100: oklch(93.2% 0.032 255.585); @@ -379,6 +379,14 @@ 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); @@ -446,6 +454,15 @@ .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); + } .w-fit { width: fit-content; } @@ -455,6 +472,9 @@ .max-w-2xl { max-width: var(--container-2xl); } + .min-w-full { + min-width: 100%; + } .flex-shrink-0 { flex-shrink: 0; } @@ -624,6 +644,9 @@ .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); } @@ -831,6 +854,9 @@ --tw-tracking: var(--tracking-wide); letter-spacing: var(--tracking-wide); } + .text-wrap { + text-wrap: wrap; + } .text-ellipsis { text-overflow: ellipsis; } @@ -873,9 +899,6 @@ .text-red-500 { color: var(--color-red-500); } - .text-red-800 { - color: var(--color-red-800); - } .text-white { color: var(--color-white); } @@ -1313,6 +1336,12 @@ 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);