diff --git a/doc/TechnicalSpecification.md b/doc/TechnicalSpecification.md index 886ed13..dce8da4 100644 --- a/doc/TechnicalSpecification.md +++ b/doc/TechnicalSpecification.md @@ -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 This section outlines the specific technical requirements for the database store for diff --git a/internal/templates/pages/profile.templ b/internal/templates/pages/profile.templ index 2480b9b..51a406b 100644 --- a/internal/templates/pages/profile.templ +++ b/internal/templates/pages/profile.templ @@ -2,7 +2,7 @@ package templates import "github.com/haydenhargreaves/Potion/internal/templates/components" import domain "github.com/haydenhargreaves/Potion/internal/domain/server" -import domain_user"github.com/haydenhargreaves/Potion/internal/domain/user" +import domain_user "github.com/haydenhargreaves/Potion/internal/domain/user" templ userDetailsSection(user domain_user.User) {
@@ -11,18 +11,123 @@ templ userDetailsSection(user domain_user.User) { class="w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none" src={ user.ImageUrl } /> -
-

{ user.Name }

-

{ user.Email }

+
+
+

{ user.Name }

+

{ user.Email }

+
+
+

10 recipes

+

14 favorites

+
} +templ recipesSection() { +
+

My Recipes

+ +
+} + +templ favoritesSection() { +
+

My Favorites

+ +
+} + +templ activitySection() { +
+

My Favorites

+ +
+} + +templ recipeListItem() { +
  • +

    + + My Awesome Chili Recipe + +

    + +

    + Difficulty: Medium +

    +

    + Duration: 60 min +

    +

    + Category: Dinner +

    +

    + Tags: comfort food, spicy, beef +

    +
  • +} + +templ activityListItem() { +
  • +

    + Rated "Spicy Chicken Wings" +

    +

    + 2 days ago +

    +
  • +} + templ logoutSection() { -
    +
    Logout @@ -32,11 +137,12 @@ templ logoutSection() { templ ProfilePage(user domain_user.User) { @components.Navbar(" profile") -
    -
    +
    +
    @userDetailsSection(user) + @recipesSection() + @favoritesSection() + @activitySection() @logoutSection()
    diff --git a/internal/templates/pages/profile_templ.go b/internal/templates/pages/profile_templ.go index 845c66e..a116777 100644 --- a/internal/templates/pages/profile_templ.go +++ b/internal/templates/pages/profile_templ.go @@ -46,14 +46,14 @@ func userDetailsSection(user domain_user.User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - 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(user.Name) 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: 16, Col: 62} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -66,13 +66,235 @@ func userDetailsSection(user domain_user.User) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, 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: 16, Col: 46} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 17, Col: 47} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

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

    10 recipes

    14 favorites

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func recipesSection() 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_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

    My Recipes

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func favoritesSection() 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_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

    My Favorites

    ") + 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_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, 10, "

    My Favorites

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func recipeListItem() 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, 12, "
  • My Awesome Chili Recipe

    Difficulty: Medium | Duration: 60 min | Category: Dinner

    Difficulty: Medium

    Duration: 60 min

    Category: Dinner

    Tags: comfort food, spicy, beef

  • ") + 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_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, 13, "
  • Rated \"Spicy Chicken Wings\"

    2 days ago

  • ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -96,21 +318,21 @@ func logoutSection() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent + templ_7745c5c3_Var11 := templ.GetChildren(ctx) + if templ_7745c5c3_Var11 == nil { + templ_7745c5c3_Var11 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
    Logout
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\" 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") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -134,16 +356,16 @@ func ProfilePage(user domain_user.User) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var7 := templ.GetChildren(ctx) - if templ_7745c5c3_Var7 == nil { - templ_7745c5c3_Var7 = templ.NopComponent + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = components.Navbar(" profile").Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -151,11 +373,23 @@ func ProfilePage(user domain_user.User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } + templ_7745c5c3_Err = recipesSection().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = favoritesSection().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 { + return templ_7745c5c3_Err + } templ_7745c5c3_Err = logoutSection().Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/web/static/css/tailwind.css b/web/static/css/tailwind.css index eb2fa10..d64a267 100644 --- a/web/static/css/tailwind.css +++ b/web/static/css/tailwind.css @@ -17,7 +17,6 @@ --color-blue-500: oklch(62.3% 0.214 259.815); --color-blue-600: oklch(54.6% 0.245 262.881); --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-200: oklch(90.2% 0.063 306.703); --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-700: oklch(37.3% 0.034 259.733); --color-gray-800: oklch(27.8% 0.033 256.848); + --color-gray-900: oklch(21% 0.034 264.665); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; @@ -49,8 +49,6 @@ --text-3xl--line-height: calc(2.25 / 1.875); --text-4xl: 2.25rem; --text-4xl--line-height: calc(2.5 / 2.25); - --text-5xl: 3rem; - --text-5xl--line-height: 1; --text-6xl: 3.75rem; --text-6xl--line-height: 1; --text-8xl: 6rem; @@ -240,6 +238,9 @@ .static { position: static; } + .top-1 { + top: calc(var(--spacing) * 1); + } .top-1\/2 { top: calc(1/2 * 100%); } @@ -249,6 +250,9 @@ .left-0 { left: calc(var(--spacing) * 0); } + .left-1 { + left: calc(var(--spacing) * 1); + } .left-1\/2 { left: calc(1/2 * 100%); } @@ -273,6 +277,9 @@ .my-1 { margin-block: calc(var(--spacing) * 1); } + .my-1\.5 { + margin-block: calc(var(--spacing) * 1.5); + } .my-2 { margin-block: calc(var(--spacing) * 2); } @@ -300,6 +307,9 @@ .mt-16 { margin-top: calc(var(--spacing) * 16); } + .mt-auto { + margin-top: auto; + } .mr-2 { margin-right: calc(var(--spacing) * 2); } @@ -410,12 +420,18 @@ .min-h-screen { min-height: 100vh; } + .w-1 { + width: calc(var(--spacing) * 1); + } .w-1\/3 { width: calc(1/3 * 100%); } .w-1\/4 { width: calc(1/4 * 100%); } + .w-3 { + width: calc(var(--spacing) * 3); + } .w-3\/4 { width: calc(3/4 * 100%); } @@ -428,6 +444,9 @@ .w-5 { width: calc(var(--spacing) * 5); } + .w-9 { + width: calc(var(--spacing) * 9); + } .w-9\/10 { width: calc(9/10 * 100%); } @@ -446,16 +465,33 @@ .max-w-2xl { max-width: var(--container-2xl); } + .flex-shrink { + flex-shrink: 1; + } .flex-shrink-0 { flex-shrink: 0; } + .shrink-0 { + flex-shrink: 0; + } .flex-grow { 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 { --tw-translate-x: calc(calc(1/2 * 100%) * -1); 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 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -468,9 +504,15 @@ --tw-scale-y: 50%; 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; } + .resize { + resize: both; + } .resize-none { resize: none; } @@ -495,6 +537,9 @@ .items-start { align-items: flex-start; } + .justify-around { + justify-content: space-around; + } .justify-between { justify-content: space-between; } @@ -504,6 +549,9 @@ .justify-end { justify-content: flex-end; } + .justify-evenly { + justify-content: space-evenly; + } .justify-start { justify-content: flex-start; } @@ -645,6 +693,9 @@ .bg-red-100 { background-color: var(--color-red-100); } + .bg-red-500 { + background-color: var(--color-red-500); + } .bg-white { background-color: var(--color-white); } @@ -686,6 +737,9 @@ .p-4 { padding: calc(var(--spacing) * 4); } + .p-8 { + padding: calc(var(--spacing) * 8); + } .px-1 { padding-inline: calc(var(--spacing) * 1); } @@ -849,6 +903,9 @@ .text-gray-800 { color: var(--color-gray-800); } + .text-gray-900 { + color: var(--color-gray-900); + } .text-red-500 { color: var(--color-red-500); } @@ -858,6 +915,9 @@ .uppercase { text-transform: uppercase; } + .italic { + font-style: italic; + } .underline { text-decoration-line: underline; } @@ -920,6 +980,15 @@ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } + .transition-colors { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-100 { + --tw-duration: 100ms; + transition-duration: 100ms; + } .duration-150 { --tw-duration: 150ms; transition-duration: 150ms; @@ -1008,6 +1077,16 @@ color: var(--color-blue-700); } } + .odd\:bg-gray-50 { + &:nth-child(odd) { + background-color: var(--color-gray-50); + } + } + .even\:bg-gray-50 { + &:nth-child(even) { + background-color: var(--color-gray-50); + } + } .valid\:my-2 { &:valid { margin-block: calc(var(--spacing) * 2); @@ -1079,6 +1158,27 @@ } } } + .hover\:text-blue-500 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-500); + } + } + } + .hover\:text-blue-600 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-600); + } + } + } + .hover\:text-blue-700 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-700); + } + } + } .hover\:shadow { &:hover { @media (hover: hover) { @@ -1189,6 +1289,11 @@ margin-top: calc(var(--spacing) * -2); } } + .md\:block { + @media (width >= 48rem) { + display: block; + } + } .md\:flex { @media (width >= 48rem) { display: flex; @@ -1408,6 +1513,26 @@ inherits: false; 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 { syntax: "*"; inherits: false; @@ -1617,6 +1742,11 @@ --tw-scale-x: 1; --tw-scale-y: 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-gradient-position: initial; --tw-gradient-from: #0000;