Layouts and Partials
Overview
When you create a new Firn site for the first time, it will create a folder:_firn/layouts
. The layout folder stores Clojure files (.clj
) that are
responsible for how your org-file is rendered to-html; The act of "applying" a
template means to pass the content of the org-file through a specific clojure hiccup
template that organizes how the content is displayed.
When an org-mode file is processed by Firn it looks for the in-buffer-setting (or what might be called "Front Matter")#+FIRN_LAYOUT:
to see if it uses a Layout. If none are specified, the default
template is used.
A simple layout file
Let's consider a simple layout file:
(defn default ; define a clojure func
[{:keys [build-url title render partials]}] ; destructured commonly used functions and data
(let [{:keys [head]} partials] ; Ignore for now, partials will be explained later
[:html ; => opens a `html` tag
(head build-url) ; => Renders the `head` partial
[:body ; => opens a `body` tag
[:main ; => Ditto
[:article.def-wrapper ; => opens a `article` html tag with a class of `def-wrapper`
[:div.def-content ; => see above
[:h1 title] ; => renders an `h1` tag with the file title.
(render :file) ; ; => `render` is where the magic happens!
]]]]])) ; => all these closing brackets can be thought of as closing html tags (for now)
The above may look a little strange if you are not familiar with Clojure. The
next document will expand on what the render
function does.
Your layout files can have several functions in them, but the last function in the file is the one that is loaded as your layout.
Partials
In the example above you may have noticed the partials
binding appear. Partials
are similar to layouts: they are clojure functions that render html. Partials
are used for rendering particularly common pieces of html that might be shared
across several layouts (such as the head
of your HTML document as in the example
above).
Using partials requires the following:
Create a partial in the
partials
directory.A partial must be a clojure function, just the same as a layout file.
The last function in your partial file is the partial that is applied.
partials
are a map of all the partial functions and is passed into layouts when they are rendered:(defn default [{:keys [partials]}] ; `partials` is a a map.
You can optionally bind the partials you need in a let block so that they are easily callable as functions. The name of your partial is the name of the partial file. For example, the docs you are reading has a
partials/head.clj
file, and is accessible like so:(defn default ; define a clojure func [{:keys [partials]}] ; destructure the `partials` key. (let [{:keys [head]} partials] [:html ; => opens a `html` tag (head build-url) ; => Renders the `head` partial ; ....
The user layout map
The following is a description of the map that gets passed to all user layouts. As such, all of these keys may be destructured as mentioned above. Some values may be removed / added.
{;; Layout stuff --
:render (partial render {:file file :config config})
:partials (config :partials)
;; Site-side stuff --
:site-map (config :site-map)
:site-links (config :site-links)
:site-logs (config :site-logs)
:site-title (cfg/prop config :site-title)
:site-author (cfg/prop config :site-author)
:site-desc (cfg/prop config :site-desc)
:site-url site-url
:org-tags (config :org-tags)
:firn-tags (config :firn-tags)
:build-url (build-url site-url)
:config config
;; File wide meta --
:file file
:meta (file :meta)
:logbook (-> file :meta :logbook)
:file-links (-> file :meta :links) ;; TODO - possible re/move this too?
:title (-> file :meta :title)
:firn-under (-> file :meta :firn-under) ;; TODO this should be removed; should be handled by the render function...?
:logbook-total (-> file :meta :logbook-total)
:date-updated (-> file :meta :date-updated)
:date-created (-> file :meta :date-created)}