diff options
| -rw-r--r-- | bin/serve.fnl | 134 | ||||
| -rw-r--r-- | lib/string.fnl | 19 | ||||
| -rw-r--r-- | spellfix.fnl | 2 | ||||
| -rw-r--r-- | static/favicon.png | bin | 0 -> 3720 bytes | |||
| -rw-r--r-- | static/style.css | 17 | ||||
| -rw-r--r-- | texts.fnl | 101 |
6 files changed, 225 insertions, 48 deletions
diff --git a/bin/serve.fnl b/bin/serve.fnl index 4cbb905..62e3962 100644 --- a/bin/serve.fnl +++ b/bin/serve.fnl @@ -11,7 +11,7 @@ (local str (require :lib.string)) (local texts (require :texts)) (local spellfix (require :spellfix)) -(local {: must} (require :lib.utils)) +(local {: must : measure} (require :lib.utils)) (local ozchai (require :parser.ozchai)) (local ipuer (require :parser.ipuer)) @@ -39,6 +39,16 @@ (string.gsub """ "\"") (string.gsub "&" "&")))) +(fn category-menu-path [category] + (. {"Красный чай" "red-tea" + "Шен пуэр" "sheng-puer" + "Шу пуэр" "shou-puer" + "Улун" "oolong" + "Зеленый чай" "green-tea" + "Белый чай" "white-tea" + "Желтый чай" "yellow-tea" + "Посуда" "teaware"} category)) + (fn get-query-string [query key] (if (and query (. query key) @@ -55,9 +65,9 @@ (tonumber (. query key 1)) nil)) -(fn collect-form [params] +(fn collect-form [params category] {:query (str.trim (or (get-query-string params "query") "")) - :tags (filter #(~= "" $2) (or params.tags [])) + :tags (filter #(~= "" $2) (or params.tags [category])) :min-price (get-query-number params "min-price") :max-price (get-query-number params "max-price") :price-per (= "on" (get-query-string params "price-per"))}) @@ -140,7 +150,7 @@ (if (. query-synonyms q) (.. "(" q "* OR " (. query-synonyms q) "*)") (.. q "*"))) - (str.split query)) + (str.split query " ")) " AND "))) (when (and min-price (< 0 min-price)) (if price-per @@ -202,29 +212,24 @@ (fn site-name-template [name] (if (= name "ipuer") - [:a {:class "site-icon" :href "https://ipuer.ru" - :alt "Логотип Институт чай пуэр"} - [:img {:src "/static/ipuer.jpg"}] + [:a {:class "site-icon" :href "https://ipuer.ru"} + [:img {:src "/static/ipuer.jpg" :alt "Логотип Институт чай пуэр"}] "Институт чая пуэр"] (= name "artoftea") - [:a {:class "site-icon" :href "https://artoftea.ru" - :alt "Логотип Art of tea"} - [:img {:src "/static/artoftea.png"}] + [:a {:class "site-icon" :href "https://artoftea.ru"} + [:img {:src "/static/artoftea.png" :alt "Логотип Art of tea"}] "Art of tea"] (= name "ozchai") - [:a {:class "site-icon" :href "https://ozchai.ru" - :alt "Логотип #OZCHAI"} - [:img {:src "/static/ozchai.ico"}] + [:a {:class "site-icon" :href "https://ozchai.ru"} + [:img {:src "/static/ozchai.ico" :alt "Логотип #OZCHAI"}] "Чайная #OZCHAI"] (= name "clubcha") - [:a {:class "site-icon" :href "https://clubcha.ru" - :alt "Логотип Железный Феникс"} - [:img {:src "/static/clubcha.png"}] + [:a {:class "site-icon" :href "https://clubcha.ru"} + [:img {:src "/static/clubcha.png" :alt "Логотип Железный Феникс"}] "Железный Феникс"] (= name "chaekshop") - [:a {:class "site-icon" :href "https://chaekshop.ru" - :alt "Логотип Интернет-магазин фермерского китайского чая «Чаёк»"} - [:img {:src "/static/chaekshop.svg"}] + [:a {:class "site-icon" :href "https://chaekshop.ru"} + [:img {:src "/static/chaekshop.svg" :alt "Логотип Интернет-магазин «Чаёк»"}] "Интернет-магазин «Чаёк»"] "")) @@ -267,7 +272,7 @@ (if (< page last-page) [:a {:href (form->path (+ page 1) form)} "→"] "")] - [:div {} "Всего результатов: " [:strong {} (string.format "%d" total)]]] + [:div {} "Всего: " [:strong {} (string.format "%d" total)]]] "")) (fn aside-template [form paginator] @@ -275,9 +280,9 @@ [:div {:class "aside-content"} (if (not (form-empty? form)) [:a {:href "/" :style "display: block;"} - [:img {:class "logo" :src "static/logo.svg" + [:img {:class "logo" :src "/static/logo.svg" :alt "Логотип meicha.ru" :title "Логотип meicha.ru"}]] - [:img {:class "logo" :src "static/logo.svg" + [:img {:class "logo" :src "/static/logo.svg" :alt "Логотип meicha.ru" :title "Логотип meicha.ru"}]) [:form {:class "form"} [:input {:type :search :name "query" :value form.query @@ -305,22 +310,49 @@ [:button {:type :submit} "Искать"]] paginator]]) +(fn menu-template [] + [:nav {:class "menu"} + [:a {:href "/red-tea"} "Красный чай"] + [:a {:href "/sheng-puer"} "Шен пуэр"] + [:a {:href "/shou-puer"} "Шу пуэр"] + [:a {:href "/oolong"} "Улун"] + [:a {:href "/green-tea"} "Зеленый чай"] + [:a {:href "/white-tea"} "Белый чай"] + [:a {:href "/yellow-tea"} "Желтый чай"] + [:a {:href "/teaware"} "Посуда"]]) + (fn base-template [form page total items] (local paginator (paginator-template form page 48 total)) + (local menu-path + (if (and form.tags (< 0 (# form.tags))) + (category-menu-path (. form.tags 1)) + nil)) (local spellfix-suggestion (if (and (not (str.empty? form.query)) items (< 0 (# items))) nil (spellfix.guess form.query))) - [:html {:lang "en"} + [:html {:lang "ru-RU"} [:head {} - [:meta {:charset "UTF-8"}] - [:link {:rel :stylesheet :href "static/style.css"}] - [:title {} "A new cool web server for lua"]] + [:meta {:charset "utf-8"}] + [:meta {:name "viewport" :content "width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=5.0"}] + [:link {:rel "stylesheet" :href "/static/style.css"}] + [:link {:rel "icon" :href "/static/favicon.png"}] + [:title {} (if (str.empty? form.query) + texts.meta-title + (.. form.query " | " texts.meta-title))] + [:meta {:name "description" :content texts.meta-description}]] [:body {} [:div {:class "container"} [:div {:class "content"} (aside-template form paginator) [:section {} + (menu-template) + (if (. form.tags 1) + [:h1 {} (. form.tags 1)] + "") + (if (and menu-path (. texts (.. menu-path "-description"))) + [:NO-ESCAPE (. texts (.. menu-path "-description"))] + "") (if (< 0 (# items)) [:div {:class "list"} (table.unpack (map #(item-template $2) items))] @@ -333,20 +365,40 @@ [:footer {} paginator]]]]]]) (fn root-handler [{: path : query}] - (if (= path "/") - (let [headers {:content-type "text/html"} - page (or (get-query-number query "page") 1) - form (collect-form query) - {: results : total} - (if (not (form-empty? form)) - (query-products form page) - {:total 48 :results (random-products 48)})] - (values - 200 headers - (html.render - (base-template form page total results) - true))) - (values 404 {} "not found"))) + (fn respond [query category] + (let [headers {:content-type "text/html"} + page (or (get-query-number query "page") 1) + form (collect-form query category) + {: results : total} + (if (not (form-empty? form)) + (measure "query products" #(query-products form page)) + {:total 48 :results (measure "random products" #(random-products 48))})] + (values + 200 headers + (.. "<!DOCTYPE html>\n" + (measure "render" + #(html.render + (base-template form page total results) + true)))))) + + (match (str.split path "/") + ["red-tea"] (respond query "Красный чай") + ["sheng-puer"] (respond query "Шен пуэр") + ["shou-puer"] (respond query "Шу пуэр") + ["oolong"] (respond query "Улун") + ["green-tea"] (respond query "Зеленый чай") + ["white-tea"] (respond query "Белый чай") + ["yellow-tea"] (respond query "Желтый чай") + ["teaware"] (respond query "Посуда") + [] (respond query) + _ (values 404 {} "not found"))) + +(fn robots-handler [] + (values 200 {:content-type "text/plain"} "User-agent: *\nAllow: /")) -(must (luna.router.route "GET /" root-handler)) +(must (luna.router.route + "GET /" + (fn [req] + (measure "root handler" #(root-handler req))))) +(must (luna.router.route "GET /robots.txt" robots-handler)) (must (luna.router.static "GET /static/" "static/")) diff --git a/lib/string.fnl b/lib/string.fnl index 1696a64..6538827 100644 --- a/lib/string.fnl +++ b/lib/string.fnl @@ -12,11 +12,22 @@ (table.insert result (must (luna.utf8.sub str i 1)))) result) -(fn split [str] - (accumulate [res [] v _ (str:gmatch "%S+")] +(fn split [str delimiter] + (if (empty? str) + [] (do - (table.insert res v) - res))) + (local result {}) + (local len (# str)) + (var cursor 1) + (var (start end) (str:find delimiter)) + (while start + (when (< cursor start) + (table.insert result (str:sub cursor (- start 1)))) + (set cursor (+ end 1)) + (set (start end) (str:find delimiter cursor))) + (when (<= cursor len) + (table.insert result (str:sub cursor len))) + result))) (fn ends-with [str end] (= (string.sub str (- (# end))) end)) diff --git a/spellfix.fnl b/spellfix.fnl index 00642ac..5ecb870 100644 --- a/spellfix.fnl +++ b/spellfix.fnl @@ -301,7 +301,7 @@ (array.sort index #(< $1.distance $2.distance))) (local most-similar (. sorted-index 1)) most-similar.word) - (str.split string)) + (str.split string " ")) " ")) (if (~= result string) result diff --git a/static/favicon.png b/static/favicon.png Binary files differnew file mode 100644 index 0000000..644e91f --- /dev/null +++ b/static/favicon.png diff --git a/static/style.css b/static/style.css index 39f3685..1dc0bc2 100644 --- a/static/style.css +++ b/static/style.css @@ -24,6 +24,17 @@ body { top: 3rem; } +.menu { + display: flex; + gap: 0.75rem 1.5rem; + flex-wrap: wrap; + margin-bottom: 2rem; +} + +.menu a { + color: blue; +} + .list { display: flex; flex-wrap: wrap; @@ -83,6 +94,10 @@ body { width: 10rem; } +.form { + margin-bottom: 1rem; +} + .form input[type="search"], .form select, .form-price, @@ -103,7 +118,7 @@ body { .form-price input { flex: 1; - max-width: calc(50% - 0.5rem); + max-width: calc(50% - 1rem); } .form-price-per input { @@ -1,2 +1,101 @@ {:no-results "По вашему запросу нет результатов. Попробуйте изменить параметры поиска." - :no-results-with-suggestion "По вашему запросу нет результатов. Возможно, вы имели в виду <a href=\"?query=%s\">%s</a>?"} + :no-results-with-suggestion "По вашему запросу нет результатов. Возможно, вы имели в виду <a href=\"?query=%s\">%s</a>?" + :meta-title "meicha.ru — каталог китайского чая" + :meta-description "Каталог китайского чая и связанных товаров, автоматически собирающий данные с сайтов чайных." + :red-tea-description " +<p>Красный китайский чай, известный за пределами Китая как черный чай, имеет несколько характерных особенностей:</p> +<ol> +<li>Процесс ферментации: Листья проходят полную ферментацию, что придаёт чаю насыщенный вкус и тёмный цвет.</li> +<li>Вкус: Красный чай обычно обладает крепким, богатым вкусом с нотами карамели, шоколада или фруктов.</li> +<li>Аромат: У него яркий и глубокий аромат, который может варьироваться от сладковатого до древесного.</li> +<li>Цвет настоя: Напиток имеет тёмно-красный или бурый цвет.</li> +<li>Польза для здоровья: Содержит антиоксиданты, которые могут поддерживать здоровье сердца и способствовать пищеварению.</li> +<li>Популярные сорта: Среди известных сортов — Цзюньшань Хун Ча, Дянь Хун и Лапсанг Сушонг.</li> +</ol> +<p>Этот чай часто используется как в чистом виде, так и в сочетании с молоком или специями.</p>" + :white-tea-description " +<p>Белый чай, один из самых деликатных видов чая, имеет свои особенности:</p> +<ol> +<li>Минимальная обработка: Листья собираются и сушатся на солнце, что сохраняет их натуральный вкус и аромат.</li> +<li>Вкус: Обладает легким, нежным вкусом с цветочными и травяными нотами, иногда с лёгкой сладостью.</li> +<li>Цвет настоя: Напиток имеет светло-желтый или бледно-зеленый цвет.</li> +<li>Антиоксиданты: Содержит высокое количество антиоксидантов, полезных для здоровья.</li> +<li>Популярные сорта: К известным сортам относятся Бянь Хао (Silver Needle) и Шуан Гу (White Peony).</li> +<li>Чувствительность к завариванию: Требует более низкой температуры воды и короткого времени настаивания, чтобы избежать горечи.</li> +</ol> +<p>Этот чай часто ценится за свою утонченность и лёгкость, идеально подходит для медитативного наслаждения.</p>" + :green-tea-description " +<p>Зеленый чай имеет ряд отличительных особенностей:</p> +<ol> +<li>Минимальная ферментация: Листья подвергаются легкой обработке (парообработке или обжарке), что сохраняет их свежесть и зеленый цвет.</li> +<li>Вкус: Обладает свежим, травянистым вкусом, который может варьироваться от сладковатого до слегка горьковатого, в зависимости от сорта.</li> +<li>Цвет настоя: Напиток обычно светло-зеленый или желтый.</li> +<li>Польза для здоровья: Содержит много антиоксидантов и может поддерживать метаболизм, а также улучшать общее состояние здоровья.</li> +<li>Популярные сорта: Известные сорта включают Сенча, Матча, Лунцзин (Драконий колодец) и Гунпай.</li> +<li>Чувствительность к завариванию: Требует более низкой температуры воды и короткого времени настаивания, чтобы избежать горечи и сохранить аромат.</li> +</ol> +<p>Зеленый чай часто ценится за свою лёгкость и разнообразие вкусовых профилей, что делает его популярным выбором во многих культурах.</p>" + :sheng-puer-description " +<p>Шен пуэр — это сырой (неферментированный) чай из провинции Юннань, который обладает уникальными характеристиками. Вот несколько его особенностей:</p> +<ol> +<li>Производственный процесс: Шен пуэр производится из свежих листьев чайного дерева, которые подвергаются процессу сушки и скручивания. В отличие от шен пуэра, шуй пуэр проходит процесс ферментации.</li> +<li>Вкус и аромат: У шен пуэра ярко выраженный свежий, травяной вкус с легкой сладостью и иногда фруктовыми нотами. С возрастом чай становится более мягким и глубоким, развивая сложные ароматы.</li> +<li>Возраст и созревание: Шен пуэр может долго храниться, и со временем его вкус и аромат становятся более насыщенными и гармоничными. Старые сорта ценятся высоко.</li> +<li>Цвет настоя: Настой шен пуэра обычно светлый, золотисто-желтый, особенно в молодом виде. С возрастом цвет может становиться более насыщенным.</li> +<li>Польза для здоровья: Шен пуэр считается полезным для пищеварения и может помогать в контроле веса. Содержит антиоксиданты и другие полезные соединения.</li> +<li>Культуры и традиции: Потребление шен пуэра связано с определёнными культурными традициями, включая специальные ритуалы заваривания чая.</li> +</ol> +<p>Эти характеристики делают шен пуэр уникальным и желанным для многих любителей чая.</p>" + :shou-puer-description " +<p>Шу пуэр — это ферментированный чай, также из провинции Юннань, который отличается от шен пуэра рядом особенностей:</p> +<ol> +<li>Производственный процесс: Шу пуэр проходит процесс искусственной ферментации, который называется \"вотя\" (или \"шу пуэр\"). Это позволяет ускорить процесс созревания и придаёт чаю характерный вкус.</li> +<li>Вкус и аромат: Шу пуэр обычно имеет более насыщенный, земляной и глубокий вкус с нотами древесины, шоколада и иногда даже кофе. Он более мягкий и менее терпкий, чем шен пуэр.</li> +<li>Цвет настоя: Настой шу пуэра тёмный, насыщенно коричневый или чёрный, что отражает его степень ферментации.</li> +<li>Созревание: Шу пуэр можно пить сразу после производства, хотя и он может улучшаться с возрастом, становясь более мягким и глубоким.</li> +<li>Польза для здоровья: Шу пуэр также обладает полезными свойствами, включая поддержку пищеварения, улучшение обмена веществ и антиоксидантные свойства.</li> +<li>Культуры и традиции: Шу пуэр также окружён культурными традициями, с акцентом на методы заваривания и сервировки, которые могут варьироваться в зависимости от региона и предпочтений.</li> +</ol> +<p>Шу пуэр привлекает тех, кто предпочитает более тёмные и насыщенные чаи, и его ценят за богатство вкуса и аромата.</p> +" + :oolong-description " +<p>Улуны — это полуферментированные чаи, которые занимают промежуточное положение между зелеными и черными чаями. Вот основные особенности улунов:</p> +<ol> +<li>Производственный процесс: Улуны проходят частичную ферментацию, что придаёт им уникальные характеристики. Процесс включает в себя сушки, скручивание и иногда обжаривание.</li> +<li>Вкус и аромат: Улуны могут иметь широкий спектр вкусов — от цветочных и фруктовых до ореховых и карамельных. В зависимости от степени ферментации вкус может быть как мягким и сладким, так и более насыщенным и сложным.</li> +<li>Цвет настоя: Настой улунов обычно золотистого или медного цвета, в зависимости от типа и степени ферментации.</li> +<li>Разнообразие: Существует множество сортов улунов, таких как Тайваньский оолонг, Да Хун Пао, Тегуаньинь и другие. Каждый сорт обладает своими уникальными особенностями и вкусами.</li> +<li>Польза для здоровья: Улуны содержат антиоксиданты и могут способствовать улучшению обмена веществ, поддержанию здоровья кожи и снижению уровня стресса.</li> +<li>Методы заваривания: Улуны часто заваривают в гайвани или чайниках с использованием высоких температур воды, что позволяет раскрыть их аромат и вкус. Многие любители чая практикуют многократное заваривание одних и тех же листьев.</li> +</ol> +<p>Улуны привлекают многих любителей чая своей сложностью и разнообразием, а также богатым ароматом и вкусом, который раскрывается в процессе заваривания.</p>" + :yellow-tea-description " +<p>Желтый чай — это один из самых редких и деликатных видов чая, который ценится за свой особый процесс обработки и уникальный вкус. Вот его основные особенности:</p> +<ol> +<li>Производственный процесс: Желтый чай проходит легкую ферментацию, схожую с процессом производства зеленого чая, но включает дополнительный этап \"прокаливания\" или \"завяливания\". Это помогает смягчить вкус и добавить сладость.</li> +<li>Вкус и аромат: У желтого чая мягкий, сладковатый вкус с легкими цветочными и фруктовыми нотами. Он часто менее терпкий, чем зеленый чай, и обладает более насыщенным послевкусием.</li> +<li>Цвет настоя: Настой желтого чая имеет светло-желтый или золотистый оттенок, который становится более насыщенным с возрастом.</li> +<li>Редкость и ценность: Желтый чай редко производится и чаще всего встречается в Китае, что делает его довольно дорогим и желанным среди ценителей.</li> +<li>Польза для здоровья: Как и другие виды чая, желтый чай богат антиоксидантами и может способствовать улучшению обмена веществ и поддержанию здоровья сердца.</li> +<li>Методы заваривания: Для заваривания желтого чая рекомендуется использовать воду температурой около 80-85°C и настаивать 2-3 минуты, чтобы избежать горечи и раскрыть его тонкие ароматы.</li> +</ol> +<p>Желтый чай привлекает тех, кто ищет что-то особенное и уникальное в мире чая, благодаря своей утонченности и редкости.</p>" + :teaware-description " +<p>Чайная посуда играет важную роль в культуре чаепития и может значительно влиять на вкус и аромат чая. Вот основные особенности различных видов чайной посуды:</p> + +<h2>Чайники</h2> +Материал: Чайники могут быть керамическими, фарфоровыми, стеклянными, металлическими или глиняными (например, из юннаньской глины). Каждый материал по-своему влияет на теплообмен и вкус. +Форма: Форма чайника может варьироваться, что также влияет на процесс заваривания. Например, чайники с широким дном позволяют лучше раскрывать ароматы. + +<h2>Гайвани</h2> + +Это традиционный китайский чайник для заваривания улунов и других сортов. Он обычно имеет широкое горлышко и позволяет наблюдать за цветом настоя. + +<h2>Чашки</h2> +Материалы: Чашки могут быть из фарфора, стекла, глины или металла. Фарфоровые чашки сохраняют тепло и подчеркивают аромат, а глиняные — могут добавлять свои нотки во вкус. +Размер и форма: Меньшие чашки предпочтительнее для крепких чаёв, таких как пуэр, в то время как большие могут использоваться для легких, цветочных сортов. +Сито и фильтры: +Используются для отделения чайных листьев от настоя. Это может быть встроенное сито в чайнике или отдельные фильтры. + +<p>Выбор чайной посуды может зависеть от типа чая, способа заваривания и культурных традиций. Правильная посуда не только помогает раскрыть вкус и аромат чая, но и создает атмосферу чаепития.</p>" +} |
