diff --git a/README.md b/README.md
index 346b7f8..afa141e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,5 @@
# Potion: Recipe Sharing Platform
+
+## Todo List
+
+- [-] Ingrident lists/sections
diff --git a/doc/TechnicalSpecification.md b/doc/TechnicalSpecification.md
index 0a2ed9e..bf3949b 100644
--- a/doc/TechnicalSpecification.md
+++ b/doc/TechnicalSpecification.md
@@ -239,19 +239,19 @@ also have a list of attributes which are to be implemented at the database level
data fields will also have a small example object. A more in-depth data structure can be
found in **OTHER** section.
-- [ ] Recipes: Represents a single recipe.
- - [ ] ID (PK) Serial
- - [ ] Title (Unique, Required) string(128)
- - [ ] Description (Required) text
- - [ ] Instructions (Required) string(1024)[]
- - [ ] Serves (Required) int(0..16)
- - [ ] Difficulty (Required) int(1..5)
- - [ ] Duration (Required) JSONB({ "total": int, "prep": int, "cook": int })
- - [ ] Category (Required) E_Meal (defined in the [enums](#enums-and-types) section)
- - [ ] Ingredients (Required) JSONB({ "item_a": [{ "name": string, "quantity": string }], "item_b": ... })
- - [ ] UserId (FK: User.Id) Serial
- - [ ] Modified () date/time stamp
- - [ ] Created (Required) date/time stamp
+- [x] Recipes: Represents a single recipe.
+ - [x] ID (PK) Serial
+ - [x] Title (Required) string(128)
+ - [x] Description (Required) text
+ - [x] Instructions (Required) string(1024)[]
+ - [x] Serves (Required) int(0..16)
+ - [x] Difficulty (Required) int(1..5)
+ - [x] Duration (Required) JSONB({ "total": int, "prep": int, "cook": int })
+ - [x] Category (Required) E_Meal (defined in the [enums](#enums-and-types) section)
+ - [x] Ingredients (Required) JSONB({ "item_a": [{ "name": string, "quantity": string }], "item_b": ... })
+ - [x] UserId (FK: User.Id) Serial
+ - [x] Modified () date/time stamp
+ - [x] Created (Required) date/time stamp
- [x] Users: Represents a single user.
- [x] ID (PK) Serial
@@ -325,14 +325,14 @@ found in **OTHER** section.
Below is a breakdown of the required enumerated types that should be stored in the database.
Various tables will reference these types.
-- [ ] E_Meal: Type to represent the type of meal of a recipe.
- - [ ] breakfast: string
- - [ ] lunch: string
- - [ ] dinner: string
- - [ ] desert: string
- - [ ] snack: string
- - [ ] side: string
- - [ ] other: string
+- [x] E_Meal: Type to represent the type of meal of a recipe.
+ - [x] breakfast: string
+ - [x] lunch: string
+ - [x] dinner: string
+ - [x] dessert: string
+ - [x] snack: string
+ - [x] side: string
+ - [x] other: string
- [ ] E_Notification: Type to represent a type of user notification.
- [ ] comment: string
diff --git a/internal/app/handlers/recipe_handler.go b/internal/app/handlers/recipe_handler.go
new file mode 100644
index 0000000..ee12ece
--- /dev/null
+++ b/internal/app/handlers/recipe_handler.go
@@ -0,0 +1,49 @@
+package handlers
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ // domain "github.com/haydenhargreaves/Potion/internal/domain/server"
+)
+
+func CreateRecipe(ctx *gin.Context) {
+ // deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
+
+ title := ctx.PostForm("title")
+ description := ctx.PostForm("description")
+ preparation := ctx.PostForm("preparation-time")
+ cook := ctx.PostForm("cook-time")
+ serving := ctx.PostForm("serving-size")
+ category := ctx.PostForm("category")
+ difficulty := ctx.PostForm("difficulty")
+ ingredients := ctx.PostFormArray("ingredients")
+ quantity := ctx.PostFormArray("quantity")
+ instructions := ctx.PostFormArray("instructions")
+ tags := ctx.PostForm("tags") // this is a list of strings split with a comma (,)
+
+ // Have to get the image differently
+ image, err := ctx.FormFile("image")
+ if err != nil {
+ ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
+ return
+ }
+
+ ctx.JSON(http.StatusOK, gin.H{
+ "title": title,
+ "description": description,
+ "cook time": cook,
+ "preparation time": preparation,
+ "serving size": serving,
+ "category": category,
+ "difficulty": difficulty,
+ "ingredients": ingredients,
+ "quantity": quantity,
+ "instructions": instructions,
+ "tags": tags,
+ "image": image.Filename,
+ })
+
+ // deps.RecipeService.CreateRecipe(ctx)
+ // ctx.JSON(http.StatusCreated, gin.H{"recipe": recipe})
+}
diff --git a/internal/app/handlers/state_handler.go b/internal/app/handlers/state_handler.go
new file mode 100644
index 0000000..274f864
--- /dev/null
+++ b/internal/app/handlers/state_handler.go
@@ -0,0 +1,75 @@
+package handlers
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+)
+
+const TAG_HTML = `
+
+ @dropdownButton("Beginner")
@dropdownButton("Easy")
@dropdownButton("Intermediate")
@dropdownButton("Challegening")
diff --git a/internal/templates/components/dropdowns_templ.go b/internal/templates/components/dropdowns_templ.go
index 9a881d1..1a3d6e9 100644
--- a/internal/templates/components/dropdowns_templ.go
+++ b/internal/templates/components/dropdowns_templ.go
@@ -131,6 +131,10 @@ func FilterDropdown() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
+ templ_7745c5c3_Err = dropdownButton("Beginner").Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
templ_7745c5c3_Err = dropdownButton("Easy").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
diff --git a/internal/templates/pages/create.templ b/internal/templates/pages/create.templ
index 76e7974..73edb4b 100644
--- a/internal/templates/pages/create.templ
+++ b/internal/templates/pages/create.templ
@@ -3,5 +3,282 @@ package templates
import "github.com/haydenhargreaves/Potion/internal/templates/components"
templ CreatePage() {
- @components.Navbar("create")
+ @components.Navbar("create")
+
+}
+
+templ Page() {
+ @components.BannerText("Create Your Masterpiece")
+
+
+
+ Welcome to the Recipe Creation Wizard! Simply fill in the details about your culinary creation,
+ including the recipe's name, a description, and other specifics like its category, duration,
+ and difficulty. Don't forget to dynamically add all your ingredients and instructions using
+ the dedicated buttons, and feel free to upload an appealing image. All required fields are
+ marked with an * . Once everything looks perfect, just hit the "Create Recipe"
+ button to
+ share your masterpiece!
+
+
+
+
}
diff --git a/internal/templates/pages/create_templ.go b/internal/templates/pages/create_templ.go
index 711e8ac..fe16e17 100644
--- a/internal/templates/pages/create_templ.go
+++ b/internal/templates/pages/create_templ.go
@@ -35,6 +35,51 @@ func CreatePage() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = Page().Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+func Page() templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var2 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var2 == nil {
+ templ_7745c5c3_Var2 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = components.BannerText("Create Your Masterpiece").Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
Welcome to the Recipe Creation Wizard! Simply fill in the details about your culinary creation, including the recipe's name, a description, and other specifics like its category, duration, and difficulty. Don't forget to dynamically add all your ingredients and instructions using the dedicated buttons, and feel free to upload an appealing image. All required fields are marked with an * . Once everything looks perfect, just hit the \"Create Recipe\" button to share your masterpiece!
Recipe Title *
Description *
Category * Select a category Breakfast Lunch Dinner Dessert Snack Side Other
Difficulty * Select a difficulty Beginner Easy Intermediate Challenging Extreme
Ingredients * Add Ingredient Instructions *
Add Instruction Step Recipe Image
Create Recipe ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
return nil
})
}
diff --git a/web/static/css/tailwind.css b/web/static/css/tailwind.css
index 3addad4..8c1bf62 100644
--- a/web/static/css/tailwind.css
+++ b/web/static/css/tailwind.css
@@ -8,8 +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-400: oklch(70.4% 0.191 22.216);
--color-red-500: oklch(63.7% 0.237 25.331);
--color-blue-100: oklch(93.2% 0.032 255.585);
--color-blue-200: oklch(88.2% 0.059 254.128);
@@ -19,6 +17,7 @@
--color-blue-600: oklch(54.6% 0.245 262.881);
--color-blue-700: oklch(48.8% 0.243 264.376);
--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);
--color-gray-100: oklch(96.7% 0.003 264.542);
--color-gray-200: oklch(92.8% 0.006 264.531);
@@ -35,6 +34,8 @@
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
+ --text-base: 1rem;
+ --text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-xl: 1.25rem;
@@ -205,9 +206,6 @@
}
}
@layer utilities {
- .pointer-events-none {
- pointer-events: none;
- }
.absolute {
position: absolute;
}
@@ -217,9 +215,6 @@
.static {
position: static;
}
- .top-1 {
- top: calc(var(--spacing) * 1);
- }
.top-1\/2 {
top: calc(1/2 * 100%);
}
@@ -229,9 +224,6 @@
.left-0 {
left: calc(var(--spacing) * 0);
}
- .left-1 {
- left: calc(var(--spacing) * 1);
- }
.left-1\/2 {
left: calc(1/2 * 100%);
}
@@ -250,9 +242,6 @@
.mx-4 {
margin-inline: calc(var(--spacing) * 4);
}
- .mx-8 {
- margin-inline: calc(var(--spacing) * 8);
- }
.my-2 {
margin-block: calc(var(--spacing) * 2);
}
@@ -262,9 +251,6 @@
.my-8 {
margin-block: calc(var(--spacing) * 8);
}
- .my-auto {
- margin-block: auto;
- }
.mt-2 {
margin-top: calc(var(--spacing) * 2);
}
@@ -280,15 +266,18 @@
.mt-16 {
margin-top: calc(var(--spacing) * 16);
}
- .mt-auto {
- margin-top: auto;
- }
.mb-1 {
margin-bottom: calc(var(--spacing) * 1);
}
+ .mb-2 {
+ margin-bottom: calc(var(--spacing) * 2);
+ }
.mb-6 {
margin-bottom: calc(var(--spacing) * 6);
}
+ .mb-8 {
+ margin-bottom: calc(var(--spacing) * 8);
+ }
.mb-10 {
margin-bottom: calc(var(--spacing) * 10);
}
@@ -352,9 +341,6 @@
.w-1\/3 {
width: calc(1/3 * 100%);
}
- .w-3 {
- width: calc(var(--spacing) * 3);
- }
.w-3\/4 {
width: calc(3/4 * 100%);
}
@@ -367,21 +353,12 @@
.w-5 {
width: calc(var(--spacing) * 5);
}
- .w-9 {
- width: calc(var(--spacing) * 9);
- }
.w-9\/10 {
width: calc(9/10 * 100%);
}
.w-24 {
width: calc(var(--spacing) * 24);
}
- .w-28 {
- width: calc(var(--spacing) * 28);
- }
- .w-32 {
- width: calc(var(--spacing) * 32);
- }
.w-44 {
width: calc(var(--spacing) * 44);
}
@@ -397,27 +374,16 @@
.max-w-xl {
max-width: var(--container-xl);
}
- .flex-shrink {
- flex-shrink: 1;
- }
.flex-shrink-0 {
flex-shrink: 0;
}
- .border-collapse {
- border-collapse: collapse;
- }
- .-translate-x-1 {
- --tw-translate-x: calc(var(--spacing) * -1);
- translate: var(--tw-translate-x) var(--tw-translate-y);
+ .flex-grow {
+ flex-grow: 1;
}
.-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);
@@ -425,8 +391,8 @@
.cursor-pointer {
cursor: pointer;
}
- .resize {
- resize: both;
+ .resize-none {
+ resize: none;
}
.flex-col {
flex-direction: column;
@@ -458,6 +424,9 @@
.gap-8 {
gap: calc(var(--spacing) * 8);
}
+ .gap-x-1 {
+ column-gap: calc(var(--spacing) * 1);
+ }
.gap-x-2 {
column-gap: calc(var(--spacing) * 2);
}
@@ -467,9 +436,6 @@
.gap-x-8 {
column-gap: calc(var(--spacing) * 8);
}
- .gap-x-16 {
- column-gap: calc(var(--spacing) * 16);
- }
.overflow-hidden {
overflow: hidden;
}
@@ -492,10 +458,6 @@
border-style: var(--tw-border-style);
border-width: 1px;
}
- .border-1 {
- border-style: var(--tw-border-style);
- border-width: 1px;
- }
.border-2 {
border-style: var(--tw-border-style);
border-width: 2px;
@@ -529,15 +491,18 @@
.border-gray-300 {
border-color: var(--color-gray-300);
}
- .border-red-400 {
- border-color: var(--color-red-400);
- }
.border-red-500 {
border-color: var(--color-red-500);
}
.border-white {
border-color: var(--color-white);
}
+ .bg-blue-100 {
+ background-color: var(--color-blue-100);
+ }
+ .bg-blue-500 {
+ background-color: var(--color-blue-500);
+ }
.bg-gray-100 {
background-color: var(--color-gray-100);
}
@@ -559,6 +524,10 @@
--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));
}
+ .from-blue-200 {
+ --tw-gradient-from: var(--color-blue-200);
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
.from-blue-400 {
--tw-gradient-from: var(--color-blue-400);
--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));
@@ -571,15 +540,16 @@
--tw-gradient-to: var(--color-purple-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));
}
+ .to-purple-200 {
+ --tw-gradient-to: var(--color-purple-200);
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
.p-2 {
padding: calc(var(--spacing) * 2);
}
.p-4 {
padding: calc(var(--spacing) * 4);
}
- .p-8 {
- padding: calc(var(--spacing) * 8);
- }
.px-1 {
padding-inline: calc(var(--spacing) * 1);
}
@@ -589,6 +559,9 @@
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
+ .px-5 {
+ padding-inline: calc(var(--spacing) * 5);
+ }
.px-8 {
padding-inline: calc(var(--spacing) * 8);
}
@@ -633,6 +606,10 @@
font-size: var(--text-3xl);
line-height: var(--tw-leading, var(--text-3xl--line-height));
}
+ .text-base {
+ font-size: var(--text-base);
+ line-height: var(--tw-leading, var(--text-base--line-height));
+ }
.text-lg {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
@@ -694,9 +671,6 @@
.text-gray-800 {
color: var(--color-gray-800);
}
- .text-red-400 {
- color: var(--color-red-400);
- }
.text-red-500 {
color: var(--color-red-500);
}
@@ -706,9 +680,6 @@
.uppercase {
text-transform: uppercase;
}
- .underline {
- text-decoration-line: underline;
- }
.shadow {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -787,6 +758,48 @@
.\[-webkit-line-clamp\:4\] {
-webkit-line-clamp: 4;
}
+ .file\:mr-4 {
+ &::file-selector-button {
+ margin-right: calc(var(--spacing) * 4);
+ }
+ }
+ .file\:rounded-lg {
+ &::file-selector-button {
+ border-radius: var(--radius-lg);
+ }
+ }
+ .file\:border-0 {
+ &::file-selector-button {
+ border-style: var(--tw-border-style);
+ border-width: 0px;
+ }
+ }
+ .file\:bg-blue-100 {
+ &::file-selector-button {
+ background-color: var(--color-blue-100);
+ }
+ }
+ .file\:px-4 {
+ &::file-selector-button {
+ padding-inline: calc(var(--spacing) * 4);
+ }
+ }
+ .file\:py-2 {
+ &::file-selector-button {
+ padding-block: calc(var(--spacing) * 2);
+ }
+ }
+ .file\:text-sm {
+ &::file-selector-button {
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ }
+ }
+ .file\:text-blue-700 {
+ &::file-selector-button {
+ color: var(--color-blue-700);
+ }
+ }
.hover\:cursor-pointer {
&:hover {
@media (hover: hover) {
@@ -801,6 +814,13 @@
}
}
}
+ .hover\:bg-blue-200 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-blue-200);
+ }
+ }
+ }
.hover\:bg-gray-50 {
&:hover {
@media (hover: hover) {
@@ -815,13 +835,6 @@
}
}
}
- .hover\:bg-red-200 {
- &:hover {
- @media (hover: hover) {
- background-color: var(--color-red-200);
- }
- }
- }
.hover\:text-blue-400 {
&:hover {
@media (hover: hover) {
@@ -930,6 +943,11 @@
margin-inline: calc(var(--spacing) * 0);
}
}
+ .md\:mx-16 {
+ @media (width >= 48rem) {
+ margin-inline: calc(var(--spacing) * 16);
+ }
+ }
.md\:flex {
@media (width >= 48rem) {
display: flex;
@@ -1026,12 +1044,6 @@
line-height: var(--tw-leading, var(--text-sm--line-height));
}
}
- .md\:text-xl {
- @media (width >= 48rem) {
- font-size: var(--text-xl);
- line-height: var(--tw-leading, var(--text-xl--line-height));
- }
- }
.lg\:flex {
@media (width >= 64rem) {
display: flex;