reagent/test/demo.cljs

286 lines
8.7 KiB
Plaintext
Raw Normal View History

2014-01-02 13:04:30 +00:00
(ns demo
(:require [cloact.core :as cloact :refer [atom]]
2014-01-06 11:46:58 +00:00
[clojure.string :as string]
[demoutil :as demoutil])
2014-01-02 13:04:30 +00:00
(:require-macros [demoutil :refer [get-source]]
[cloact.debug :refer [dbg println]]))
(defn src-parts [src]
2014-01-06 11:46:58 +00:00
(string/split src #"\n(?=[(])"))
2014-01-02 13:04:30 +00:00
(defn src-defs [parts]
2014-01-06 11:46:58 +00:00
(let [ws #"\s+"]
(into {} (for [x parts]
[(-> x (string/split ws) second keyword) x]))))
2014-01-02 13:04:30 +00:00
(def srcmap
2014-01-06 11:46:58 +00:00
(-> "demo.cljs" get-source src-parts src-defs))
2014-01-02 13:04:30 +00:00
(def nssrc
"(ns example
(:require [cloact.core :as cloact :refer [atom]]))
2014-01-02 13:04:30 +00:00
")
(defn src-for-names [names]
2014-01-06 11:46:58 +00:00
(string/join "\n" (-> srcmap
(assoc :ns nssrc)
(select-keys names)
vals)))
2014-01-02 16:45:31 +00:00
2014-01-05 12:29:22 +00:00
(defn src-for [defs]
2014-01-06 11:46:58 +00:00
[:pre (-> defs src-for-names demoutil/syntaxify)])
2014-01-02 13:04:30 +00:00
(defn demo-component [{:keys [comp defs src]}]
2014-01-07 11:45:08 +00:00
(let [colored (if src
(demoutil/syntaxify src)
(src-for defs))
showing (atom true)]
(fn []
[:div
(when comp
[:div.demo-example
[:a.demo-example-hide {:on-click (fn [e]
(.preventDefault e)
(swap! showing not))}
(if @showing "hide" "show")]
[:h3.demo-heading "Example "]
(when @showing
(if defs
[:div.simple-demo [comp]]
[comp]))])
(when @showing
[:div.demo-source
[:h3.demo-heading "Source"]
colored])])))
2014-01-02 15:18:21 +00:00
2014-01-02 13:04:30 +00:00
(defn simple-component []
[:div
2014-01-03 09:56:15 +00:00
[:p "I am a component!"]
2014-01-02 13:04:30 +00:00
[:p.someclass
"I have " [:strong "bold"]
2014-01-03 09:56:15 +00:00
[:span {:style {:color "red"}} " and red "] "text."]])
2014-01-02 13:04:30 +00:00
2014-01-03 09:56:15 +00:00
(defn simple-parent []
2014-01-02 13:04:30 +00:00
[:div
2014-01-03 09:56:15 +00:00
[:p "I include simple-component."]
[simple-component]])
(defn lister [props]
[:ul
(for [item (:items props)]
2014-01-03 15:52:05 +00:00
[:li {:key item} "Item " item])])
2014-01-03 09:56:15 +00:00
(defn lister-user []
[:div
"Here is a list:"
[lister {:items (range 3)}]])
2014-01-02 15:18:21 +00:00
2014-01-03 12:22:41 +00:00
(def click-count (atom 0))
(defn counting-component []
[:div
2014-01-03 14:52:18 +00:00
"The atom " [:code "click-count"] " has value: "
@click-count ". "
2014-01-04 14:03:26 +00:00
[:input {:type "button" :value "Click me!"
2014-01-03 12:22:41 +00:00
:on-click #(swap! click-count inc)}]])
2014-01-04 14:03:26 +00:00
(defn atom-input [{:keys [value]}]
[:input {:type "text"
:value @value
:on-change #(reset! value (-> % .-target .-value))}])
(defn shared-state []
2014-01-03 12:22:41 +00:00
(let [val (atom "foo")]
(fn []
[:div
2014-01-04 09:56:21 +00:00
[:p "The value is now: " @val]
2014-01-04 14:03:26 +00:00
[:p "Change it here: "
[atom-input {:value val}]]])))
2014-01-03 14:52:18 +00:00
2014-01-04 09:56:21 +00:00
(defn timer-component []
(let [seconds-elapsed (atom 0)]
(fn []
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:div
"Seconds Elapsed: " @seconds-elapsed])))
2014-01-03 14:52:18 +00:00
(defn render-simple []
(cloact/render-component [simple-component]
(.-body js/document)))
2014-01-03 12:22:41 +00:00
2014-01-07 11:45:08 +00:00
(defn calc-bmi [params to-calc]
(let [{:keys [height weight bmi]} params
h (/ height 100)]
(case to-calc
:bmi (assoc params :bmi (/ weight (* h h)))
:weight (assoc params :weight (* bmi h h)))))
2014-01-02 15:18:21 +00:00
2014-01-07 11:45:08 +00:00
(def bmi-data (atom (calc-bmi {:height 180 :weight 80} :bmi)))
2014-01-02 15:18:21 +00:00
2014-01-07 11:45:08 +00:00
(defn set-bmi [key val]
(swap! bmi-data #(calc-bmi (assoc % key val)
(case key :bmi :weight :bmi))))
2014-01-02 15:18:21 +00:00
2014-01-07 11:45:08 +00:00
(defn slider [{:keys [value min max param]}]
2014-01-02 15:18:21 +00:00
[:div
[:input {:type "range" :min min :max max :value value
:style {:width "100%"}
2014-01-07 11:45:08 +00:00
:on-change #(set-bmi param (-> % .-target .-value))}]])
2014-01-02 15:18:21 +00:00
(defn bmi-component []
(let [{:keys [weight height bmi]} @bmi-data
[color diagnose] (cond
(< bmi 18.5) ["orange" "underweight"]
(< bmi 25) ["inherit" "normal"]
(< bmi 30) ["orange" "overweight"]
:else ["red" "obese"])]
[:div
2014-01-03 14:52:18 +00:00
[:h3 "BMI calculator"]
2014-01-02 15:18:21 +00:00
[:div
"Height: " (int height) "cm"
2014-01-03 14:52:18 +00:00
[slider {:value height :min 100 :max 220 :param :height}]]
2014-01-02 15:18:21 +00:00
[:div
"Weight: " (int weight) "kg"
2014-01-03 14:52:18 +00:00
[slider {:value weight :min 30 :max 150 :param :weight}]]
2014-01-02 15:18:21 +00:00
[:div
"BMI: " (int bmi) " "
[:span {:style {:color color}} diagnose]
2014-01-07 11:45:08 +00:00
[slider {:value bmi :min 10 :max 50 :param :bmi}]]]))
2014-01-02 15:18:21 +00:00
2014-01-03 09:56:15 +00:00
(defn intro []
2014-01-07 11:45:08 +00:00
[:div.demo-text
2014-01-03 12:22:41 +00:00
[:h2 "Introduction to Cloact"]
2014-01-03 09:56:15 +00:00
2014-01-05 12:29:22 +00:00
[:p [:a {:href "https://github.com/holmsand/cloact"} "Cloact"]
" provides a minimalistic interface between "
2014-01-04 14:03:26 +00:00
[:a {:href "https://github.com/clojure/clojurescript"} "ClojureScript"]
" and " [:a {:href "http://facebook.github.io/react/"} "React"]
". It allows you to define React components using nothing but
plain ClojureScript functions, that describe your UI using a
Hiccup-like syntax."]
2014-01-03 09:56:15 +00:00
[:p "A very basic component may look something like this: "]
[demo-component {:comp simple-component
:defs [:simple-component]}]
[:p "You can build new components using other components as
building blocks. That looks like this:"]
[demo-component {:comp simple-parent
:defs [:simple-parent]}]
2014-01-07 11:45:08 +00:00
[:p "Data is passed to child components using plain old Clojure
2014-01-03 09:56:15 +00:00
maps. For example, here is a component that shows items in a "
2014-01-07 11:45:08 +00:00
[:code "seq"] ":" ]
2014-01-03 09:56:15 +00:00
[demo-component {:comp lister-user
2014-01-03 15:52:05 +00:00
:defs [:lister :lister-user]}]
[:p [:strong "Note: "]
"The " [:code "{:key item}"] " part of the " [:code ":li"] " isn't
really necessary in this simple example, but passing a unique key
for every item in a dynamically generated list of components is
good practice, and helps React to improve performance a lot for
large lists."]])
2014-01-03 12:22:41 +00:00
(defn managing-state []
2014-01-07 11:45:08 +00:00
[:div.demo-text
2014-01-03 12:22:41 +00:00
[:h2 "Managing state in Cloact"]
[:p "The easiest way to manage state in Cloact is to use Cloact's
own version of " [:code "atom"] ". It works exactly like the one in
clojure.core, except that it keeps track of every time it is
2014-01-03 14:52:18 +00:00
deref'ed. Any component that uses an " [:code "atom"]" is automagically
re-rendered when its value changes."]
2014-01-03 12:22:41 +00:00
[:p "Let's demonstrate that with a simple example:"]
[demo-component {:comp counting-component
:defs [:ns :click-count :counting-component]}]
[:p "Sometimes you may want to maintain state locally in a
2014-01-03 14:52:18 +00:00
component. That is easy to do with an " [:code "atom"] " as well."]
2014-01-03 12:22:41 +00:00
2014-01-04 14:03:26 +00:00
[:p "Here is an example of that, where we call setTimeout every
time the component is rendered to update a simple clock:"]
[demo-component {:comp timer-component
:defs [:timer-component]}]
2014-01-04 09:56:21 +00:00
[:p "The previous example also uses another feature of Cloact: a component
2014-01-03 12:22:41 +00:00
function can return another function, that is used to do the actual
rendering. It is called with the same arguments as any other
component function. This allows you to perform some setup of newly
created components, without resorting to React's lifecycle
2014-01-04 09:56:21 +00:00
events."]
2014-01-04 14:03:26 +00:00
[:p "By simply passing atoms around you can share state management
between components, like this:"]
[demo-component {:comp shared-state
:defs [:ns :atom-input :shared-state]}]])
2014-01-03 09:56:15 +00:00
2014-01-03 14:52:18 +00:00
(defn essential-api []
2014-01-07 11:45:08 +00:00
[:div.demo-text
2014-01-03 14:52:18 +00:00
[:h2 "Essential API"]
[:p "Cloact supports most of React's API, but there is really only
one entry-point that is necessary for most applications: "
2014-01-04 14:03:26 +00:00
[:code "cloact.core/render-component"] "."]
2014-01-03 14:52:18 +00:00
[:p "It takes too arguments: a component, and a DOM node. For
example, splashing the very first example all over the page would
look like this:"]
[demo-component {:defs [:ns :simple-component :render-simple]}]])
2014-01-03 09:56:15 +00:00
2014-01-02 15:18:21 +00:00
(defn bmi-demo []
2014-01-07 11:45:08 +00:00
[:div.demo-text
2014-01-03 14:52:18 +00:00
[:h2 "Putting it all together"]
[:p "Here is a slightly less contrived example: a simple BMI
calculator."]
[:p "Data is kept in a single " [:code "cloact.core/atom"] ": a map
with height, weight and BMI as keys."]
2014-01-02 15:18:21 +00:00
[demo-component {:comp bmi-component
:defs [:ns :calc-bmi :bmi-data :set-bmi :slider
:bmi-component]}]])
2014-01-02 13:04:30 +00:00
(defn test-results []
2014-01-07 11:45:08 +00:00
[:div.demo-text
[:h2 "Test results"]
[runtests/test-output]])
(defn complete-simple-demo []
2014-01-07 11:45:08 +00:00
[:div.demo-text
[:h2 "Another demo"]
[demo-component {:comp simpleexample/simple-example
:src (get-source "simpleexample.cljs")}]])
(defn todomvc-demo []
2014-01-07 11:45:08 +00:00
[:div.demo-text
[:h2 "Todomvc"]
[demo-component {:comp todomvc/todo-app
:src (get-source "todomvc.cljs")}]])
2014-01-02 13:04:30 +00:00
(defn demo []
[:div
[:div.test-output-mini
[runtests/test-output-mini]]
[:div.cloact-demo
[:h1 "This will become a demo"]
[intro]
[managing-state]
[essential-api]
[bmi-demo]
[test-results]
[complete-simple-demo]
[todomvc-demo]
[:p "WIP"]]])
2014-01-05 10:16:01 +00:00
(defn ^:export mountdemo []
(cloact/render-component [demo] (.-body js/document)))
(defn ^:export genpage []
(cloact/render-component-to-string [demo]))