Compare commits
3 Commits
1dc10d61bc
...
0c85ca5938
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c85ca5938 | |||
| 23392cc5c1 | |||
| 5e22be5074 |
218
controllers/cartItemController.go
Normal file
218
controllers/cartItemController.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"net/http"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"example.com/gin/test/models"
|
||||
//"example.com/gin/test/services"
|
||||
"example.com/gin/test/repositories"
|
||||
)
|
||||
|
||||
type CartItemController interface {
|
||||
//CRUDController
|
||||
CartItemView(*gin.Context)
|
||||
AddItemHandler(*gin.Context)
|
||||
DeleteItemHandler(*gin.Context)
|
||||
EditItemHandler(*gin.Context)
|
||||
}
|
||||
|
||||
type cartItemController struct {}
|
||||
|
||||
func NewCartItemController() CartItemController {
|
||||
return &cartItemController{}
|
||||
}
|
||||
|
||||
func generateSessionId() string {
|
||||
bytes := make([]byte, 16) // 16 bytes = 128 bits
|
||||
_, err := rand.Read(bytes)
|
||||
if err != nil {
|
||||
panic("failed to generate session ID")
|
||||
}
|
||||
return hex.EncodeToString(bytes)
|
||||
}
|
||||
|
||||
func GetSessionId(ctx *gin.Context) string {
|
||||
sessionId, err := ctx.Cookie("session_id")
|
||||
|
||||
if err != nil {
|
||||
sessionId = generateSessionId()
|
||||
ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true)
|
||||
}
|
||||
|
||||
return sessionId
|
||||
}
|
||||
|
||||
func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) {
|
||||
sessionId := GetSessionId(ctx)
|
||||
shopItemIdStr := ctx.PostForm("ShopItemId")
|
||||
shopItemId, err := strconv.Atoi(shopItemIdStr)
|
||||
|
||||
if err != nil {
|
||||
return models.CartItem{}, err
|
||||
}
|
||||
|
||||
quantity := 1
|
||||
|
||||
shopItem, err := repositories.ShopItems.GetById(shopItemIdStr)
|
||||
|
||||
if err != nil {
|
||||
return models.CartItem{}, err
|
||||
}
|
||||
|
||||
cartItem := models.CartItem{
|
||||
SessionId: sessionId,
|
||||
ShopItemId: uint(shopItemId),
|
||||
ShopItem: shopItem,
|
||||
Quantity: quantity,
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
|
||||
func (rc *cartItemController) Create(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Create(cartItem)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
ReplyOK(c, "cartItem was created")
|
||||
}
|
||||
|
||||
|
||||
func (rc *cartItemController) Update(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Update(cartItem)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
ReplyOK(c, "cartItem was updated")
|
||||
}
|
||||
|
||||
//func (rc *cartItemController) Delete(c *gin.Context) {
|
||||
// err := repositories.CartItems.DeleteBySessionId(c.Param("id"))
|
||||
//
|
||||
// if err != nil {
|
||||
// ReplyError(c, fmt.Errorf("cartItem deletion failed: %s", err))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ReplyOK(c, "cartItem was deleted")
|
||||
//}
|
||||
|
||||
func (rc *cartItemController) CartItemView(c *gin.Context) {
|
||||
//sessionId := GetSessionId(c)
|
||||
|
||||
//cartItems, err := repositories.CartItems.GetAllBySession(sessionId)
|
||||
cartItems, err := repositories.CartItems.GetAll()
|
||||
|
||||
if err != nil {
|
||||
c.HTML(http.StatusBadRequest, "cart.html", gin.H{ "data": gin.H{ "error": err } })
|
||||
}
|
||||
|
||||
fmt.Printf("CARTITEMS: %v\n", cartItems)
|
||||
|
||||
data := CreateSessionData(c, gin.H{
|
||||
"cartItems": cartItems,
|
||||
})
|
||||
|
||||
c.HTML(http.StatusOK, "cart.html", data)
|
||||
}
|
||||
|
||||
func (rc *cartItemController) AddItemHandler(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
c.HTML(http.StatusBadRequest, "cart.html", gin.H{ "error": err })
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Create(cartItem)
|
||||
if err != nil {
|
||||
data := CreateSessionData(c, gin.H{
|
||||
"error": err,
|
||||
"success": "",
|
||||
})
|
||||
|
||||
c.HTML(http.StatusOK, "cart.html", data)
|
||||
return
|
||||
}
|
||||
|
||||
rc.CartItemView(c)
|
||||
}
|
||||
|
||||
func (rc *cartItemController) DeleteItemHandler(c *gin.Context) {
|
||||
err := repositories.CartItems.DeleteById(c.PostForm("id"))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
data := CreateSessionData(c, gin.H{
|
||||
"error": err,
|
||||
"success": "",
|
||||
})
|
||||
|
||||
c.HTML(http.StatusOK, "index.html", data)
|
||||
}
|
||||
|
||||
rc.CartItemView(c)
|
||||
}
|
||||
|
||||
func (rc *cartItemController) EditItemHandler(c *gin.Context) {
|
||||
cartItemId := c.PostForm("id")
|
||||
cartItem, err := repositories.CartItems.GetById(cartItemId)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("BLAA")
|
||||
fmt.Println(err)
|
||||
rc.CartItemView(c)
|
||||
return
|
||||
}
|
||||
|
||||
action := c.PostForm("action")
|
||||
|
||||
if action == "increase" {
|
||||
cartItem.Quantity += 1
|
||||
}
|
||||
|
||||
if action == "decrease" {
|
||||
cartItem.Quantity -= 1
|
||||
|
||||
if cartItem.Quantity == 0 {
|
||||
cartItem.Quantity = 1
|
||||
}
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Update(cartItem)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("BLUB")
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
rc.CartItemView(c)
|
||||
}
|
||||
@@ -160,6 +160,7 @@ func (rc *shopItemController) Update(c *gin.Context) {
|
||||
ReplyOK(c, "shopItem was updated")
|
||||
}
|
||||
|
||||
//TODO: delete associated cartitems
|
||||
func (rc *shopItemController) Delete(c *gin.Context) {
|
||||
err := repositories.ShopItems.DeleteById(c.Param("id"))
|
||||
|
||||
|
||||
6
main.go
6
main.go
@@ -17,6 +17,7 @@ import(
|
||||
var(
|
||||
shopItemController controllers.ShopItemController = controllers.NewShopItemController()
|
||||
userController controllers.UserController = controllers.UserController{}
|
||||
cartItemController controllers.CartItemController = controllers.NewCartItemController()
|
||||
authValidator middlewares.AuthValidator = middlewares.AuthValidator{}
|
||||
)
|
||||
|
||||
@@ -84,6 +85,11 @@ func main() {
|
||||
viewRoutes.GET("/tags", authValidator.RequireAuth, shopItemController.TagView)
|
||||
viewRoutes.POST("/tags/:id", authValidator.RequireAuth, shopItemController.TagHandler)
|
||||
viewRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.AddTagHandler)
|
||||
viewRoutes.GET("/cart", cartItemController.CartItemView)
|
||||
viewRoutes.POST("/cart", cartItemController.AddItemHandler)
|
||||
viewRoutes.POST("/cart/delete", cartItemController.DeleteItemHandler)
|
||||
viewRoutes.POST("/cart/edit", cartItemController.EditItemHandler)
|
||||
|
||||
//write middleware that redirects to homescreen on register/login/reset for logged in users
|
||||
viewRoutes.GET("/login", userController.LoginView)
|
||||
viewRoutes.GET("/logout", userController.Logout)
|
||||
|
||||
13
models/cart.go
Normal file
13
models/cart.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CartItem struct {
|
||||
gorm.Model
|
||||
SessionId string `json:"sessionid" binding:"required" gorm:"not null"`
|
||||
ShopItemId uint
|
||||
ShopItem ShopItem `json:"shopitem" gorm:"foreignKey:ShopItemId"` //gorm one2one
|
||||
Quantity int `json:"quantity" binding:"required"`
|
||||
}
|
||||
90
repositories/cartItemRepository.go
Normal file
90
repositories/cartItemRepository.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package repositories
|
||||
|
||||
import(
|
||||
"strconv"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"example.com/gin/test/models"
|
||||
)
|
||||
|
||||
type CartItemRepository interface {
|
||||
Create(models.CartItem) (models.CartItem, error)
|
||||
GetAll() ([]models.CartItem, error)
|
||||
GetById(string) (models.CartItem, error)
|
||||
GetAllBySession(string) ([]models.CartItem, error)
|
||||
Update(models.CartItem) (models.CartItem, error)
|
||||
DeleteById(string) (error)
|
||||
}
|
||||
|
||||
type GORMCartItemRepository struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewGORMCartItemRepository(db *gorm.DB) CartItemRepository {
|
||||
return &GORMCartItemRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) Create(cartItem models.CartItem) (models.CartItem, error) {
|
||||
//Omit the shopitem so it is not created again in db leading to unique constain fails
|
||||
result := r.DB.Omit("ShopItem").Create(&cartItem)
|
||||
if result.Error != nil {
|
||||
return models.CartItem{}, result.Error
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) GetAll() ([]models.CartItem, error) {
|
||||
var cartItems []models.CartItem
|
||||
result := r.DB.Preload("ShopItem").Find(&cartItems)
|
||||
|
||||
return cartItems, result.Error
|
||||
}
|
||||
|
||||
func (t *GORMCartItemRepository) GetById(id string) (models.CartItem, error) {
|
||||
cartItemId, err := strconv.Atoi(id)
|
||||
|
||||
if err != nil {
|
||||
return models.CartItem{}, err
|
||||
}
|
||||
|
||||
var cartItem models.CartItem
|
||||
result := t.DB.First(&cartItem, uint(cartItemId))
|
||||
|
||||
if result.Error != nil {
|
||||
return models.CartItem{}, result.Error
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
|
||||
func (r *GORMCartItemRepository) GetAllBySession(sessionId string) ([]models.CartItem, error) {
|
||||
var cartItems []models.CartItem
|
||||
result := r.DB.Preload("ShopItem").Where("session_id = ?", sessionId).Find(&cartItems)
|
||||
|
||||
return cartItems, result.Error
|
||||
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) Update(cartItem models.CartItem) (models.CartItem, error) {
|
||||
result := r.DB.Save(&cartItem)
|
||||
if result.Error != nil {
|
||||
return models.CartItem{}, result.Error
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) DeleteById(id string) error {
|
||||
cartItemId, err := strconv.Atoi(id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result := r.DB.Omit("ShopItem").Delete(&models.CartItem{}, cartItemId)
|
||||
return result.Error
|
||||
}
|
||||
@@ -12,6 +12,7 @@ var(
|
||||
ShopItems ShopItemRepository
|
||||
Users UserRepository
|
||||
Tags TagRepository
|
||||
CartItems CartItemRepository
|
||||
)
|
||||
|
||||
func InitRepositories() {
|
||||
@@ -20,7 +21,7 @@ func InitRepositories() {
|
||||
panic("failed to connect to database")
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&models.ShopItem{}, &models.User{}, &models.Tag{})
|
||||
err = db.AutoMigrate(&models.ShopItem{}, &models.User{}, &models.Tag{}, &models.CartItem{})
|
||||
if err != nil {
|
||||
panic("failed to migrate database")
|
||||
}
|
||||
@@ -28,4 +29,5 @@ func InitRepositories() {
|
||||
ShopItems = NewGORMShopItemRepository(db)
|
||||
Users = NewGORMUserRepository(db)
|
||||
Tags = NewGORMTagRepository(db)
|
||||
CartItems = NewGORMCartItemRepository(db)
|
||||
}
|
||||
|
||||
@@ -587,6 +587,10 @@ video {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.col-span-12 {
|
||||
grid-column: span 12 / span 12;
|
||||
}
|
||||
|
||||
.m-2 {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
@@ -595,11 +599,6 @@ video {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.-mx-2 {
|
||||
margin-left: -0.5rem;
|
||||
margin-right: -0.5rem;
|
||||
@@ -610,19 +609,47 @@ video {
|
||||
margin-right: -1rem;
|
||||
}
|
||||
|
||||
.-mx-3 {
|
||||
margin-left: -0.75rem;
|
||||
margin-right: -0.75rem;
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.mb-2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mb-5 {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.mb-6 {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.mb-8 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.mt-1 {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
@@ -643,26 +670,6 @@ video {
|
||||
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 {
|
||||
display: block;
|
||||
}
|
||||
@@ -699,18 +706,10 @@ video {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
.h-8 {
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.h-\[460px\] {
|
||||
height: 460px;
|
||||
}
|
||||
@@ -723,6 +722,14 @@ video {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.w-10 {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
@@ -739,22 +746,6 @@ video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-1\/2 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.max-w-7xl {
|
||||
max-width: 80rem;
|
||||
}
|
||||
|
||||
.max-w-2xl {
|
||||
max-width: 42rem;
|
||||
}
|
||||
@@ -763,6 +754,10 @@ video {
|
||||
max-width: 72rem;
|
||||
}
|
||||
|
||||
.max-w-7xl {
|
||||
max-width: 80rem;
|
||||
}
|
||||
|
||||
.max-w-md {
|
||||
max-width: 28rem;
|
||||
}
|
||||
@@ -787,8 +782,8 @@ video {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
.grid-cols-12 {
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
@@ -807,6 +802,14 @@ video {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gap-5 {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.gap-x-6 {
|
||||
-moz-column-gap: 1.5rem;
|
||||
column-gap: 1.5rem;
|
||||
@@ -816,6 +819,10 @@ video {
|
||||
row-gap: 2.5rem;
|
||||
}
|
||||
|
||||
.gap-y-4 {
|
||||
row-gap: 1rem;
|
||||
}
|
||||
|
||||
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-x-reverse: 0;
|
||||
margin-right: calc(1rem * var(--tw-space-x-reverse));
|
||||
@@ -840,10 +847,26 @@ video {
|
||||
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.whitespace-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.rounded-3xl {
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
|
||||
.rounded-\[50px\] {
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.rounded-full {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
@@ -852,20 +875,11 @@ video {
|
||||
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-width: 1px;
|
||||
}
|
||||
@@ -874,20 +888,49 @@ video {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.border-b {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.border-dashed {
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.border-gray-200 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-blue-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-blue-900 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(30 58 138 / 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-200 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-gray-300 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-gray-800 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
|
||||
@@ -898,74 +941,46 @@ video {
|
||||
background-color: rgb(17 24 39 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-green-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-indigo-50 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(238 242 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-indigo-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(79 70 229 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
--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 {
|
||||
.bg-red-900 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.fill-red-50 {
|
||||
fill: #fef2f2;
|
||||
}
|
||||
|
||||
.stroke-gray-900 {
|
||||
stroke: #111827;
|
||||
}
|
||||
|
||||
.stroke-red-500 {
|
||||
stroke: #ef4444;
|
||||
}
|
||||
|
||||
.object-cover {
|
||||
@@ -977,6 +992,10 @@ video {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.p-2\.5 {
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
.p-4 {
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -1011,14 +1030,29 @@ video {
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.py-16 {
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
.py-2 {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.py-16 {
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
.py-2\.5 {
|
||||
padding-top: 0.625rem;
|
||||
padding-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.py-24 {
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
}
|
||||
|
||||
.py-4 {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.py-8 {
|
||||
@@ -1054,11 +1088,30 @@ video {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-2xl\/9 {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-4xl {
|
||||
font-size: 2.25rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.text-base {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
@@ -1084,11 +1137,6 @@ video {
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -1097,14 +1145,35 @@ video {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.leading-10 {
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.leading-7 {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.leading-9 {
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.tracking-tight {
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.text-black {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-300 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
||||
@@ -1125,6 +1194,11 @@ video {
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(17 24 39 / var(--tw-text-opacity, 1));
|
||||
@@ -1155,17 +1229,17 @@ video {
|
||||
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 {
|
||||
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow-transparent {
|
||||
--tw-shadow-color: transparent;
|
||||
--tw-shadow: var(--tw-shadow-colored);
|
||||
}
|
||||
|
||||
.outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
@@ -1182,6 +1256,16 @@ video {
|
||||
outline-color: #d1d5db;
|
||||
}
|
||||
|
||||
.transition-all {
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.duration-500 {
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
.placeholder\:text-gray-400::-moz-placeholder {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(156 163 175 / var(--tw-text-opacity, 1));
|
||||
@@ -1197,6 +1281,14 @@ video {
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.focus-within\:outline-gray-300:focus-within {
|
||||
outline-color: #d1d5db;
|
||||
}
|
||||
|
||||
.focus-within\:outline-red-500:focus-within {
|
||||
outline-color: #ef4444;
|
||||
}
|
||||
|
||||
.focus-within\:ring-2:focus-within {
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
@@ -1212,29 +1304,9 @@ video {
|
||||
--tw-ring-offset-width: 2px;
|
||||
}
|
||||
|
||||
.hover\:bg-gray-700:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-indigo-500:hover {
|
||||
--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\:border-gray-300:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-blue-700:hover {
|
||||
@@ -1242,14 +1314,24 @@ video {
|
||||
background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-red-700:hover {
|
||||
.hover\:bg-gray-400:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(156 163 175 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-red-900:hover {
|
||||
.hover\:bg-gray-50:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-gray-700:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(55 65 81 / 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-green-700:hover {
|
||||
@@ -1257,6 +1339,26 @@ video {
|
||||
background-color: rgb(21 128 61 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-indigo-100:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(224 231 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-indigo-500:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(99 102 241 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-indigo-700:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(67 56 202 / 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\:text-indigo-500:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(99 102 241 / var(--tw-text-opacity, 1));
|
||||
@@ -1267,6 +1369,11 @@ video {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:shadow-gray-200:hover {
|
||||
--tw-shadow-color: #e5e7eb;
|
||||
--tw-shadow: var(--tw-shadow-colored);
|
||||
}
|
||||
|
||||
.focus\:border-blue-500:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
||||
@@ -1320,10 +1427,47 @@ video {
|
||||
outline-color: #4f46e5;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:fill-red-400 {
|
||||
fill: #f87171;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:stroke-black {
|
||||
stroke: #000;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:stroke-white {
|
||||
stroke: #fff;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:opacity-75 {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
@media not all and (min-width: 1024px) {
|
||||
.max-lg\:mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.max-lg\:w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.max-lg\:max-w-lg {
|
||||
max-width: 32rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (min-width: 768px) {
|
||||
.max-md\:mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.max-md\:text-center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sm\:static {
|
||||
position: static;
|
||||
@@ -1362,16 +1506,16 @@ video {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.sm\:px-8 {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.sm\:px-6 {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.sm\:px-8 {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.sm\:py-24 {
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
@@ -1388,14 +1532,6 @@ video {
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.md\:h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.md\:w-48 {
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
.md\:flex-1 {
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
@@ -1407,9 +1543,26 @@ video {
|
||||
.md\:flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.md\:items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.md\:px-5 {
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:col-span-10 {
|
||||
grid-column: span 10 / span 10;
|
||||
}
|
||||
|
||||
.lg\:col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
|
||||
.lg\:aspect-auto {
|
||||
aspect-ratio: auto;
|
||||
}
|
||||
@@ -1418,6 +1571,10 @@ video {
|
||||
height: 20rem;
|
||||
}
|
||||
|
||||
.lg\:w-\[180px\] {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.lg\:max-w-7xl {
|
||||
max-width: 80rem;
|
||||
}
|
||||
@@ -1430,10 +1587,23 @@ video {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.lg\:p-8 {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.lg\:px-6 {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.lg\:px-8 {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.lg\:pl-3 {
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
@@ -1453,21 +1623,6 @@ video {
|
||||
border-color: rgb(75 85 99 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.dark\:bg-gray-800 {
|
||||
--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));
|
||||
@@ -1478,14 +1633,9 @@ video {
|
||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.dark\:bg-red-700 {
|
||||
.dark\:bg-gray-800 {
|
||||
--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));
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.dark\:bg-red-600 {
|
||||
|
||||
35
views/addtag.html
Normal file
35
views/addtag.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{ 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">Add Tag</h2>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||
<form class="space-y-6" action="#" method="POST" enctype="multipart/form-data">
|
||||
<div>
|
||||
<label for="name" class="block text-sm/6 font-medium text-gray-900">Name</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="name" id="name" required class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-10 text-center text-sm/6 text-red-500">
|
||||
{{ .data.error }}
|
||||
</p>
|
||||
<p class="mt-10 text-center text-sm/6 text-green-500">
|
||||
{{ .data.success }}
|
||||
</p>
|
||||
|
||||
|
||||
<div>
|
||||
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Add Tag</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{ template "footer.html" . }}
|
||||
96
views/cart.html
Normal file
96
views/cart.html
Normal file
@@ -0,0 +1,96 @@
|
||||
{{ template "header.html" . }}
|
||||
|
||||
<section class="py-24 relative">
|
||||
<div class="w-full max-w-7xl px-4 md:px-5 lg-6 mx-auto">
|
||||
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Shopping Cart
|
||||
</h2>
|
||||
|
||||
{{ range .data.cartItems }}
|
||||
|
||||
<div class="rounded-3xl border-2 border-gray-200 p-4 lg:p-8 grid grid-cols-12 mb-8 max-lg:max-w-lg max-lg:mx-auto gap-y-4 ">
|
||||
<div class="col-span-12 lg:col-span-2 img box">
|
||||
<img src="/{{ .ShopItem.Image }}" alt="speaker image" class="max-lg:w-full lg:w-[180px] rounded-lg object-cover">
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-10 detail w-full lg:pl-3">
|
||||
<div class="flex items-center justify-between w-full mb-4">
|
||||
<h5 class="font-manrope font-bold text-2xl leading-9 text-gray-900">{{ .ShopItem.Name }}</h5>
|
||||
<form action="/cart/delete" method="POST">
|
||||
<input type="hidden" id="{{ .ID }}" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="rounded-full group flex items-center justify-center focus-within:outline-red-500">
|
||||
<svg width="34" height="34" viewBox="0 0 34 34" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="fill-red-50 transition-all duration-500 group-hover:fill-red-400"
|
||||
cx="17" cy="17" r="17" fill="" />
|
||||
<path class="stroke-red-500 transition-all duration-500 group-hover:stroke-white"
|
||||
d="M14.1673 13.5997V12.5923C14.1673 11.8968 14.7311 11.333 15.4266 11.333H18.5747C19.2702 11.333 19.834 11.8968 19.834 12.5923V13.5997M19.834 13.5997C19.834 13.5997 14.6534 13.5997 11.334 13.5997C6.90804 13.5998 27.0933 13.5998 22.6673 13.5997C21.5608 13.5997 19.834 13.5997 19.834 13.5997ZM12.4673 13.5997H21.534V18.8886C21.534 20.6695 21.534 21.5599 20.9807 22.1131C20.4275 22.6664 19.5371 22.6664 17.7562 22.6664H16.2451C14.4642 22.6664 13.5738 22.6664 13.0206 22.1131C12.4673 21.5599 12.4673 20.6695 12.4673 18.8886V13.5997Z"
|
||||
stroke="#EF4444" stroke-width="1.6" stroke-linecap="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<p class="font-normal text-base leading-7 text-gray-500 mb-6">
|
||||
{{ .ShopItem.Abstract }}
|
||||
</p>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center gap-4">
|
||||
<form action="/cart/edit" method="POST">
|
||||
<input type="hidden" id="{{ .ID }}" name="id" value="{{ .ID }}">
|
||||
<button type="submit" name="action" value="decrease"
|
||||
class="group rounded-[50px] border border-gray-200 shadow-sm shadow-transparent p-2.5 flex items-center justify-center bg-white transition-all duration-500 hover:shadow-gray-200 hover:bg-gray-50 hover:border-gray-300 focus-within:outline-gray-300">
|
||||
<svg class="stroke-gray-900 transition-all duration-500 group-hover:stroke-black"
|
||||
width="18" height="19" viewBox="0 0 18 19" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.5 9.5H13.5" stroke="" stroke-width="1.6" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<p class="border border-gray-200 text-center rounded-full w-10 text-gray-900 font-semibold text-sm py-1.5 px-3 bg-gray-100 text-center">{{ .Quantity }}</p>
|
||||
<button type="submit" name="action" value="increase"
|
||||
class="group rounded-[50px] border border-gray-200 shadow-sm shadow-transparent p-2.5 flex items-center justify-center bg-white transition-all duration-500 hover:shadow-gray-200 hover:bg-gray-50 hover:border-gray-300 focus-within:outline-gray-300">
|
||||
<svg class="stroke-gray-900 transition-all duration-500 group-hover:stroke-black"
|
||||
width="18" height="19" viewBox="0 0 18 19" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.75 9.5H14.25M9 14.75V4.25" stroke="" stroke-width="1.6"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<h6 class="text-indigo-600 font-manrope font-bold text-2xl leading-9 text-right">{{ .ShopItem.Price }}€</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="flex flex-col md:flex-row items-center md:items-center justify-between lg:px-6 pb-6 border-b border-gray-200 max-lg:max-w-lg max-lg:mx-auto">
|
||||
<h5 class="text-gray-900 font-manrope font-semibold text-2xl leading-9 w-full max-md:text-center max-md:mb-4">Subtotal</h5>
|
||||
|
||||
<div class="flex items-center justify-between gap-5 ">
|
||||
<button
|
||||
class="rounded-full py-2.5 px-3 bg-indigo-50 text-indigo-600 font-semibold text-xs text-center whitespace-nowrap transition-all duration-500 hover:bg-indigo-100">Promo
|
||||
Code?</button>
|
||||
<h6 class="font-manrope font-bold text-3xl lead-10 text-indigo-600">$440</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-lg:max-w-lg max-lg:mx-auto">
|
||||
<p class="font-normal text-base leading-7 text-gray-500 text-center mb-5 mt-6">Shipping taxes, and discounts
|
||||
calculated
|
||||
at checkout</p>
|
||||
<button
|
||||
class="rounded-full py-4 px-6 bg-indigo-600 text-white font-semibold text-lg w-full text-center transition-all duration-500 hover:bg-indigo-700 ">Checkout</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
{{ template "footer.html" . }}
|
||||
@@ -33,8 +33,7 @@
|
||||
</div>
|
||||
{{ else }}
|
||||
<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="/login" 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">Login</a>
|
||||
<a href="/register" 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">Register</a>
|
||||
<a href="/cart" 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">🛒 Cart</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
<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>
|
||||
<form action="/cart" method="POST">
|
||||
<div class="flex -mx-2 mb-4">
|
||||
<input type="hidden" id="{{ .data.shopItem.ID}}" name="ShopItemId" value="{{ .data.shopItem.ID }}">
|
||||
<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>
|
||||
<button type="submit" 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 }}
|
||||
@@ -22,6 +24,7 @@
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</form>
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user