summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/serve.fnl3
-rw-r--r--dicts.fnl2
-rw-r--r--pages/shop/_product/edit.fnl7
-rw-r--r--pages/shop/add.fnl5
-rw-r--r--pages/shop/index.fnl92
-rwxr-xr-xrun.sh4
-rw-r--r--shop.fnl11
-rw-r--r--static/style.css4
8 files changed, 98 insertions, 30 deletions
diff --git a/bin/serve.fnl b/bin/serve.fnl
index 0948a83..a1d1737 100644
--- a/bin/serve.fnl
+++ b/bin/serve.fnl
@@ -43,6 +43,9 @@
expires_at TEXT NOT NULL
);
+ CREATE VIRTUAL TABLE IF NOT EXISTS products_search
+ USING fts5(title, short_description, name);
+
CREATE TABLE IF NOT EXISTS products(
name TEXT PRIMARY KEY,
creation_time TEXT NOT NULL,
diff --git a/dicts.fnl b/dicts.fnl
index a8fb52c..a705d07 100644
--- a/dicts.fnl
+++ b/dicts.fnl
@@ -10,7 +10,7 @@
{:value "liu-bao" :label "Лю бао"}
{:value "teapot" :label "Чайник"}
{:value "gaiwan" :label "Гайвань"}
- {:value "pourer" :label "Чахай"}])])
+ {:value "pourer" :label "Чахай"}])
(local tea-season
[{:value "spring" :label "Весна"}
diff --git a/pages/shop/_product/edit.fnl b/pages/shop/_product/edit.fnl
index 3e4f2f0..3995096 100644
--- a/pages/shop/_product/edit.fnl
+++ b/pages/shop/_product/edit.fnl
@@ -2,6 +2,7 @@
(local templates (require :templates))
(local {: product-form} (require :pages.shop.add))
(local forms (require :forms))
+(local shop (require :shop))
(local lib (require :lib))
(fn find-product [db name]
@@ -69,8 +70,10 @@
authenticated?)))
(do
(lib.with-tx db
- (fn [tx] (update-product tx product-form data
- {:name request.params._product})))
+ (fn [tx]
+ (update-product tx product-form data
+ {:name request.params._product})
+ (shop.update-search-index tx)))
(values 302 {:Location (.. "/shop/" data.name)} ""))))
(values 200 {}
(templates.base
diff --git a/pages/shop/add.fnl b/pages/shop/add.fnl
index 01b83d6..460cc81 100644
--- a/pages/shop/add.fnl
+++ b/pages/shop/add.fnl
@@ -1,6 +1,7 @@
(import-macros {:compile-html HTML} :macros)
(local templates (require :templates))
(local dicts (require :dicts))
+(local shop (require :shop))
(local forms (require :forms))
(local lib (require :lib))
@@ -88,7 +89,9 @@
authenticated?)))
(do
(lib.with-tx db
- (fn [tx] (insert-product tx product-form request.form)))
+ (fn [tx]
+ (insert-product tx product-form request.form)
+ (shop.update-search-index tx)))
(values 302 {:Location "/shop"} ""))))
(values 200 {} (templates.base (content product-form {} {}
authenticated?))))))
diff --git a/pages/shop/index.fnl b/pages/shop/index.fnl
index da83114..29d93b6 100644
--- a/pages/shop/index.fnl
+++ b/pages/shop/index.fnl
@@ -4,11 +4,33 @@
(local dicts (require :dicts))
(local templates (require :templates))
-(fn all-products [db authenticated?]
+(fn all-products [db filters authenticated?]
+ (local where-stmts [])
+ (local where-args [])
+ (var has-search-query? false)
+
+ (when (not authenticated?)
+ (table.insert where-stmts "products.published = true"))
+
+ (when filters.type
+ (table.insert where-stmts "products.type = ?")
+ (table.insert where-args filters.type))
+
+ (when filters.search
+ (table.insert where-stmts "products_search MATCH ?")
+ (table.insert where-args filters.search)
+ (set has-search-query? true))
+
(local where
- (if (not authenticated?)
- "WHERE products.published = true"
+ (if (< 0 (# where-stmts))
+ (.. "WHERE " (table.concat where-stmts " AND\n"))
""))
+
+ (local from-sql
+ (if has-search-query?
+ "products_search INNER JOIN products ON products_search.name = products.name"
+ "products"))
+
(_G.must
(luna.db.query-assoc db
(..
@@ -27,9 +49,12 @@
products.image3,
products.image4,
products.image5
- FROM products "
+ FROM " from-sql " "
where
- " ORDER BY products.position") [])))
+ " ORDER BY products.position ASC,
+ products.creation_time DESC"
+ (if has-search-query? ", rank" ""))
+ where-args)))
(fn item-template [product basket]
(local item-url (.. "/shop/" product.name))
@@ -65,7 +90,7 @@
(templates.product-overview product "mb-0-25 font-size-0-875")
[:div {} product.short-description]]))
-(fn content [db basket authenticated?]
+(fn content [db products filters basket authenticated?]
[(HTML
[:aside {}
(templates.header "/shop" authenticated?)
@@ -77,25 +102,46 @@
[:div {:class "content"}
[:div {:class "back"} [:a {:href "/"} "⟵ Обратно на главную"]]
[:h2 {:class "product-page-title"} "Магазин"]
- (if authenticated?
- (HTML
- [:div {:class "mb-1" :style "margin-top: -0.5rem"}
- [:a {:style "white-space: nowrap"
- :href (.. "/shop/add")} "+ Добавить"]
- [:a {:style "white-space: nowrap; margin-left: 1rem;"
- :href (.. "/shop/order/list")} "☰ Список заказов"]])
- "")
- [:div {:class "shop-items"}
- (let [products (all-products db authenticated?)]
- (if (< 0 (# products))
- (table.concat
- (icollect [_ v (ipairs products)]
- (item-template v basket)))
- (HTML [:em {} "Пока что здесь ничего нет!"])))]])])
+ (if authenticated?
+ (HTML
+ [:div {:class "mb-1" :style "margin-top: -0.5rem"}
+ [:a {:style "white-space: nowrap"
+ :href (.. "/shop/add")} "+ Добавить"]
+ [:a {:style "white-space: nowrap; margin-left: 1rem;"
+ :href (.. "/shop/order/list")} "☰ Список заказов"]])
+ "")
+ [:form {:class "d-flex gap-0-5 mb-1"}
+ [:input {:name "search" :type "search"
+ :placeholder "Поиск" :value (or filters.search "")}]
+ [:select {:name "type"}
+ [:option {:value ""} "Все товары"]
+ (table.concat
+ (icollect [_ v (ipairs dicts.product-type)]
+ (HTML [:option (fn [] {:value v.value
+ :selected (= filters.type v.value)})
+ v.label])))]
+ [:button {:type "submit"} "Применить"]]
+ [:div {:class "shop-items"}
+ (if (< 0 (# products))
+ (table.concat
+ (icollect [_ v (ipairs products)]
+ (item-template v basket)))
+ (HTML [:em {} "Пока что здесь ничего нет!"]))]])])
(fn render [request db authenticated?]
(let [order-id (shop.order-id request)
- basket (if order-id (shop.basket db order-id) [])]
- (values 200 {} (templates.base (content db basket authenticated?)))))
+ basket (if order-id (shop.basket db order-id) [])
+ type (if (and request.query.type
+ (not (lib.empty? (. request.query.type 1))))
+ (. request.query.type 1)
+ nil)
+ search (if (and request.query.search
+ (not (lib.empty? (. request.query.search 1))))
+ (. request.query.search 1)
+ nil)
+ filters { : type : search }
+ products (all-products db filters authenticated?)]
+ (values 200 {} (templates.base
+ (content db products filters basket authenticated?)))))
{: render}
diff --git a/run.sh b/run.sh
index 235fcd6..2b11a1f 100755
--- a/run.sh
+++ b/run.sh
@@ -9,12 +9,12 @@ usage () {
serve () {
echo "running in jit"
- go run -tags jit ../. -n ${1:-1} bin/serve.fnl
+ go run -tags jit,fts5 ../. -n ${1:-1} bin/serve.fnl
}
debug () {
echo "running debug version in jit"
- go run -tags jit ../. -n ${1:-1} -D bin/serve.fnl
+ go run -tags jit,fts5 ../. -n ${1:-1} -D bin/serve.fnl
}
deploy () {
diff --git a/shop.fnl b/shop.fnl
index 9711095..24ff3d9 100644
--- a/shop.fnl
+++ b/shop.fnl
@@ -124,6 +124,14 @@
LIMIT 1"
[order-id product-name])))))
+(fn update-search-index [tx]
+ (_G.must
+ (luna.db.exec-tx tx "DELETE FROM products_search" []))
+ (_G.must
+ (luna.db.exec-tx tx "INSERT INTO products_search
+ SELECT title, short_description, name
+ FROM products;" [])))
+
{: create-order
: place-order
: finish-order
@@ -132,4 +140,5 @@
: create-order-line
: delete-order-line
: basket
- : in-basket?}
+ : in-basket?
+ : update-search-index}
diff --git a/static/style.css b/static/style.css
index ea8243f..17b1d26 100644
--- a/static/style.css
+++ b/static/style.css
@@ -560,6 +560,10 @@ p {
gap: 0.25rem !important;
}
+.gap-0-5 {
+ gap: 0.5rem !important;
+}
+
.gap-1 {
gap: 1rem !important;
}