Skip to content

garlic0x1/hiccl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Readme

HTML generator for Common Lisp

Purpose

Spinneret is great but having to use macros to compose elements is less intuitive than simply having a function to render S-Expressions into HTML.

Hiccl also aims to be easy to extend with generic functions.

Usage

Hiccl exposes one macro, `render`, which wraps `render-forms` to use &body args for editor support. It takes an output argument (same as format) and any number of SXML expressions.

  • Symbols are raw (you can write literal HTML between `|` symbols)
  • Strings are sanitized
  • Lists are HTML nodes

Outputting to `nil` returns a string.

NOTE: In the following examples, the HTML has been formatted for the readme. Hiccl does not pretty print it’s output.

(hiccl:render nil
 `(:div :hi "world"
    (:span "tag can be symbol")
    "no </\"xss\"> allowed"
    |symbols <are> "raw" </are>|
    (:a :href "hTtPs://link.org" "clickme")))
<div hi="world">
  <span>
    tag can be symbol
  </span>
  no &lt;/&quot;xss&quot;&gt; allowed
  symbols <are> "raw" </are>
  <a href="hTtPs://link.org">clickme</a>
</div>

JSX style syntax

class and id tags can use the following shorthand notation:

(hiccl:render nil
  '(:div.c1#id1.c2 :class "c3" :id "id2"))
<div class="c3 c1 c2" id="id2 id1">
</div>

Order is not guarunteed at the moment, but I will consider adding it.

Specifying output

Render to a stream by specifying the `out` argument, renders to string if nil.

(hiccl:render *standard-output* sxml)
;; alternatively you can use `t` like in format
(hiccl:render t sxml)
;; to get a string
(hiccl:render nil sxml)

Composing components

(defun hello-component (name)
  `(:span ,(format nil "Hello ~a" name)))

(hiccl:render nil
 `(:div
   "hello-component:"
   ,(hello-component "garlic")))
<div>
  hello-component:
  <span>Hello garlic</span>
</div>

Boolean attributes

To use boolean attributes, just make its value nil:

(hiccl:render nil '(:div :bool nil))
<div bool>
</div>

Extending the renderer

The renderer uses generic functions that you can extend to handle your objects:

(defclass thing ()
  ((a :initarg :a :accessor thing-a)
   (b :initarg :b :accessor thing-b)))

(defmethod hiccl::render-form (out (obj thing))
  (hiccl:render out
    `(:div.thing
      (:div.a ,(thing-a obj))
      (:div.b ,(thing-b obj)))))

(hiccl:render nil (make-instance 'thing :a "hi" :b "world"))
<div class="thing">
  <div class="a">
    hi
  </div>
  <div class="b">
    world
  </div>
</div>

You can also add special cases for HTML tags with methods:

(defmethod hiccl::apply-tag (out (tag (eql :my-comment)) body)
  (format out "<!--~%SPECIAL COMMENT~%~{~a~%~}-->" body))

(hiccl:render nil '(:my-comment "hi"))
<!--
SPECIAL COMMENT
hi
-->

These are not exported, so remember to use hiccl::* to refer to them.

About

HTML generator for Common Lisp

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published