Compare commits

...

4 Commits

Author SHA1 Message Date
db447b3a7d Merge pull request '(UI/STYLE): Implemented the first rendition of the profile page.' (#17) from feature/profile into master
Reviewed-on: #17
2025-07-13 20:00:01 -07:00
Hayden Hargreaves
9be423cea0 (UI): Finished up the profile implementation for now.
The other sections not working yet were marked as under construction.
There still needs to be a page for "see all..." for the recipes, but
that will be a task for another time.
2025-07-13 19:58:47 -07:00
Hayden Hargreaves
3b6ebd0dae (DB/UI): Created user list API and wired to UI.
The profile list will now properly display the users recipes! The
favorites list does not exist yet, since there is no backend support for
favoriting/saving recipes. So the list displays the same content as the
user recipe list. Same goes for the activity list, not yet implemented.
2025-07-13 14:01:05 -07:00
Hayden Hargreaves
ae1f4f8e99 (UI/STYLE): Implemented the first rendition of the profile page.
Needs a backend wire job, but it looks pretty good. I can't really test
this page on a real mobile device either, since it requires the user to
be logged in and the testing doesn't work with google.
2025-07-12 14:22:23 -07:00
11 changed files with 906 additions and 89 deletions

View File

@ -213,6 +213,35 @@ creation process will take place here
##### UI Requirements
- [ ] User details section
- [ ] Google details: profile picture, full name and email
- [ ] User recipe section
- [ ] List of all the recipes created by the user
- [ ] Paginated? **Maybe a max size and a button for seeing them all***
- [ ] Short and sweet, not much data displayed, no image and no description
- [ ] Different layout then used elsewhere, spanned across the entire page
- [ ] User saved recipe section
- [ ] List of all the recipes liked/saved by the user
- [ ] Max size of **x*** amount, a see all button will take the user to their favorites page
- [ ] Should look the like section above
- [ ] User activity section
- [ ] List of all recent "engagement" the user has created
- [ ] Just a message and a date
'*': Not sure yet, still under consideration
##### API Requirements
## Database Requirements ## Database Requirements
This section outlines the specific technical requirements for the database store for This section outlines the specific technical requirements for the database store for

View File

@ -58,9 +58,18 @@ func ProfilePage(ctx *gin.Context) {
// Else, get the user data // Else, get the user data
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies) deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
user := deps.UserService.GetAuthenicatedUser(ctx) user := deps.UserService.GetAuthenicatedUser(ctx)
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
if err != nil {
fmt.Printf("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()),
})
return
}
title := "Potion - Profile" title := "Potion - Profile"
page := pages.ProfilePage(user) page := pages.ProfilePage(user, recipes)
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page)) ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
} }

View File

@ -1 +1,49 @@
package handlers package handlers
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
)
func GetUserRecipes(ctx *gin.Context) {
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
// Ensure logged in
if !domain.IsLoggedIn(ctx) {
ctx.JSON(http.StatusUnauthorized, gin.H{
"status": http.StatusUnauthorized,
"message": "User is not authorized to access this endpoint. Please login to continue.",
"recipes": nil,
})
return
}
userId, ok := ctx.MustGet("userId").(int)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": "Unable to access user id from store.",
"recipes": nil,
})
return
}
recipes, err := deps.RecipeService.GetUserRecipes(userId)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"status": http.StatusBadRequest,
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
"recipes": nil,
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"status": http.StatusOK,
"message": "User recipes successfully retrieved.",
"recipes": recipes,
})
}

View File

@ -181,6 +181,7 @@ func (s *Server) Setup() *Server {
// Recipe endpoints // Recipe endpoints
router_api.POST("/recipe", handlers.CreateRecipe) router_api.POST("/recipe", handlers.CreateRecipe)
router_api.POST("/recipe/search", handlers.SearchRecipes) router_api.POST("/recipe/search", handlers.SearchRecipes)
router_api.GET("/user/recipes", handlers.GetUserRecipes)
// Catch un-routed URLS // Catch un-routed URLS
s.Router.NoRoute(func(ctx *gin.Context) { s.Router.NoRoute(func(ctx *gin.Context) {

View File

@ -150,3 +150,7 @@ func (s *RecipeService) GetRecipe(id int) (*domain.Recipe, error) {
func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) { func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) {
return s.recipeRepository.SearchRecipes(filters) return s.recipeRepository.SearchRecipes(filters)
} }
func (s *RecipeService) GetUserRecipes(id int) ([]domain.Recipe, error) {
return s.recipeRepository.GetUserRecipes(id)
}

View File

@ -5,4 +5,6 @@ type RecipeRepository interface {
GetRecipe(id int) (*Recipe, error) GetRecipe(id int) (*Recipe, error)
SearchRecipes(filters SearchFilters) ([]Recipe, error) SearchRecipes(filters SearchFilters) ([]Recipe, error)
CreateRecipeTags(recipe Recipe, tags []string) error CreateRecipeTags(recipe Recipe, tags []string) error
GetUserRecipes(id int) ([]Recipe, error)
GetRecipeTags(recipe *Recipe) error
} }

View File

@ -6,4 +6,5 @@ type RecipeService interface {
CreateRecipe(ctx *gin.Context) (*Recipe, error) CreateRecipe(ctx *gin.Context) (*Recipe, error)
GetRecipe(id int) (*Recipe, error) GetRecipe(id int) (*Recipe, error)
SearchRecipes(filters SearchFilters) ([]Recipe, error) SearchRecipes(filters SearchFilters) ([]Recipe, error)
GetUserRecipes(id int) ([]Recipe, error)
} }

View File

@ -128,34 +128,6 @@ func (r *RecipeRepository) GetRecipe(id int) (*domain.Recipe, error) {
return nil, fmt.Errorf("Failed to location recipe in database: %s", err.Error()) return nil, fmt.Errorf("Failed to location recipe in database: %s", err.Error())
} }
// Get tags from external tables
query = `
SELECT t.* FROM tags t
JOIN recipetags rt ON rt.tagid = t.id
WHERE rt.recipeid = $1;
`
rows, err := tx.Query(query, recipe.Id)
if err != nil {
return nil, fmt.Errorf("Failed to get tags for recipe. %s\n", err.Error())
}
defer rows.Close()
for rows.Next() {
var tag domain.Tag
err := rows.Scan(&tag.Id, &tag.Name, &tag.Created)
if err != nil {
return nil, fmt.Errorf("Failed to scan tag onto domain model. %s\n", err.Error())
}
recipe.Tags = append(recipe.Tags, tag)
}
if err := tx.Commit(); err != nil {
tx.Rollback()
return nil, err
}
// Parse duration // Parse duration
if len(durationBytes) > 0 { if len(durationBytes) > 0 {
var duration domain.RecipeDuration var duration domain.RecipeDuration
@ -180,6 +152,14 @@ func (r *RecipeRepository) GetRecipe(id int) (*domain.Recipe, error) {
recipe.Ingredients = []domain.RecipeIngredient{} recipe.Ingredients = []domain.RecipeIngredient{}
} }
// Add tags
r.GetRecipeTags(&recipe)
if err := tx.Commit(); err != nil {
tx.Rollback()
return nil, err
}
return &recipe, nil return &recipe, nil
} }
@ -387,6 +367,9 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain
recipe.Ingredients = []domain.RecipeIngredient{} recipe.Ingredients = []domain.RecipeIngredient{}
} }
// Add tags
r.GetRecipeTags(&recipe)
recipes = append(recipes, recipe) recipes = append(recipes, recipe)
} }
@ -456,3 +439,135 @@ func (r *RecipeRepository) CreateRecipeTags(recipe domain.Recipe, tags []string)
return nil return nil
} }
// GetUserRecipes gets a list of a users owned recipes. This function does not ensure the user is
// authenticated or exists. If nothing is found, a blank slice will be returned. The resulting list
// is sorted by the created dates, newest first. Any errors will be bubbled to the caller.
func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) {
tx, err := r.db.Begin()
if err != nil {
tx.Rollback()
return nil, err
}
query := `
SELECT id, title, description, instructions, serves, difficulty, duration, category, ingredients,
userid, modified, created
FROM recipes
WHERE userid = $1
ORDER BY created DESC;
`
rows, err := tx.Query(query, id)
if err != nil {
return nil, fmt.Errorf("Failed to query DB for user recipes. %s\n", err.Error())
}
defer rows.Close()
// Prepare statement for tag query
// tagQuery := `
// `
var recipes []domain.Recipe
for rows.Next() {
var recipe domain.Recipe
var durationBytes []byte
var ingredientBytes []byte
// Scan results from recipe query onto recipe object
if err := rows.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 scan row onto recipe object. %s\n", 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
r.GetRecipeTags(&recipe)
recipes = append(recipes, recipe)
}
if err := tx.Commit(); err != nil {
tx.Rollback()
return nil, err
}
return recipes, nil
}
// GetRecipeTags requires a recipe to be filled with at least an ID. This function will use the ID
// defined in the provided recipe to fill the Tags array with the recipe's tags from the database.
// The recipe is modified in place and is not returned. Any errors will be bubbled to the caller.
func (r *RecipeRepository) GetRecipeTags(recipe *domain.Recipe) error {
tx, err := r.db.Begin()
if err != nil {
tx.Rollback()
return err
}
recipe.Tags = []domain.Tag{}
query := `
SELECT t.* FROM tags t
JOIN recipetags rt ON rt.tagid = t.id
WHERE rt.recipeid = $1;
`
rows, err := tx.Query(query, recipe.Id)
if err != nil {
return fmt.Errorf("Failed to get tags for recipe. %s\n", err.Error())
}
defer rows.Close()
for rows.Next() {
var tag domain.Tag
err := rows.Scan(&tag.Id, &tag.Name, &tag.Created)
if err != nil {
return fmt.Errorf("Failed to scan tag onto domain model. %s\n", err.Error())
}
recipe.Tags = append(recipe.Tags, tag)
}
if err := tx.Commit(); err != nil {
tx.Rollback()
return err
}
return nil
}

View File

@ -1,28 +1,167 @@
package templates package templates
import "github.com/haydenhargreaves/Potion/internal/templates/components" import "github.com/haydenhargreaves/Potion/internal/templates/components"
import "fmt"
import "strings"
import domain "github.com/haydenhargreaves/Potion/internal/domain/server" import domain "github.com/haydenhargreaves/Potion/internal/domain/server"
import domain_user"github.com/haydenhargreaves/Potion/internal/domain/user" import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
import domainUser "github.com/haydenhargreaves/Potion/internal/domain/user"
templ userDetailsSection(user domain_user.User) { func displayDifficulty(diff int) string {
switch diff {
case 1:
return "Beginner"
case 2:
return "Easy"
case 3:
return "Intermediate"
case 4:
return "Challenging"
case 5:
return "Extreme"
default:
return ""
}
}
func displayTags(tags []domainRecipe.Tag) string {
names := make([]string, 0, len(tags))
for _, tag := range tags {
names = append(names, tag.Name)
}
return strings.Join(names, ", ")
}
templ userDetailsSection(user domainUser.User, recipeCount int) {
<section class="w-full flex flex-col justify-center my-8 py-4 border-b border-gray-300"> <section class="w-full flex flex-col justify-center my-8 py-4 border-b border-gray-300">
<div class="w-full p-4 md:p-8 flex items-center gap-x-8"> <div class="w-full p-4 md:p-8 flex items-center gap-x-8">
if user.ImageUrl != "" {
<img <img
class="w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none" class="w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none"
src={ user.ImageUrl } src={ user.ImageUrl }
/> />
} else {
<img
class="w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none"
src={ fmt.Sprintf("https://ui-avatars.com/api/?name=%s+%s&size=150", strings.Split(user.Name, " ")[0], strings.Split(user.Name, " ")[1])}
/>
}
<div class="flex flex-col gap-y-4">
<div class=""> <div class="">
<h1 class="text-md md:text-2xl font-semibold">{ user.Name }</h1> <h1 class="text-md md:text-2xl font-semibold">{ user.Name }</h1>
<p class="text-xs md:text-sm">{ user.Email }</p> <p class="text-xs md:text-sm">{ user.Email }</p>
</div> </div>
<div class="flex gap-x-4">
<p class="text-xs md:text-sm"><span class="font-bold">{ recipeCount }</span> recipes</p>
<p class="text-xs md:text-sm"><span class="font-bold">0</span> favorites</p>
</div>
</div>
</div> </div>
</section> </section>
} }
templ recipesSection(recipes []domainRecipe.Recipe) {
<section class="p-8">
<h2 class="text-2xl font-semibold text-gray-800">My Recipes</h2>
<ul class="w-full my-2">
if len(recipes) <= 4 {
for _, recipe :=range recipes {
@recipeListItem(recipe)
}
} else {
for _, recipe := range recipes[:4] {
@recipeListItem(recipe)
}
}
<a href="/" class="bg-red-500">
<li
class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center"
>
See all...
</li>
</a>
</ul>
</section>
}
templ favoritesSection(recipes []domainRecipe.Recipe) {
<section class="p-8">
<h2 class="text-2xl font-semibold text-gray-800">My Favorites</h2>
<p class="text-sm my-2">Favorites section is under construction!</p>
</section>
}
templ activitySection() {
<section class="p-8">
<h2 class="text-2xl font-semibold text-gray-800">Recent Activity</h2>
<p class="text-sm my-2">Activity section is under construction!</p>
<!--
<ul class="w-full my-2">
@activityListItem()
@activityListItem()
@activityListItem()
@activityListItem()
@activityListItem()
@activityListItem()
<a href="/" class="bg-red-500">
<li
class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center"
>
See all...
</li>
</a>
</ul>
-->
</section>
}
templ recipeListItem(recipe domainRecipe.Recipe) {
<li class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150">
<p class="text-base md:text-lg">
<a href={ templ.SafeURL(fmt.Sprintf(domain.WEB_RECIPE, recipe.Id)) } class="hover:text-blue-600 duration-100">
{ recipe.Title }
</a>
</p>
<p class="hidden md:block text-sm text-gray-700 my-1.5">
Difficulty: <span class="font-semibold">{ displayDifficulty(recipe.Difficulty) }</span>
| Duration: <span class="font-semibold">{ recipe.Duration.Total } min</span>
| Category: <span class="font-semibold">{ recipe.Category }</span>
</p>
<p class="md:hidden text-xs md:text-sm text-gray-700 my-1">
Difficulty: <span class="font-semibold">{ displayDifficulty(recipe.Difficulty) }</span>
</p>
<p class="md:hidden text-xs md:text-sm text-gray-700 my-1">
Duration: <span class="font-semibold">{ recipe.Duration.Total } min</span>
</p>
<p class="md:hidden text-xs md:text-sm text-gray-700 my-1">
Category: <span class="font-semibold">{ recipe.Category }</span>
</p>
if len(recipe.Tags) > 0 {
<p class="text-xs italic text-gray-500">
Tags: { displayTags(recipe.Tags) }
</p>
}
</li>
}
templ activityListItem() {
<li
class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150 flex justify-between items-center"
>
<p class="text-sm md:text-base text-gray-800">
Rated "Spicy Chicken Wings"
</p>
<p class="text-xs md:text-sm text-gray-600 w-fit shrink-0">
2 days ago
</p>
</li>
}
templ logoutSection() { templ logoutSection() {
<section class="w-full flex flex-col justify-center items-center py-8 border-t border-gray-300"> <section class="w-full flex flex-col justify-center items-center py-8 border-t border-gray-300 mt-auto">
<a <a
href={domain.API_AUTH_LOGOUT} href={ domain.API_AUTH_LOGOUT }
class="text-center border border-red-500 text-red-500 w-9/10 md:w-1/3 py-2 rounded-lg hover:cursor-pointer hover:bg-red-100 duration-300" class="text-center border border-red-500 text-red-500 w-9/10 md:w-1/3 py-2 rounded-lg hover:cursor-pointer hover:bg-red-100 duration-300"
> >
Logout Logout
@ -30,13 +169,14 @@ templ logoutSection() {
</section> </section>
} }
templ ProfilePage(user domain_user.User) { templ ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe) {
@components.Navbar(" profile") @components.Navbar(" profile")
<div class="w-full h-screen flex justify-center"> <div class="w-full h-fit flex justify-center">
<div <div class="mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col">
class="mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col justify-between" @userDetailsSection(user, len(recipes))
> @recipesSection(recipes)
@userDetailsSection(user) @favoritesSection(recipes)
@activitySection()
@logoutSection() @logoutSection()
</div> </div>
</div> </div>

View File

@ -9,10 +9,38 @@ import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime" import templruntime "github.com/a-h/templ/runtime"
import "github.com/haydenhargreaves/Potion/internal/templates/components" import "github.com/haydenhargreaves/Potion/internal/templates/components"
import "fmt"
import "strings"
import domain "github.com/haydenhargreaves/Potion/internal/domain/server" import domain "github.com/haydenhargreaves/Potion/internal/domain/server"
import domain_user "github.com/haydenhargreaves/Potion/internal/domain/user" import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
import domainUser "github.com/haydenhargreaves/Potion/internal/domain/user"
func userDetailsSection(user domain_user.User) templ.Component { func displayDifficulty(diff int) string {
switch diff {
case 1:
return "Beginner"
case 2:
return "Easy"
case 3:
return "Intermediate"
case 4:
return "Challenging"
case 5:
return "Extreme"
default:
return ""
}
}
func displayTags(tags []domainRecipe.Tag) string {
names := make([]string, 0, len(tags))
for _, tag := range tags {
names = append(names, tag.Name)
}
return strings.Join(names, ", ")
}
func userDetailsSection(user domainUser.User, recipeCount int) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@ -33,46 +61,374 @@ func userDetailsSection(user domain_user.User) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent templ_7745c5c3_Var1 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<section class=\"w-full flex flex-col justify-center my-8 py-4 border-b border-gray-300\"><div class=\"w-full p-4 md:p-8 flex items-center gap-x-8\"><img class=\"w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none\" src=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<section class=\"w-full flex flex-col justify-center my-8 py-4 border-b border-gray-300\"><div class=\"w-full p-4 md:p-8 flex items-center gap-x-8\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.ImageUrl != "" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<img class=\"w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none\" src=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var2 string var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.ImageUrl) templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.ImageUrl)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 12, Col: 23} return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 41, Col: 23}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\"><div class=\"\"><h1 class=\"text-md md:text-2xl font-semibold\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<img class=\"w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none\" src=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name) templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("https://ui-avatars.com/api/?name=%s+%s&size=150", strings.Split(user.Name, " ")[0], strings.Split(user.Name, " ")[1]))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 15, Col: 61} return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 46, Col: 140}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h1><p class=\"text-xs md:text-sm\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"flex flex-col gap-y-4\"><div class=\"\"><h1 class=\"text-md md:text-2xl font-semibold\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 16, Col: 46} return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 52, Col: 62}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p></div></div></section>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</h1><p class=\"text-xs md:text-sm\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 53, Col: 47}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</p></div><div class=\"flex gap-x-4\"><p class=\"text-xs md:text-sm\"><span class=\"font-bold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(recipeCount)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 56, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</span> recipes</p><p class=\"text-xs md:text-sm\"><span class=\"font-bold\">0</span> favorites</p></div></div></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func recipesSection(recipes []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 {
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_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">My Recipes</h2><ul class=\"w-full my-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(recipes) <= 4 {
for _, recipe := range recipes {
templ_7745c5c3_Err = recipeListItem(recipe).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
} else {
for _, recipe := range recipes[:4] {
templ_7745c5c3_Err = recipeListItem(recipe).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a href=\"/\" class=\"bg-red-500\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func favoritesSection(recipes []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 {
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_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">My Favorites</h2><p class=\"text-sm my-2\">Favorites section is under construction!</p></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func activitySection() 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_Var9 := templ.GetChildren(ctx)
if templ_7745c5c3_Var9 == nil {
templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">Recent Activity</h2><p class=\"text-sm my-2\">Activity section is under construction!</p><!--\n\t\t<ul class=\"w-full my-2\">\n\t\t\t@activityListItem()\n\t\t\t@activityListItem()\n\t\t\t@activityListItem()\n\t\t\t@activityListItem()\n\t\t\t@activityListItem()\n\t\t\t@activityListItem()\n\t\t\t<a href=\"/\" class=\"bg-red-500\">\n\t\t\t\t<li\n\t\t\t\t\tclass=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\"\n\t\t\t\t>\n\t\t\t\t\tSee all...\n\t\t\t\t</li>\n\t\t\t</a>\n\t\t</ul>\n --></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func recipeListItem(recipe 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 {
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_Var10 := templ.GetChildren(ctx)
if templ_7745c5c3_Var10 == nil {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150\"><p class=\"text-base md:text-lg\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 templ.SafeURL = templ.SafeURL(fmt.Sprintf(domain.WEB_RECIPE, recipe.Id))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var11)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\" class=\"hover:text-blue-600 duration-100\">")
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/pages/profile.templ`, Line: 123, Col: 18}
}
_, 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, 16, "</a></p><p class=\"hidden md:block text-sm text-gray-700 my-1.5\">Difficulty: <span class=\"font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(displayDifficulty(recipe.Difficulty))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 127, Col: 81}
}
_, 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, 17, "</span> | Duration: <span class=\"font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 128, Col: 66}
}
_, 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, 18, " min</span> | Category: <span class=\"font-semibold\">")
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/pages/profile.templ`, Line: 129, Col: 60}
}
_, 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, 19, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Difficulty: <span class=\"font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(displayDifficulty(recipe.Difficulty))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 132, Col: 81}
}
_, 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, 20, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Duration: <span class=\"font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 135, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " min</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Category: <span class=\"font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 138, Col: 58}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</span></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(recipe.Tags) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<p class=\"text-xs italic text-gray-500\">Tags: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(displayTags(recipe.Tags))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 142, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
func activityListItem() 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_Var20 := templ.GetChildren(ctx)
if templ_7745c5c3_Var20 == nil {
templ_7745c5c3_Var20 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150 flex justify-between items-center\"><p class=\"text-sm md:text-base text-gray-800\">Rated \"Spicy Chicken Wings\"</p><p class=\"text-xs md:text-sm text-gray-600 w-fit shrink-0\">2 days ago</p></li>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -96,21 +452,21 @@ func logoutSection() templ.Component {
}() }()
} }
ctx = templ.InitializeContext(ctx) ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx) templ_7745c5c3_Var21 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil { if templ_7745c5c3_Var21 == nil {
templ_7745c5c3_Var5 = templ.NopComponent templ_7745c5c3_Var21 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<section class=\"w-full flex flex-col justify-center items-center py-8 border-t border-gray-300\"><a href=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<section class=\"w-full flex flex-col justify-center items-center py-8 border-t border-gray-300 mt-auto\"><a href=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var6 templ.SafeURL = domain.API_AUTH_LOGOUT var templ_7745c5c3_Var22 templ.SafeURL = domain.API_AUTH_LOGOUT
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6))) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var22)))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" class=\"text-center border border-red-500 text-red-500 w-9/10 md:w-1/3 py-2 rounded-lg hover:cursor-pointer hover:bg-red-100 duration-300\">Logout</a></section>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\" class=\"text-center border border-red-500 text-red-500 w-9/10 md:w-1/3 py-2 rounded-lg hover:cursor-pointer hover:bg-red-100 duration-300\">Logout</a></section>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -118,7 +474,7 @@ func logoutSection() templ.Component {
}) })
} }
func ProfilePage(user domain_user.User) templ.Component { func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@ -134,20 +490,32 @@ func ProfilePage(user domain_user.User) templ.Component {
}() }()
} }
ctx = templ.InitializeContext(ctx) ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var7 := templ.GetChildren(ctx) templ_7745c5c3_Var23 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil { if templ_7745c5c3_Var23 == nil {
templ_7745c5c3_Var7 = templ.NopComponent templ_7745c5c3_Var23 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = components.Navbar(" profile").Render(ctx, templ_7745c5c3_Buffer) templ_7745c5c3_Err = components.Navbar(" profile").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"w-full h-screen flex justify-center\"><div class=\"mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col justify-between\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<div class=\"w-full h-fit flex justify-center\"><div class=\"mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = userDetailsSection(user).Render(ctx, templ_7745c5c3_Buffer) templ_7745c5c3_Err = userDetailsSection(user, len(recipes)).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = recipesSection(recipes).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = favoritesSection(recipes).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = activitySection().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -155,7 +523,7 @@ func ProfilePage(user domain_user.User) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</div></div>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -17,7 +17,6 @@
--color-blue-500: oklch(62.3% 0.214 259.815); --color-blue-500: oklch(62.3% 0.214 259.815);
--color-blue-600: oklch(54.6% 0.245 262.881); --color-blue-600: oklch(54.6% 0.245 262.881);
--color-blue-700: oklch(48.8% 0.243 264.376); --color-blue-700: oklch(48.8% 0.243 264.376);
--color-blue-800: oklch(42.4% 0.199 265.638);
--color-purple-100: oklch(94.6% 0.033 307.174); --color-purple-100: oklch(94.6% 0.033 307.174);
--color-purple-200: oklch(90.2% 0.063 306.703); --color-purple-200: oklch(90.2% 0.063 306.703);
--color-gray-50: oklch(98.5% 0.002 247.839); --color-gray-50: oklch(98.5% 0.002 247.839);
@ -29,6 +28,7 @@
--color-gray-600: oklch(44.6% 0.03 256.802); --color-gray-600: oklch(44.6% 0.03 256.802);
--color-gray-700: oklch(37.3% 0.034 259.733); --color-gray-700: oklch(37.3% 0.034 259.733);
--color-gray-800: oklch(27.8% 0.033 256.848); --color-gray-800: oklch(27.8% 0.033 256.848);
--color-gray-900: oklch(21% 0.034 264.665);
--color-black: #000; --color-black: #000;
--color-white: #fff; --color-white: #fff;
--spacing: 0.25rem; --spacing: 0.25rem;
@ -49,8 +49,6 @@
--text-3xl--line-height: calc(2.25 / 1.875); --text-3xl--line-height: calc(2.25 / 1.875);
--text-4xl: 2.25rem; --text-4xl: 2.25rem;
--text-4xl--line-height: calc(2.5 / 2.25); --text-4xl--line-height: calc(2.5 / 2.25);
--text-5xl: 3rem;
--text-5xl--line-height: 1;
--text-6xl: 3.75rem; --text-6xl: 3.75rem;
--text-6xl--line-height: 1; --text-6xl--line-height: 1;
--text-8xl: 6rem; --text-8xl: 6rem;
@ -240,6 +238,9 @@
.static { .static {
position: static; position: static;
} }
.top-1 {
top: calc(var(--spacing) * 1);
}
.top-1\/2 { .top-1\/2 {
top: calc(1/2 * 100%); top: calc(1/2 * 100%);
} }
@ -249,6 +250,9 @@
.left-0 { .left-0 {
left: calc(var(--spacing) * 0); left: calc(var(--spacing) * 0);
} }
.left-1 {
left: calc(var(--spacing) * 1);
}
.left-1\/2 { .left-1\/2 {
left: calc(1/2 * 100%); left: calc(1/2 * 100%);
} }
@ -273,6 +277,9 @@
.my-1 { .my-1 {
margin-block: calc(var(--spacing) * 1); margin-block: calc(var(--spacing) * 1);
} }
.my-1\.5 {
margin-block: calc(var(--spacing) * 1.5);
}
.my-2 { .my-2 {
margin-block: calc(var(--spacing) * 2); margin-block: calc(var(--spacing) * 2);
} }
@ -300,6 +307,9 @@
.mt-16 { .mt-16 {
margin-top: calc(var(--spacing) * 16); margin-top: calc(var(--spacing) * 16);
} }
.mt-auto {
margin-top: auto;
}
.mr-2 { .mr-2 {
margin-right: calc(var(--spacing) * 2); margin-right: calc(var(--spacing) * 2);
} }
@ -410,12 +420,18 @@
.min-h-screen { .min-h-screen {
min-height: 100vh; min-height: 100vh;
} }
.w-1 {
width: calc(var(--spacing) * 1);
}
.w-1\/3 { .w-1\/3 {
width: calc(1/3 * 100%); width: calc(1/3 * 100%);
} }
.w-1\/4 { .w-1\/4 {
width: calc(1/4 * 100%); width: calc(1/4 * 100%);
} }
.w-3 {
width: calc(var(--spacing) * 3);
}
.w-3\/4 { .w-3\/4 {
width: calc(3/4 * 100%); width: calc(3/4 * 100%);
} }
@ -428,6 +444,9 @@
.w-5 { .w-5 {
width: calc(var(--spacing) * 5); width: calc(var(--spacing) * 5);
} }
.w-9 {
width: calc(var(--spacing) * 9);
}
.w-9\/10 { .w-9\/10 {
width: calc(9/10 * 100%); width: calc(9/10 * 100%);
} }
@ -446,16 +465,33 @@
.max-w-2xl { .max-w-2xl {
max-width: var(--container-2xl); max-width: var(--container-2xl);
} }
.flex-shrink {
flex-shrink: 1;
}
.flex-shrink-0 { .flex-shrink-0 {
flex-shrink: 0; flex-shrink: 0;
} }
.shrink-0 {
flex-shrink: 0;
}
.flex-grow { .flex-grow {
flex-grow: 1; flex-grow: 1;
} }
.border-collapse {
border-collapse: collapse;
}
.-translate-x-1 {
--tw-translate-x: calc(var(--spacing) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
}
.-translate-x-1\/2 { .-translate-x-1\/2 {
--tw-translate-x: calc(calc(1/2 * 100%) * -1); --tw-translate-x: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y); translate: var(--tw-translate-x) var(--tw-translate-y);
} }
.-translate-y-1 {
--tw-translate-y: calc(var(--spacing) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
}
.-translate-y-1\/2 { .-translate-y-1\/2 {
--tw-translate-y: calc(calc(1/2 * 100%) * -1); --tw-translate-y: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y); translate: var(--tw-translate-x) var(--tw-translate-y);
@ -468,9 +504,15 @@
--tw-scale-y: 50%; --tw-scale-y: 50%;
scale: var(--tw-scale-x) var(--tw-scale-y); scale: var(--tw-scale-x) var(--tw-scale-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 {
cursor: pointer; cursor: pointer;
} }
.resize {
resize: both;
}
.resize-none { .resize-none {
resize: none; resize: none;
} }
@ -645,6 +687,9 @@
.bg-red-100 { .bg-red-100 {
background-color: var(--color-red-100); background-color: var(--color-red-100);
} }
.bg-red-500 {
background-color: var(--color-red-500);
}
.bg-white { .bg-white {
background-color: var(--color-white); background-color: var(--color-white);
} }
@ -656,6 +701,9 @@
--tw-gradient-position: to right in oklab; --tw-gradient-position: to right in oklab;
background-image: linear-gradient(var(--tw-gradient-stops)); background-image: linear-gradient(var(--tw-gradient-stops));
} }
.bg-none {
background-image: none;
}
.from-blue-100 { .from-blue-100 {
--tw-gradient-from: var(--color-blue-100); --tw-gradient-from: var(--color-blue-100);
--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)); --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));
@ -686,6 +734,9 @@
.p-4 { .p-4 {
padding: calc(var(--spacing) * 4); padding: calc(var(--spacing) * 4);
} }
.p-8 {
padding: calc(var(--spacing) * 8);
}
.px-1 { .px-1 {
padding-inline: calc(var(--spacing) * 1); padding-inline: calc(var(--spacing) * 1);
} }
@ -858,6 +909,9 @@
.uppercase { .uppercase {
text-transform: uppercase; text-transform: uppercase;
} }
.italic {
font-style: italic;
}
.underline { .underline {
text-decoration-line: underline; text-decoration-line: underline;
} }
@ -920,6 +974,10 @@
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration)); transition-duration: var(--tw-duration, var(--default-transition-duration));
} }
.duration-100 {
--tw-duration: 100ms;
transition-duration: 100ms;
}
.duration-150 { .duration-150 {
--tw-duration: 150ms; --tw-duration: 150ms;
transition-duration: 150ms; transition-duration: 150ms;
@ -1008,6 +1066,11 @@
color: var(--color-blue-700); color: var(--color-blue-700);
} }
} }
.even\:bg-gray-50 {
&:nth-child(even) {
background-color: var(--color-gray-50);
}
}
.valid\:my-2 { .valid\:my-2 {
&:valid { &:valid {
margin-block: calc(var(--spacing) * 2); margin-block: calc(var(--spacing) * 2);
@ -1079,6 +1142,13 @@
} }
} }
} }
.hover\:text-blue-600 {
&:hover {
@media (hover: hover) {
color: var(--color-blue-600);
}
}
}
.hover\:shadow { .hover\:shadow {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
@ -1189,6 +1259,11 @@
margin-top: calc(var(--spacing) * -2); margin-top: calc(var(--spacing) * -2);
} }
} }
.md\:block {
@media (width >= 48rem) {
display: block;
}
}
.md\:flex { .md\:flex {
@media (width >= 48rem) { @media (width >= 48rem) {
display: flex; display: flex;
@ -1408,6 +1483,26 @@
inherits: false; inherits: false;
initial-value: 1; initial-value: 1;
} }
@property --tw-rotate-x {
syntax: "*";
inherits: false;
}
@property --tw-rotate-y {
syntax: "*";
inherits: false;
}
@property --tw-rotate-z {
syntax: "*";
inherits: false;
}
@property --tw-skew-x {
syntax: "*";
inherits: false;
}
@property --tw-skew-y {
syntax: "*";
inherits: false;
}
@property --tw-border-style { @property --tw-border-style {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
@ -1617,6 +1712,11 @@
--tw-scale-x: 1; --tw-scale-x: 1;
--tw-scale-y: 1; --tw-scale-y: 1;
--tw-scale-z: 1; --tw-scale-z: 1;
--tw-rotate-x: initial;
--tw-rotate-y: initial;
--tw-rotate-z: initial;
--tw-skew-x: initial;
--tw-skew-y: initial;
--tw-border-style: solid; --tw-border-style: solid;
--tw-gradient-position: initial; --tw-gradient-position: initial;
--tw-gradient-from: #0000; --tw-gradient-from: #0000;