#+TITLE: Templating System #+AUTHOR: Asteroid Radio Development Team #+DATE: 2026-01-17 * Introduction The radiance ecosystem includes an HTML templating system that is built on top of [[https://quickdocs.org/clip][Clip]] and [[https://shinmera.github.io/lquery/][lquery]] for advanced costumization. While =clip= enables conditional logic on rendering parts in an HTML document, re-using the same tag mechanics, =lquery= enables dynamically setting of element properties with some lisp integrations. Dominating these tools enables some smarter approaches on page content building with conditional rendering and code reuse. * Clip mechanics ** Conditionals Clip uses HTML tags for its logic and has 3 simple conditional directives: =if=, =when= and =unless=, that work exactly as their lisp counterparts, having the =test= attribute as the validator for truthness. The =if= check is accomplished by the =c:if= tag, and requires a =c:then= tag for the body of its branch. It also has =c:else= and =c:elseif= to enable multiple branching: #+begin_src html #+end_src The above example tests for the truthness of the variable =framesetp= and executes the associate branch based on that. The =test= argument can, naturally, receive any kind of lisp syntax. The =c:when= and =c:unless= directives, like their lisp counterparts, only have a branch that is executed when the check of =test= argument value is true or false accordingly. *Note:* Clip also has =c:case= and =c:cond= conditionals that should work like they lisp counterparts but I didn't need them until now so I'll not try to explain them. ** Data usage Using a variable content in the template engine is accomplished by the =lquery= tag attribute, which will be explained later. But as this is a tag attribute, it requires an HTML tag to be attached. To enable the possibility of inserting something anywhere on the HTML document, Clip supplies the =c:splice= tag, a virtual HTML node that is removed after rendering, leaving only the content inserted by =lquery=. The follow example inserts a textual value of the =content= variable directly into the HTML page: #+begin_src html #+end_src Those two usages are so frequently that Clip supplies shorhand aliases for both as the =c:s= and =c:h= tags: #+begin_src html content navbar #+end_src A great usage of this feature is our new navbar reusable HTML partial, that can be loaded from a speficic lisp function on any page: #+begin_src html (asteroid::load-template "partial/navbar") #+end_src *Note:* As far as I understand, the templating engine works on a different package, so refering to the =asteroid= package is always required inside a template to use defined functions. ** Clipboard environments Clip uses the concept of environment as the data that is available to be used in the templating system. The =c:let= directive lets define a new clipboard environment directly on the template. This will supersede the default clipboard, so any useful data needs to also be added to the clipboard for easy access: #+begin_src html #+end_src The above example defines a local =new-var= with the value ="hello"= and a local =forward= with the parent =var= variable content. Alternatively, if forwarding a variable to the new clipboard environment is not desired, the special =(** :var)= syntax can be used to access the parent clipboard. The =c:using= directive creates a new clipboard environment with the contents of an existing variable on the parent clipboard. #+begin_src html attribute1 #+end_src The example creates a new clipboard environment inside the =c:using= attribute that has direct access to all properties of some structured variable =obj=. This tag transparently destructures any kind of composed data structure like =plists=, =alists= and =classes=. Like the simplicity of structural access of the =c:using= tag, the =clip= function enables the same easy of access in any template context. For example, the same splice of the previous example can be obtained with: #+begin_src html (clip obj :attribute1) #+end_src This approach is, clearly, more useful when a single value is wanted, while the previous when several values on the structured variable will be used. ** Iterators Clip also has the =c:iterate= directive that iterates a sequence, and its body is rendered having the clipboard environment matching each element of that iteration. As I am yet to use this directive, I will leave its documentation to a later moment. * lquery mechanics The [[https://shinmera.github.io/lquery/][lquery]] library enables changing any property of an HTML node, being its =text= or =html= content, =css= styles, element attributes (=attr=) and assigned css classes. Its usage is very simple: an =lquery= attribute is added to an HTML document, and its value is a s-expression with an accepted funtion and the value for it to work on. The following topics present some basic accepted =lquery= functions in use on our templates. ** HTML node content There are two basic =lquery= functions that change the content of the assigned HTML node: - =html= renders HTML elements as child - =text= sets a text content to the element The =lquery= s-expression accepts variable or lisp calls for any of the referred functions. For example, the following example sets the content of the =script= tag to the result of the =(asteroid::get-auth-state-js-var)= function: #+begin_src html #+end_src *Note:* the template render process works on a different package, so call to application defined functions needs to include the package name. ** HTML node styling =lquery= also grants easy styling customization of an HTML node. HTML styling can be accomplished in two ways: - =css=, which sets the HTML =style= attribute of the element. It's called as a plist with all the properties to set. - css classes that can be added (=add-class=) or removed (=remove-class=) The following example adds the =display= and =marging= style properties to the document when the variable =framesetp= is true (=margin= is overwriten in this case): #+begin_src html
#+end_src ** HTML attributes The =attr= function of the =lquery= s-expression allows customization of any valid HTML node attribute. The following example sets two attributes of an anchor tag: - =href=, which uses the =eval= function to evaluate some lisp call - =target= which only has a value when the variable =framesetp= is true #+begin_src html #+end_src