diff options
| author | unwox <me@unwox.com> | 2025-09-07 20:22:47 +0600 |
|---|---|---|
| committer | unwox <me@unwox.com> | 2025-09-07 22:16:39 +0600 |
| commit | 88d1725520afde9fe10a3daa1ad5c1c0a552f041 (patch) | |
| tree | 04069377658ac0b6c2fa903e0d2b42e8f2221031 | |
| parent | 4b0373bb42e21153f63d33f3546be9095d495f27 (diff) | |
small fixes
| -rw-r--r-- | bin/serve.fnl | 8 | ||||
| -rw-r--r-- | dicts.fnl | 12 | ||||
| -rw-r--r-- | forms.fnl | 60 | ||||
| -rw-r--r-- | pages/auth.fnl | 6 | ||||
| -rw-r--r-- | pages/shop/_product/edit.fnl | 10 | ||||
| -rw-r--r-- | pages/shop/_product/index.fnl | 22 | ||||
| -rw-r--r-- | pages/shop/add.fnl | 14 | ||||
| -rw-r--r-- | pages/shop/index.fnl | 22 | ||||
| -rw-r--r-- | static/style.css | 22 | ||||
| -rw-r--r-- | templates.fnl | 2 | ||||
| -rw-r--r-- | test.fnl | 26 |
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, @@ -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} @@ -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 "") @@ -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 {} "Чайная комната «Белая жаба»"] [: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"} |
