Case study

Extending Quarto workshop @ posit::conf(2025)

Charlotte Wickham
&  
Mine Çetinkaya-Rundel

A case study: Course notes

Notes that we want as slides (format: revealjs) and a document (format: html).

Title slide in every slide deck controlled by metadata

Partial

Special slide combines boilerplate with content.

Filter

Your turn 1

Your turn: Add a filter

Write the participate.lua filter to combine the content of the question in the div with class .participate with boilerplate text:

Answer in our Discord!

Your slide should look like this:

Hints:

  • Recall the useful pattern: create an empty pandoc.Blocks(), insert Blocks, extend with Blocks.
  • You can pass pandoc.Str() a string with spaces.

Exercise: 04-case-study/your-turns/1-add-filter

08:00

Your turn 2

Your turn: Predict the output

Take a look at the version of participate.lua on the next slide.

With your neighbor, predict what the “Participate” slide will look like.

Exercise: 04-case-study/your-turns/2-predict-output

05:00

participate.lua

Full Screen

participate.lua
local function column(width)
  return pandoc.Attr("", {'column'}, {width=width})
end 

Div = function(el)
  if not el.classes:includes("participate") then
    return nil
  end

  local content = pandoc.Div(el.content, pandoc.Attr("", {'question'}, {}))

  if not quarto.format.isHtmlSlideOutput() then
    return content
  end

  local boilerplate = pandoc.Para(pandoc.Inlines({
    pandoc.Image(
      "",
      "Discord-Logo-Black.png", 
      nil, 
      pandoc.Attr("", {}, {alt="Discord Logo"})
    ),
    pandoc.Str("Answer in our "),
    pandoc.Link(
      pandoc.Str("Discord"), 
      pandoc.utils.stringify(quarto.metadata.get("discord")))
  }))
  
  local inner_columns = pandoc.Blocks({
    pandoc.Div(content, column('75%')), 
    pandoc.Div(boilerplate, column('25%'))
  })
  local result = pandoc.Div(inner_columns, pandoc.Attr("", {"columns"}, {}))
  return result
end

Your turn 3

Your turn: Now add a partial!

Take what you developed so far in this module and add your title-slide.html partial and slides.scss theme from earlier.

Exercise: 04-case-study/your-turns/3-add-partial

Wrap-up

Bring it all together

Example: 04-case-study/example


example
|- Discord-Logo-Black.png
|- example.qmd
|- participate.lua
|- question.css
|- slides.scss
|- title-slide.html

Bring it all together…

as an extension!

Example: 04-case-study/coursenotes


coursenotes
|- _extensions
   |- coursenotes
      |- _extension.yml
      |- Discord-Logo-Black.png
      |- participate.lua
      |- question.css
      |- slides.scss
      |- title-slide.html
|- template.qmd

Reusable components

  • {{< include >}}s are a convenient way to reuse content across documents
    • The same content
    • Basically copy-paste
  • template-partials are a way to create reusable components with meta-data
    • The same structure, but different content
    • format specific
  • filters are a way to modify document content
    • The same structure, but different content
    • Not format specific (they operate on the document AST), but can function differently for different formats
  • _extensions are combinations of partials and filters, and possibly other things, that are designed for portability and reusability

Workshop survey

Before we move on to Q&A, please take a note of the workshop survey:


Questions?

Any questions, but especially of the kind:

  • How can I solve _my problem_ with a filter, partial, etc.?

  • Do I need a filter or partial or something else for solving _my problem_?