145 lines
5.2 KiB
Org Mode
145 lines
5.2 KiB
Org Mode
#+TITLE: Intro to Hiccup
|
|
|
|
|
|
* Introduction
|
|
|
|
hiccup is a html DSL, used extensively in the clojure's eco-system, there are others as well but hiccup is the most widely used.
|
|
|
|
In hiccup everything is a list, this means you can easily compose html using standard language constructs.
|
|
To render the hiccup to html elements we call the (html) function from the hiccup library for server side with reagent or client side code this will likely be a different function like (render).
|
|
|
|
There are a few variant's the main ones being https://github.com/weavejester/hiccup and https://github.com/lambdaisland/hiccup , the lambdaisland one is particular helpful if you want to share html between the frontend and backend as its closer to reagents builtin hiccup.
|
|
|
|
|
|
#+BEGIN_SRC edn :results silent :export none :tangle deps.edn
|
|
{:paths ["src" "resources"]
|
|
:deps
|
|
{org.clojure/clojure {:mvn/version "1.10.0"}
|
|
org.clojure/clojurescript {:mvn/version "1.11.60"}}}
|
|
#+END_SRC
|
|
|
|
|
|
#+BEGIN_SRC text :results silent :export none :tangle readme.org
|
|
#+TITLE: Getting started
|
|
#+END_SRC
|
|
|
|
|
|
** Simple examples
|
|
If using reagent you don't need to pass into h/html but this is server side reagent also has some helpers to work with react nicer.
|
|
#+BEGIN_SRC clojure :tangle src/core.clj
|
|
[:span "bar"]
|
|
#+END_SRC
|
|
|
|
*** Styles classes and ID's
|
|
Attributes are added as a map of values styles are also a map
|
|
#+BEGIN_SRC clojure :tangle src/core.clj
|
|
[:span {:class "class1 class2" :title "my title" :style {:color "red"}} "bar"]
|
|
#+END_SRC
|
|
|
|
You can use shorthand to add id's and classes
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
[:span#id.class1.class2 "bar"]
|
|
#+END_SRC
|
|
|
|
** Example of manipulating hiccup with clojure functions
|
|
|
|
You can use clojure core language to manipulate these vectors.
|
|
|
|
place parts inside another containing element
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
(into [:div.container]
|
|
[[:span "span 1"]
|
|
[:span "span 2"]])
|
|
#+END_SRC
|
|
|
|
You could also use merge, in this example the spans are merged inside the div vector.
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
(merge [:div] [:span "span 1"] [:span "span 2"] [:span "span 3"])
|
|
#+END_SRC
|
|
|
|
We can take advantage of lazyness if we like
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
(defn navbar-link [{:keys [href title text] :or {text href title nil} :as link}]
|
|
[:a.link.dim.white.dib.mr3 {:key href :href href :title title} text])
|
|
|
|
[:div (into [:nav.f6.fw6.ttu.tracked] (vec (take 2 (mapv navbar-link
|
|
[{:key "link1" :href "link1" :title "title here"}
|
|
{:key "link2" :href "link2" :title nil}
|
|
{:key "link3" :href "link3" :text "link text"}
|
|
{:key "link4" :href "link4"}]))))]
|
|
|
|
#+END_SRC
|
|
|
|
** Compossible components
|
|
The main advantage comes from the ability to compose the parts together, so we can break our html apart and recombine using all the function at our disposal.
|
|
In this example our navigation is defined as a hash map, the data is separated out from the html, we can then pass the data to our component to render it.
|
|
In this example we have a link component and a nav component the link component take the values as key, value pairs and uses de structuring while also setting default if values are not set.
|
|
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
(defn navbar-link [{:keys [href title text] :or {text href title nil} :as link}]
|
|
[:a.link.dim.white.dib.mr3 {:key href :href href :title title} text])
|
|
|
|
(defn navbar [links]
|
|
[:header.bg-black-90.w-100.ph3.pv3.pv4-ns.ph4-m.ph5-l
|
|
(into [:nav.f6.fw6.ttu.tracked]
|
|
(mapv navbar-link links))])
|
|
|
|
[navbar [{:href "link1" :title "title here"}
|
|
{:href "link2" :title nil}
|
|
{:href "link3" :text "link text"}
|
|
{:href "link4"}]]
|
|
#+END_SRC
|
|
|
|
In this example we create some simple top trump style cards using a map with a vector of nested maps for the stats.
|
|
We use map and into to convert the stats value
|
|
|
|
#+BEGIN_SRC clojure :results output :tangle src/core.clj
|
|
(defn playing-card
|
|
[{:keys [title image stats]}]
|
|
[:article
|
|
[:div.border-solid.border-2.border-sky-500.m-4.w-100
|
|
[:div.dt.w-100.mt1
|
|
[:div [:h1.f5.f4-ns.mv0 title]]
|
|
[:img.db.w-100.h-100.br2.br--top {:src image}]
|
|
|
|
#_[:div.dtc.tr [:h2.f5.mv0 "amount"]]]
|
|
(into [:ul.ma2.pa2]
|
|
(mapv (fn build-stats [[stat value]]
|
|
[:li [:div stat [:div.fr (str value)]]])
|
|
stats))
|
|
[:p.f6.lh-copy.measure.mt2.mid-gray ""]]])
|
|
|
|
[:div
|
|
[playing-card
|
|
{:title "Bee"
|
|
:image "https://loremflickr.com/300/300/bee"
|
|
:stats {:strength "6"
|
|
:lifespan "3" ;; 6 weeks
|
|
:danger "5"
|
|
:mobility "9"}}]
|
|
[playing-card
|
|
{:title "Spider"
|
|
:image "https://loremflickr.com/300/300/spider"
|
|
:stats {:strength "4"
|
|
:lifespan "5" ;; 1 year
|
|
:danger "8"
|
|
:mobility "5"}}]
|
|
[playing-card
|
|
{:title "Ant"
|
|
:image "https://loremflickr.com/300/300/ant"
|
|
:stats {:strength "8"
|
|
:lifespan "8" ;; 7 years
|
|
:danger "4"
|
|
:mobility "3"}}]
|
|
[playing-card
|
|
{:title "Dragonfly"
|
|
:image "https://loremflickr.com/300/300/dragonfly"
|
|
:stats {:strength "2"
|
|
:lifespan "1" ;;2 weeks
|
|
:danger "1"
|
|
:mobility "9"}}]]
|
|
#+END_SRC
|
|
|
|
|
|
|