composing html with macros
boogsbunny opened this issue · 4 comments
I'm still wrapping around my head composing macros correctly including order of evaluation, so I would appreciate your input here please. For example, I have this code:
(defclass accordion-component (component)
((trigger :accessor trigger
:initarg :trigger
:initform "")
(content :accessor content
:initarg :content
:initform "")))
(defmethod render-html ((accordion accordion-component))
(with-slots (trigger content) accordion
(check-type trigger string)
(spinneret:with-html
(:div
(:h3 (:button (:span trigger)))
(:div content)))))
(defmacro accordion (&rest slots)
`(let ((accordion (make-instance 'accordion-component ,@slots)))
(render-html accordion)))
and I'd like to be able to call accordion like so:
(spinneret:with-html-string (accordion :trigger "what" :content (:p "this is it")))
where trigger
is just a string and content
would be some spinneret code.
How would I go on about just placing that content inside the div correctly?
The current output is this:
<p>this is it
<div>
<h3>
<button><span>what</span></button>
</h3>
<div>
</div>
</div>
but I'm looking for this:
<div>
<h3>
<button><span>what</span></button>
</h3>
<div>
<p>this is it
</div>
</div>
I came up with this solution, though I'm not sure if it's bad practice to use eval
?
(defmethod render-html ((accordion accordion-component))
(with-slots (trigger content) accordion
(check-type trigger string)
(eval `(spinneret:with-html
(:div
(:h3 (:button (:span ,trigger)))
(:div ,content))))))
(spinneret:with-html-string (accordion :trigger "what" :content '(:p "hi")))
I haven't had the chance to look over your question in detail, but I'm sure we can do better than eval. There is a section in the README on how to use deftag
to solve order-of-evaluation issues; that might be helpful.
Yeah, I see that. I actually don't care about defining a particular tag here per se.
I just want to be able to call the accordion macro, place arbitrary html inside the spinneret:with-html macro, and get the evaluation back.
Curious to hear what you think is best practices when you get a chance to look over this!