mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
Merge pull request #260 from vharmain/frontend-examples
Frontend examples
This commit is contained in:
commit
59d68d65ef
18 changed files with 676 additions and 1 deletions
13
examples/frontend-links/README.md
Normal file
13
examples/frontend-links/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# reitit-frontend example
|
||||
|
||||
## Usage
|
||||
|
||||
```clj
|
||||
> lein figwheel
|
||||
```
|
||||
|
||||
Go with browser to http://localhost:3449
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2018 Metosin Oy
|
||||
62
examples/frontend-links/project.clj
Normal file
62
examples/frontend-links/project.clj
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
(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.0"]
|
||||
[ring-server "0.5.0"]
|
||||
[reagent "0.8.1"]
|
||||
[ring "1.7.1"]
|
||||
[hiccup "1.0.5"]
|
||||
[org.clojure/clojurescript "1.10.520"]
|
||||
[metosin/reitit "0.3.1"]
|
||||
[metosin/reitit-spec "0.3.1"]
|
||||
[metosin/reitit-frontend "0.3.1"]
|
||||
;; Just for pretty printting the match
|
||||
[fipp "0.6.14"]]
|
||||
|
||||
:plugins [[lein-cljsbuild "1.1.7"]
|
||||
[lein-figwheel "0.5.18"]
|
||||
[cider/cider-nrepl "0.21.1"]]
|
||||
|
||||
:repl-options {:nrepl-middleware [cider.piggieback/wrap-cljs-repl]}
|
||||
|
||||
:source-paths ["src"]
|
||||
:resource-paths ["resources" "target/cljsbuild"]
|
||||
|
||||
:profiles
|
||||
{:dev
|
||||
{:dependencies
|
||||
[[binaryage/devtools "0.9.10"]
|
||||
[cider/piggieback "0.4.0"]
|
||||
[figwheel-sidecar "0.5.18"]]}}
|
||||
|
||||
:cljsbuild
|
||||
{:builds
|
||||
[{:id "app"
|
||||
:figwheel true
|
||||
:source-paths ["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})
|
||||
10
examples/frontend-links/resources/public/index.html
Normal file
10
examples/frontend-links/resources/public/index.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reitit frontend example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
11
examples/frontend-links/src/backend/server.clj
Normal file
11
examples/frontend-links/src/backend/server.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(ns backend.server
|
||||
(:require [clojure.java.io :as io]
|
||||
[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))
|
||||
147
examples/frontend-links/src/frontend/core.cljs
Normal file
147
examples/frontend-links/src/frontend/core.cljs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
(ns frontend.core
|
||||
(:require [clojure.string :as string]
|
||||
[fipp.edn :as fedn]
|
||||
[reagent.core :as r]
|
||||
[reitit.coercion :as rc]
|
||||
[reitit.coercion.spec :as rss]
|
||||
[reitit.frontend :as rf]
|
||||
[reitit.frontend.easy :as rfe]
|
||||
[spec-tools.data-spec :as ds]))
|
||||
|
||||
;; Components similar to react-router `Link`, `NavLink` and `Redirect`
|
||||
;; with Reitit frontend.
|
||||
|
||||
(defn home-page []
|
||||
[:div
|
||||
[:h2 "Welcome to frontend"]
|
||||
[:p "This is home page"]])
|
||||
|
||||
(defn about-page []
|
||||
[:div
|
||||
[:h2 "About frontend"]
|
||||
[:p "This is about page"]])
|
||||
|
||||
(defn redirect!
|
||||
"If `push` is truthy, previous page will be left in history."
|
||||
[{:keys [to path-params query-params push]}]
|
||||
(if push
|
||||
(rfe/push-state to path-params query-params)
|
||||
(rfe/replace-state to path-params query-params)))
|
||||
|
||||
(defn Redirect
|
||||
"Component that only causes a redirect side-effect."
|
||||
[props]
|
||||
(r/create-class
|
||||
{:component-did-mount (fn [this] (redirect! (r/props this)))
|
||||
:component-did-update (fn [this [_ prev-props]]
|
||||
(if (not= (r/props this) prev-props)
|
||||
(redirect! (r/props this))))
|
||||
:render (fn [this] nil)}))
|
||||
|
||||
(defn item-page [match]
|
||||
(let [{:keys [path query]} (:parameters match)
|
||||
{:keys [id]} path]
|
||||
(if (< id 1)
|
||||
[Redirect {:to ::frontpage}]
|
||||
[:div
|
||||
[:h2 "Selected item " id]
|
||||
(when (:foo query)
|
||||
[:p "Optional foo query param: " (:foo query)])])))
|
||||
|
||||
(def routes
|
||||
[["/"
|
||||
{:name ::frontpage
|
||||
:view home-page}]
|
||||
|
||||
["/about"
|
||||
{:name ::about
|
||||
:view about-page}]
|
||||
|
||||
["/item/:id"
|
||||
{:name ::item
|
||||
:view item-page
|
||||
:parameters
|
||||
{:path {:id int?}
|
||||
:query {(ds/opt :foo) keyword?}}}]])
|
||||
|
||||
(def router
|
||||
(rf/router routes {:data {:coercion rss/coercion}}))
|
||||
|
||||
(defonce current-match (r/atom nil))
|
||||
|
||||
(defn- resolve-href
|
||||
[to path-params query-params]
|
||||
(if (keyword? to)
|
||||
(rfe/href to path-params query-params)
|
||||
(let [match (rf/match-by-path router to)
|
||||
route (-> match :data :name)
|
||||
params (or path-params (:path-params match))
|
||||
query (or query-params (:query-params match))]
|
||||
(if match
|
||||
(rfe/href route params query)
|
||||
to))))
|
||||
|
||||
(defn Link
|
||||
[{:keys [to path-params query-params active]} & children]
|
||||
(let [href (resolve-href to path-params query-params)]
|
||||
(into
|
||||
[:a {:href href} (when active "> ")] ;; Apply styles or whatever
|
||||
children)))
|
||||
|
||||
(defn- name-matches?
|
||||
[name path-params match]
|
||||
(and (= name (-> match :data :name))
|
||||
(= (not-empty path-params)
|
||||
(-> match :parameters :path not-empty))))
|
||||
|
||||
(defn- url-matches?
|
||||
[url match]
|
||||
(= (-> url (string/split #"\?") first)
|
||||
(:path match)))
|
||||
|
||||
(defn NavLink
|
||||
[{:keys [to path-params] :as props} & children]
|
||||
(let [active (or (name-matches? to path-params @current-match)
|
||||
(url-matches? to @current-match))]
|
||||
[Link (assoc props :active active) children]))
|
||||
|
||||
(defn current-page []
|
||||
[:div
|
||||
|
||||
[:h4 "Link"]
|
||||
[:ul
|
||||
[:li [Link {:to ::frontpage} "Frontpage"]]
|
||||
[:li [Link {:to "/about"} "About"]]
|
||||
[:li [Link {:to ::item :path-params {:id 1}} "Item 1"]]
|
||||
[:li [Link {:to "/item/2?foo=bar"} "Item 2"]]
|
||||
[:li [Link {:to "/item/-1"} "Item -1 (redirects to frontpage)"]]
|
||||
[:li [Link {:to "http://www.google.fi"} "Google"]]]
|
||||
|
||||
[:h4 "NavLink"]
|
||||
[:ul
|
||||
[:li [NavLink {:to ::frontpage} "Frontpage"]]
|
||||
[:li [NavLink {:to "/about"} "About"]]
|
||||
[:li [NavLink {:to ::item :path-params {:id 1}} "Item 1"]]
|
||||
[:li [NavLink {:to "/item/2?foo=bar"} "Item 2"]]
|
||||
[:li [NavLink {:to "/item/-1"} "Item -1 (redirects to frontpage)"]]
|
||||
[:li [NavLink {:to "http://www.google.fi"} "Google"]]]
|
||||
|
||||
(if @current-match
|
||||
(let [view (:view (:data @current-match))]
|
||||
[view @current-match]))
|
||||
|
||||
[:pre (with-out-str (fedn/pprint @current-match))]])
|
||||
|
||||
(defn init! []
|
||||
(rfe/start!
|
||||
router
|
||||
(fn [m] (reset! current-match m))
|
||||
;; set to false to enable HistoryAPI
|
||||
{:use-fragment true})
|
||||
(r/render [current-page] (.getElementById js/document "app")))
|
||||
|
||||
(init!)
|
||||
|
||||
(comment
|
||||
(rf/match-by-path router "/about?kissa=1&koira=true")
|
||||
(rf/match-by-path router "/item/2?kissa=1&koira=true"))
|
||||
13
examples/frontend-prompt/README.md
Normal file
13
examples/frontend-prompt/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# reitit-frontend example
|
||||
|
||||
## Usage
|
||||
|
||||
```clj
|
||||
> lein figwheel
|
||||
```
|
||||
|
||||
Go with browser to http://localhost:3449
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2018 Metosin Oy
|
||||
62
examples/frontend-prompt/project.clj
Normal file
62
examples/frontend-prompt/project.clj
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
(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.0"]
|
||||
[ring-server "0.5.0"]
|
||||
[reagent "0.8.1"]
|
||||
[ring "1.7.1"]
|
||||
[hiccup "1.0.5"]
|
||||
[org.clojure/clojurescript "1.10.520"]
|
||||
[metosin/reitit "0.3.1"]
|
||||
[metosin/reitit-spec "0.3.1"]
|
||||
[metosin/reitit-frontend "0.3.1"]
|
||||
;; Just for pretty printting the match
|
||||
[fipp "0.6.14"]]
|
||||
|
||||
:plugins [[lein-cljsbuild "1.1.7"]
|
||||
[lein-figwheel "0.5.18"]
|
||||
[cider/cider-nrepl "0.21.1"]]
|
||||
|
||||
:repl-options {:nrepl-middleware [cider.piggieback/wrap-cljs-repl]}
|
||||
|
||||
:source-paths ["src"]
|
||||
:resource-paths ["resources" "target/cljsbuild"]
|
||||
|
||||
:profiles
|
||||
{:dev
|
||||
{:dependencies
|
||||
[[binaryage/devtools "0.9.10"]
|
||||
[cider/piggieback "0.4.0"]
|
||||
[figwheel-sidecar "0.5.18"]]}}
|
||||
|
||||
:cljsbuild
|
||||
{:builds
|
||||
[{:id "app"
|
||||
:figwheel true
|
||||
:source-paths ["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})
|
||||
10
examples/frontend-prompt/resources/public/index.html
Normal file
10
examples/frontend-prompt/resources/public/index.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reitit frontend example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
11
examples/frontend-prompt/src/backend/server.clj
Normal file
11
examples/frontend-prompt/src/backend/server.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(ns backend.server
|
||||
(:require [clojure.java.io :as io]
|
||||
[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))
|
||||
70
examples/frontend-prompt/src/frontend/core.cljs
Normal file
70
examples/frontend-prompt/src/frontend/core.cljs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
(ns frontend.core
|
||||
(:require [fipp.edn :as fedn]
|
||||
[reagent.core :as r]
|
||||
[reitit.coercion :as rc]
|
||||
[reitit.coercion.spec :as rss]
|
||||
[reitit.frontend :as rf]
|
||||
[reitit.frontend.easy :as rfe]
|
||||
[spec-tools.data-spec :as ds]))
|
||||
|
||||
;; Implementing conditional prompt on navigation with Reitit frontend.
|
||||
|
||||
(defn home-page []
|
||||
[:div
|
||||
[:h2 "Home"]
|
||||
[:p "You will not be prompted to leave this page"]])
|
||||
|
||||
(defn prompt-page []
|
||||
[:div
|
||||
[:h2 "Prompt"]
|
||||
[:p "You will be prompted to leave this page"]])
|
||||
|
||||
(def routes
|
||||
[["/"
|
||||
{:name ::home
|
||||
:view home-page}]
|
||||
|
||||
["/prompt"
|
||||
{:name ::prompt
|
||||
:view prompt-page
|
||||
;; Routes can contain arbitrary keys so we add custom :prompt
|
||||
;; key here. See how it's handled in `on-navigate` function.
|
||||
:prompt "Are you sure you want to leave?"
|
||||
;; It would be possible to define a function here that resolves
|
||||
;; wheter prompting is needed or not but we'll keep it simple.
|
||||
}]])
|
||||
|
||||
(def router
|
||||
(rf/router routes {:data {:coercion rss/coercion}}))
|
||||
|
||||
(defonce current-match (r/atom nil))
|
||||
|
||||
(defn current-page []
|
||||
[:div
|
||||
|
||||
[:ul
|
||||
[:li [:a {:href (rfe/href ::home)} "Home"]]
|
||||
[:li [:a {:href (rfe/href ::prompt)} "Prompt page"]]]
|
||||
|
||||
(if @current-match
|
||||
(let [view (-> @current-match :data :view)]
|
||||
[view @current-match]))
|
||||
[:pre (with-out-str (fedn/pprint @current-match))]])
|
||||
|
||||
(defn on-navigate [m]
|
||||
(if-let [prompt (and (not= @current-match m)
|
||||
(-> @current-match :data :prompt))]
|
||||
(if (js/window.confirm prompt) ;; Returns true if OK is pressed.
|
||||
(reset! current-match m)
|
||||
(.back js/window.history)) ;; Restore browser location
|
||||
(reset! current-match m)))
|
||||
|
||||
(defn init! []
|
||||
(rfe/start!
|
||||
router
|
||||
on-navigate
|
||||
;; set to false to enable HistoryAPI
|
||||
{:use-fragment true})
|
||||
(r/render [current-page] (.getElementById js/document "app")))
|
||||
|
||||
(init!)
|
||||
26
examples/frontend-re-frame/README.md
Normal file
26
examples/frontend-re-frame/README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# frontend-re-frame
|
||||
|
||||
A [re-frame](https://github.com/Day8/re-frame) application designed to ... well, that part is up to you.
|
||||
|
||||
## Development Mode
|
||||
|
||||
### Run application:
|
||||
|
||||
```
|
||||
lein clean
|
||||
lein figwheel dev
|
||||
```
|
||||
|
||||
Figwheel will automatically push cljs changes to the browser.
|
||||
|
||||
Wait a bit, then browse to [http://localhost:3449](http://localhost:3449).
|
||||
|
||||
## Production Build
|
||||
|
||||
|
||||
To compile clojurescript to javascript:
|
||||
|
||||
```
|
||||
lein clean
|
||||
lein cljsbuild once min
|
||||
```
|
||||
56
examples/frontend-re-frame/project.clj
Normal file
56
examples/frontend-re-frame/project.clj
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
(defproject frontend-re-frame "0.1.0-SNAPSHOT"
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
[org.clojure/clojurescript "1.10.520"]
|
||||
[metosin/reitit "0.3.1"]
|
||||
[reagent "0.8.1"]
|
||||
[re-frame "0.10.6"]]
|
||||
|
||||
:plugins [[lein-cljsbuild "1.1.7"]
|
||||
[lein-figwheel "0.5.18"]
|
||||
[cider/cider-nrepl "0.21.1"]]
|
||||
|
||||
:repl-options {:nrepl-middleware [cider.piggieback/wrap-cljs-repl]}
|
||||
:min-lein-version "2.5.3"
|
||||
:source-paths ["src/clj" "src/cljs"]
|
||||
:clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
|
||||
:figwheel
|
||||
{:css-dirs ["resources/public/css"]
|
||||
:server-port 3449
|
||||
:nrepl-port 7002
|
||||
:ring-handler backend.server/handler}
|
||||
|
||||
:profiles
|
||||
{:dev
|
||||
{:dependencies
|
||||
[[binaryage/devtools "0.9.10"]
|
||||
[cider/piggieback "0.4.0"]
|
||||
[figwheel-sidecar "0.5.18"]]
|
||||
|
||||
:plugins [[lein-figwheel "0.5.18"]]}
|
||||
:prod {}}
|
||||
|
||||
:cljsbuild
|
||||
{:builds
|
||||
[{:id "dev"
|
||||
:source-paths ["src/cljs"]
|
||||
:figwheel {:on-jsload "frontend-re-frame.core/mount-root"}
|
||||
:compiler {:main frontend-re-frame.core
|
||||
:output-to "resources/public/js/compiled/app.js"
|
||||
:output-dir "resources/public/js/compiled/out"
|
||||
:asset-path "js/compiled/out"
|
||||
:source-map-timestamp true
|
||||
:preloads [devtools.preload]
|
||||
:external-config {:devtools/config {:features-to-install :all}}
|
||||
}}
|
||||
|
||||
{:id "min"
|
||||
:source-paths ["src/cljs"]
|
||||
:compiler {:main frontend-re-frame.core
|
||||
:output-to "resources/public/js/compiled/app.js"
|
||||
:optimizations :advanced
|
||||
:closure-defines {goog.DEBUG false}
|
||||
:pretty-print false}}
|
||||
|
||||
|
||||
]}
|
||||
)
|
||||
13
examples/frontend-re-frame/resources/public/index.html
Normal file
13
examples/frontend-re-frame/resources/public/index.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="js/compiled/app.js"></script>
|
||||
<script>frontend_re_frame.core.init();</script>
|
||||
</body>
|
||||
</html>
|
||||
11
examples/frontend-re-frame/src/clj/backend/server.clj
Normal file
11
examples/frontend-re-frame/src/clj/backend/server.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(ns backend.server
|
||||
(:require [clojure.java.io :as io]
|
||||
[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))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(ns frontend-re-frame.core)
|
||||
155
examples/frontend-re-frame/src/cljs/frontend_re_frame/core.cljs
Normal file
155
examples/frontend-re-frame/src/cljs/frontend_re_frame/core.cljs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
(ns frontend-re-frame.core
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[reitit.core :as r]
|
||||
[reitit.coercion :as rc]
|
||||
[reitit.coercion.spec :as rss]
|
||||
[reitit.frontend :as rf]
|
||||
[reitit.frontend.controllers :as rfc]
|
||||
[reitit.frontend.easy :as rfe]))
|
||||
|
||||
;;; Events ;;;
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::initialize-db
|
||||
(fn [_ _]
|
||||
{:current-route nil}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::navigate
|
||||
(fn [db [_ route]]
|
||||
;; See `navigate` effect in routes.cljs
|
||||
{::navigate! route}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::navigated
|
||||
(fn [db [_ new-match]]
|
||||
(let [old-match (:current-route db)
|
||||
controllers (rfc/apply-controllers (:controllers old-match) new-match)]
|
||||
(assoc db :current-route (assoc new-match :controllers controllers)))))
|
||||
|
||||
;;; Subscriptions ;;;
|
||||
|
||||
(re-frame/reg-sub
|
||||
::current-route
|
||||
(fn [db]
|
||||
(:current-route db)))
|
||||
|
||||
;;; Views ;;;
|
||||
|
||||
(defn home-page []
|
||||
[:div
|
||||
[:h1 "This is home page"]
|
||||
[:button
|
||||
;; Dispatch navigate event that triggers a (side)effect.
|
||||
{:on-click #(re-frame/dispatch [::navigate ::sub-page2])}
|
||||
"Go to sub-page 2"]])
|
||||
|
||||
(defn sub-page1 []
|
||||
[:div
|
||||
[:h1 "This is sub-page 1"]])
|
||||
|
||||
(defn sub-page2 []
|
||||
[:div
|
||||
[:h1 "This is sub-page 2"]])
|
||||
|
||||
;;; Effects ;;;
|
||||
|
||||
;; Triggering navigation from events.
|
||||
(re-frame/reg-fx
|
||||
::navigate!
|
||||
(fn [k params query]
|
||||
(rfe/push-state k params query)))
|
||||
|
||||
;;; Routes ;;;
|
||||
|
||||
(defn href
|
||||
"Return relative url for given route. Url can be used in HTML links."
|
||||
([k]
|
||||
(href k nil nil))
|
||||
([k params]
|
||||
(href k params nil))
|
||||
([k params query]
|
||||
(rfe/href k params query)))
|
||||
|
||||
(def routes
|
||||
["/"
|
||||
[""
|
||||
{:name ::home
|
||||
:view home-page
|
||||
:link-text "Home"
|
||||
:controllers
|
||||
[{;; Do whatever initialization needed for home page
|
||||
;; I.e (re-frame/dispatch [::events/load-something-with-ajax])
|
||||
:start (fn [& params](js/console.log "Entering home page"))
|
||||
;; Teardown can be done here.
|
||||
:stop (fn [& params] (js/console.log "Leaving home page"))}]}]
|
||||
["sub-page1"
|
||||
{:name ::sub-page1
|
||||
:view sub-page1
|
||||
:link-text "Sub page 1"
|
||||
:controllers
|
||||
[{:start (fn [& params] (js/console.log "Entering sub-page 1"))
|
||||
:stop (fn [& params] (js/console.log "Leaving sub-page 1"))}]}]
|
||||
["sub-page2"
|
||||
{:name ::sub-page2
|
||||
:view sub-page2
|
||||
:link-text "Sub-page 2"
|
||||
:controllers
|
||||
[{:start (fn [& params] (js/console.log "Entering sub-page 2"))
|
||||
:stop (fn [& params] (js/console.log "Leaving sub-page 2"))}]}]])
|
||||
|
||||
(defn on-navigate [new-match]
|
||||
(when new-match
|
||||
(re-frame/dispatch [::navigated new-match])))
|
||||
|
||||
(def router
|
||||
(rf/router
|
||||
routes
|
||||
{:data {:coercion rss/coercion}}))
|
||||
|
||||
(defn init-routes! []
|
||||
(js/console.log "initializing routes")
|
||||
(rfe/start!
|
||||
router
|
||||
on-navigate
|
||||
{:use-fragment true}))
|
||||
|
||||
(defn nav [{:keys [router current-route]}]
|
||||
[:ul
|
||||
(for [route-name (r/route-names router)
|
||||
:let [route (r/match-by-name router route-name)
|
||||
text (-> route :data :link-text)]]
|
||||
[:li {:key route-name}
|
||||
(when (= route-name (-> current-route :data :name))
|
||||
"> ")
|
||||
;; Create a normal links that user can click
|
||||
[:a {:href (href route-name)} text]])])
|
||||
|
||||
(defn router-component [{:keys [router]}]
|
||||
(let [current-route @(re-frame/subscribe [::current-route])]
|
||||
[:div
|
||||
[nav {:router router :current-route current-route}]
|
||||
(when current-route
|
||||
[(-> current-route :data :view)])]))
|
||||
|
||||
;;; Setup ;;;
|
||||
|
||||
(def debug? ^boolean goog.DEBUG)
|
||||
|
||||
(defn dev-setup []
|
||||
(when debug?
|
||||
(enable-console-print!)
|
||||
(println "dev mode")))
|
||||
|
||||
(defn mount-root []
|
||||
(re-frame/clear-subscription-cache!)
|
||||
(init-routes!) ;; Reset routes on figwheel reload
|
||||
(reagent/render [router-component {:router router}]
|
||||
(.getElementById js/document "app")))
|
||||
|
||||
(defn ^:export init []
|
||||
(re-frame/dispatch-sync [::initialize-db])
|
||||
(dev-setup)
|
||||
(mount-root))
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
([match]
|
||||
(match->path match nil))
|
||||
([match query-params]
|
||||
(some-> match :path (cond-> query-params (str "?" (impl/query-string query-params))))))
|
||||
(some-> match :path (cond-> (seq query-params) (str "?" (impl/query-string query-params))))))
|
||||
|
||||
;;
|
||||
;; Different routers
|
||||
|
|
|
|||
|
|
@ -354,6 +354,10 @@
|
|||
(-> router
|
||||
(r/match-by-name! ::route {:a "olipa", :b "kerran"})
|
||||
(r/match->path))))
|
||||
(is (= "/olipa/kerran"
|
||||
(-> router
|
||||
(r/match-by-name! ::route {:a "olipa", :b "kerran"})
|
||||
(r/match->path {}))))
|
||||
(is (= "/olipa/kerran?iso=p%C3%B6ril%C3%A4inen"
|
||||
(-> router
|
||||
(r/match-by-name! ::route {:a "olipa", :b "kerran"})
|
||||
|
|
|
|||
Loading…
Reference in a new issue