summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2025-09-07 20:22:47 +0600
committerunwox <me@unwox.com>2025-09-07 22:16:39 +0600
commit88d1725520afde9fe10a3daa1ad5c1c0a552f041 (patch)
tree04069377658ac0b6c2fa903e0d2b42e8f2221031
parent4b0373bb42e21153f63d33f3546be9095d495f27 (diff)
small fixes
-rw-r--r--bin/serve.fnl8
-rw-r--r--dicts.fnl12
-rw-r--r--forms.fnl60
-rw-r--r--pages/auth.fnl6
-rw-r--r--pages/shop/_product/edit.fnl10
-rw-r--r--pages/shop/_product/index.fnl22
-rw-r--r--pages/shop/add.fnl14
-rw-r--r--pages/shop/index.fnl22
-rw-r--r--static/style.css22
-rw-r--r--templates.fnl2
-rw-r--r--test.fnl26
11 files changed, 113 insertions, 91 deletions
diff --git a/bin/serve.fnl b/bin/serve.fnl
index a76de08..327060d 100644
--- a/bin/serve.fnl
+++ b/bin/serve.fnl
@@ -52,13 +52,17 @@
CREATE TABLE IF NOT EXISTS products(
name TEXT PRIMARY KEY,
creation_time TEXT NOT NULL,
+ position INTEGER NOT NULL DEFAULT 0,
+ published BOOLEAN NOT NULL DEFAULT false,
title TEXT NOT NULL,
type TEXT NOT NULL,
packaging TEXT NOT NULL,
description TEXT,
short_description TEXT NOT NULL,
- position INTEGER NOT NULL DEFAULT 0,
- published BOOLEAN NOT NULL DEFAULT false,
+ year INTEGER,
+ season TEXT,
+ region TEXT,
+ recommendations TEXT,
price_per REAL,
stock REAL,
vendor TEXT,
diff --git a/dicts.fnl b/dicts.fnl
index d7c72b6..4f42526 100644
--- a/dicts.fnl
+++ b/dicts.fnl
@@ -5,7 +5,15 @@
{:value "red" :label "Красный"}
{:value "green" :label "Зеленый"}
{:value "shu-puerh" :label "Шу пуэр"}
- {:value "sheng-puerh" :label "Шэн пуэр"}])
+ {:value "sheng-puerh" :label "Шэн пуэр"}
+ {:value "yellow" :label "Желтый"}
+ {:value "liu-bao" :label "Лю бао"}])
+
+(local tea-season
+ [{:value "spring" :label "Весна"}
+ {:value "summer" :label "Лето"}
+ {:value "autumn" :label "Осень"}
+ {:value "winter" :label "Зима"}])
(local tea-packaging
[{:value "loose" :label "Россыпь"}
@@ -19,4 +27,4 @@
(set result item.label)))
result)
-{: tea-type : tea-packaging : label}
+{: tea-type : tea-packaging : tea-season : label}
diff --git a/forms.fnl b/forms.fnl
index 0d75afb..ee5d08b 100644
--- a/forms.fnl
+++ b/forms.fnl
@@ -1,8 +1,8 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local lib (require :lib))
(local required-marker
- (<> [:span {:class "form-required-marker"} " (обяз.)"]))
+ (HTML [:span {:class "form-required-marker"} " (обяз.)"]))
(fn textarea-input [name label required? minlength maxlength help]
(local minlength (or minlength 0))
@@ -16,7 +16,7 @@
"Некорректная длина текста."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name}
label (if required? required-marker "")]
@@ -25,8 +25,8 @@
:maxlength (tostring maxlength)
:required required?})
(or value "")]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn text-input [name label required? minlength maxlength help]
(local minlength (or minlength 0))
@@ -40,7 +40,7 @@
"Некорректная длина текста."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name}
label (if required? required-marker "")]
@@ -49,8 +49,8 @@
:maxlength (tostring maxlength)
:required required?
:value value})]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn password-input [name label required? minlength maxlength help]
(local minlength (or minlength 0))
@@ -64,7 +64,7 @@
"Некорректная длина текста."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name}
label (if required? required-marker "")]
@@ -73,8 +73,8 @@
:maxlength (tostring maxlength)
:required required?
:value value})]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn url-input [name label required? help]
{: name : label : required? : help
@@ -85,14 +85,14 @@
"Некорректная длина ссылки."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name}
label (if required? required-marker "")]
[:input (fn [] {:type "url" :name name :id name :class "form-input"
:required required? :value value})]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn number-input [name label required? min max help]
(local min (or min 0))
@@ -106,15 +106,15 @@
"Некорректное число."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name} label (if required? required-marker "")]
[:input (fn [] {:type "number" :name name :id name :class "form-input"
:required required?
:min (tostring min) :max (tostring max)
:value (tostring value)})]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn checkbox-input [name label required? help]
{: name : label : required? : help
@@ -122,14 +122,14 @@
(fn [value] (= value "on"))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:input (fn [] {:type "checkbox" :name name :id name :class "form-input"
:required required?
:checked (or (= value "on") (= value true))})]
[:label {:class "form-label" :for name} label (if required? required-marker "")]
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn file-input [name label required? accept thumbnail-width help]
{:type "file" : name : label : required? : help
@@ -145,21 +145,21 @@
(local empty-value? (lib.empty? value))
(local required? (and empty-value? required?))
- (<>
+ (HTML
[:div {:class "form-row"}
[:div {:class "d-flex gap-1"}
(if (and value (lib.ends-with? value ".jpg"))
- (<> [:img {:class "form-file-img" :src (.. "/static/files/" value)}])
+ (HTML [:img {:class "form-file-img" :src (.. "/static/files/" value)}])
"")
[:div {}
[:label {:class "form-label" :for name} label (if required? required-marker "")]
[:input (fn [] {:type "file" :name name :id name :class "form-input"
:required required? :accept accept})]]]
(if (not empty-value?)
- (<> [:input {:type "hidden" :name (.. name "_previous") :value value}])
+ (HTML [:input {:type "hidden" :name (.. name "_previous") :value value}])
"")
- (if error (<> [:div {:class "form-error"} error]) "")
- (if help (<> [:div {:class "form-help"} help]) "")]))})
+ (if error (HTML [:div {:class "form-error"} error]) "")
+ (if help (HTML [:div {:class "form-help"} help]) "")]))})
(fn select-input [name label required? options help]
{: name : label : required? : options : help
@@ -172,7 +172,7 @@
(if exists? nil "Некорректное значение."))
:html
(fn [value error]
- (<>
+ (HTML
[:div {:class "form-row"}
[:label {:class "form-label" :for name} label (if required? required-marker "")]
[:select (fn [] {:name name :id name
@@ -180,7 +180,7 @@
[:option [:selected "selected"] ""]
(table.concat
(icollect [_ option (ipairs options)]
- (<>
+ (HTML
[:option
(fn [] {:value option.value :selected (= value option.value)})
option.label])))]
@@ -188,18 +188,18 @@
(if help [:div {:class "form-help"} help] "")]))})
(fn render-form [form data errors]
- (<>
+ (HTML
[:form {:class "form" :enctype "multipart/form-data" :method "POST"}
(table.concat
(lib.append
(icollect [_ group (ipairs form)]
- (<>
+ (HTML
[:div {:class "form-group"}
[:h3 {:class "form-subheader"} group.title]
(table.concat
(icollect [_ field (ipairs group.fields)]
(field.html (. data field.name) (. errors field.name))))]))
- (<> [:button {:type "submit"} "Сохранить"])))]))
+ (HTML [:button {:type "submit"} "Сохранить"])))]))
(fn convert-values-from-html [form data db]
(each [_ group (ipairs form)]
diff --git a/pages/auth.fnl b/pages/auth.fnl
index 9cb7a66..c6c1832 100644
--- a/pages/auth.fnl
+++ b/pages/auth.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local forms (require :forms))
(local lib (require :lib))
(local templates (require :templates))
@@ -11,10 +11,10 @@
(fn content [data errors]
(set data.password nil)
- [(<>
+ [(HTML
[:div {:class "side"}
(templates.header "/auth")])
- (<>
+ (HTML
[:section {:class "content"}
[:div {:class "mb-1"} [:a {:href "/"} "⟵ Обратно на главную"]]
[:h2 {} "Войти"]
diff --git a/pages/shop/_product/edit.fnl b/pages/shop/_product/edit.fnl
index 9465d94..7e7548d 100644
--- a/pages/shop/_product/edit.fnl
+++ b/pages/shop/_product/edit.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local templates (require :templates))
(local {: product-form} (require :pages.shop.add))
(local forms (require :forms))
@@ -14,6 +14,10 @@
products.title,
products.position,
products.short_description,
+ products.recommendations,
+ products.year,
+ products.season,
+ products.region,
products.stock,
products.type,
products.packaging,
@@ -42,10 +46,10 @@
(error "empty data for insert SQL-statement"))))
(fn content [form data errors authenticated?]
- [(<>
+ [(HTML
[:div {:class "side"}
(templates.header "/shop" authenticated?)])
- (<>
+ (HTML
[:div {:class "content"}
[:div {:class "mb-1"}
[:a {:href (.. "/shop/" data.name)} "⟵ Обратно к товару"]]
diff --git a/pages/shop/_product/index.fnl b/pages/shop/_product/index.fnl
index 722c952..2904b61 100644
--- a/pages/shop/_product/index.fnl
+++ b/pages/shop/_product/index.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local templates (require :templates))
(local dicts (require :dicts))
(local lib (require :lib))
@@ -41,25 +41,25 @@
(for [i 1 5]
(table.insert images (. product (.. "image" i))))
- [(<>
+ [(HTML
[:div {:class "side"}
(templates.header "/shop" authenticated?)])
- (<>
+ (HTML
[:div {:class "content"}
[:div {:class "mb-1"} [:a {:href "/shop"} "⟵ Обратно к списку"]]
(let [link (.. "/static/files/" product.image1)]
- (<> [:a {:href link :target "_blank"}
- [:img {:class "product-page-img-mobile mb-1-5"
- :src (.. link "-thumbnail.jpg")}]]))
+ (HTML [:a {:href link :target "_blank"}
+ [:img {:class "product-page-img-mobile mb-1-5"
+ :src (.. link "-thumbnail.jpg")}]]))
[:div {:class "product-page-layout"}
[:div {}
[:h2 {:class "product-page-title mb-1"} product.title]
[:section {:class "mb-2"}
(if authenticated?
- (<> [:div {:class "mb-0-5"}
- [:a {:href (.. "/shop/" product.name "/edit")}
- "✎ Редактировать"]])
+ (HTML [:div {:class "mb-0-5"}
+ [:a {:href (.. "/shop/" product.name "/edit")}
+ "✎ Редактировать"]])
"")
[:div {:class "mb-0-5" :style "font-style: italic;"}
(or (dicts.label dicts.tea-type product.type) product.type) ", "
@@ -71,8 +71,8 @@
(table.concat
(icollect [idx image (ipairs images)]
(let [link (.. "/static/files/" image)]
- (<> [:a {:href link :target "_blank"}
- [:img {:class "product-page-img" :src (.. link "-thumbnail.jpg")}]]))))]]])])
+ (HTML [:a {:href link :target "_blank"}
+ [:img {:class "product-page-img" :src (.. link "-thumbnail.jpg")}]]))))]]])])
(fn render [request db authenticated?]
(let [product (find-product db request.params._product)]
diff --git a/pages/shop/add.fnl b/pages/shop/add.fnl
index 8fcfdf1..5b5bfc5 100644
--- a/pages/shop/add.fnl
+++ b/pages/shop/add.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local templates (require :templates))
(local dicts (require :dicts))
(local forms (require :forms))
@@ -17,8 +17,14 @@
(forms.text-input "title" "Полное название" true 0 200)
(forms.select-input "type" "Вид чая" true dicts.tea-type)
(forms.select-input "packaging" "Упаковка" true dicts.tea-packaging)
+ (forms.number-input "year" "Год изготовления" false 1950
+ (tonumber (os.date "%Y")))
+ (forms.select-input "season" "Сезон изготовления" false dicts.tea-season)
+ (forms.text-input "region" "Место изготовления" false 0 500)
(forms.textarea-input "short_description" "Короткое описание" true 0 1000)
- (forms.textarea-input "description" "Полное описание" true 0 20000)
+ (forms.textarea-input "description" "Полное описание" false 0 20000)
+ (forms.textarea-input "recommendations" "Рекомендации по завариванию"
+ false 0 20000)
(forms.number-input "price_per" "Цена" true 0 100000
"За штуку или грамм.")
(forms.number-input "stock" "Сколько в наличии" true 0 100000
@@ -53,10 +59,10 @@
(error "empty data for insert SQL-statement"))))
(fn content [form data errors authenticated?]
- [(<>
+ [(HTML
[:div {:class "side"}
(templates.header "/shop" authenticated?)])
- (<>
+ (HTML
[:div {:class "content"}
[:div {:class "mb-1"}
[:a {:href "/shop"} "⟵ Обратно к списку"]]
diff --git a/pages/shop/index.fnl b/pages/shop/index.fnl
index 5a96ab2..bbe08fa 100644
--- a/pages/shop/index.fnl
+++ b/pages/shop/index.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local lib (require :lib))
(local dicts (require :dicts))
(local templates (require :templates))
@@ -42,16 +42,16 @@
;; (if (< 0 product.stock)
;; (each [_ q (ipairs (quantity-steps product.stock 50))]
;; (table.insert quantity-options
- ;; (<>
+ ;; (HTML
;; [:option {:value (tostring q)}
;; (.. q " грамм за " (* product.price-per q) "₽")])))
- ;; (table.insert quantity-options (<> [:option {:value "0"} "Товар закончился"])))
+ ;; (table.insert quantity-options (HTML [:option {:value "0"} "Товар закончился"])))
(local images [])
(for [i 2 5]
(table.insert images (. product (.. "image" i))))
- (<>
+ (HTML
[:section {:class (.. "shop-item"
(if (not product.published)
" shop-item-not-published" ""))}
@@ -61,7 +61,7 @@
:src (.. "/static/files/" (. product.image1) "-thumbnail.jpg")}]
(table.concat
(icollect [idx image (ipairs images)]
- (<>
+ (HTML
[:img {:class "shop-item-img" :src (.. "/static/files/" image "-thumbnail.jpg")
:loading "lazy"
:style (.. "z-index: " (+ idx 2) ";"
@@ -79,11 +79,11 @@
[:div {} product.short-description]]))
(fn content [db basket basket-total authenticated?]
- [(<>
+ [(HTML
[:div {:class "side"}
(templates.header "/shop" authenticated?)
(if (< 0 (# basket))
- (<>
+ (HTML
[:article {:class "article"}
[:h2 {} "Корзина"]
[:div {}
@@ -94,14 +94,14 @@
[:div {:class "basket-total"} (.. "Итого: " basket-total "₽")]
[:a {:href "/shop/order"} "Оформить заказ"]])
"")])
- (<>
+ (HTML
[:div {:class "content"}
[:div {:class "mb-1"} [:a {:href "/"} "⟵ Обратно на главную"]]
[:h2 {:class "mb-1 product-page-title"}
"Магазин"
(if authenticated?
- (<> [:a {:style "font-size: 1rem; margin-left: 0.75rem;"
- :href (.. "/shop/add")} "+ Добавить"])
+ (HTML [:a {:style "font-size: 1rem; margin-left: 0.75rem;"
+ :href (.. "/shop/add")} "+ Добавить"])
"")]
[:div {:class "shop-items"}
(let [products (all-products db authenticated?)]
@@ -109,7 +109,7 @@
(table.concat
(icollect [_ v (ipairs products)]
(item-template v)))
- (<> [:em {} "Пока что здесь ничего нет!"])))]])])
+ (HTML [:em {} "Пока что здесь ничего нет!"])))]])])
(fn create-order [db]
(let [id (_G.must (luna.crypto.random-string 64))]
diff --git a/static/style.css b/static/style.css
index 39450f6..6b25428 100644
--- a/static/style.css
+++ b/static/style.css
@@ -14,7 +14,7 @@
font-family: "Open Sans";
font-weight: regular;
font-style: italic;
- src: url("/static/fonts/OpenSans-RegularItalic.ttf") format("truetype");
+ src: url("/static/fonts/OpenSans-Italic.ttf") format("truetype");
}
@font-face {
@@ -79,7 +79,7 @@ body {
font-family: "Open Sans";
font-weight: regular;
font-style: italic;
- src: url("/static/fonts/OpenSans-RegularItalic.ttf") format("truetype");
+ src: url("/static/fonts/OpenSans-Italic.ttf") format("truetype");
}
@font-face {
@@ -168,15 +168,6 @@ nav a.active {
height: 215px;
}
-.logo-glasses {
- position: absolute;
- top: -10px;
- left: 35px;
- width: 70px;
- object-fit: contain;
- pointer-events: none;
-}
-
.logo img,
.logo a {
height: 95px;
@@ -187,6 +178,15 @@ nav a.active {
font-weight: 900;
}
+.logo .glasses {
+ position: absolute;
+ top: -10px;
+ left: 35px;
+ width: 70px;
+ object-fit: contain;
+ pointer-events: none;
+}
+
h1,
h2,
h3,
diff --git a/templates.fnl b/templates.fnl
index 07680f8..fb9a882 100644
--- a/templates.fnl
+++ b/templates.fnl
@@ -35,7 +35,7 @@
[:article {:class "article"}
[:div {:class "logo"}
(if authenticated?
- (HTML [:img {:class "logo-glasses" :src "/static/glasses.png"
+ (HTML [:img {:class "glasses" :src "/static/glasses.png"
:alt "Солнцезащитные очки"}])
"")
(if (~= current-path "")
diff --git a/test.fnl b/test.fnl
index df0df6d..d0cae36 100644
--- a/test.fnl
+++ b/test.fnl
@@ -1,4 +1,4 @@
-(import-macros {:compile-html <>} :macros)
+(import-macros {:compile-html HTML} :macros)
(local fennel (require :vendor.fennel))
(fn improve-typography [text]
@@ -20,11 +20,11 @@
(fn header [current-path]
(local logo
- (<> [:img {:class "logo" :src "/static/logo.svg"
+ (HTML [:img {:class "logo" :src "/static/logo.svg"
:alt "Белая жаба в мультяшном стиле с чайником на голове"}]))
- (<> [:article {:class "article"}
- (if (~= current-path "") (<> [:a {:href "/"} logo]) logo)
+ (HTML [:article {:class "article"}
+ (if (~= current-path "") (HTML [:a {:href "/"} logo]) logo)
[:h1 {} "Чайная комната «Белая&nbsp;жаба»"]
[:nav {}
[:a {:href "/shop" :class "active"}
@@ -56,35 +56,35 @@
рублей с человека.")})
(print
- (<> [:div (fn [] {:huemoe nil :hello "world" :required true}) "whatever"]))
+ (HTML [:div (fn [] {:huemoe nil :hello "world" :required true}) "whatever"]))
; (macrodebug
-; (<> [:div (fn [] {:hello "world" :required true}) "whatever"]))
+; (HTML [:div (fn [] {:hello "world" :required true}) "whatever"]))
; (macrodebug
-; (<>
+; (HTML
; [:div {:class "side"}
; (unpack [])]))
; (macrodebug
-; (<>
+; (HTML
; [:div {:class "side"}
; [:article {:class "article"}
; (header "")
; [:h2 {} "Адрес"]
; [:p {} "test!"]]]))
-; (print (<>
+; (print (HTML
; [:img {:class "side"}]))
; (local hello {:world "test"})
; (print
; (fennel.view
-; [(<> [:div {:class "first"} "11111"])
-; (<> [:div {:class "second"} "22222"])]))
+; [(HTML [:div {:class "first"} "11111"])
+; (HTML [:div {:class "second"} "22222"])]))
-; (print (<>
+; (print (HTML
; [:div {:class "side"}
; [:article {:class "article"}
; (header "")
@@ -94,7 +94,7 @@
; [:p {} "<script>doesnt work!</script>"]]]))
; (macrodebug
-; (<>
+; (HTML
; [:div {:class "side"}
; (header "")
; [:article {:class "article"}