-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcore.cljs
171 lines (145 loc) · 4.88 KB
/
core.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
(ns app.core
(:require ["react-dom/client" :as rdom]
[app.lib :refer [defnc]]
[helix.core :refer [$]]
[helix.dom :as d]
[reitit.core :as r]
[reitit.coercion.spec :as rss]
[reitit.frontend :as rf]
[reitit.frontend.controllers :as rfc]
[reitit.frontend.easy :as rfe]
[refx.alpha :as refx]))
;;; Effects ;;;
;; Triggering navigation from events.
(refx/reg-fx :push-state
(fn [route]
(apply rfe/push-state route)))
;;; Events ;;;
(refx/reg-event-db ::initialize-db
(fn [db _]
(if db
db
{:current-route nil})))
(refx/reg-event-fx ::push-state
(fn [_ [_ & route]]
{:push-state route}))
(refx/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 ;;;
(refx/reg-sub ::current-route
(fn [db]
(:current-route db)))
;;; Views ;;;
(defnc home-page []
(d/div
(d/h1 "This is home page")
(d/button
;; Dispatch navigate event that triggers a (side)effect.
{:on-click #(refx/dispatch [::push-state ::sub-page2])}
"Go to sub-page 2")))
(defnc sub-page1 []
(d/div
(d/h1 "This is sub-page 1")))
(defnc sub-page2 []
(d/div
(d/h1 "This is sub-page 2")))
(defnc sub-page3 []
(let [current-route (refx/use-sub [::current-route])]
(d/div
(d/h1 "This is sub-page 3")
(when current-route (d/h2 (str (-> current-route :path-params)))))))
;;; 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 (refx/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"))}]}]
["sub-page3/:sub"
{:name ::sub-page3
:view sub-page3
:link-text "Sub-page 3"
:parameters {:path {:sub string?}}
:controllers
[{:parameters {:path [:sub]}
:start (fn [& _params] (js/console.log "Entering sub-page 3"))
:stop (fn [& _params] (js/console.log "Leaving sub-page 3"))}]}]])
(defn on-navigate [new-match]
(when new-match
(refx/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 on route
; to not use this on servers you need special rules
; to redirect 404 to index.html configuration
; check ./nginx folder for an working docker example
{:use-fragment true}))
(defnc nav [{:keys [router current-route]}]
(d/ul
(for [route-name (r/route-names router)
:let [route (r/match-by-name router route-name)
text (-> route :data :link-text)]]
(d/li {:key route-name}
(when (= route-name (-> current-route :data :name))
"> ")
;; Create a normal links that user can click
(if (= route-name ::sub-page3)
(d/a {:href (href route-name {:sub "test"})} text)
(d/a {:href (href route-name)} text))))))
(defnc router-component [{:keys [router]}]
(let [current-route (refx/use-sub [::current-route])]
(d/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 ^:export init []
(refx/clear-subscription-cache!)
(refx/dispatch-sync [::initialize-db])
(dev-setup)
(init-routes!)
(doto (rdom/createRoot (js/document.getElementById "app"))
(.render ($ router-component {:router router}))))