Skip to content

Instantly share code, notes, and snippets.

@andreloureiro
Created April 1, 2016 20:07
Show Gist options
  • Save andreloureiro/464e7221a309ebf77cfd37e4f2f5ae9f to your computer and use it in GitHub Desktop.
Save andreloureiro/464e7221a309ebf77cfd37e4f2f5ae9f to your computer and use it in GitHub Desktop.
(ns nix.example
(:require [nix.core :refer [Observable run]]
[nix.dom :refer [make-dom-driver]]))
;; Checkbox Example
(defn CheckboxToggle [{:keys [DOM]}]
(let [{:keys [select]} DOM
checkbox-evs$ (:events (select "#cbox"))
checkbox-change$ (-> (checkbox-evs$ "change")
(.map #(.. % -target -checked))
(.startWith false))]
{:DOM (-> checkbox-change$
(.map (fn [v]
[:div nil
[:input {:id "cbox" :type "checkbox"}]
[:p nil (if v "toggled" "not")]])))}))
;; Input update
(defn InputUpdate [{:keys [DOM]}]
(let [{:keys [select]} DOM
input-evs$ (:events (select "#inputName"))
input-value$ (-> (input-evs$ "input")
(.map #(.. % -target -value))
(.startWith ""))]
{:DOM (-> input-value$
(.map (fn [v] [:div nil
[:input {:id "inputName" :type "text"}]
[:p nil (str "your name: " v)]])))}))
;; Counter
(defn render-vtree$ [state$]
(-> state$
(.scan (fn [state action] (action state)))
(.map (fn [v]
[:div nil
[:button {:id "increment"} "increment"]
[:button {:id "decrement"} "decrement"]
[:p nil (str v)]]))))
(defn Counter [{:keys [DOM]}]
(let [{:keys [select]} DOM
btn-inc-evs$ (:events (select "#increment"))
increment$ (-> (btn-inc-evs$ "click")
(.map #(fn [c] (inc c))))
btn-dec-evs$ (:events (select "#decrement"))
decrement$ (-> (btn-dec-evs$ "click")
(.map #(fn [c] (dec c))))
state$ (-> Observable
(.merge increment$ decrement$)
(.startWith 0))]
{:DOM (render-vtree$ state$)}))
;; BMI
(defn LabeledSlider [{:keys [DOM props$]}]
(let [{:keys [select]} DOM
slider-evs$ (:events (select "#slider"))
slider-value$ (-> (slider-evs$ "input")
(.map #(.. % -target -value))
(.startWith 10))]
{:DOM (-> Observable
(.combineLatest
props$
slider-value$
(fn [{:keys [label]} slider-value]
[:div nil
[:p nil (str label ": " slider-value " cm")]
[:input {:id "slider"
:type "range"
:min 0
:max 100
:value slider-value}]])))
:value$ slider-value$}))
(defn BMI [{:keys [DOM]}]
(let [{:keys [select]} DOM
height-component (LabeledSlider {:DOM DOM
:props$ (-> Observable
(.of {:label "Height"}))} )
weight-component (LabeledSlider {:DOM DOM
:props$ (-> Observable
(.of {:label "Weight"}))})
state$ (-> Observable
(.combineLatest
(:value$ height-component)
(:value$ weight-component)
(fn [height weight]
(let [height-meters (* height 0.01)
bmi (/ weight (* height-meters height-meters))]
{:height height
:weight weight
:bmi bmi}))))]
{:DOM (-> state$
(.combineLatest
(:DOM height-component)
(:DOM weight-component)
(fn [state height-dom weight-dom]
[:div nil
height-dom
weight-dom
[:strong nil (str "BMI is " (:bmi state))]])
))}))
;; (defn BMI [{:keys [DOM]}]
;; (let [{:keys [select]} DOM
;; height$ (-> (select "#height" "input")
;; (.map #(.. % -target -value))
;; (.startWith 170))
;; weight$ (-> (select "#weight" "input")
;; (.map #(.. % -target -value))
;; (.startWith 70))
;; state$ (-> Observable
;; (.combineLatest
;; height$
;; weight$
;; (fn [height weight]
;; (let [height-meters (* height 0.01)
;; bmi (/ weight (* height-meters height-meters))]
;; {:height height
;; :weight weight
;; :bmi bmi}))))]
;; {:DOM (-> state$
;; (.map (fn [state]
;; [:div nil
;; [:p nil (str "Height " (:height state) " cm")]
;; [:input {:id "height" :type "range" :min 140 :max 210 :value (:height state)}]
;; [:p nil (str "Weight " (:weight state) " kg")]
;; [:input {:id "weight" :type "range" :min 40 :max 140 :value (:weight state)}]
;; [:strong nil (str "BMI is " (:bmi state))]])))}))
;; Example container
(defn example-select-action$ [{:keys [select]} id v]
(let [btn-evs$ (:events (select id))]
(-> (btn-evs$ "click")
(.map (fn [_] v)))))
(defn Examples [{:keys [DOM]}]
(let [select-counter$ (example-select-action$ DOM "#one" 0)
select-checkbox$ (example-select-action$ DOM "#two" 1)
select-bmi$ (example-select-action$ DOM "#three" 2)
select-input-update$ (example-select-action$ DOM "#four" 3)
active-view$ (-> Observable
(.merge select-counter$ select-checkbox$ select-bmi$ select-input-update$)
(.startWith 2))
{counter-dom$ :DOM} (Counter {:DOM DOM})
{checkbox-toggle-dom$ :DOM} (CheckboxToggle {:DOM DOM})
{bmi-dom$ :DOM} (BMI {:DOM DOM})
{input-update-dom$ :DOM} (InputUpdate {:DOM DOM})]
{:DOM (-> active-view$
(.combineLatest
counter-dom$
checkbox-toggle-dom$
bmi-dom$
input-update-dom$
(fn [active-view
counter-dom
checkbox-toggle-dom
bmi-dom
input-update-dom]
[:div nil
[:h1 nil "Nix Examples"]
[:button {:id "one"} "counter"]
[:button {:id "two"} "checkbox toggle"]
[:button {:id "three"} "bmi"]
[:button {:id "four"} "input update"]
[:hr]
(condp = active-view
0 counter-dom
1 checkbox-toggle-dom
2 bmi-dom
3 input-update-dom
[:div nil "Select an example"])
])))}))
(defn input-value$ [{:keys [select]}]
(let [input-evs$ (:events (select "#input"))]
(-> (input-evs$ "input")
(.map #(.. % -target -value))
(.startWith ""))))
(def drivers {:DOM (make-dom-driver "#app")})
(run Examples drivers)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment