mirror of https://github.com/status-im/reagent.git
Merge branch 'betterdemo'
This commit is contained in:
commit
572e4bbf96
|
@ -2,7 +2,7 @@
|
|||
(:require [reagent.core :as r]
|
||||
[reagent.interop :as i :refer-macros [.' .!]]
|
||||
[clojure.string :as string]
|
||||
[sitetools.core :as tools :refer [link]]
|
||||
[sitetools.core :as tools :refer [dispatch link]]
|
||||
[reagentdemo.common :as common :refer [demo-component]]
|
||||
[reagentdemo.intro :as intro]
|
||||
[reagentdemo.news :as news]
|
||||
|
@ -19,28 +19,26 @@
|
|||
:alt "Fork me on GitHub"
|
||||
:src "https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png"}]])
|
||||
|
||||
(def index-page "index.html")
|
||||
(def news-page "news/index.html")
|
||||
(def index-page "/index.html")
|
||||
(def title "Minimalistic React for ClojureScript")
|
||||
|
||||
(tools/register-page index-page [#'intro/main] title)
|
||||
|
||||
(tools/register-page index-page [#'intro/main]
|
||||
"Reagent: Minimalistic React for ClojureScript")
|
||||
(tools/register-page news-page [#'news/main]
|
||||
"Reagent news")
|
||||
|
||||
(defn demo []
|
||||
[:div
|
||||
[:div.nav
|
||||
[:ul.nav
|
||||
[:li.brand [link {:href index-page} "Reagent:"]]
|
||||
[:li [link {:href index-page} "Intro"]]
|
||||
[:li [link {:href news-page} "News"]]
|
||||
[:li [:a github "GitHub"]]]]
|
||||
@test-results
|
||||
[tools/page-content]
|
||||
[:div.nav>ul.nav
|
||||
[:li.brand [link {:href index-page} "Reagent:"]]
|
||||
[:li [link {:href index-page} "Intro"]]
|
||||
[:li [link {:href news/url} "News"]]
|
||||
[:li>a github "GitHub"]]
|
||||
[:div @test-results]
|
||||
[tools/main-content]
|
||||
[github-badge]])
|
||||
|
||||
(defn init! []
|
||||
(tools/start! {:body [#'demo]
|
||||
:title-prefix "Reagent: "
|
||||
:css-infiles ["site/public/css/examples.css"
|
||||
"site/public/css/main.css"]}))
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
[reagentdemo.news.undodemo :as undodemo]
|
||||
[reagentdemo.news.clockpost :as clock]
|
||||
[reagentdemo.news.news050 :as news050]
|
||||
[reagentdemo.news.news051 :as news051]))
|
||||
[reagentdemo.news.news051 :as news051]
|
||||
[sitetools.core :as tools]))
|
||||
|
||||
(defn main []
|
||||
[:div
|
||||
|
@ -14,3 +15,6 @@
|
|||
[anyargs/main {:summary true}]
|
||||
[async/main {:summary true}]
|
||||
[undodemo/main {:summary true}]])
|
||||
|
||||
(def url "/news/index.html")
|
||||
(tools/register-page url [#'main] "News")
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[reagentdemo.common :as common :refer [demo-component]]
|
||||
[geometry.core :as geometry]))
|
||||
|
||||
(def url "news/any-arguments.html")
|
||||
(def url "/news/any-arguments.html")
|
||||
(def title "All arguments allowed")
|
||||
|
||||
(def ns-src (s/syntaxed "(ns example
|
||||
|
@ -133,5 +133,4 @@
|
|||
|
||||
[demo-component {:comp geometry-example}]])]]))
|
||||
|
||||
(tools/register-page url [main]
|
||||
(str "Reagent 0.4.0: " title))
|
||||
(tools/register-page url [#'main] title)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[sitetools.core :as tools :refer [link]]
|
||||
[reagentdemo.common :as common :refer [demo-component]]))
|
||||
|
||||
(def url "news/reagent-is-async.html")
|
||||
(def url "/news/reagent-is-async.html")
|
||||
(def title "Faster by waiting")
|
||||
|
||||
(def ns-src (s/syntaxed "(ns example
|
||||
|
@ -197,5 +197,4 @@
|
|||
:ncolors-choose :color-plate
|
||||
:palette :color-demo])]}]])]]))
|
||||
|
||||
(tools/register-page url [main]
|
||||
(str "Reagent: " title))
|
||||
(tools/register-page url [#'main] title)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[reagentdemo.common :as common :refer [demo-component]]
|
||||
[reagentdemo.news.binaryclock :as binaryclock]))
|
||||
|
||||
(def url "news/binary-clock.html")
|
||||
(def url "/news/binary-clock.html")
|
||||
(def title "A binary clock")
|
||||
|
||||
(defn fn-src [src]
|
||||
|
@ -122,5 +122,4 @@
|
|||
description that corresponds to those arguments, and leave it
|
||||
to React to actually display that UI."]])]]))
|
||||
|
||||
(tools/register-page url [main]
|
||||
(str "Reagent: " title))
|
||||
(tools/register-page url [#'main] title)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[sitetools.core :as tools :refer [link]]
|
||||
[reagentdemo.common :as common :refer [demo-component]]))
|
||||
|
||||
(def url "news/news050.html")
|
||||
(def url "/news/news050.html")
|
||||
(def title "News in 0.5.0")
|
||||
|
||||
(def new-in-alpha [:strong "New since 0.5.0-alpha: "])
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[reagentdemo.common :as common :refer [demo-component]]
|
||||
[todomvc.core :as todomvc]))
|
||||
|
||||
(def url "news/cloact-reagent-undo-demo.html")
|
||||
(def url "/news/cloact-reagent-undo-demo.html")
|
||||
(def title "Cloact becomes Reagent: Undo is trivial")
|
||||
|
||||
(def ns-src (s/syntaxed "(ns example
|
||||
|
@ -89,4 +89,4 @@
|
|||
|
||||
[undo-demo-cleanup]])]]))
|
||||
|
||||
(tools/register-page url [main] title)
|
||||
(tools/register-page url [#'main] title)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[clojure.string :as string]))
|
||||
|
||||
|
||||
;;;; Source splitting
|
||||
;;; Source splitting
|
||||
|
||||
(defn src-parts [src]
|
||||
(string/split src #"\n(?=[(])"))
|
||||
|
@ -23,9 +23,19 @@
|
|||
;;; Macros
|
||||
|
||||
(defmacro syntaxed [src]
|
||||
(assert (string? src))
|
||||
`(reagentdemo.syntax/syntaxify ~src))
|
||||
|
||||
;; ;; A much simpler way to find source: currently broken with #js annotations
|
||||
;; (defmacro src-for [& syms]
|
||||
;; (let [s (map #(list 'with-out-str (list 'cljs.repl/source %)) syms)]
|
||||
;; `(->> [~@s]
|
||||
;; (string/join "\n")
|
||||
;; syntaxed)))
|
||||
|
||||
;; (defmacro src-from-file [f]
|
||||
;; (let [src (-> f io/resource slurp)]
|
||||
;; `(syntaxed ~src)))
|
||||
|
||||
(defmacro src-of
|
||||
([funs]
|
||||
`(src-of ~funs nil))
|
||||
|
@ -40,8 +50,7 @@
|
|||
(str ".cljs"))
|
||||
resource)
|
||||
src (-> f io/resource slurp)
|
||||
fm (fun-map src)
|
||||
sel (if (nil? funs)
|
||||
src
|
||||
(-> src fun-map (src-for-names funs)))]
|
||||
`(reagentdemo.syntax/syntaxify ~sel))))
|
||||
`(syntaxed ~sel))))
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
|
||||
;; Styles for syntax highlighting
|
||||
|
||||
(def comment-style {:style {:color "gray"
|
||||
:font-style "italic"}})
|
||||
(def string-style {:style {:color "green"}})
|
||||
(def comment-style {:style {:color "gray" :font-style "italic"}})
|
||||
(def string-style {:style {:color "green"}})
|
||||
(def keyword-style {:style {:color "blue"}})
|
||||
(def builtin-style {:style {:font-weight "bold"
|
||||
:color "#687868"}})
|
||||
(def def-style {:style {:color "#55c"
|
||||
:font-weight "bold"}})
|
||||
(def builtin-style {:style {:color "#687868" :font-weight "bold"}})
|
||||
(def def-style {:style {:color "#5050c0" :font-weight "bold"}})
|
||||
|
||||
(def paren-style-1 {:style {:color "#272"}})
|
||||
(def paren-style-2 {:style {:color "#940"}})
|
||||
|
@ -29,7 +26,7 @@
|
|||
"update-in" "sorted-map" "inc" "dec" "false" "true" "not"
|
||||
"=" "partial" "first" "second" "rest" "list" "conj"
|
||||
"drop" "when-let" "if-let" "add-watch" "mod" "quot"
|
||||
"bit-test" "vector"})
|
||||
"bit-test" "vector" "do"})
|
||||
|
||||
(def styles {:comment comment-style
|
||||
:str-litt string-style
|
||||
|
@ -39,50 +36,52 @@
|
|||
|
||||
(def paren-styles [paren-style-1 paren-style-2 paren-style-3])
|
||||
|
||||
(defn tokenize [src]
|
||||
(let [ws " \\t\\n"
|
||||
open "\\[({"
|
||||
close ")\\]}"
|
||||
sep (str ws open close)
|
||||
(def tokenize-pattern
|
||||
(let [ws " \\t\\n"
|
||||
open "\\[({"
|
||||
close ")\\]}"
|
||||
sep (str ws open close)
|
||||
comment-p ";.*"
|
||||
str-p "\"[^\"]*\""
|
||||
open-p (str "[" open "]")
|
||||
close-p (str "[" close "]")
|
||||
iden-p (str "[^" sep "]+")
|
||||
meta-p (str "\\^" iden-p)
|
||||
any-p (str "[" ws "]+" "|\\^[^" sep "]+|.")
|
||||
patt (re-pattern (str "("
|
||||
(string/join ")|(" [comment-p str-p open-p
|
||||
close-p meta-p iden-p any-p])
|
||||
")"))
|
||||
keyw-re #"^:"
|
||||
qualif-re #"^r/"]
|
||||
(for [[s comment str-litt open close met iden any] (re-seq patt src)]
|
||||
(cond
|
||||
comment [:comment s]
|
||||
str-litt [:str-litt s]
|
||||
open [:open s]
|
||||
close [:close s]
|
||||
met [:other s]
|
||||
iden (cond
|
||||
(re-find keyw-re s) [:keyw s]
|
||||
(builtins s) [:builtin s]
|
||||
(re-find qualif-re s) [:builtin s]
|
||||
:else [:iden s])
|
||||
any [:other s]))))
|
||||
str-p "\"[^\"]*\""
|
||||
open-p (str "[" open "]")
|
||||
close-p (str "[" close "]")
|
||||
iden-p (str "[^" sep "]+")
|
||||
meta-p (str "\\^" iden-p)
|
||||
any-p (str "[" ws "]+|\\^[^" sep "]+|.")]
|
||||
(re-pattern (str "("
|
||||
(string/join ")|(" [comment-p str-p open-p
|
||||
close-p meta-p iden-p any-p])
|
||||
")"))))
|
||||
|
||||
(def keyw-re #"^:")
|
||||
(def qualif-re #"^[a-z]+/")
|
||||
(def def-re #"^def|^ns\b")
|
||||
|
||||
(defn tokenize [src]
|
||||
(for [[s comment strlitt open close met iden any]
|
||||
(re-seq tokenize-pattern src)]
|
||||
(cond
|
||||
(some? comment) [:comment s]
|
||||
(some? strlitt) [:str-litt s]
|
||||
(some? open) [:open s]
|
||||
(some? close) [:close s]
|
||||
(some? met) [:other s]
|
||||
(some? iden) (cond (re-find keyw-re s) [:keyw s]
|
||||
(builtins s) [:builtin s]
|
||||
(re-find qualif-re s) [:builtin s]
|
||||
:else [:iden s])
|
||||
(some? any) [:other s])))
|
||||
|
||||
(defn syntaxify [src]
|
||||
(let [def-re #"^def|^ns\b"
|
||||
ncol (count paren-styles)
|
||||
paren-style (fn [level]
|
||||
(nth paren-styles (mod level ncol)))]
|
||||
(let [ncol (count paren-styles)
|
||||
paren-style #(nth paren-styles (mod % ncol))]
|
||||
(loop [tokens (tokenize (str src " "))
|
||||
prev nil
|
||||
level 0
|
||||
res []]
|
||||
(let [[kind val] (first tokens)
|
||||
level' (case kind
|
||||
:open (inc level)
|
||||
:open (inc level)
|
||||
:close (dec level)
|
||||
level)
|
||||
style (case kind
|
||||
|
@ -94,7 +93,7 @@
|
|||
remain (rest tokens)]
|
||||
(if-not (empty? remain)
|
||||
(recur remain
|
||||
(if (= kind :other) prev val)
|
||||
(case kind :other prev val)
|
||||
level'
|
||||
(if (nil? style)
|
||||
(let [old (peek res)]
|
||||
|
@ -102,4 +101,4 @@
|
|||
(conj (pop res) (str old val))
|
||||
(conj res val)))
|
||||
(conj res [:span style val])))
|
||||
(apply vector :pre res))))))
|
||||
(into [:pre] res))))))
|
||||
|
|
|
@ -1,258 +1,205 @@
|
|||
(ns sitetools.core
|
||||
(:require [clojure.string :as string]
|
||||
[goog.events :as evt]
|
||||
[goog.history.EventType :as hevt]
|
||||
[reagent.core :as r]
|
||||
[reagent.debug :refer-macros [dbg log dev?]]
|
||||
[reagent.interop :as i :refer-macros [.' .!]])
|
||||
(:import [goog History]
|
||||
[goog.history Html5History]
|
||||
[goog.net Jsonp]))
|
||||
(:import goog.History
|
||||
[goog.history Html5History EventType]))
|
||||
|
||||
(when (exists? js/console)
|
||||
(enable-console-print!))
|
||||
(enable-console-print!)
|
||||
|
||||
(declare page-content)
|
||||
(defn rswap! [a f & args]
|
||||
;; Like swap!, except that recursive swaps on the same atom are ok,
|
||||
;; and always returns nil.
|
||||
{:pre [(satisfies? ISwap a)
|
||||
(ifn? f)]}
|
||||
(if a.rswapping
|
||||
(-> (or a.rswapfs (set! a.rswapfs (array)))
|
||||
(.push #(apply f % args)))
|
||||
(do (set! a.rswapping true)
|
||||
(try (swap! a (fn [state]
|
||||
(loop [s (apply f state args)]
|
||||
(if-some [sf (some-> a.rswapfs .shift)]
|
||||
(recur (sf s))
|
||||
s))))
|
||||
(finally
|
||||
(set! a.rswapping false)))))
|
||||
nil)
|
||||
|
||||
|
||||
;;; Configuration
|
||||
|
||||
(defonce config (r/atom {:page-map {"index.html" [:div "Empty"]}
|
||||
:page-titles {}
|
||||
:body [page-content]
|
||||
(declare main-content)
|
||||
|
||||
(defonce config (r/atom {:body [#'main-content]
|
||||
:pages {"/index.html" {:content [:div]
|
||||
:title ""}}
|
||||
:site-dir "outsite/public"
|
||||
:css-infiles ["site/public/css/main.css"]
|
||||
:css-file "css/built.css"
|
||||
:js-file "js/main.js"
|
||||
:js-dir "js/out"
|
||||
:main-div "main-content"
|
||||
:allow-html5-history false}))
|
||||
:default-title ""}))
|
||||
|
||||
(defonce page (r/atom "index.html"))
|
||||
(defonce page-state (r/atom {:has-history false}))
|
||||
(defonce history nil)
|
||||
|
||||
(defn register-page
|
||||
([pageurl comp]
|
||||
(register-page pageurl comp nil))
|
||||
([pageurl comp title]
|
||||
(assert (string? pageurl)
|
||||
(str "expected string, not " pageurl))
|
||||
(assert (vector? comp)
|
||||
(str "expected vector, not " (pr-str comp)))
|
||||
(assert (or (nil? title)
|
||||
(string? title)))
|
||||
(swap! config update-in [:page-map] assoc pageurl comp)
|
||||
(swap! config update-in [:page-titles] assoc pageurl title)
|
||||
pageurl))
|
||||
(defn demo-handler [state [id x :as event]]
|
||||
(case id
|
||||
:set-content (let [page x
|
||||
title (:title page)
|
||||
title (if title
|
||||
(str (:title-prefix state) title)
|
||||
(str (:default-title state)))]
|
||||
(when r/is-client
|
||||
(set! js/document.title title))
|
||||
(assoc state :current-page page :title title))
|
||||
:set-page (let [path x
|
||||
_ (assert (string? path))
|
||||
ps (:pages state)
|
||||
p (get ps path (get ps "/index.html"))]
|
||||
(recur state [:set-content p]))
|
||||
:goto-page (let [path x
|
||||
_ (assert (string? path))]
|
||||
(when-some [h history]
|
||||
(.setToken h x)
|
||||
(r/next-tick #(set! js/document.body.scrollTop 0))
|
||||
state)
|
||||
(recur state [:set-page x]))))
|
||||
|
||||
(defn dispatch [event]
|
||||
;; (dbg event)
|
||||
(rswap! config demo-handler event))
|
||||
|
||||
(defn register-page [url comp title]
|
||||
{:pre [(re-matches #"/.*[.]html" url)
|
||||
(vector? comp)]}
|
||||
(swap! config update-in [:pages]
|
||||
assoc url {:content comp :title title}))
|
||||
|
||||
|
||||
;;; History
|
||||
|
||||
(defn init-history [page]
|
||||
(when-not history
|
||||
(let [html5 (and page
|
||||
(Html5History.isSupported)
|
||||
(#{"http:" "https:"} js/location.protocol))]
|
||||
(doto (set! history
|
||||
(if html5
|
||||
(doto (Html5History.)
|
||||
(.setUseFragment false)
|
||||
(.setPathPrefix (-> js/location.pathname
|
||||
(string/replace
|
||||
(re-pattern (str page "$")) "")
|
||||
(string/replace #"/*$" ""))))
|
||||
(History.)))
|
||||
(evt/listen EventType.NAVIGATE #(when (.-isNavigation %)
|
||||
(dispatch [:set-page (.-token %)])))
|
||||
(.setEnabled true))
|
||||
(let [token (.getToken history)
|
||||
p (if (and page (not html5) (empty? token))
|
||||
page
|
||||
token)]
|
||||
(dispatch [:set-page p])))))
|
||||
|
||||
(defn to-relative [f]
|
||||
(string/replace f #"^/" ""))
|
||||
|
||||
|
||||
;;; Components
|
||||
|
||||
(defn link
|
||||
[props child]
|
||||
(let [p (:href props)
|
||||
f ((:page-map @config) p)]
|
||||
(assert (vector? f) (str "couldn't resolve page " p))
|
||||
(assert (string? p))
|
||||
[:a (assoc props
|
||||
:href p
|
||||
:on-click (if (:has-history @page-state)
|
||||
(fn [e]
|
||||
(.preventDefault e)
|
||||
(reset! page p)
|
||||
(r/next-tick
|
||||
#(set! (.-scrollTop (.-body js/document))
|
||||
0)))
|
||||
identity))
|
||||
child]))
|
||||
(defn link [props child]
|
||||
[:a (assoc props
|
||||
:href (-> props :href to-relative)
|
||||
:on-click #(do (.preventDefault %)
|
||||
(dispatch [:goto-page (:href props)])))
|
||||
child])
|
||||
|
||||
(defn page-content []
|
||||
(get-in @config [:page-map @page]
|
||||
(get-in @config [:page-map "index.html"])))
|
||||
|
||||
|
||||
|
||||
;;; Implementation:
|
||||
|
||||
(defn get-title []
|
||||
(get-in @config [:page-titles @page]
|
||||
(or (get-in @config [:page-titles "index.html"])
|
||||
"")))
|
||||
|
||||
(defn default-content []
|
||||
[:div "Empty"])
|
||||
|
||||
(add-watch page ::title-watch
|
||||
(fn [_ _ _ p]
|
||||
(when r/is-client
|
||||
(set! (.-title js/document) (get-title)))
|
||||
;; First title on a page wins
|
||||
#_(reset! page-title "")))
|
||||
|
||||
;;; History
|
||||
|
||||
(defn use-html5-history []
|
||||
(when r/is-client
|
||||
(let [proto (.' js/window :location.protocol)]
|
||||
(and (:allow-html5-history @config)
|
||||
(.isSupported Html5History)
|
||||
(#{"http:" "https:"} proto)))))
|
||||
|
||||
(defn create-history [p]
|
||||
(if (use-html5-history)
|
||||
(doto (Html5History.)
|
||||
(.setUseFragment false))
|
||||
(let [h (History.)]
|
||||
(when p
|
||||
(.setToken h p))
|
||||
h)))
|
||||
|
||||
(defonce history nil)
|
||||
|
||||
(defn token-base []
|
||||
(if (use-html5-history)
|
||||
(:base-path @config)))
|
||||
|
||||
(defn setup-history [p]
|
||||
(when (nil? history)
|
||||
(set! history (create-history p))
|
||||
(swap! page-state assoc :has-history (some? history))
|
||||
(when-let [h history]
|
||||
(evt/listen h hevt/NAVIGATE
|
||||
(fn [e]
|
||||
(let [t (.-token e)
|
||||
tb (token-base)]
|
||||
(reset! page (if (and tb (== 0 (.indexOf t tb)))
|
||||
(subs t (count tb))
|
||||
t)))
|
||||
(r/flush)))
|
||||
(add-watch page ::history
|
||||
(fn [_ _ oldp newp]
|
||||
(when-not (= oldp newp)
|
||||
(.setToken h (str (token-base) newp)))))
|
||||
(.setEnabled h true))))
|
||||
|
||||
(defn base-path [loc p]
|
||||
;; Find base-path for html5 history
|
||||
(let [split #".[^/]*"
|
||||
depth (->> (case p "" "." p) (re-seq split) count)
|
||||
base (->> loc (re-seq split) (drop-last depth) (apply str))]
|
||||
(string/replace (str base "/") #"^/" "")))
|
||||
|
||||
(defn set-start-page [p]
|
||||
(when (and (not (:base-path @config))
|
||||
(use-html5-history))
|
||||
(swap! config assoc :base-path
|
||||
(base-path (.' js/window -location.pathname) p)))
|
||||
(reset! page p))
|
||||
|
||||
(defn prefix [href]
|
||||
(let [depth (-> #"/" (re-seq @page) count)]
|
||||
(str (->> "../" (repeat depth) (apply str)) href)))
|
||||
(defn main-content []
|
||||
(get-in @config [:current-page :content]))
|
||||
|
||||
|
||||
;;; Static site generation
|
||||
|
||||
(defn body []
|
||||
(let [b (:body @config)]
|
||||
(assert (vector? b) (str "body is not a vector: " b))
|
||||
b))
|
||||
(defn base [page]
|
||||
(let [depth (->> page to-relative (re-seq #"/") count)]
|
||||
(->> "../" (repeat depth) (apply str))))
|
||||
|
||||
(defn danger [t s]
|
||||
[t {:dangerouslySetInnerHTML {:__html s}}])
|
||||
|
||||
(defn html-template [{:keys [title body timestamp page-conf
|
||||
opt-none req]}]
|
||||
(let [c @config
|
||||
main (str (:js-file c) timestamp)
|
||||
css-file (:css-file c)
|
||||
opt-none (:opt-none c)]
|
||||
(defn html-template [{:keys [title body-html timestamp page-conf
|
||||
js-file css-file main-div]}]
|
||||
(let [main (str js-file timestamp)]
|
||||
(r/render-to-static-markup
|
||||
[:html
|
||||
[:head
|
||||
[:meta {:charset "utf-8"}]
|
||||
[:meta {:charset 'utf-8}]
|
||||
[:meta {:name 'viewport
|
||||
:content "width=device-width, initial-scale=1.0"}]
|
||||
[:base {:href (prefix "")}]
|
||||
[:base {:href (-> page-conf :page-path base)}]
|
||||
[:link {:href (str css-file timestamp) :rel 'stylesheet}]
|
||||
[:title title]]
|
||||
[:body
|
||||
[:div {:id (:main-div @config)}
|
||||
(danger :div body)]
|
||||
(danger :script (str "var pageConfig = " (-> page-conf
|
||||
clj->js
|
||||
js/JSON.stringify)))
|
||||
[:div {:id main-div} (danger :div body-html)]
|
||||
(danger :script (str "var pageConfig = "
|
||||
(-> page-conf clj->js js/JSON.stringify)))
|
||||
[:script {:src main :type "text/javascript"}]]])))
|
||||
|
||||
(defn gen-page [page-name timestamp]
|
||||
(reset! page page-name)
|
||||
(let [b (r/render-component-to-string (body))]
|
||||
(str "<!doctype html>"
|
||||
(html-template {:title (get-title)
|
||||
:body b
|
||||
:page-conf {:allow-html5-history true
|
||||
:page-name page-name}
|
||||
:timestamp timestamp}))))
|
||||
(defn gen-page [page-path conf]
|
||||
(dispatch [:set-page page-path])
|
||||
(let [conf (merge conf @config)
|
||||
b (:body conf)
|
||||
bhtml (r/render-component-to-string b)]
|
||||
(str "<!doctype html>\n"
|
||||
(html-template (assoc conf
|
||||
:page-conf {:page-path page-path}
|
||||
:body-html bhtml)))))
|
||||
|
||||
(defn fs [] (js/require "fs"))
|
||||
(defn path [] (js/require "path"))
|
||||
|
||||
(defn mkdirs [f]
|
||||
(let [fs (js/require "fs")
|
||||
path (js/require "path")
|
||||
items (as-> f _
|
||||
(.' path dirname _)
|
||||
(.' path normalize _)
|
||||
(string/split _ #"/"))
|
||||
parts (reductions #(str %1 "/" %2) items)]
|
||||
(doseq [d parts]
|
||||
(when-not (.' fs existsSync d)
|
||||
(.' fs mkdirSync d)))))
|
||||
(doseq [d (reductions #(str %1 "/" %2)
|
||||
(-> (.' (path) normalize f)
|
||||
(string/split #"/")))]
|
||||
(when-not (.' (fs) existsSync d)
|
||||
(.' (fs) mkdirSync d))))
|
||||
|
||||
(defn write-file [f content]
|
||||
(let [fs (js/require "fs")]
|
||||
(mkdirs f)
|
||||
(.' fs writeFileSync f content)))
|
||||
|
||||
(defn read-file [f]
|
||||
(let [fs (js/require "fs")]
|
||||
(.' fs readFileSync f)))
|
||||
(mkdirs (.' (path) dirname f))
|
||||
(.' (fs) writeFileSync f content))
|
||||
|
||||
(defn path-join [& paths]
|
||||
(let [path (js/require "path")]
|
||||
(apply (.' path :join) paths)))
|
||||
(apply (.' (path) :join) paths))
|
||||
|
||||
(defn read-css []
|
||||
(clojure.string/join "\n"
|
||||
(map read-file (:css-infiles @config))))
|
||||
|
||||
(defn write-resources [dir]
|
||||
(write-file (path-join dir (:css-file @config))
|
||||
(read-css)))
|
||||
(defn write-resources [dir {:keys [css-file css-infiles]}]
|
||||
(write-file (path-join dir css-file)
|
||||
(->> css-infiles
|
||||
(map #(.' (fs) readFileSync %))
|
||||
(string/join "\n"))))
|
||||
|
||||
|
||||
;;; Main entry points
|
||||
|
||||
(defn ^:export genpages [opts]
|
||||
(log "Generating site")
|
||||
(swap! config merge (js->clj opts :keywordize-keys true))
|
||||
(let [dir (:site-dir @config)
|
||||
timestamp (str "?" (.' js/Date now))]
|
||||
(doseq [f (keys (:page-map @config))]
|
||||
(write-file (path-join dir f)
|
||||
(gen-page f timestamp)))
|
||||
(write-resources dir))
|
||||
(let [conf (swap! config merge (js->clj opts :keywordize-keys true))
|
||||
conf (assoc conf :timestamp (str "?" (js/Date.now)))
|
||||
{:keys [site-dir pages]} conf]
|
||||
(doseq [f (keys pages)]
|
||||
(write-file (->> f to-relative (path-join site-dir))
|
||||
(gen-page f conf)))
|
||||
(write-resources site-dir conf))
|
||||
(log "Wrote site"))
|
||||
|
||||
(defn start! [site-config]
|
||||
(swap! config merge site-config)
|
||||
(when r/is-client
|
||||
(let [conf (when (exists? js/pageConfig)
|
||||
(js->clj js/pageConfig :keywordize-keys true))
|
||||
page-name (:page-name conf)]
|
||||
(swap! config merge conf)
|
||||
(when (nil? history)
|
||||
(when page-name
|
||||
(set-start-page page-name))
|
||||
(setup-history page-name)
|
||||
(set! (.-title js/document) (get-title)))
|
||||
(r/render-component (body)
|
||||
(.' js/document getElementById
|
||||
(:main-div @config))))))
|
||||
(let [page-conf (when (exists? js/pageConfig)
|
||||
(js->clj js/pageConfig :keywordize-keys true))
|
||||
conf (swap! config merge page-conf)
|
||||
{:keys [page-path body main-div]} conf]
|
||||
(init-history page-path)
|
||||
(r/render-component body (js/document.getElementById main-div)))))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(defproject reagent "0.5.2-SNAPSHOT"
|
||||
(defproject reagent "0.6.0-SNAPSHOT"
|
||||
:url "http://github.com/reagent-project/reagent"
|
||||
:license {:name "MIT"}
|
||||
:description "A simple ClojureScript interface to React"
|
||||
|
@ -13,7 +13,7 @@
|
|||
:source-paths ["src"]
|
||||
|
||||
:codox {:language :clojurescript
|
||||
:exclude clojure.string}
|
||||
:exclude clojure.string}
|
||||
|
||||
:profiles {:test {:cljsbuild
|
||||
{:builds {:client {:source-paths ["test"]}}}}
|
||||
|
|
Loading…
Reference in New Issue