Open basus opened 4 years ago
would defining the header as a variable that you insert in every template work? it's not nesting, but…
Hmm, I suppose I could define each component of the template separately (possibly as Pollen code) and then each template.html.p
file combines the components I want.
One approach I’ve used was to create a separate module, and all the reusable HTML snippets I might want in a template are implemented there as functions. (Example) Then I require
and re-provide
this module from pollen.rkt
so it is available for use inside templates.
My understanding is that the more code you put inside Racket modules as opposed to putting it inside the template itself, the better, because Racket modules can be precompiled and cached while templates are evaluated fresh every time they are used.
Note the use of #lang pollen/mode
to allow using Pollen syntax inside a Racket module (more info in the Pollen docs). This is just a convenience that comes in handy for templatey stuff. Another way of representing HTML snippets as functions is to use scribble/html
, as shown in @soegaard's web-tutorial project (see this file in particular).
At one point I thought about having templates for templates but it all got too ridiculous. In my experience most of what you describe is a matter of importing a common header and footer, which is easy enough to do with file->string
, for instance:
;; test.html.pm
#lang pollen
hello world
;; template.html.p
◊(local-require racket/file)
◊(file->string "header.rktd")
◊(->html doc)
;; header.rktd
<h1>Included!</h1>
I ended up addressing this by doing as much as possible with X-expressions in Racket. I have a bunch of snippets which look like:
;; Default code snippets, mostly for inclusion in templates
(define (default-head)
`(head
,@(meta:defaults)
,(head:title)
,@(head:stylesheets "/css/fonts.css" "/css/style.css")))
(define (default-navigation)
`(header ,(navigation "Colophon" "Posts" "Drafts" "Series")))
(define (body-with #:id [id #f]
#:class [cls #f]
#:navigation [nav (default-navigation)]
#:contents contents)
(let ((attrs (match* (id cls)
[ [#f #f] '() ]
[ [id #f] `((id ,id)) ]
[ [#f cls] `((class ,cls)) ]
[ [id cls] `((class ,cls) (id ,id)) ]
)))
`(body ,attrs ,nav ,contents)))
and then I can build templates like so:
<!DOCTYPE html>
<html lang="en">
◊(->html (default-head))
◊(->html (body-with
#:class "theme-dark"
#:contents `(div ((id "content"))
,@(select* 'root doc))))
</html>
I'm wondering if there's some way to stack or nest templates? For example, I want a toplevel
template.html.p
that defines the general look and feel of my site, but then I wantblog/template.html.p
to define the look of blog posts. But the blog post template will share the<head>
and navigation elements with the top-level templates, so it would be nice to have those in the toplevel, and just define an included smaller part in the blog template.From my reading of the Pollen documentation on templates, it seems like there's only one template associated with a source file, and there isn't a way to nest them the way I'd like. Is there some way to do this?