Fix header level 3, rename file.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Oly 2023-06-22 14:17:31 +01:00
parent 7e19e7c20b
commit b0e57579c3
3 changed files with 60 additions and 33 deletions

View File

@ -1,4 +1,4 @@
#+TITLE: Intro to HoneySQL & Hiccup #+TITLE: Intro to Hiccup
* Hiccup * Hiccup

View File

@ -1,9 +1,8 @@
#+TITLE: Minimal clojurescript reagent example #+TITLE: ClojureScript reagent example's
* Introduction * Introduction
Reagent is a popular react wrapper in the clojurescript it greatly simplify build react SPA Applications this is usually a good starting point when learning, but there are lots of other options that are worth considering. Reagent is a popular react wrapper in the clojurescript it greatly simplify build react SPA Applications this is usually a good starting point when learning, but there are lots of other options that are worth considering.
#+BEGIN_SRC html :results silent :exports none :tangle resources/public/index.html #+BEGIN_SRC html :results silent :exports none :tangle resources/public/index.html
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -21,7 +20,7 @@ Reagent is a popular react wrapper in the clojurescript it greatly simplify buil
</html> </html>
#+END_SRC #+END_SRC
#+BEGIN_SRC edn :results silent :tangle deps.edn #+BEGIN_SRC edn :results silent :exports none :tangle deps.edn
{:paths ["src" "resources"] {:paths ["src" "resources"]
:deps :deps
{org.clojure/clojure {:mvn/version "1.10.0"} {org.clojure/clojure {:mvn/version "1.10.0"}
@ -30,7 +29,7 @@ Reagent is a popular react wrapper in the clojurescript it greatly simplify buil
thheller/shadow-cljs {:mvn/version "2.24.0"}}} thheller/shadow-cljs {:mvn/version "2.24.0"}}}
#+END_SRC #+END_SRC
#+BEGIN_SRC edn :results silent :tangle shadow-cljs.edn #+BEGIN_SRC edn :results silent :exports none :tangle shadow-cljs.edn
{:deps {:aliases [:dev]} {:deps {:aliases [:dev]}
:dev-http {8080 ["resources/public/" "classpath:public"]} :dev-http {8080 ["resources/public/" "classpath:public"]}
:source ["src" "../../components"] :source ["src" "../../components"]
@ -44,8 +43,7 @@ Reagent is a popular react wrapper in the clojurescript it greatly simplify buil
:devtools {:after-load app.main/reload!}}}} :devtools {:after-load app.main/reload!}}}}
#+END_SRC #+END_SRC
#+BEGIN_SRC json :results silent :exports none :tangle package.json
#+BEGIN_SRC json :results silent :tangle package.json
{ {
"dependencies": { "dependencies": {
"react": "^18.2.0", "react": "^18.2.0",
@ -59,7 +57,7 @@ Reagent is a popular react wrapper in the clojurescript it greatly simplify buil
} }
#+END_SRC #+END_SRC
#+BEGIN_SRC text :results silent :tangle readme.org #+BEGIN_SRC text :results silent :exports none :tangle readme.org
#+TITLE: Getting started #+TITLE: Getting started
* Install the npm requirements. * Install the npm requirements.
@ -71,7 +69,7 @@ npx shadow-cljs watch app
#+END_SRC #+END_SRC
#+BEGIN_SRC json :tangle src/clojure_demo/core.cljs #+BEGIN_SRC json :tangle :exports none src/clojure_demo/core.cljs
(ns clojure-demo.core (ns clojure-demo.core
(:require (:require
["react-dom/client" :refer [createRoot]] ["react-dom/client" :refer [createRoot]]
@ -88,14 +86,22 @@ Form one components are the most basic simply rendering some html with values th
In the example below the function just returns some hiccup with the parameters inserted, you need to specify =:key= when dynamically repeating the elements and these should be reproducible unique id's where possible not randomly generated or indexed numbers if the data is unordered. In the example below the function just returns some hiccup with the parameters inserted, you need to specify =:key= when dynamically repeating the elements and these should be reproducible unique id's where possible not randomly generated or indexed numbers if the data is unordered.
*** Example navbar component
#+BEGIN_SRC clojure :tangle src/clojure_demo/core.cljs #+BEGIN_SRC clojure :tangle src/clojure_demo/core.cljs
(defn navbar-link [{:keys [href title text] :or {text nil title nil}}] (defn navbar-link [{:keys [href title text] :or {text nil title nil}}]
[:a.link.dim.dib.mr3 {:key href :href href :title title} text]) [:a.link.dim.dib.mr3.mb2.dark-blue {:key href :href href :title title} text])
[navbar-link {:href "https://clojure.org" :title "linke title" :text "link here"}] (defn navbar []
[:div
[navbar-link {:href "https://clojure.org" :title "Clojure site" :text "Clojure"}]
[navbar-link {:href "https://github.com/reagent-project/reagent" :title "Reagent" :text "Reagent"}]
[navbar-link {:href "https://github.com/metosin/reitit" :title "Reitit" :text "Reitit"}]])
[navbar]
#+END_SRC #+END_SRC
*** Example product cards
#+BEGIN_SRC clojurescript :results output :tangle src/clojure_demo/core.cljs #+BEGIN_SRC clojurescript :results output :tangle src/clojure_demo/core.cljs
(defn product-card (defn product-card
[{:keys [title amount description link]}] [{:keys [title amount description link]}]
@ -151,14 +157,14 @@ Form two components are used so we can track local state of a component, this is
[:div [:div
(str @form-data) (str @form-data)
[:form {:on-submit prn} [:form {:on-submit prn}
[:input.db {:type "text" [:input.db.ma2.pa2 {:type "text"
:default-value (str (:test @form-data)) :default-value (str (:test @form-data))
:name "address-line-1" :name "address-line-1"
:on-change form-change :placeholder "Address Line 1"}] :on-change form-change :placeholder "Address Line 1"}]
[:input.db {:type "text" :name "address-line-2" :on-change form-change :placeholder "Address Line 2"}] [:input.db.ma2.pa2 {:type "text" :name "address-line-2" :on-change form-change :placeholder "Address Line 2"}]
[:input.db {:name "address-line-3" :on-change form-change :placeholder "Address Line 3"}] [:input.db.ma2.pa2 {:name "address-line-3" :on-change form-change :placeholder "Address Line 3"}]
[:input.db {:name "city" :on-change form-change :placeholder "City"}] [:input.db.ma2.pa2 {:name "city" :on-change form-change :placeholder "City"}]
[:input.db {: "postcode" :on-change form-change :placeholder "Postcode / Zipcode"}]]]))) [:input.db.ma2.pa2 {:name "postcode" :on-change form-change :placeholder "Postcode / Zipcode"}]]])))
[:div [my-address-form]] [:div [my-address-form]]
#+END_SRC #+END_SRC
@ -168,6 +174,8 @@ Form two components are used so we can track local state of a component, this is
This form of component give's you full access to the react life cycle methods, so render did-mount did-unmount etc This form of component give's you full access to the react life cycle methods, so render did-mount did-unmount etc
usually this form of component is only needed when rendering graphics or things like graphs, it's also useful for capturing errors and handling them as in the example below, which renders your components but if =component-did-catch= is trigger the error is caught and displayed instead. usually this form of component is only needed when rendering graphics or things like graphs, it's also useful for capturing errors and handling them as in the example below, which renders your components but if =component-did-catch= is trigger the error is caught and displayed instead.
*** Error boundary example
If you hit an error react will stop rendering and remove the user interface, you can use an error boundary to capture this so part of the UI can still render.
#+BEGIN_SRC clojurescript :results output :tangle src/clojure_demo/core.cljs #+BEGIN_SRC clojurescript :results output :tangle src/clojure_demo/core.cljs
(defn err-boundary (defn err-boundary
[& children] [& children]
@ -181,8 +189,22 @@ usually this form of component is only needed when rendering graphics or things
(into [:<>] children) (into [:<>] children)
(let [[_ info] @err-state] (let [[_ info] @err-state]
[:pre [:code (pr-str info)]])))}))) [:pre [:code (pr-str info)]])))})))
[err-boundary [:div ""]]
#+END_SRC #+END_SRC
*** Example of using the google maps library
https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import
#+BEGIN_SRC clojurescript :results output :tangle src/clojure_demo/core.cljs
(defn load-google-maps-script [api-key]
(let [script (.createElement js/document "script")]
;; copied from googles recommended way of loading google maps
(set! (.-innerHTML script) (str "(g=>{var h,a,k,p=\"The Google Maps JavaScript API\",c=\"google\",l=\"importLibrary\",q=\"__ib__\",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement(\"script\"));e.set(\"libraries\",[...r]+\"\");for(k in g)e.set(k.replace(/[A-Z]/g,t=>\"_\"+t[0].toLowerCase()),g[k]);e.set(\"callback\",c+\".maps.\"+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+\" could not load.\"));a.nonce=m.querySelector(\"script[nonce]\")?.nonce||\"\";m.head.append(a)}));d[l]?console.warn(p+\" only loads once. Ignoring:\",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
key: \"" api-key "\", v: \"weekly\"});"))
(.appendChild (.-head js/document) script)))
#+END_SRC
* Fetching a html element reference * Fetching a html element reference
If we wish to capture a node we can use =:ref= and store the result in an atom, we can then de reference the atom and call a method on the node using =aget=. If we wish to capture a node we can use =:ref= and store the result in an atom, we can then de reference the atom and call a method on the node using =aget=.
@ -202,6 +224,7 @@ If we wish to capture a node we can use =:ref= and store the result in an atom,
(defn current-page [] (defn current-page []
[:div [:div
[navbar]
[:div.flex [:div.flex
[product-card [product-card
{:title "Cat 01" {:title "Cat 01"

View File

@ -87,7 +87,7 @@
(defn code-editor (defn code-editor
[{:keys [class results]} content] [{:keys [exports class results]} content]
(let [language class (let [language class
editor (atom nil) editor (atom nil)
evaled-result (reagent/atom nil) evaled-result (reagent/atom nil)
@ -126,24 +126,27 @@
:parent @editor}))))) :parent @editor})))))
:component-will-unmount (fn [_] (.destroy @view)) :component-will-unmount (fn [_] (.destroy @view))
:reagent-render (fn [] :reagent-render (fn []
[:div.mb2 (if exports
[:div.ba.ma0.f5.b--black-05.pa2.overflow-auto.editor {:ref #(reset! editor %)}] nil ;[:<>]
(when @evaled-result [:div.mb2
[:pre.ba.ma0.f6.code.b--black-05.pa2.pl4.overflow-auto [:div.ba.ma0.f5.b--black-05.pa2.overflow-auto.editor {:ref #(reset! editor %)}]
{:style {:white-space "pre-line"}} (when @evaled-result
;; See org mode :results key [:pre.ba.ma0.f6.code.b--black-05.pa2.pl4.overflow-auto
(case results {:style {:white-space "pre-line"}}
"verbatim" (str @evaled-result) ;; See org mode :results key
"value" (str @evaled-result) (case results
"output" @evaled-result "verbatim" (str @evaled-result)
"silent" "" "value" (str @evaled-result)
@evaled-result)])])}))) "output" @evaled-result
"silent" ""
@evaled-result)])]))})))
(def theme (def theme
(merge tachyon-theme (merge tachyon-theme
{:SRC code-editor {:SRC code-editor
:HEADER1 (fn [v _] [:h1.f2.fw6.f3-ns.lh-title.mt0.mb2 {:id (slugify v)} [:a {:name (slugify v)} v]]) :HEADER1 (fn [v _] [:h1.f2.fw6.f3-ns.lh-title.mt0.mb2 {:id (slugify v)} [:a {:name (slugify v)} v]])
:HEADER2 (fn [v _] [:h2.f3.fw6.f3-ns.lh-title.mt0.mb2 {:id (slugify v)} [:a {:name (slugify v)} v]]) :HEADER2 (fn [v _] [:h2.f3.fw6.f3-ns.lh-title.mt0.mb2 {:id (slugify v)} [:a {:name (slugify v)} v]])
:HEADER3 (fn [v _] [:h2.f4.fw6.f3-ns.lh-title.mt0.mb2 {:id (slugify v)} [:a {:name (slugify v)} v]])
:LINE :p.f5.f5-ns.lh-copy.mt0 :LINE :p.f5.f5-ns.lh-copy.mt0
:BULLETS :ul.mt0 :BULLETS :ul.mt0
:LINK :a #_link-handler})) :LINK :a #_link-handler}))
@ -281,16 +284,17 @@
:body (-> site-data :dslpage :intro) :body (-> site-data :dslpage :intro)
:articles :articles
[{:title "Hiccup HTML Demo" [{:title "Hiccup HTML Demo"
:link (rfe/href ::demo {:page "dsl-demo"}) :link (rfe/href ::demo {:page "hiccup-dsl-demo"})
:img-src "https://miro.medium.com/max/1400/1*CEYFj5R57UFyCXts2nsBqA.png"} :img-src "https://miro.medium.com/max/1400/1*CEYFj5R57UFyCXts2nsBqA.png"}
{:title "Honey SQL Demo" {:title "Honey SQL Demo"
:description "Querying a database using the HoneySQL DSL"
:link (rfe/href ::demo {:page "honey-sql-demo"}) :link (rfe/href ::demo {:page "honey-sql-demo"})
:img-src "https://miro.medium.com/max/1400/1*CEYFj5R57UFyCXts2nsBqA.png"} :img-src "https://miro.medium.com/max/1400/1*CEYFj5R57UFyCXts2nsBqA.png"}
{:title "Datalog Demo" {:title "Datalog Demo"
:link (rfe/href ::demo {:page "datalog-demo"}) :link (rfe/href ::demo {:page "datalog-demo"})
:img-src "https://raw.githubusercontent.com/tonsky/datascript/master/extras/logo.svg"}]}]]) :img-src "https://raw.githubusercontent.com/tonsky/datascript/master/extras/logo.svg"}]}]])
(def toc (partial contains? (into #{} (map keyword [:HEADER1 :HEADER2 :HEDAER3 :HEADER4 :HEADER5 :HEADER6])))) (def toc (partial contains? (into #{} (map keyword [:HEADER1 :HEADER2 :HEADER3 :HEADER4 :HEADER5 :HEADER6]))))
(def org-code (partial contains? (into #{} (map keyword [:SRC])))) (def org-code (partial contains? (into #{} (map keyword [:SRC]))))
@ -423,7 +427,7 @@
[:div [:div
[navbar [{:href (rfe/href ::frontpage) :title "title here" :text "home" :key "homepage"} [navbar [{:href (rfe/href ::frontpage) :title "title here" :text "home" :key "homepage"}
{:href (rfe/href ::dsl) :text "DSL's" :key "dsl"} {:href (rfe/href ::dsl) :text "DSL's" :key "dsl"}
{:href (rfe/href ::about) :text "About" :key "about"} {:title "Domain Specific Languages" :href (rfe/href ::about) :text "About" :key "about"}
#_{:href (rfe/href ::i-do-not-exist) :text "missing"}]] #_{:href (rfe/href ::i-do-not-exist) :text "missing"}]]
[:main.ma4 [:main.ma4
(when-let [view (-> @site-state :current-route :data :view)] [view (-> @site-state :current-route)])] (when-let [view (-> @site-state :current-route :data :view)] [view (-> @site-state :current-route)])]