diff --git a/.drone.yml b/.drone.yml
index 5571165..6cca8f4 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -4,7 +4,9 @@ steps:
- name: Build
image: clojure:tools-deps
commands:
- - clj -Adev -m figwheel.main -bo prod
+ - cd reagent-reitit-demo
+ - cp resources/public/rename-me-index.html resources/public/index.html
+ - clj -A:prod
- name: deploy-site
pull: True
@@ -17,6 +19,8 @@ steps:
from_secret: ssh_key
port: 22
duration: 4m
+ ## strip components removes parts of path at destination
+ strip_components: 1
target: /var/www/clojure-demos/
source:
- - resources/public/*
+ - reagent-reitit-demo/resources/public/*
diff --git a/datalog-demo/resources/public/rename-me-index.html b/datalog-demo/resources/public/rename-me-index.html
index ef36acc..b427263 100644
--- a/datalog-demo/resources/public/rename-me-index.html
+++ b/datalog-demo/resources/public/rename-me-index.html
@@ -5,7 +5,7 @@
-
Atom Juice Merchant Website
+ Clojure demos
diff --git a/reagent-reitit-demo/deps.edn b/reagent-reitit-demo/deps.edn
index 02b9b9f..497a6cd 100644
--- a/reagent-reitit-demo/deps.edn
+++ b/reagent-reitit-demo/deps.edn
@@ -1,13 +1,15 @@
{:deps {org.clojure/clojure {:mvn/version "1.10.0"}
org.clojure/clojurescript {:mvn/version "1.10.764"}
cljs-ajax {:mvn/version "0.8.1"}
+ ;; react
reagent {:mvn/version "0.9.1"}
reagent-utils {:mvn/version "0.3.3"}
olymk2/cl-org {:git/url "https://gitlab.com/olymk2/cl-org.git"
:sha "c366560dd59e16759ca24209b253f55e46ecbbe3"}
-
+ ;;rouoting
metosin/reitit {:mvn/version "0.5.10"}
metosin/reitit-spec {:mvn/version "0.5.10"}
metosin/reitit-frontend {:mvn/version "0.5.10"}
com.bhauman/figwheel-main {:mvn/version "0.2.11"}}
- :paths ["src" "resources"]}
+ :paths ["src" "resources"]
+ :aliases {:prod {:main-opts ["-m" "figwheel.main" "-bo" "dev"]}}}
diff --git a/reagent-reitit-demo/dev.cljs.edn b/reagent-reitit-demo/dev.cljs.edn
index 6798d2b..e4f26c2 100644
--- a/reagent-reitit-demo/dev.cljs.edn
+++ b/reagent-reitit-demo/dev.cljs.edn
@@ -5,4 +5,4 @@
:source-map true
:source-map-timestamp true
:devcards true
- :main core.demo}
+ :main demo.core}
diff --git a/reagent-reitit-demo/resources/public/rename-me-index.html b/reagent-reitit-demo/resources/public/rename-me-index.html
index ef36acc..b427263 100644
--- a/reagent-reitit-demo/resources/public/rename-me-index.html
+++ b/reagent-reitit-demo/resources/public/rename-me-index.html
@@ -5,7 +5,7 @@
- Atom Juice Merchant Website
+ Clojure demos
diff --git a/reagent-reitit-demo/src/demo/core.cljs b/reagent-reitit-demo/src/demo/core.cljs
new file mode 100644
index 0000000..2394301
--- /dev/null
+++ b/reagent-reitit-demo/src/demo/core.cljs
@@ -0,0 +1,224 @@
+(ns ^:figwheel-hooks demo.core
+ (:require [reagent.core :as reagent]
+ [ajax.core :refer [GET raw-response-format]]
+ ;[demo.org :refer [parse->to-hiccup parse-flat]]
+ [cl-eorg.parser :as o :refer [parse parse-flat]]
+ [cl-eorg.html :refer [org->replacements]]
+ [reitit.frontend :as rf]
+ [reitit.frontend.easy :as rfe]
+ [reitit.coercion.spec :as rss]
+ [spec-tools.data-spec :as ds]))
+
+;; put constant data here
+(def site-data
+ {:demos {:dsl-demo
+ {:file "dsl-demo.org" :git-link "https://github.com/atomjuice/dsl-demo"}
+ :datalog-demo
+ {:file "datalog-demo.org" :git-link "https://github.com/atomjuice/dsl-demo"}
+ :reagent-demo
+ {:file "reagent-reitit.org" :git-link "https://github.com/atomjuice/dsl-demo"}}
+ :homepage {:intro "Clojure tutorials examples and exploration"}
+ :lorem "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."})
+
+;; Store site state
+(defonce site-state (reagent/atom {}))
+
+;; for one component to render an article
+(defn article [{:keys [title description tagline]}]
+ [:article {:data-name "article-full-bleed-background"}
+ [:div.cf {:style {:background "url(http://placekitten.com/g/600/300)"
+ :no-repeat "center center fixed" :background-size "cover"}}
+ [:div.fl.pa3.pa4-ns.bg-white.black-70.measure-narrow.f3.times
+ [:header.b--black-70.pv4 {:class (when tagline "bb")}
+ [:h3.f2.fw7.ttu.tracked.lh-title.mt0.mb3.avenir title]
+ (when tagline [:h4.f3.fw4.i.lh-title.mt0 tagline])]
+ [:section.pt5.pb4 [:p.times.lh-copy.measure.f5.mt0 description]]]]])
+
+;; form one component to render article tiles
+(defn articles [{:keys [title body articles]}]
+ [:section.mw7.center.avenir {:key title}
+ [:h2.baskerville.fw1.ph3.ph0-l title]
+ (when body [:p body])
+ (map (fn [{:keys [title author link description img-src img-alt]}]
+ [:article.bt.bb.b--black-10
+ [:a.db.pv4.ph3.ph0-l.no-underline.black.dim {:href link}
+ [:div.flex.flex-column.flex-row-ns
+ (when img-src
+ [:div.pr3-ns.mb4.mb0-ns.w-100.w-40-ns
+ [:img.db {:src img-src :alt img-alt}]])
+ [:div.w-100.w-60-ns.pl3-ns
+ [:h1.f3.fw1.baskerville.mt0.lh-title title]
+ [:p.f6.f5-l.lh-copy description]
+ [:p.f6.lh-copy.mv0 author]]]]])
+ articles)])
+
+;; form one component to render a product
+(defn product-card
+ [{:keys [title amount description link]}]
+ [:article.br2.ba.dark-gray.b--black-10.ma2.w-100.w-50-m.w-25-l.mw5
+ [:img.db.w-100.br2.br--top {:src link}]
+ [:div.pa2.ph3-ns.pb3-ns
+ [:div.dt.w-100.mt1
+ [:div.dtc [:h1.f5.f4-ns.mv0 title]]
+ [:div.dtc.tr [:h2.f5.mv0 amount]]]
+ [:p.f6.lh-copy.measure.mt2.mid-gray description]]])
+
+(defn circle [{:keys [img alt]}]
+ [:div.pa4.tc [:img.br-100.ba.h3.w3.dib {:src img :alt alt}]])
+
+;; form one component to render a nav link
+(defn navbar-link [{:keys [href title text] :or {text nil title nil}}]
+ [:a.link.dim.white.dib.mr3 {:key href :href href :title title} text])
+
+;; form one component to render a navbar
+(defn navbar [links]
+ [:header.bg-black-90.w-100.ph3.pv3.pv4-ns.ph4-m.ph5-l
+ [:nav.f6.fw6.ttu.tracked
+ (map navbar-link links)]])
+
+;; form2 component notice the render function takes the same param as the component function
+;; this is important, you can hit issues if you forget this in form 2 components.
+(defn my-component [title value]
+ (let [local-state (reagent/atom value)]
+ (fn [title]
+ [:h1 {:class (when @local-state "hide")
+ :on-click (fn [] (swap! local-state inc))} (str title " " @local-state)])))
+
+
+;; form one homepage component
+
+
+(defn home-page []
+ [:<>
+ [articles
+ {:title "Clojure Demos"
+ :body (-> site-data :homepage :intro)
+ :articles [{:title "DSL Demo"
+ :link (rfe/href ::demo {:page "dsl-demo"})
+ :img-src "https://miro.medium.com/max/1400/1*CEYFj5R57UFyCXts2nsBqA.png"}
+ {:title "Datalog Demo"
+ :link (rfe/href ::demo {:page "datalog-demo"})
+ :img-src "https://raw.githubusercontent.com/tonsky/datascript/master/extras/logo.svg"}
+ {:title "Reagent Demo"
+ :link (rfe/href ::demo {:page "reagent-demo"})
+ :img-src "https://raw.githubusercontent.com/reagent-project/reagent/master/logo/logo-text.png"}]}]])
+
+;; form two component render demo
+(defn demo-page [route]
+ (let [demo-key (keyword (-> route :parameters :path :page))
+ content (reagent/atom {})]
+ (GET (-> site-data :demos demo-key :file)
+ {:response-format (raw-response-format)
+ :handler (fn [response]
+ (->> response
+ parse
+ org->replacements
+ (reset! content))
+ #_(reset! content (org->replacements (parse response))))})
+ (fn [route]
+ [:main.mt4
+ [:div.mw7.center.avenir @content]])))
+
+;; form one render about page component
+(defn about-page []
+ [:main.mt4
+ [:section.mw7.center.avenir
+ [:h1 "Clojure library examples to aid learning"]
+ [:p "Selection of clojure demos, rendered in reagent which itself is an example of using reagent."]
+ [my-component "Clickable component" 1]
+ [my-component "Clickable component" 2]
+ [:p "Image circle componenet"]
+ [circle {:img "http://placekitten.com/g/300/300" :alt "test"}]
+ [:p "Product card component"]
+ [:div.flex.flex-column.flex-row-ns
+ [product-card
+ {:title "Cat 01"
+ :amount "£54.59"
+ :description "Cat description here"
+ :link "http://placekitten.com/g/600/300"}]
+ [product-card
+ {:title "Cat 02"
+ :amount "£10.59"
+ :description "Cat description here"
+ :link "http://placekitten.com/g/600/300"}]]
+ [:p "Article component"]
+ [article {:title "Example Article component"
+ :description (-> site-data :lorem)
+ :tagline "https://tachyons.io/components/"}]]])
+
+;; form 3 component wrap rendering to catch errors and render them
+;; or just render the rest of the page if all is good
+;; this uses =create-class= and a hash map of life cycle functions
+
+
+(defn err-boundary
+ [& children]
+ (let [err-state (reagent/atom nil)]
+ (reagent/create-class
+ {:display-name "ErrBoundary"
+ :component-did-catch (fn [err info]
+ (reset! err-state [err info]))
+ :reagent-render (fn [& children]
+ (if (nil? @err-state)
+ (into [:<>] children)
+ (let [[_ info] @err-state]
+ [:pre [:code (pr-str info)]])))})))
+
+;; define our routes, just nested vectors of the route definition hash maps
+(def routes
+ [["/"
+ {:name ::frontpage
+ :my-data "hi"
+ :view home-page}]
+
+ ["/about"
+ {:name ::about
+ :view about-page}]
+
+ ["/demo/:page"
+ {:name ::demo
+ :view demo-page
+ :parameters {:path {:page string?}
+ :query {(ds/opt :foo) keyword?}}}]])
+
+;; top level component contains nav and adds in the select page into a containing element
+;; we are adding in a style sheet but this will often be done in index.html
+(defn current-page []
+ [:<> [:link {:rel "stylesheet" :href "https://unpkg.com/tachyons@4.12.0/css/tachyons.min.css"}]
+ [navbar [{:href (rfe/href ::frontpage) :title "title here" :text "home"}
+ {:href (rfe/href ::about) :text "About"}
+ {:href (rfe/href ::i-do-not-exist) :text "missing"}]]
+ [:main.mt4
+ (when-let [view (-> @site-state :current-route :data :view)] [view (-> @site-state :current-route)])]])
+
+
+;; This simply calls reagent render and puts the result in a div with the id of app
+;; you can create your own index.html or figwheel provides one with the app id which will replace the default data
+;; ^:after-load is meta data its not needed but informs figwheel to run this code after a page load
+
+
+(defn mount-root-page []
+ ;; this select the main node from the html file and injects your page content
+ (reagent/render
+ (fn [] [err-boundary [current-page]])
+ (.getElementById js/document "app")))
+
+(defn ^:after-load render-site []
+ ;; this select the main node from the html file and injects your page content
+ (mount-root-page))
+
+(defn startup! []
+ (rfe/start!
+ (rf/router routes {:data {:coercion rss/coercion}})
+ (fn [m] (swap! site-state assoc :current-route m))
+ ;; set to false to enable HistoryAPI
+ {:use-fragment true})
+ (render-site))
+
+;; we defonce the startup so that hot reloading does not reinitialize the state of the site
+(def launch (do (startup!) true))
+
+(comment
+ @site-state
+
+ (GET "/test.org" {:handler (fn [response] (swap! site-state assoc :content response))}))
diff --git a/reagent-reitit-demo/src/org.cljs b/reagent-reitit-demo/src/org.cljs
deleted file mode 100644
index 951fcd7..0000000
--- a/reagent-reitit-demo/src/org.cljs
+++ /dev/null
@@ -1,162 +0,0 @@
-(ns demo.org
- (:require [clojure.string :as str]))
-
-
-(def ESCAPE "\n")
-
-(def BLANK 0)
-(def META 1)
-(def META_OTHER 2)
-(def HEADER 5)
-(def BOLD 10)
-(def ITALIC 11)
-(def UNDERLINED 12)
-(def VERBATIM 13)
-(def LIST 20)
-(def TEXT 21)
-(def IMAGE 22)
-(def LINK 23)
-(def CAPTION 24)
-(def BULLET 25)
-(def SOURCE 50)
-(def EXAMPLE 51)
-(def RESULTS 52)
-(def COMMENT 53)
-(def TABLE 54)
-
-(def METADATA ["TITLE"
- "AUTHOR"
- "EMAIL"
- "DESCRIPTION"
- "KEYWORDS"
- "FILETAGS"
- "DATE"
- "HTML_DOCTYPE"
- "SETUPFILE"])
-
-(def t_META #"^[#]\+(?:TITLE|AUTHOR|EMAIL|DESCRIPTION|KEYWORDS|FILETAGS|DATE|HTML_DOCTYPE|SETUPFILE)\:")
-(def t_BLANK_LINE #"^\s*$")
-(def t_COMMENT_BEGIN #"^\#\+BEGIN_COMMENT")
-(def t_COMMENT_END #"^\#\+END_COMMENT")
-(def t_EXAMPLE_BEGIN #"^\#\+BEGIN_EXAMPLE")
-(def t_EXAMPLE_END #"^\#\+END_EXAMPLE")
-(def t_SRC_BEGIN #"^\#\+BEGIN_SRC\s+")
-(def t_SRC_END #"^\#\+END_SRC")
-(def t_TABLE_START #"^\s*\|")
-(def t_TABLE_END #"^(?!\s*\|).*$")
-(def t_RESULTS_START #"^\#\+RESULTS\:")
-(def t_CAPTIONS #"^\#\+CAPTION:")
-(def t_NAME #"^\#\+NAME:")
-; t_IMG #"^\[\[(\w|\.|-|_|/)+\]\]$"
-(def t_IMG #"^\[\[")
-(def t_IMG_END #"\]\]")
-(def t_RESULTS_END #"^\s*$")
-(def t_END_LABELS #"^(?!\[|\#).*")
-(def t_BULLET_START #"^\s*[\+|\-|0-9\.]")
-(def t_BULLET_END #"^(?!\s*[\+|\-|0-9\.]).*$")
-
-(def t_HEADER #"^\*+")
-(def t_META_OTHER #"^[#]\+[A-Z\_]+\:")
-
-(def TYPE_SINGLE 0)
-(def TYPE_BLOCK 1)
-(def TYPE_ATTRIBUTE 2)
-
-(defn TokenStruct [values]
- (merge {:start "" :end false :type TYPE_SINGLE :start_pos 2 :end_pos nil :count 0 :key ""} values))
-
-(def token-map {:token nil :value nil :attrs nil})
-
-(defn token
- ([token-type value] (token token-type value nil))
- ([token-type value attrs]
- {:token token-type :value (or value "") :attrs attrs}))
-
-(def TOKENS [[:META (TokenStruct {:start t_META, :end_pos -1 :key-fn #(clojure.string/join (drop 2 (butlast %)))})],
- [:COMMENT (TokenStruct {:start t_COMMENT_BEGIN, :end t_COMMENT_END, :type TYPE_BLOCK, :end_pos -1})],
- [:EXAMPLE (TokenStruct {:start t_EXAMPLE_BEGIN, :end t_EXAMPLE_END, :type TYPE_BLOCK, :end_pos -})],
- [:IMAGE (TokenStruct {:start t_IMG, :end_pos -2})],
- [:CAPTION (TokenStruct {:start t_CAPTIONS, :type TYPE_ATTRIBUTE, :key "caption"})],
- [:br (TokenStruct {:start t_BLANK_LINE, :end_pos -1})],
- [:SOURCE (TokenStruct {:start t_SRC_BEGIN, :end t_SRC_END})],
- [:TABLE (TokenStruct {:start t_TABLE_START, :end t_TABLE_END, :start_pos 0})],
- [:BULLET (TokenStruct {:start t_BULLET_START, :end t_BULLET_END, :start_pos 0})],
- [:RESULTS (TokenStruct {:start t_RESULTS_START, :end t_RESULTS_END})],
- [:HEADER (TokenStruct {:start t_HEADER, :start_pos 1, :count 0})],
- [:META_OTHER (TokenStruct {:start t_META_OTHER, :start_pos 2, :end_pos -1})]])
-
-
-(def rm-ns (comp keyword name))
-
-(defn mk-key [k t pos]
- (case (name k)
- "HEADER" (keyword (str (name k) pos))
- (rm-ns k)))
-
-(clojure.string/join (drop 2 (butlast "#+title:")))
-(re-find t_META "#+TITLE: abc12345def")
-(re-find t_HEADER "** test")
-(str/split "#+TITLE: abc12345def" t_META)
-(def t
- "#+TITLE: abc12345def
-#+DESCRIPTION: test descriptioon
-
-* title
-paragraph
-text
-** header test
-hi there
-")
-
-(defn re-split [rx line]
- (let [matches (re-find rx line)
- pos (if (string? matches)
- (count matches)
- (count (or (str (first matches)) matches)))
- remainder (subs line pos)]
- [matches pos remainder]))
-
-(defn match-token [line]
- (->> TOKENS
- (reduce (fn [m [k v]]
- (let [s (re-find (:start v) line)
- pos (if (string? s) (count s) (count (or (str (first s)) s)))
- v (subs line pos)]
- (when (not (nil? s))
- (reduced (remove nil? [(mk-key k v pos) (if (= "" v) nil v)]))))) [])
- (#(or % [:p line]))))
-
-
-(defn parse-line [text]
- (loop [line (str/split-lines text)
- r []]
- (if (empty? line)
- r
- (recur (next line)
- (if (= :HEADER1 (first (last r)))
- (conj (last r) (match-token (first line)))
- (conj r (match-token (first line))))))))
-
-(defn parse-flat [text]
- (->> (str/split-lines text)
- (map (fn [a] (match-token a)))))
-
-(parse-line t )
-(parse-flat t )
-
-(defn to->html [dsl]
- (map #(apply conj [(case (first %)
- :TITLE :h1
- :HEADER1 :h1
- :HEADER2 :h2
- :br :br
- :SOURCE :pre
- (first %))] (rest %)) dsl))
-
-(defn parse->to-hiccup [org-document]
- (to->html (parse-flat org-document)))
-
-(parse->to-hiccup t)
-(parse->to-hiccup "")
-
-(map #(clojure.set/rename-keys (parse-line t) {:HEADER :h1}) (parse-line t ))
diff --git a/spec-demo/resources/public/rename-me-index.html b/spec-demo/resources/public/rename-me-index.html
index ef36acc..b427263 100644
--- a/spec-demo/resources/public/rename-me-index.html
+++ b/spec-demo/resources/public/rename-me-index.html
@@ -5,7 +5,7 @@
- Atom Juice Merchant Website
+ Clojure demos