Shared code is a double-edged sword.
On the one hand, you only needed to write it once. On the other, it can be hard to change without considering all the places that use that code.
As such, while the rest of this section is dedicated to sharing code - specifically the HTML boilerplate that most pages on a site inherit - don't take it as tacit permission to always make things into shared components. Use your best judgement.
src/example/page_html/core.clj
and put the following into it
We put the _html
suffix to distinguish it from our namespaces that correspond more to pages
and logical features.
The reason for using page_html/core.clj
instead of page_html.clj
is that
core.clj
is Clojure's cultural equivalent of an index.js
file. You can expect for folks to use :as
to remove it from the name in other namespaces.(ns example.page-html.core)
(defn view [& {:keys [body]}]
[:html
[:head]
[:body
body]])
example.hello.routes
to use the page component.(ns example.hello.routes
(:require [example.page-html.core :as page-html]
[example.system :as-alias system]
[hiccup2.core :as hiccup]
[next.jdbc :as jdbc]))
(defn hello-handler
[{::system/keys [db]} _request]
(let [{:keys [planet]} (jdbc/execute-one!
db
["SELECT 'earth' as planet"])]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str
(hiccup/html
(page-html/view
:body [:h1 (str "Hello, " planet)])))}))
(defn routes
[system]
[["/" {:get {:handler (partial #'hello-handler system)}}]])
example.goodbye.routes
(ns example.goodbye.routes
(:require [example.page-html.core :as page-html]
[hiccup2.core :as hiccup]))
(defn goodbye-handler
[_system _request]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str
(hiccup/html
(page-html/view :body [:h1 "Goodbye, world"])))})
(defn routes
[system]
[["/goodbye" {:get {:handler (partial #'goodbye-handler system)}}]])
:title
argument to example.page-html.core/view
HTML producing functions tend to grow optional arguments. I think its worth demonstrating how you would go about adding one.
(ns example.page-html.core)
(defn view [& {:keys [body title]
:or {title "The Website"}}]
[:html
[:head
[:title title]
[:meta {:name "viewport"
:content "width=device-width, initial-scale=1.0"}]]
[:body
body]])