v0.30: product pages, categories, sale prices and order status timeline
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
{{define "admin_categories.html"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Title}}</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="/static/css/admin.css">
|
||||
</head>
|
||||
<body class="admin-body">
|
||||
{{template "admin_nav" .}}
|
||||
<main class="admin-main container">
|
||||
<h1 class="admin-page-title">Категории</h1>
|
||||
|
||||
<section class="admin-section">
|
||||
<h2 class="admin-section__title">Добавить категорию</h2>
|
||||
<form method="POST" action="/admin/categories" class="admin-form admin-form--row">
|
||||
<label class="admin-form__label">
|
||||
Название
|
||||
<input type="text" name="name" class="admin-form__input" required>
|
||||
</label>
|
||||
<label class="admin-form__label">
|
||||
Описание
|
||||
<input type="text" name="description" class="admin-form__input">
|
||||
</label>
|
||||
<button type="submit" class="btn btn--primary">Добавить</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="admin-section">
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Название</th>
|
||||
<th>Slug</th>
|
||||
<th>Товаров</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Categories}}
|
||||
<tr>
|
||||
<td><strong>{{.Name}}</strong></td>
|
||||
<td><a href="/category/{{.Slug}}" target="_blank">{{.Slug}}</a></td>
|
||||
<td>{{.Count}}</td>
|
||||
<td>
|
||||
<form method="POST" action="/admin/categories/{{.ID}}/delete" onsubmit="return confirm('Удалить категорию?')">
|
||||
<button type="submit" class="btn btn--danger btn--sm">Удалить</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -8,6 +8,7 @@
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/" class="admin-nav__link">Главная</a>
|
||||
<a href="/admin/products" class="admin-nav__link">Товары</a>
|
||||
<a href="/admin/categories" class="admin-nav__link">Категории</a>
|
||||
<a href="/admin/products/new" class="admin-nav__link admin-nav__link--accent">+ Добавить</a>
|
||||
</nav>
|
||||
<div class="admin-header__user">
|
||||
|
||||
@@ -44,18 +44,21 @@
|
||||
<input type="number" name="price" class="admin-form__input" value="{{printf "%.0f" .Product.Price}}" min="0" step="1" required>
|
||||
</label>
|
||||
<label class="admin-form__label">
|
||||
Категория
|
||||
<input type="text" name="category" class="admin-form__input" value="{{.Product.Category}}" list="categories">
|
||||
<datalist id="categories">
|
||||
<option value="Электроника">
|
||||
<option value="Одежда">
|
||||
<option value="Дом и сад">
|
||||
<option value="Аксессуары">
|
||||
<option value="Разное">
|
||||
</datalist>
|
||||
Цена со скидкой (₽)
|
||||
<input type="number" name="sale_price" class="admin-form__input" value="{{if .Product.HasSale}}{{printf "%.0f" .Product.SalePrice}}{{end}}" min="0" step="1" placeholder="Без скидки">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="admin-form__label">
|
||||
Категория
|
||||
<select name="category_id" class="admin-form__input">
|
||||
<option value="">— без категории —</option>
|
||||
{{range .Categories}}
|
||||
<option value="{{.ID}}" {{if catSelected .ID $.Product.CategoryID}}selected{{end}}>{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="admin-form__checkbox">
|
||||
<input type="checkbox" name="is_active" {{if .Product.IsActive}}checked{{end}}>
|
||||
Показывать в каталоге
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
{{define "product.html"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Product.Name}} — Shop</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="/static/css/shop.css">
|
||||
</head>
|
||||
<body>
|
||||
{{template "shop_header" .}}
|
||||
<main class="shop-page container">
|
||||
<nav class="breadcrumb">
|
||||
<a href="/">Главная</a>
|
||||
{{if .Product.CategorySlug}}
|
||||
<span>/</span>
|
||||
<a href="/category/{{.Product.CategorySlug}}">{{.Product.Category}}</a>
|
||||
{{end}}
|
||||
<span>/</span>
|
||||
<span>{{.Product.Name}}</span>
|
||||
</nav>
|
||||
|
||||
<div class="product-detail">
|
||||
<div class="product-detail__gallery">
|
||||
<img src="{{.Product.ImageURL}}" alt="{{.Product.Name}}" class="product-detail__main">
|
||||
{{if .Product.Images}}
|
||||
<div class="product-detail__thumbs">
|
||||
{{range .Product.Images}}
|
||||
<img src="{{.FilePath}}" alt="">
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="product-detail__info">
|
||||
{{if .Product.CategorySlug}}
|
||||
<a href="/category/{{.Product.CategorySlug}}" class="product-detail__cat">{{.Product.Category}}</a>
|
||||
{{end}}
|
||||
<h1>{{.Product.Name}}</h1>
|
||||
<div class="price-block price-block--lg">
|
||||
{{if .Product.HasSale}}
|
||||
<span class="price-block__old">{{printf "%.0f" .Product.Price}} ₽</span>
|
||||
<span class="price-block__sale">{{printf "%.0f" .Product.SalePrice}} ₽</span>
|
||||
<span class="price-block__badge">-{{.Product.DiscountPercent}}%</span>
|
||||
{{else}}
|
||||
<span class="price-block__current">{{printf "%.0f" .Product.Price}} ₽</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<p class="product-detail__short">{{plain .Product.Description}}</p>
|
||||
<form method="POST" action="/cart/add" class="product-detail__buy">
|
||||
<input type="hidden" name="product_id" value="{{.Product.ID}}">
|
||||
<input type="number" name="quantity" value="1" min="1" max="99" class="qty-input">
|
||||
<button type="submit" class="btn btn--primary btn--lg">Добавить в корзину</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if .Product.Details}}
|
||||
<section class="product-detail__content shop-card">
|
||||
<h2>Описание</h2>
|
||||
<div class="product-detail__html">{{safeHTML .Product.Details}}</div>
|
||||
</section>
|
||||
{{end}}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
||||
{{define "category.html"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Category.Name}} — Shop</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="/static/css/shop.css">
|
||||
</head>
|
||||
<body>
|
||||
{{template "shop_header" .}}
|
||||
<main class="shop-page container">
|
||||
<nav class="breadcrumb">
|
||||
<a href="/">Главная</a>
|
||||
<span>/</span>
|
||||
<span>{{.Category.Name}}</span>
|
||||
</nav>
|
||||
<h1>{{.Category.Name}}</h1>
|
||||
{{if .Category.Description}}<p class="shop-hint">{{.Category.Description}}</p>{{end}}
|
||||
<div class="products">
|
||||
{{range .Products}}
|
||||
{{template "product_card" .}}
|
||||
{{else}}
|
||||
<p class="empty">В этой категории пока нет товаров.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -43,7 +43,7 @@
|
||||
<h2 class="section__title">Популярные категории</h2>
|
||||
<div class="categories">
|
||||
{{range .Categories}}
|
||||
<a href="#catalog" class="category-card">
|
||||
<a href="/category/{{.Slug}}" class="category-card">
|
||||
<span class="category-card__name">{{.Name}}</span>
|
||||
<span class="category-card__count">{{.Count}} товаров</span>
|
||||
</a>
|
||||
@@ -60,24 +60,7 @@
|
||||
</div>
|
||||
<div class="products">
|
||||
{{range .Products}}
|
||||
<article class="product-card">
|
||||
<div class="product-card__image">
|
||||
<img src="{{.ImageURL}}" alt="{{.Name}}" loading="lazy">
|
||||
<span class="product-card__badge">{{.Category}}</span>
|
||||
</div>
|
||||
<div class="product-card__body">
|
||||
<h3 class="product-card__title">{{.Name}}</h3>
|
||||
<p class="product-card__desc">{{plain .Description}}</p>
|
||||
<div class="product-card__footer">
|
||||
<span class="product-card__price">{{printf "%.0f" .Price}} ₽</span>
|
||||
<form method="POST" action="/cart/add">
|
||||
<input type="hidden" name="product_id" value="{{.ID}}">
|
||||
<input type="hidden" name="quantity" value="1">
|
||||
<button type="submit" class="btn btn--primary btn--sm">В корзину</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{{template "product_card" .}}
|
||||
{{else}}
|
||||
<p class="empty">Товары скоро появятся в каталоге.</p>
|
||||
{{end}}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{{define "product_card"}}
|
||||
<article class="product-card">
|
||||
<a href="/product/{{.ID}}" class="product-card__link">
|
||||
<div class="product-card__image">
|
||||
<img src="{{.ImageURL}}" alt="{{.Name}}" loading="lazy">
|
||||
{{if .HasSale}}<span class="product-card__sale">-{{.DiscountPercent}}%</span>{{end}}
|
||||
<span class="product-card__badge">{{.Category}}</span>
|
||||
</div>
|
||||
<div class="product-card__body">
|
||||
<h3 class="product-card__title">{{.Name}}</h3>
|
||||
<p class="product-card__desc">{{plain .Description}}</p>
|
||||
<div class="product-card__footer">
|
||||
<div class="price-block">
|
||||
{{if .HasSale}}
|
||||
<span class="price-block__old">{{printf "%.0f" .Price}} ₽</span>
|
||||
<span class="product-card__price price-block__sale">{{printf "%.0f" .SalePrice}} ₽</span>
|
||||
{{else}}
|
||||
<span class="product-card__price">{{printf "%.0f" .Price}} ₽</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<form method="POST" action="/cart/add" class="product-card__cart">
|
||||
<input type="hidden" name="product_id" value="{{.ID}}">
|
||||
<input type="hidden" name="quantity" value="1">
|
||||
<button type="submit" class="btn btn--primary btn--sm">В корзину</button>
|
||||
</form>
|
||||
</article>
|
||||
{{end}}
|
||||
@@ -6,9 +6,9 @@
|
||||
<span class="logo__text">Shop</span>
|
||||
</a>
|
||||
<nav class="nav">
|
||||
<a href="/#catalog" class="nav__link">Каталог</a>
|
||||
<a href="/#catalog" class="nav__link">Каталог</a>
|
||||
<a href="/#categories" class="nav__link">Категории</a>
|
||||
<a href="/#delivery" class="nav__link">Доставка</a>
|
||||
</nav>
|
||||
<div class="header__actions">
|
||||
{{if .User}}
|
||||
|
||||
@@ -19,8 +19,15 @@
|
||||
<div class="cart-item">
|
||||
<img src="{{.Product.ImageURL}}" alt="{{.Product.Name}}" class="cart-item__img">
|
||||
<div class="cart-item__info">
|
||||
<h3>{{.Product.Name}}</h3>
|
||||
<p class="cart-item__price">{{printf "%.0f" .Product.Price}} ₽</p>
|
||||
<h3><a href="/product/{{.ProductID}}">{{.Product.Name}}</a></h3>
|
||||
<div class="price-block">
|
||||
{{if .Product.HasSale}}
|
||||
<span class="price-block__old">{{printf "%.0f" .Product.Price}} ₽</span>
|
||||
<span class="price-block__sale">{{printf "%.0f" .Product.SalePrice}} ₽</span>
|
||||
{{else}}
|
||||
<span class="cart-item__price">{{printf "%.0f" .Product.Price}} ₽</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/cart/update" class="cart-item__qty">
|
||||
<input type="hidden" name="product_id" value="{{.ProductID}}">
|
||||
@@ -164,10 +171,24 @@
|
||||
{{range .Orders}}
|
||||
<div class="order-card">
|
||||
<div class="order-card__head">
|
||||
<strong>Заказ #{{.ID}}</strong>
|
||||
<span>{{.CreatedAt.Format "02.01.2006 15:04"}}</span>
|
||||
<span class="admin-badge admin-badge--ok">{{.Status}}</span>
|
||||
<div>
|
||||
<strong>Заказ #{{.ID}}</strong>
|
||||
<span class="order-card__date">{{.CreatedAt.Format "02.01.2006 15:04"}}</span>
|
||||
</div>
|
||||
<span class="order-status {{orderClass .Status}}">{{orderLabel .Status}}</span>
|
||||
</div>
|
||||
|
||||
{{if ne .Status "cancelled"}}
|
||||
<div class="order-timeline">
|
||||
{{range orderTimeline}}
|
||||
<div class="order-timeline__step {{if stepCurrent $.Status .}}order-timeline__step--current{{end}} {{if stepDone $.Status .}}order-timeline__step--done{{end}}">
|
||||
<span class="order-timeline__dot"></span>
|
||||
<span class="order-timeline__label">{{orderLabel .}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<ul class="order-card__items">
|
||||
{{range .Items}}
|
||||
<li>{{.ProductName}} × {{.Quantity}} — {{printf "%.0f" .Price}} ₽</li>
|
||||
|
||||
Reference in New Issue
Block a user