2 Commits

Author SHA1 Message Date
07ee8a004c crud tags 2025-03-03 17:30:31 +01:00
4e296ca445 update item views 2025-03-03 15:54:53 +01:00
8 changed files with 522 additions and 17 deletions

View File

@@ -32,6 +32,9 @@ type ShopItemController interface {
EditItemHandler(*gin.Context) EditItemHandler(*gin.Context)
DeleteItemView(*gin.Context) DeleteItemView(*gin.Context)
DeleteItemHandler(*gin.Context) DeleteItemHandler(*gin.Context)
TagView(*gin.Context)
TagHandler(*gin.Context)
AddTagHandler(*gin.Context)
} }
type shopItemController struct {} type shopItemController struct {}
@@ -366,6 +369,77 @@ func (rc *shopItemController) DeleteItemHandler(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", data) c.HTML(http.StatusOK, "index.html", data)
} }
func (rc *shopItemController) TagHandler(ctx *gin.Context) {
name := ctx.PostForm("name")
action := ctx.PostForm("action")
tag, err := repositories.Tags.GetById(ctx.Param("id"))
if err != nil {
fmt.Println(err)
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{ "error": err })
return
}
if action == "update" {
tag.Name = name
tag, err = repositories.Tags.Update(tag)
if err != nil {
fmt.Println(err)
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{ "error": err })
return
}
}
if action == "delete" {
repositories.Tags.DeleteById(ctx.Param("id"))
}
rc.TagView(ctx)
}
func (rc *shopItemController) AddTagHandler(c *gin.Context) {
tag, err := models.NewTag(c)
if err != nil {
fmt.Println(err)
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{ "error": err })
return
}
_, err = repositories.Tags.Create(tag)
if err != nil {
data := CreateSessionData(c, gin.H{
"error": err,
"success": "",
})
c.HTML(http.StatusOK, "tagview.html", data)
return
}
rc.TagView(c)
}
func (rc *shopItemController) TagView(c *gin.Context) {
tags, err := repositories.Tags.GetAll()
if err != nil {
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{ "data": gin.H{ "error": err } })
}
data := CreateSessionData(c, gin.H{
"tags": tags,
})
if err != nil {
c.HTML(http.StatusBadRequest, "tagview.html", data)
}
c.HTML(http.StatusOK, "tagview.html", data)
}
func (rc *shopItemController) CreateTag(c *gin.Context) { func (rc *shopItemController) CreateTag(c *gin.Context) {
tag, err := models.NewTagByJson(c) tag, err := models.NewTagByJson(c)

View File

@@ -78,9 +78,12 @@ func main() {
viewRoutes.GET("/", userController.MainView) viewRoutes.GET("/", userController.MainView)
viewRoutes.GET("/shopitems/:id", shopItemController.ShopItemView) viewRoutes.GET("/shopitems/:id", shopItemController.ShopItemView)
viewRoutes.GET("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemView) viewRoutes.GET("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemView)
viewRoutes.GET("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemView)
viewRoutes.POST("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemHandler) viewRoutes.POST("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemHandler)
viewRoutes.GET("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemView)
viewRoutes.POST("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemHandler) viewRoutes.POST("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemHandler)
viewRoutes.GET("/tags", authValidator.RequireAuth, shopItemController.TagView)
viewRoutes.POST("/tags/:id", authValidator.RequireAuth, shopItemController.TagHandler)
viewRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.AddTagHandler)
//write middleware that redirects to homescreen on register/login/reset for logged in users //write middleware that redirects to homescreen on register/login/reset for logged in users
viewRoutes.GET("/login", userController.LoginView) viewRoutes.GET("/login", userController.LoginView)
viewRoutes.GET("/logout", userController.Logout) viewRoutes.GET("/logout", userController.Logout)

View File

@@ -8,7 +8,7 @@ import (
type Tag struct { type Tag struct {
gorm.Model gorm.Model
Name string `json:"name" binding:"required" gorm:"unique;not null"` Name string `json:"name" binding:"required" gorm:"not null"`
ShopItems []ShopItem `gorm:"many2many:item_tags;"` ShopItems []ShopItem `gorm:"many2many:item_tags;"`
} }

View File

@@ -574,6 +574,10 @@ video {
position: relative; position: relative;
} }
.inset-0 {
inset: 0px;
}
.inset-y-0 { .inset-y-0 {
top: 0px; top: 0px;
bottom: 0px; bottom: 0px;
@@ -596,6 +600,21 @@ video {
margin-right: auto; margin-right: auto;
} }
.-mx-2 {
margin-left: -0.5rem;
margin-right: -0.5rem;
}
.-mx-4 {
margin-left: -1rem;
margin-right: -1rem;
}
.-mx-3 {
margin-left: -0.75rem;
margin-right: -0.75rem;
}
.mb-4 { .mb-4 {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
@@ -616,6 +635,34 @@ video {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.mt-4 {
margin-top: 1rem;
}
.mt-6 {
margin-top: 1.5rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.mr-2 {
margin-right: 0.5rem;
}
.mr-4 {
margin-right: 1rem;
}
.mt-12 {
margin-top: 3rem;
}
.ml-4 {
margin-left: 1rem;
}
.block { .block {
display: block; display: block;
} }
@@ -632,6 +679,10 @@ video {
display: none; display: none;
} }
.aspect-square {
aspect-ratio: 1 / 1;
}
.h-10 { .h-10 {
height: 2.5rem; height: 2.5rem;
} }
@@ -656,6 +707,18 @@ video {
height: 2rem; height: 2rem;
} }
.h-6 {
height: 1.5rem;
}
.h-\[460px\] {
height: 460px;
}
.h-full {
height: 100%;
}
.min-h-full { .min-h-full {
min-height: 100%; min-height: 100%;
} }
@@ -676,10 +739,34 @@ video {
width: 100%; width: 100%;
} }
.w-1\/2 {
width: 50%;
}
.w-6 {
width: 1.5rem;
}
.w-1\/3 {
width: 33.333333%;
}
.max-w-7xl { .max-w-7xl {
max-width: 80rem; max-width: 80rem;
} }
.max-w-2xl {
max-width: 42rem;
}
.max-w-6xl {
max-width: 72rem;
}
.max-w-md {
max-width: 28rem;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@@ -688,6 +775,10 @@ video {
flex-shrink: 0; flex-shrink: 0;
} }
.flex-grow {
flex-grow: 1;
}
.cursor-pointer { .cursor-pointer {
cursor: pointer; cursor: pointer;
} }
@@ -696,6 +787,10 @@ video {
grid-template-columns: repeat(1, minmax(0, 1fr)); grid-template-columns: repeat(1, minmax(0, 1fr));
} }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.flex-col { .flex-col {
flex-direction: column; flex-direction: column;
} }
@@ -712,6 +807,15 @@ video {
justify-content: space-between; justify-content: space-between;
} }
.gap-x-6 {
-moz-column-gap: 1.5rem;
column-gap: 1.5rem;
}
.gap-y-10 {
row-gap: 2.5rem;
}
.space-x-4 > :not([hidden]) ~ :not([hidden]) { .space-x-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0; --tw-space-x-reverse: 0;
margin-right: calc(1rem * var(--tw-space-x-reverse)); margin-right: calc(1rem * var(--tw-space-x-reverse));
@@ -748,6 +852,20 @@ video {
border-radius: 0.375rem; border-radius: 0.375rem;
} }
.rounded-full {
border-radius: 9999px;
}
.rounded-l-md {
border-top-left-radius: 0.375rem;
border-bottom-left-radius: 0.375rem;
}
.rounded-r-md {
border-top-right-radius: 0.375rem;
border-bottom-right-radius: 0.375rem;
}
.border { .border {
border-width: 1px; border-width: 1px;
} }
@@ -790,6 +908,66 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
} }
.bg-blue-500 {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1));
}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
}
.bg-gray-300 {
--tw-bg-opacity: 1;
background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));
}
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
}
.bg-yellow-500 {
--tw-bg-opacity: 1;
background-color: rgb(234 179 8 / var(--tw-bg-opacity, 1));
}
.bg-red-900 {
--tw-bg-opacity: 1;
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
}
.bg-blue-900 {
--tw-bg-opacity: 1;
background-color: rgb(30 58 138 / var(--tw-bg-opacity, 1));
}
.bg-blue-600 {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
}
.bg-red-600 {
--tw-bg-opacity: 1;
background-color: rgb(220 38 38 / var(--tw-bg-opacity, 1));
}
.bg-red-300 {
--tw-bg-opacity: 1;
background-color: rgb(252 165 165 / var(--tw-bg-opacity, 1));
}
.bg-red-800 {
--tw-bg-opacity: 1;
background-color: rgb(153 27 27 / var(--tw-bg-opacity, 1));
}
.bg-green-600 {
--tw-bg-opacity: 1;
background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1));
}
.object-cover { .object-cover {
-o-object-fit: cover; -o-object-fit: cover;
object-fit: cover; object-fit: cover;
@@ -838,6 +1016,16 @@ video {
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
.py-16 {
padding-top: 4rem;
padding-bottom: 4rem;
}
.py-8 {
padding-top: 2rem;
padding-bottom: 2rem;
}
.pb-3 { .pb-3 {
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
} }
@@ -896,6 +1084,11 @@ video {
line-height: 1rem; line-height: 1rem;
} }
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.font-bold { .font-bold {
font-weight: 700; font-weight: 700;
} }
@@ -962,6 +1155,11 @@ video {
color: rgb(255 255 255 / var(--tw-text-opacity, 1)); color: rgb(255 255 255 / var(--tw-text-opacity, 1));
} }
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity, 1));
}
.shadow-sm { .shadow-sm {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@@ -1024,6 +1222,41 @@ video {
background-color: rgb(99 102 241 / var(--tw-bg-opacity, 1)); background-color: rgb(99 102 241 / var(--tw-bg-opacity, 1));
} }
.hover\:bg-gray-400:hover {
--tw-bg-opacity: 1;
background-color: rgb(156 163 175 / var(--tw-bg-opacity, 1));
}
.hover\:bg-gray-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));
}
.hover\:bg-gray-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
}
.hover\:bg-blue-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1));
}
.hover\:bg-red-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1));
}
.hover\:bg-red-900:hover {
--tw-bg-opacity: 1;
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
}
.hover\:bg-green-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(21 128 61 / var(--tw-bg-opacity, 1));
}
.hover\:text-indigo-500:hover { .hover\:text-indigo-500:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(99 102 241 / var(--tw-text-opacity, 1)); color: rgb(99 102 241 / var(--tw-text-opacity, 1));
@@ -1087,6 +1320,10 @@ video {
outline-color: #4f46e5; outline-color: #4f46e5;
} }
.group:hover .group-hover\:opacity-75 {
opacity: 0.75;
}
@media (min-width: 640px) { @media (min-width: 640px) {
.sm\:static { .sm\:static {
position: static; position: static;
@@ -1121,11 +1358,25 @@ video {
max-width: 24rem; max-width: 24rem;
} }
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sm\:px-8 { .sm\:px-8 {
padding-left: 2rem; padding-left: 2rem;
padding-right: 2rem; padding-right: 2rem;
} }
.sm\:px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.sm\:py-24 {
padding-top: 6rem;
padding-bottom: 6rem;
}
.sm\:pr-0 { .sm\:pr-0 {
padding-right: 0px; padding-right: 0px;
} }
@@ -1145,16 +1396,40 @@ video {
width: 12rem; width: 12rem;
} }
.md\:flex-1 {
flex: 1 1 0%;
}
.md\:grid-cols-2 { .md\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
} }
.md\:flex-row {
flex-direction: row;
}
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
.lg\:aspect-auto {
aspect-ratio: auto;
}
.lg\:h-80 {
height: 20rem;
}
.lg\:max-w-7xl {
max-width: 80rem;
}
.lg\:grid-cols-3 { .lg\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
} }
.lg\:grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.lg\:px-8 { .lg\:px-8 {
padding-left: 2rem; padding-left: 2rem;
padding-right: 2rem; padding-right: 2rem;
@@ -1165,6 +1440,11 @@ video {
.xl\:grid-cols-4 { .xl\:grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
} }
.xl\:gap-x-8 {
-moz-column-gap: 2rem;
column-gap: 2rem;
}
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@@ -1178,6 +1458,41 @@ video {
background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1)); background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
} }
.dark\:bg-blue-700 {
--tw-bg-opacity: 1;
background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1));
}
.dark\:bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));
}
.dark\:bg-gray-600 {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity, 1));
}
.dark\:bg-gray-700 {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
}
.dark\:bg-red-700 {
--tw-bg-opacity: 1;
background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1));
}
.dark\:bg-yellow-700 {
--tw-bg-opacity: 1;
background-color: rgb(161 98 7 / var(--tw-bg-opacity, 1));
}
.dark\:bg-red-600 {
--tw-bg-opacity: 1;
background-color: rgb(220 38 38 / var(--tw-bg-opacity, 1));
}
.dark\:text-gray-300 { .dark\:text-gray-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity, 1)); color: rgb(209 213 219 / var(--tw-text-opacity, 1));
@@ -1188,6 +1503,21 @@ video {
color: rgb(17 24 39 / var(--tw-text-opacity, 1)); color: rgb(17 24 39 / var(--tw-text-opacity, 1));
} }
.dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
}
.dark\:hover\:bg-gray-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity, 1));
}
.dark\:hover\:bg-gray-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
}
.dark\:focus\:border-blue-500:focus { .dark\:focus\:border-blue-500:focus {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));

View File

@@ -28,6 +28,7 @@
{{ if .loggedIn }} {{ if .loggedIn }}
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0 px-4 sm:px-8"> <div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0 px-4 sm:px-8">
<a href="/additem" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Add Item</a> <a href="/additem" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Add Item</a>
<a href="/tags" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Tags</a>
<a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a> <a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a>
</div> </div>
{{ else }} {{ else }}

View File

@@ -1,10 +1,67 @@
{{ template "header.html" . }} {{ template "header.html" . }}
<div class="bg-gray-100 dark:bg-gray-800 py-8">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row -mx-4">
<div class="md:flex-1 px-4">
<div class="h-[460px] rounded-lg bg-gray-300 dark:bg-gray-700 mb-4">
<img class="w-full h-full object-cover" src="/{{ .data.shopItem.Image}}" alt="Product Image">
</div>
<div class="flex -mx-2 mb-4">
<div class="w-1/3 px-2">
<button class="w-full bg-gray-900 dark:bg-gray-600 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Add to Cart</button>
</div>
{{ if .loggedIn }}
<div class="w-1/3 px-2">
<a href="{{ .data.shopItem.ID }}/edit"><button class="w-full bg-blue-900 dark:bg-gray-600 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Edit</button></a>
</div>
<div class="w-1/3 px-2">
<a href="{{ .data.shopItem.ID }}/delete"><button class="w-full bg-red-900 dark:bg-red-600 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Delete</button></a>
</div>
{{ end }}
</div>
</div>
<div class="md:flex-1 px-4">
<h2 class="text-2xl font-bold text-gray-800 dark:text-white mb-2">{{ .data.shopItem.Name }}</h2>
<p class="text-gray-600 dark:text-gray-300 text-sm mb-4">
{{ .data.shopItem.Abstract }}
</p>
<div class="flex mb-4">
<div class="mr-4">
<span class="font-bold text-gray-700 dark:text-gray-300">Price:</span>
<span class="text-gray-600 dark:text-gray-300">{{ .data.shopItem.Price }}€</span>
</div>
</div>
<!--
<div class="mb-4">
<span class="font-bold text-gray-700 dark:text-gray-300">Select Size:</span>
<div class="flex items-center mt-2">
<button class="bg-gray-300 dark:bg-gray-700 text-gray-700 dark:text-white py-2 px-4 rounded-full font-bold mr-2 hover:bg-gray-400 dark:hover:bg-gray-600">Black/White</button>
<button class="bg-gray-300 dark:bg-gray-700 text-gray-700 dark:text-white py-2 px-4 rounded-full font-bold mr-2 hover:bg-gray-400 dark:hover:bg-gray-600">Colored</button>
<button class="bg-gray-300 dark:bg-gray-700 text-gray-700 dark:text-white py-2 px-4 rounded-full font-bold mr-2 hover:bg-gray-400 dark:hover:bg-gray-600">Colored Covering Page</button>
</div>
</div>
-->
<div>
<span class="font-bold text-gray-700 dark:text-gray-300">Product Description:</span>
<p class="text-gray-600 dark:text-gray-300 text-sm mt-2">
{{ .data.shopItem.Description }}
</p>
</div>
</div>
</div>
</div>
</div>
<!--
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<div class="bg-gray-200 rounded m-4 p-4"> <div class="bg-gray-200 rounded m-4 p-4">
<div class="relative w-full md:w-48 mb-4 flex rounded-lg justify-center items-center"> <div class="relative flex rounded-lg justify-center items-center">
<img src="/{{ .data.shopItem.Image }}" alt="shopping image" <img src="/{{ .data.shopItem.Image }}" alt="shopping image"
class="object-cover w-full h-48 md:h-full rounded"> class="object-cover items-center justify-center rounded">
</div> </div>
<h3 class="text-lg">{{ .data.shopItem.Name }}</h3> <h3 class="text-lg">{{ .data.shopItem.Name }}</h3>
<i class="text-xs">{{ .data.shopItem.Abstract }}</i> <i class="text-xs">{{ .data.shopItem.Abstract }}</i>
@@ -19,5 +76,5 @@
</div> </div>
</div> </div>
-->
{{ template "footer.html" . }} {{ template "footer.html" . }}

View File

@@ -1,17 +1,27 @@
<div class="bg-white">
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">
<h2 class="text-2xl font-bold tracking-tight text-gray-900">Available Zines</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="mt-6 grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-4 xl:gap-x-8">
{{ range .data.shopItems }} {{ range .data.shopItems }}
<a href="/shopitems/{{ .ID }}">
<div class="bg-gray-200 rounded m-4 p-4">
<div class="relative w-full md:w-48 mb-4 flex rounded-lg justify-center items-center"> <div class="group relative">
<img src="/{{ .Image }}" alt="shopping image" <img src="/{{ .Image }}" alt="Product Image" class="aspect-square w-full rounded-md bg-gray-200 object-cover group-hover:opacity-75 lg:aspect-auto lg:h-80">
class="object-cover w-full h-48 md:h-full rounded"> <div class="mt-4 flex justify-between">
</div> <div>
<h3 class="text-lg">{{ .Name }}</h3> <h3 class="text-sm text-gray-700">
<i class="text-xs">{{ .Abstract }}</i> <a href="/shopitems/{{ .ID }}">
<p class="">Price: {{ .Price }}</> <span aria-hidden="true" class="absolute inset-0"></span>
{{ .Name }}
</a>
</h3>
<!--<p class="mt-1 text-sm text-gray-500">{{ .Abstract }}</p>-->
</div>
<p class="text-sm font-medium text-gray-900">{{ .Price }}€</p>
</div>
</div> </div>
</a>
{{ end }} {{ end }}
</div> </div>
</div>
</div>

30
views/tagview.html Normal file
View File

@@ -0,0 +1,30 @@
{{ template "header.html" . }}
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<img class="mx-auto h-10 w-auto" src="/static/img/circlea.png" alt="Your Company">
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit Tags</h2>
</div>
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
{{ range .data.tags }}
<form action="/tags/{{ .ID }}" method="POST">
<div class="max-w-md mx-auto mt-4">
<div class="flex">
<input type="text" id="name" name="name" value="{{ .Name }}" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
<button type="submit" name="action" value="update" class="bg-blue-600 text-white ml-4 mr-4 rounded px-4 hover:bg-blue-700">Update</button>
<button type="submit" name="action" value="delete" class="bg-red-800 text-white rounded px-4 hover:bg-red-900">Delete</button>
</div>
</form>
{{ end }}
<form action="/tags" method="POST">
<div class="max-w-md mx-auto mt-4">
<div class="flex">
<input type="text" id="name" name="name" placeholder="add new tag" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
<button type="submit" class="bg-green-600 text-white ml-4 mr-4 rounded px-4 hover:bg-green-700">Add</button>
</div>
</div>
</form>
</div>
{{ template "footer.html" . }}