Producte show
Producte werden nun angezeigt .
This commit is contained in:
@@ -160,6 +160,9 @@ func (server *Server) routeInit() {
|
||||
server.Router.HandleFunc("/register", server.DoRegister).Methods("POST")
|
||||
server.Router.HandleFunc("/logout", server.Logout).Methods("GET")
|
||||
|
||||
server.Router.HandleFunc("/products", server.Products).Methods("GET")
|
||||
server.Router.HandleFunc("/products/{slug}", server.GetProductByID).Methods("GET")
|
||||
|
||||
staticFileDirectory := http.Dir("./assets/")
|
||||
staticFileHandler := http.StripPrefix("/public/", http.FileServer(staticFileDirectory))
|
||||
server.Router.PathPrefix("/public/").Handler(staticFileHandler).Methods("GET")
|
||||
|
||||
62
app/controllers/product_controller.go
Normal file
62
app/controllers/product_controller.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/unrolled/render"
|
||||
"moretcgshop/app/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (server *Server) Products(w http.ResponseWriter, r *http.Request) {
|
||||
renderer := render.New(render.Options{
|
||||
Layout: "layout",
|
||||
Extensions: []string{".html", ".tmpl"},
|
||||
})
|
||||
|
||||
q := r.URL.Query()
|
||||
|
||||
page, _ := strconv.Atoi(q.Get("page"))
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
perPage := 9
|
||||
|
||||
productModel := models.Product{}
|
||||
products, totalRows, err := productModel.GetProducts(server.DB, perPage, page)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_ = totalRows
|
||||
|
||||
_ = renderer.HTML(w, http.StatusOK, "products", map[string]interface{}{
|
||||
"products": products,
|
||||
})
|
||||
}
|
||||
|
||||
func (server *Server) GetProductByID(w http.ResponseWriter, r *http.Request) {
|
||||
renderer := render.New(render.Options{
|
||||
Layout: "layout",
|
||||
Extensions: []string{".html", ".tmpl"},
|
||||
})
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
if vars["slug"] == "" {
|
||||
return
|
||||
}
|
||||
|
||||
productModel := models.Product{}
|
||||
product, err := productModel.FindByID(server.DB, vars["slug"])
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_ = renderer.HTML(w, http.StatusOK, "product", map[string]interface{}{
|
||||
"product": product,
|
||||
"success": GetFlash(w, r, "success"),
|
||||
"error": GetFlash(w, r, "error"),
|
||||
})
|
||||
}
|
||||
16
app/models/ProductImage.go
Normal file
16
app/models/ProductImage.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type ProductImage struct {
|
||||
ID string `gorm:"size:36;not null;uniqueIndex;primary_key"`
|
||||
Product Product
|
||||
ProductID string `gorm:"size:36;index"`
|
||||
Path string `gorm:"type:text"`
|
||||
ExtraLarge string `gorm:"type:text"`
|
||||
Large string `gorm:"type:text"`
|
||||
Medium string `gorm:"type:text"`
|
||||
Small string `gorm:"type:text"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
@@ -10,5 +10,6 @@ func RegisterModels() []Model {
|
||||
{Model: Product{}},
|
||||
{Model: Category{}},
|
||||
{Model: Section{}},
|
||||
{Model: ProductImage{}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,55 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
ID string
|
||||
ParentID string
|
||||
Name string
|
||||
ID string `gorm:"size:36;not null;uniqueIndex;primary_key"`
|
||||
ParentID string `gorm:"size:36;index"`
|
||||
Name string `gorm:"size:255"`
|
||||
Slug string `gorm:"size:255"`
|
||||
ProductImages []ProductImage
|
||||
Price decimal.Decimal `gorm:"type:decimal(16,2);"`
|
||||
Categories []Category `gorm:"many2many:product_categories;"`
|
||||
ShortDescription string `gorm:"type:text"`
|
||||
Description string `gorm:"type:text"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt
|
||||
}
|
||||
|
||||
func (p *Product) GetProducts(db *gorm.DB, perPage int, page int) (*[]Product, int64, error) {
|
||||
|
||||
var count int64
|
||||
var products []Product
|
||||
|
||||
err := db.Debug().Model(&Product{}).Count(&count).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * perPage
|
||||
|
||||
err = db.Debug().Model(&Product{}).Order("created_at desc").Limit(perPage).Offset(offset).Find(&products).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return &products, count, nil
|
||||
}
|
||||
|
||||
func (p *Product) FindByID(db *gorm.DB, productID string) (*Product, error) {
|
||||
var err error
|
||||
var product Product
|
||||
|
||||
err = db.Debug().Preload("ProductImages").Model(&Product{}).Where("id = ?", productID).First(&product).Error
|
||||
//err = db.Debug().Model(&Product{}).Where("id = ?", productID).First(&product).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &product, nil
|
||||
}
|
||||
|
||||
@@ -31,29 +31,17 @@ services:
|
||||
labels:
|
||||
# Frontend
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.hochzeit.entrypoints=http"
|
||||
- "traefik.http.routers.hochzeit.rule=Host(`drone.cosysda.de`)"
|
||||
- "traefik.http.middlewares.hochzeit-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.hochzeit.middlewares=hochzeit-https-redirect"
|
||||
- "traefik.http.routers.hochzeit-secure.entrypoints=https"
|
||||
- "traefik.http.routers.hochzeit-secure.rule=Host(`drone.cosysda.de`)"
|
||||
- "traefik.http.routers.hochzeit-secure.tls=true"
|
||||
- "traefik.http.routers.hochzeit-secure.tls.certresolver=http"
|
||||
- "traefik.http.routers.hochzeit-secure.service=hochzeit"
|
||||
- "traefik.http.services.hochzeit.loadbalancer.server.port=9000"
|
||||
- "traefik.http.routers.moretcg-shop.entrypoints=http"
|
||||
- "traefik.http.routers.moretcg-shop.rule=Host(`drone.cosysda.de`)"
|
||||
- "traefik.http.middlewares.moretcg-shop-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.moretcg-shop.middlewares=moretcg-shop-https-redirect"
|
||||
- "traefik.http.routers.moretcg-shop-secure.entrypoints=https"
|
||||
- "traefik.http.routers.moretcg-shop-secure.rule=Host(`drone.cosysda.de`)"
|
||||
- "traefik.http.routers.moretcg-shop-secure.tls=true"
|
||||
- "traefik.http.routers.moretcg-shop-secure.tls.certresolver=http"
|
||||
- "traefik.http.routers.moretcg-shop-secure.service=moretcg-shop"
|
||||
- "traefik.http.services.moretcg-shop.loadbalancer.server.port=9000"
|
||||
- "traefik.docker.network=http_network"
|
||||
#- "traefik.http.routers.frontend.entrypoints=websecure"
|
||||
#- "traefik.http.services.frontend.loadbalancer.server.port=9000"
|
||||
#- "traefik.http.routers.frontend.service=frontend"
|
||||
#- "traefik.http.routers.frontend.tls.certresolver=leresolver"
|
||||
# Edge
|
||||
#- "traefik.http.routers.edge.rule=Host:edge.cosysda.de"
|
||||
#- "traefik.http.routers.edge.entrypoints=websecure"
|
||||
#- "traefik.http.services.edge.loadbalancer.server.port=8000"
|
||||
#- "traefik.http.routers.edge.service=edge"
|
||||
#- "traefik.http.routers.edge.tls.certresolver=leresolver"
|
||||
networks:
|
||||
- http_network
|
||||
- moretcg
|
||||
#volumes:
|
||||
#portainer_data:
|
||||
|
||||
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/sessions v1.2.2
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/shopspring/decimal v1.3.1
|
||||
github.com/unrolled/render v1.6.1
|
||||
golang.org/x/crypto v0.14.0
|
||||
gorm.io/driver/postgres v1.5.4
|
||||
|
||||
2
go.sum
2
go.sum
@@ -25,6 +25,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
||||
27
templates/pages/pagination.html
Normal file
27
templates/pages/pagination.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{{ define "pagination" }}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ul class="pagination">
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="{{ .pagination.PrevPage }}" tabindex="-1">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
<span class="sr-only">Previous</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ range $i, $link := .pagination.Links }}
|
||||
{{ $active := "" }}
|
||||
{{ if $link.IsCurrentPage }}
|
||||
{{ $active = "active" }}
|
||||
{{ end }}
|
||||
<li class="page-item {{ $active }}"><a class="page-link" href="{{ $link.Url }}">{{ $link.Page }}</a></li>
|
||||
{{ end }}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="{{ .pagination.NextPage }}">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
170
templates/pages/product.html
Normal file
170
templates/pages/product.html
Normal file
@@ -0,0 +1,170 @@
|
||||
{{ define "product" }}
|
||||
<section class="breadcrumb-section pb-3 pt-3">
|
||||
<div class="container">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/products">Products</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ .product.Name}}</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
<section class="product-page pb-4 pt-4">
|
||||
<div class="container">
|
||||
<div class="row product-detail-inner">
|
||||
<div class="col-lg-6 col-md-6 col-12">
|
||||
<div id="product-images" class="carousel slide" data-ride="carousel">
|
||||
<!-- slides -->
|
||||
<div class="carousel-inner">
|
||||
{{ range $i, $productImage := .product.ProductImages }}
|
||||
{{ if eq $i 0 }}
|
||||
<div class="carousel-item active"><img src="{{ $productImage.Path }}" alt="Product 1">
|
||||
</div>
|
||||
{{ else }}
|
||||
<<div class="carousel-item"><img src="{{ $productImage.Path }}" alt="Product 2"></div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div> <!-- Left right -->
|
||||
<a class="carousel-control-prev" href="#product-images" data-slide="prev"> <span
|
||||
class="carousel-control-prev-icon"></span> </a> <a class="carousel-control-next"
|
||||
href="#product-images" data-slide="next">
|
||||
<span class="carousel-control-next-icon"></span> </a><!-- Thumbnails -->
|
||||
<ol class="carousel-indicators list-inline">
|
||||
{{ range $i, $productImage := .product.ProductImages }}
|
||||
{{ if eq $i 0 }}
|
||||
<li class="list-inline-item active"><a id="carousel-selector-{{ $i }}" class="selected"
|
||||
data-slide-to="{{ $i }}" data-target="#product-images">
|
||||
<img src="{{ $productImage.Path }}" class="img-fluid"> </a></li>
|
||||
{{ else }}
|
||||
<li class="list-inline-item"><a id="carousel-selector-{{ $i }}" data-slide-to="{{ $i }}"
|
||||
data-target="#product-images"> <img
|
||||
src="{{ $productImage.Path }}" class="img-fluid"> </a></li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-12">
|
||||
<div class="product-detail">
|
||||
<h2 class="product-name">{{ .product.Name }}</h2>
|
||||
<div class="product-price">
|
||||
<span class="price">IDR {{ .product.Price }}</span>
|
||||
</div>
|
||||
{{ if .success }}
|
||||
<div class="alert alert-success">
|
||||
{{ range $i, $msg := .success }}
|
||||
{{ $msg }}<br/>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .error }}
|
||||
<div class="alert alert-danger">
|
||||
{{ range $i, $msg := .error }}
|
||||
{{ $msg }}<br/>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="product-short-desc">
|
||||
<p>{{ .product.ShortDescription }}</p>
|
||||
</div>
|
||||
<div class="product-select">
|
||||
<form method="POST" action="/carts">
|
||||
<input type="hidden" name="product_id" value="{{ .product.ID }}"/>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<input type="number" name="qty" class="form-control" value="1"/>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<button type="submit" class="btn btn-primary btn-block">Add to Cart</button>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="#" class="btn btn-secondary"><i class="fa fa-heart-o"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!--
|
||||
<div class="product-categories">
|
||||
<ul>
|
||||
<li class="categories-title">Categories :</li>
|
||||
<li><a href="#">fashion</a></li>
|
||||
<li><a href="#">electronics</a></li>
|
||||
<li><a href="#">toys</a></li>
|
||||
<li><a href="#">food</a></li>
|
||||
<li><a href="#">jewellery</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
<!--<div class="product-tags">
|
||||
<ul>
|
||||
<li class="categories-title">Tags :</li>
|
||||
<li><a href="#">fashion</a></li>
|
||||
<li><a href="#">electronics</a></li>
|
||||
<li><a href="#">toys</a></li>
|
||||
<li><a href="#">food</a></li>
|
||||
<li><a href="#">jewellery</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
<!--
|
||||
<div class="product-share">
|
||||
<ul>
|
||||
<li class="categories-title">Share :</li>
|
||||
<li><a href="#"><i class="fa fa-facebook"></i></a></li>
|
||||
<li><a href="#"><i class="fa fa-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa fa-pinterest"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="product-details">
|
||||
<div class="nav-wrapper">
|
||||
<ul class="nav nav-pills nav-fill flex-column flex-md-row" id="tabs-icons-text" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link mb-sm-3 mb-md-0 active" id="tabs-icons-text-1-tab" data-toggle="tab"
|
||||
href="#tabs-icons-text-1" role="tab" aria-controls="tabs-icons-text-1"
|
||||
aria-selected="true">Beschreibung</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link mb-sm-3 mb-md-0" id="tabs-icons-text-2-tab" data-toggle="tab"
|
||||
href="#tabs-icons-text-2" role="tab" aria-controls="tabs-icons-text-2"
|
||||
aria-selected="false">Reviews</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="tabs-icons-text-1" role="tabpanel"
|
||||
aria-labelledby="tabs-icons-text-1-tab">
|
||||
<p>{{ .product.Description }}</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tabs-icons-text-2" role="tabpanel"
|
||||
aria-labelledby="tabs-icons-text-2-tab">
|
||||
<div class="review-form">
|
||||
<h3>Write a review</h3>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label>Your Name</label>
|
||||
<input type="text" class="form-control"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Your Review</label>
|
||||
<textarea cols="4" class="form-control"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
120
templates/pages/products.html
Normal file
120
templates/pages/products.html
Normal file
@@ -0,0 +1,120 @@
|
||||
{{ define "products" }}
|
||||
<section class="breadcrumb-section pb-3 pt-3">
|
||||
<div class="container">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="#">Home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Products</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
<section class="products-grid pb-4 pt-4">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 col-12">
|
||||
<div class="sidebar">
|
||||
<!--<div class="sidebar-widget">
|
||||
<div class="widget-title">
|
||||
<h3>Shop by Price</h3>
|
||||
</div>
|
||||
<div class="widget-content shop-by-price">
|
||||
<form method="get" action="/tesas">
|
||||
<div class="price-filter">
|
||||
<div class="price-filter-inner">
|
||||
<div id="slider-range"></div>
|
||||
<div class="price_slider_amount">
|
||||
<div class="label-input">
|
||||
<input type="text" id="amount" name="price"
|
||||
placeholder="Add Your Price" />
|
||||
<button type="submit">Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="sidebar-widget">
|
||||
<div class="widget-title">
|
||||
<h3>Categories</h3>
|
||||
</div>
|
||||
<div class="widget-content widget-categories">
|
||||
<ul>
|
||||
<li><a href="#">Fashions</a></li>
|
||||
<li><a href="#">Electronics</a>
|
||||
<ul>
|
||||
<li><a href="#">Hand Phone</a></li>
|
||||
<li><a href="#">Laptops</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#">Home and Kitchen</a></li>
|
||||
<li><a href="#">Baby and Toys</a></li>
|
||||
<li><a href="#">Sports</a></li>
|
||||
<li><a href="#">Digital Goods</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="sidebar-widget">
|
||||
<div class="widget-title">
|
||||
<h3>Brands</h3>
|
||||
</div>
|
||||
<div class="widget-content widget-brands">
|
||||
<ul>
|
||||
<li><a href="#">Apple</a></li>
|
||||
<li><a href="#">Samsung</a></li>
|
||||
<li><a href="#">Lenovo</a></li>
|
||||
<li><a href="#">Asus</a></li>
|
||||
<li><a href="#">Xiaomi</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 col-md-8 col-12">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="products-top">
|
||||
<div class="products-top-inner">
|
||||
<div class="products-found">
|
||||
<p><span>25</span> products found of <span>1.342</span></p>
|
||||
</div>
|
||||
<!--
|
||||
<div class="products-sort">
|
||||
<span>Sort By : </span>
|
||||
<select>
|
||||
<option>Default</option>
|
||||
<option>Price</option>
|
||||
<option>Recent</option>
|
||||
</select>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{{ range $i, $product := .products }}
|
||||
<div class="col-lg-4 col-md-6 col-12">
|
||||
<div class="single-product">
|
||||
<div class="product-img">
|
||||
<a href="/products/{{ $product.Slug }}">
|
||||
<img src="https://placehold.jp/300x400.png" class="img-fluid" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="product-content">
|
||||
<h3><a href="/products/{{ $product.Slug }}">{{ $product.Name }}</a></h3>
|
||||
<div class="product-price">
|
||||
<span>{{ $product.Price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ template "pagination" . }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user