Stacking or nesting templates #54

Open
opened 4 years ago by basus · 5 comments
basus commented 4 years ago (Migrated from github.com)

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 want blog/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?

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 want `blog/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?
odanoburu commented 4 years ago (Migrated from github.com)

would defining the header as a variable that you insert in every template work? it's not nesting, but…

would defining the header as a variable that you insert in every template work? it's not nesting, but…
basus commented 4 years ago (Migrated from github.com)

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.

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.
otherjoel commented 4 years ago (Migrated from github.com)

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).

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](https://thelocalyarn.com/code/artifact/942ec997ff11895b)) 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](https://docs.racket-lang.org/pollen/pollen-command-syntax.html#%28part._.Adding_.Pollen-style_commands_to_a_.Racket_file%29)). 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`](https://docs.racket-lang.org/scribble-pp/html.html), as shown in @soegaard's web-tutorial project (see [this file](https://github.com/soegaard/web-tutorial/blob/master/listit/view.rkt) in particular).
mbutterick commented 4 years ago (Migrated from github.com)

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>
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> ```
basus commented 4 years ago (Migrated from github.com)

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 ended up addressing this by doing as much as possible with X-expressions in Racket. I have a bunch of snippets which look like: ```racket ;; 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> ```
This repo is archived. You cannot comment on issues.
No Milestone
No project
No Assignees
1 Participants
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: mbutterick/pollen-users#54
Loading…
There is no content yet.