From 2fe448c3d8c8695206451b0f03401ab62359758a Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 26 Feb 2024 11:12:54 +0200 Subject: [PATCH] Add frontend-malli example --- examples/README.md | 7 ++ examples/frontend-malli/README.md | 13 +++ examples/frontend-malli/checkouts/reitit-core | 1 + .../frontend-malli/checkouts/reitit-frontend | 1 + .../frontend-malli/checkouts/reitit-schema | 1 + examples/frontend-malli/project.clj | 55 ++++++++++++ .../resources/public/index.html | 10 +++ .../frontend-malli/src/backend/server.clj | 10 +++ .../frontend-malli/src/frontend/core.cljs | 83 +++++++++++++++++++ 9 files changed, 181 insertions(+) create mode 100644 examples/frontend-malli/README.md create mode 120000 examples/frontend-malli/checkouts/reitit-core create mode 120000 examples/frontend-malli/checkouts/reitit-frontend create mode 120000 examples/frontend-malli/checkouts/reitit-schema create mode 100644 examples/frontend-malli/project.clj create mode 100644 examples/frontend-malli/resources/public/index.html create mode 100644 examples/frontend-malli/src/backend/server.clj create mode 100644 examples/frontend-malli/src/frontend/core.cljs diff --git a/examples/README.md b/examples/README.md index dbc42b05c..5ba38703c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,13 @@ ## frontend-prompt ## frontend-re-frame ## frontend + +Frontend example with clojure.spec coercion. + +## frontend-malli + +Frontend example with Malli coercion. + ## http-swagger Coercion with Spec and Swagger generation. diff --git a/examples/frontend-malli/README.md b/examples/frontend-malli/README.md new file mode 100644 index 000000000..80db60522 --- /dev/null +++ b/examples/frontend-malli/README.md @@ -0,0 +1,13 @@ +# reitit-frontend example + +## Usage + +```clj +> lein figwheel +``` + +Go with browser to http://localhost:3449 + +## License + +Copyright © Metosin Oy and collaborators diff --git a/examples/frontend-malli/checkouts/reitit-core b/examples/frontend-malli/checkouts/reitit-core new file mode 120000 index 000000000..a59d247e4 --- /dev/null +++ b/examples/frontend-malli/checkouts/reitit-core @@ -0,0 +1 @@ +../../../modules/reitit-core \ No newline at end of file diff --git a/examples/frontend-malli/checkouts/reitit-frontend b/examples/frontend-malli/checkouts/reitit-frontend new file mode 120000 index 000000000..20cdd4488 --- /dev/null +++ b/examples/frontend-malli/checkouts/reitit-frontend @@ -0,0 +1 @@ +../../../modules/reitit-frontend \ No newline at end of file diff --git a/examples/frontend-malli/checkouts/reitit-schema b/examples/frontend-malli/checkouts/reitit-schema new file mode 120000 index 000000000..a68c7f051 --- /dev/null +++ b/examples/frontend-malli/checkouts/reitit-schema @@ -0,0 +1 @@ +../../../modules/reitit-schema \ No newline at end of file diff --git a/examples/frontend-malli/project.clj b/examples/frontend-malli/project.clj new file mode 100644 index 000000000..13579427a --- /dev/null +++ b/examples/frontend-malli/project.clj @@ -0,0 +1,55 @@ +(defproject frontend "0.1.0-SNAPSHOT" + :description "FIXME: write description" + :url "http://example.com/FIXME" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + + :dependencies [[org.clojure/clojure "1.10.1"] + [ring-server "0.5.0"] + [reagent "0.10.0"] + [ring "1.8.1"] + [hiccup "1.0.5"] + [org.clojure/clojurescript "1.10.773"] + [metosin/reitit "0.7.0-alpha7"] + [metosin/reitit-malli "0.7.0-alpha7"] + [metosin/reitit-frontend "0.7.0-alpha7"] + ;; Just for pretty printting the match + [fipp "0.6.23"]] + + :plugins [[lein-cljsbuild "1.1.8"] + [lein-figwheel "0.5.20"]] + + :source-paths [] + :resource-paths ["resources" "target/cljsbuild"] + + :profiles {:dev {:dependencies [[binaryage/devtools "1.0.2"]]}} + + :cljsbuild + {:builds + [{:id "app" + :figwheel true + :source-paths ["src"] + :watch-paths ["src" "checkouts/reitit-frontend/src"] + :compiler {:main "frontend.core" + :asset-path "/js/out" + :output-to "target/cljsbuild/public/js/app.js" + :output-dir "target/cljsbuild/public/js/out" + :source-map true + :optimizations :none + :pretty-print true + :preloads [devtools.preload] + :aot-cache true}} + {:id "min" + :source-paths ["src"] + :compiler {:output-to "target/cljsbuild/public/js/app.js" + :output-dir "target/cljsbuild/public/js" + :source-map "target/cljsbuild/public/js/app.js.map" + :optimizations :advanced + :pretty-print false + :aot-cache true}}]} + + :figwheel {:http-server-root "public" + :server-port 3449 + :nrepl-port 7002 + ;; Server index.html for all routes for HTML5 routing + :ring-handler backend.server/handler}) diff --git a/examples/frontend-malli/resources/public/index.html b/examples/frontend-malli/resources/public/index.html new file mode 100644 index 000000000..ce1dd45b8 --- /dev/null +++ b/examples/frontend-malli/resources/public/index.html @@ -0,0 +1,10 @@ + + + + Reitit frontend example + + +
+ + + diff --git a/examples/frontend-malli/src/backend/server.clj b/examples/frontend-malli/src/backend/server.clj new file mode 100644 index 000000000..24c80d9f5 --- /dev/null +++ b/examples/frontend-malli/src/backend/server.clj @@ -0,0 +1,10 @@ +(ns backend.server + (:require [ring.util.response :as resp] + [ring.middleware.content-type :as content-type])) + +(def handler + (-> (fn [request] + (or (resp/resource-response (:uri request) {:root "public"}) + (-> (resp/resource-response "index.html" {:root "public"}) + (resp/content-type "text/html")))) + content-type/wrap-content-type)) diff --git a/examples/frontend-malli/src/frontend/core.cljs b/examples/frontend-malli/src/frontend/core.cljs new file mode 100644 index 000000000..4b29a3a8d --- /dev/null +++ b/examples/frontend-malli/src/frontend/core.cljs @@ -0,0 +1,83 @@ +(ns frontend.core + (:require [reagent.core :as r] + [reitit.frontend :as rf] + [reitit.frontend.easy :as rfe] + [reitit.coercion.malli :as rsm] + [fipp.edn :as fedn])) + +(defn home-page [] + [:div + [:h2 "Welcome to frontend"] + + [:button + {:type "button" + :on-click #(rfe/push-state ::item {:id 3})} + "Item 3"] + + [:button + {:type "button" + :on-click #(rfe/replace-state ::item {:id 4})} + "Replace State Item 4"]]) + +(defn about-page [] + [:div + [:h2 "About frontend"] + [:ul + [:li [:a {:href "http://google.com"} "external link"]] + [:li [:a {:href (rfe/href ::foobar)} "Missing route"]] + [:li [:a {:href (rfe/href ::item)} "Missing route params"]]] + + [:div + {:content-editable true + :suppressContentEditableWarning true} + [:p "Link inside contentEditable element is ignored."] + [:a {:href (rfe/href ::frontpage)} "Link"]]]) + +(defn item-page [match] + (let [{:keys [path query]} (:parameters match) + {:keys [id]} path] + [:div + [:h2 "Selected item " id] + (if (:foo query) + [:p "Optional foo query param: " (:foo query)])])) + +(defonce match (r/atom nil)) + +(defn current-page [] + [:div + [:ul + [:li [:a {:href (rfe/href ::frontpage)} "Frontpage"]] + [:li [:a {:href (rfe/href ::about)} "About"]] + [:li [:a {:href (rfe/href ::item {:id 1})} "Item 1"]] + [:li [:a {:href (rfe/href ::item {:id 2} {:foo "bar"})} "Item 2"]]] + (if @match + (let [view (:view (:data @match))] + [view @match])) + [:pre (with-out-str (fedn/pprint @match))]]) + +(def routes + [["/" + {:name ::frontpage + :view home-page}] + + ["/about" + {:name ::about + :view about-page}] + + ["/item/:id" + {:name ::item + :view item-page + :parameters {:path [:map + [:id :int]] + :query [:map + [:foo {:optional true} :keyword]]}}]]) + +(defn init! [] + (rfe/start! + (rf/router routes {:data {:coercion rsm/coercion}}) + (fn [m] (reset! match m)) + ;; set to false to enable HistoryAPI + {:use-fragment true}) + (r/render [current-page] (.getElementById js/document "app"))) + +(init!)