diff options
Diffstat (limited to 'src/chef/frontend')
-rw-r--r-- | src/chef/frontend/admin.clj | 103 | ||||
-rw-r--r-- | src/chef/frontend/admin/recipe_editor.clj | 63 | ||||
-rw-r--r-- | src/chef/frontend/visitor/home.clj | 41 | ||||
-rw-r--r-- | src/chef/frontend/visitor/recipe.clj | 55 | ||||
-rw-r--r-- | src/chef/frontend/visitor/recipe/thumbnail.clj | 10 | ||||
-rw-r--r-- | src/chef/frontend/visitor/search.clj | 38 |
6 files changed, 310 insertions, 0 deletions
diff --git a/src/chef/frontend/admin.clj b/src/chef/frontend/admin.clj new file mode 100644 index 0000000..89a2462 --- /dev/null +++ b/src/chef/frontend/admin.clj @@ -0,0 +1,103 @@ +(ns chef.frontend.admin + (:require [chef.utils :as cutils] + [hiccup2.core :as html] + [ring.util.response :as ruresp] + + [chef.logic.categories :as clcategories] + [chef.logic.recipes :as clrecipes])) + +(defn- render-category [data children] + [:li + [:p {:style {:display :inline-block}} + (if (pos? (:categories/id data)) + [:input {:type :text :placeholder "Name" + :value (:categories/name data) + :name "name" + :hx-post (str "/api/admin/category/" (:categories/id data)) + :hx-trigger "change"}] + "Startseite")] + (when (or (neg? (:categories/id data)) + (->> (:categories/id data) + clcategories/find-categories-with-parent + count + pos?)) + (list [:p {:style {:display :inline-block + :margin-left "1em" + :margin-right "1em"}} "->"] + [:input {:type :text :placeholder "Frage" + :style {:display :inline-block + :width :auto} + :value (:categories/question data) + :name "question" + :hx-post (str "/api/admin/category/" (:categories/id data)) + :hx-trigger "change"}])) + [:img {:src "/static/icons/plus.svg" :height "30em" + :style {:vertical-align :middle + :margin-left "1em"} + :hx-post (str "/api/admin/category/create/" + (when (pos? (:categories/id data)) (str "?parent=" (:categories/id data)))) + :hx-swap "none"}] + (when (pos? (:categories/id data)) + [:img {:src "/static/icons/trash.svg" :height "30em" + :style {:vertical-align :middle + :margin-left "1em"} + :hx-delete (str "/api/admin/category/" (:categories/id data)) + :hx-swap "none"}]) + [:ul + (for [child children] + (->> (:categories/id child) + clcategories/find-categories-with-parent + (render-category child)))]]) + +(defn- render-recipe-table-row [recipe] + (let [tr-id (str "recipe-" (:recipes/id recipe))] + [:tr {:id tr-id} + [:td + [:p (:recipes/title recipe)]] + [:td + (let [category (clcategories/get-category (:recipes/category recipe))] + [:p (clcategories/generate-path category)])] + [:td + [:div + [:button {:class ["button" "primary"] + :onclick (str "window.open(\"/admin/recipe-editor/" + (:recipes/id recipe) + "\", \"\", \"width=900,height=900\")")} + "Bearbeiten"] + [:button {:class ["button error"] + :hx-trigger "click" + :hx-swap :none + :hx-delete (str "/api/admin/recipe/" (:recipes/id recipe))} + "Löschen"]]]])) + +(defn- render [] + (cutils/gen-page "chef - Admin" + [:div {:style {:margin-left "1em"}} + [:h1 "chef - Admin"] + [:h2 "Kategorien"] + [:ul + (render-category (clcategories/get-category -1) + (clcategories/find-categories-with-parent -1))] + [:h2 "Rezepte"] + [:table + [:tr + [:th "Titel"] + [:th "Kategorie"] + [:th "Aktionen"]] + (for [recipe (clrecipes/get-all-recipes)] + (render-recipe-table-row recipe))] + [:button {:class "button primary" + :hx-trigger "click" + :hx-swap :none + :hx-post "/api/admin/recipe/create/"} + "Rezept erstellen"]])) + +(defn handler [req] + (let [access-token (get-in req [:oauth2/access-tokens :auth]) + resp (-> (render) + html/html + str + ruresp/response)] + (if (some? access-token) + (assoc resp :session (assoc (:session req) :oauth-token access-token)) + (cutils/auth-only req resp)))) diff --git a/src/chef/frontend/admin/recipe_editor.clj b/src/chef/frontend/admin/recipe_editor.clj new file mode 100644 index 0000000..69c84ba --- /dev/null +++ b/src/chef/frontend/admin/recipe_editor.clj @@ -0,0 +1,63 @@ +(ns chef.frontend.admin.recipe-editor + (:require [hiccup2.core :as html] + [hiccup.util :as hutil] + [ring.util.response :as ruresp] + [chef.utils :as cutils] + + [chef.logic.categories :as clcategories] + [chef.logic.recipes :as clrecipes])) + +(defn render [recipe] + (cutils/gen-page "chef - Rezept bearbeiten" + [:div {:style {:margin-left "1em"}} + [:h1 "Rezept bearbeiten"] + [:form {:style {:width "50%"} + :hx-post (str "/api/admin/recipe/" (:recipes/id recipe)) + :hx-swap "none" + :enctype "multipart/form-data"} + [:input {:type :text :name "title" :placeholder "Titel" + :value (:recipes/title recipe)}] + [:div {:style {:display :flex}} + [:p {:style {:margin-right "0.5em"}} "Thumbnail: "] + [:input {:type :file :name "thumbnail" + :style {:height :fit-content + :padding "0.3em"}}]] + [:button {:class ["button" "error"] + :hx-trigger "click" + :hx-delete (str "/api/admin/recipe/" (:recipes/id recipe) "/thumbnail/") + :hx-swap :none} + "Thumbnail entfernen"] + [:h2 "Kategorie"] + [:select {:name "category"} + (for [category (clcategories/get-all-categories)] + [:option {:value (:categories/id category) + :selected (= (:categories/id category) (:recipes/category recipe))} + (clcategories/generate-path category)])] + [:h2 "Zutaten"] + [:div {:style {:display :flex}} + [:p {:style {:margin-right "0.5em"}} "Pro"] + [:select {:name "ingredients-unit" + :style {:height :fit-content + :padding "0.3em"}} + [:option {:value 0 :selected (= (:recipes/unit recipe) 0)} "Portion"] + [:option {:value 1 :selected (= (:recipes/unit recipe) 1)} "Person"]] + [:p ":"]] + [:textarea {:name "ingredients"} + (:recipes/ingredients recipe)] + [:p "(Je Zeile eine Zutat, in dem Format " [:code "[Beschreibung der Zutat]=[Menge als Zahl][Einheit der Menge]"] ".)"] + [:h2 "Zubereitung"] + [:textarea {:name "preparation"} + (:recipes/preparation recipe)] + [:button {:type :submit + :style {:margin-top "1em"}} "Speichern"]]] + [:script (hutil/raw-string "window.addEventListener(\"htmx:afterRequest\", () => window.close())")])) + +(defn handler [req] + (cutils/auth-only req + (if-let [id (cutils/s->int-or-nil (get-in req [:path-params :id]))] + (->> (clrecipes/get-recipe id) + render + html/html + str + ruresp/response) + (ruresp/bad-request "Bad request.")))) diff --git a/src/chef/frontend/visitor/home.clj b/src/chef/frontend/visitor/home.clj new file mode 100644 index 0000000..6503983 --- /dev/null +++ b/src/chef/frontend/visitor/home.clj @@ -0,0 +1,41 @@ +(ns chef.frontend.visitor.home + (:require [hiccup2.core :as html] + [ring.util.response :as ruresp] + [chef.utils :as cutils] + + [chef.frontend.visitor.search :as cfvsearch] + + [chef.logic.categories :as clcategories])) + +(defn- render [req] + (cutils/gen-page "chef" + (let [category (clcategories/get-category (or (get-in req [:params "category"]) -1))] + [:div {:style {:text-align :center}} + [:h1 "chef"] + [:h2 "Finde das perfekte Gericht für dich!"] + [:b (:categories/question category)] + [:div + (for [child-category (clcategories/find-categories-with-parent (:categories/id category))] + [:div + [:button {:style {:margin-bottom "1em"} + :onclick (str "window.location = \"/?category=" (:categories/id child-category) "\"")} + (:categories/name child-category)] + [:br]])] + (when (pos? (:categories/id category)) + [:h3 (clcategories/generate-path category)]) + [:input {:type :text + :style {:width "90%" :margin :auto} + :placeholder "Suche" + :hx-get (str "/components/search?category=" (:categories/id category)) + :name "query" + :hx-swap "innerHTML" + :hx-target "#search-results"}] + [:div {:id "search-results"} + (cfvsearch/render "" (:categories/id category))]]))) + +(defn handler [req] + (-> req + render + html/html + str + ruresp/response)) diff --git a/src/chef/frontend/visitor/recipe.clj b/src/chef/frontend/visitor/recipe.clj new file mode 100644 index 0000000..e3dbf97 --- /dev/null +++ b/src/chef/frontend/visitor/recipe.clj @@ -0,0 +1,55 @@ +(ns chef.frontend.visitor.recipe + (:require [chef.utils :as cutils] + [clojure.string :as cstr] + [hiccup2.core :as html] + [ring.util.response :as ruresp] + + [chef.logic.recipes :as clrecipes] + [chef.logic.categories :as clcategories])) + +(defn- render [portions recipe] + (cutils/gen-page (str "chef - " (:recipes/title recipe)) + [:div {:style {:margin-left "1em"}} + [:div + [:h1 {:style {:display :inline-block + :margin-right "0.5em"}} + (:recipes/title recipe)] + [:i (str "(" (-> (:recipes/category recipe) + clcategories/get-category + clcategories/generate-path) ")")]] + (when (some? (clrecipes/get-recipe-thumbnail (:recipes/id recipe))) + [:img {:src (str "/recipes/" (:recipes/id recipe) "/thumbnail") + :width "50%"}]) + [:h2 + "Zutaten pro " + [:input {:type :number + :value portions + :style {:width "3em" + :display :inline-block} + "_" "on change go to url `?portions=${value of me}`"}] + (condp = (:recipes/unit recipe) + 0 " Portion(en)" + 1 " Person(en)" + "") + ":"] + [:ul (for [ingredient (-> recipe + :recipes/ingredients + cutils/parse-ingredients)] + [:li + [:b (:description ingredient)] ": " + (* (:amount ingredient) portions) + (:unit ingredient)])] + [:h2 "Zubereitung"] + (->> (:recipes/preparation recipe) + cstr/split-lines + (map #(if (cstr/blank? %) + [:br] + [:p %])))])) + +(defn handler [req] + (->> (clrecipes/get-recipe (get-in req [:path-params :id])) + (render (or (cutils/s->int-or-nil (get-in req [:params "portions"])) + 1)) + html/html + str + ruresp/response)) diff --git a/src/chef/frontend/visitor/recipe/thumbnail.clj b/src/chef/frontend/visitor/recipe/thumbnail.clj new file mode 100644 index 0000000..c14f491 --- /dev/null +++ b/src/chef/frontend/visitor/recipe/thumbnail.clj @@ -0,0 +1,10 @@ +(ns chef.frontend.visitor.recipe.thumbnail + (:require [ring.util.response :as ruresp] + [chef.logic.recipes :as clrecipes]) + (:import java.io.File)) + +(defn handler [req] + (if-let [id (get-in req [:path-params :id])] + (when-let [thumbnail-file (clrecipes/get-recipe-thumbnail id)] + (ruresp/file-response (.getPath ^File thumbnail-file))) + (ruresp/bad-request "Bad request."))) diff --git a/src/chef/frontend/visitor/search.clj b/src/chef/frontend/visitor/search.clj new file mode 100644 index 0000000..7a2db93 --- /dev/null +++ b/src/chef/frontend/visitor/search.clj @@ -0,0 +1,38 @@ +(ns chef.frontend.visitor.search + (:require [chef.utils :as cutils] + [clojure.string :as cstr] + [hiccup2.core :as html] + [ring.util.response :as ruresp] + + [chef.logic.categories :as clcategories] + [chef.logic.recipes :as clrecipes])) + +(defn render [query category] + [:table + [:tr + [:th "Rezept"] + [:th "Kategorie"]] + (for [recipe (clrecipes/get-all-recipes) + :let [recipe-category (clcategories/get-category (:recipes/category recipe))]] + (when (or (= category -1) + (and (cstr/includes? (-> recipe + :recipes/title + cstr/lower-case) + query) + (some #(= (:categories/id %) category) + (clcategories/get-parents recipe-category)))) + [:tr + [:td + [:b [:a {:href (str "/recipes/" (:recipes/id recipe))} (:recipes/title recipe)]]] + [:td + (-> (:recipes/category recipe) + clcategories/get-category + clcategories/generate-path)]]))]) + +(defn handler [req] + (if-let [query (get-in req [:params "query"])] + (-> (render query (or (cutils/s->int-or-nil (get-in req [:params "category"])) -1)) + html/html + str + ruresp/response) + (ruresp/bad-request "No search query provide."))) |