diff --git a/static/slides/R/components.R b/static/slides/R/components.R
index 372ecf1..8b21eb4 100644
--- a/static/slides/R/components.R
+++ b/static/slides/R/components.R
@@ -302,3 +302,37 @@ live_coding <- function(
)
knitr::asis_output(x)
}
+
+#' Create Slide Source Panels
+#'
+#' Make sure that the slide to be included has a `name: ` property,
+#' that's how the slide will be found. It also can't be a slide created with a
+#' layout.
+slide_source_panels <- function(slide_name, slide_panel = "Slide", source_panel = "Source") {
+ htmltools::tagList(
+ htmltools::withTags(
+ div(
+ class = "panel",
+ span(class = "panel-name", slide_panel),
+ div(`data-slide-name` = slide_name, `data-type` = "slide")
+ )
+ ),
+ if (!is.null(source_panel)) {
+ htmltools::withTags(
+ div(
+ class = "panel",
+ span(class = "panel-name", source_panel),
+ div(`data-slide-name` = slide_name, `data-type` = "source")
+ )
+ )
+ },
+ htmltools::htmlDependency(
+ name = "slide-source-panels",
+ version = "0.0.1",
+ src = here::here("static", "slides", "assets", "slide-source-panels"),
+ script = "slide-source-panels.js",
+ stylesheet = "slide-source-panels.css",
+ all_files = FALSE
+ )
+ )
+}
diff --git a/static/slides/assets/slide-source-panels/slide-source-panels.css b/static/slides/assets/slide-source-panels/slide-source-panels.css
new file mode 100644
index 0000000..af36af0
--- /dev/null
+++ b/static/slides/assets/slide-source-panels/slide-source-panels.css
@@ -0,0 +1,10 @@
+[data-slide-name] .remark-slide-content {
+ --scale: 0.8;
+ position: absolute;
+ width: 1210px;
+ height: 681px;
+ transform: scale(var(--scale));
+ transform-origin: top left;
+ border: 2px solid #ddd;
+ top: calc((681px - (681px * var(--scale))) / 2);
+}
diff --git a/static/slides/assets/slide-source-panels/slide-source-panels.js b/static/slides/assets/slide-source-panels/slide-source-panels.js
new file mode 100644
index 0000000..2c4b85d
--- /dev/null
+++ b/static/slides/assets/slide-source-panels/slide-source-panels.js
@@ -0,0 +1,83 @@
+(function () {
+ const ready = function (fn) {
+ /* MIT License Copyright (c) 2016 Nuclei */
+ /* https://github.com/nuclei/readyjs */
+ const completed = () => {
+ document.removeEventListener('DOMContentLoaded', completed)
+ window.removeEventListener('load', completed)
+ fn()
+ }
+ if (document.readyState !== 'loading') {
+ setTimeout(fn)
+ } else {
+ document.addEventListener('DOMContentLoaded', completed)
+ window.addEventListener('load', completed)
+ }
+ }
+
+ ready(function () {
+ const placeholders = document.querySelectorAll('.remark-slides-area [data-slide-name]')
+
+ if (!placeholders.length) {
+ return;
+ }
+
+ function getSlideSource (name, keepName) {
+ let src = '---\n'
+ src += document
+ .getElementById('source')
+ .textContent.split(/(^|\n)---\n/)
+ .filter(s => s.match(RegExp(`name: ?${name}`)))
+ .join()
+
+ if (!keepName) {
+ src = src.replace(/\nname: ?[^\n]+/, '')
+ }
+
+ return src
+ }
+
+ function appendSlideSource (el) {
+ console.log(el.dataset)
+ const theCode = getSlideSource(el.dataset.slideName, el.dataset.keepName)
+ const pre = document.createElement('pre')
+ const code = document.createElement('code')
+ code.classList = 'markdown remark-code'
+ theCode.split('\n').forEach(function(line) {
+ const div = document.createElement('div')
+ div.classList = 'remark-code-line'
+ div.innerText = line
+ code.appendChild(div)
+ })
+ // code.innerText = theCode
+ pre.appendChild(code)
+
+ el.appendChild(pre)
+ return el
+ }
+
+ function getSlideNodeClone (name) {
+ const slide = document.getElementById('slide-' + name)
+ const newSlide = slide.cloneNode(true)
+ newSlide.removeAttribute('id')
+ return newSlide
+ }
+
+ function appendSlideNode (el) {
+ const slide = getSlideNodeClone(el.dataset.slideName)
+ el.appendChild(slide)
+ return el
+ }
+
+ placeholders.forEach(function (el) {
+ switch (el.dataset.type) {
+ case 'source':
+ appendSlideSource(el)
+ break
+ case 'slide':
+ default:
+ appendSlideNode(el)
+ }
+ })
+ })
+})()
diff --git a/static/slides/demo-slide-source-panels.Rmd b/static/slides/demo-slide-source-panels.Rmd
new file mode 100644
index 0000000..d650e39
--- /dev/null
+++ b/static/slides/demo-slide-source-panels.Rmd
@@ -0,0 +1,188 @@
+---
+scene: 0
+title: "Demo Slides"
+subtitle: "A work in progress!"
+author: "Garrick Aden-Buie & Silvia Canelón"
+date: '2021-07-07'
+output:
+ xaringan::moon_reader:
+ lib_dir: "assets/libs"
+ css:
+ - assets/css/js4shiny-xaringan-base.css
+ - assets/css/tachyons.min.css
+ - assets/css/js4shiny-xaringan-extra.css
+ includes:
+ after_body: assets/html/js4shiny-includes.html
+ seal: false
+ chakra: assets/js/remark.0.14.1.min.js
+ mathjax: NULL
+ nature:
+ ratio: 16:9
+ slideNumberFormat: "%current%"
+ highlightStyle: docco
+ highlightLines: true
+ countIncrementalSlides: true
+---
+
+class: title
+
+```{r setup, include=FALSE}
+options(htmltools.dir.version = FALSE)
+knitr::opts_chunk$set(
+ fig.width = 10,
+ fig.height = 6,
+ fig.retina = 2,
+ warning = FALSE,
+ message = FALSE
+)
+source(here::here("static", "slides", "R", "components.R"))
+# use_placeholders(TRUE, TRUE)
+xaringanExtra::use_xaringan_extra(c("tile_view", "panelset", "share_again"))
+xaringanExtra::use_editable(id = rmarkdown::metadata$title)
+```
+
+```{r js4shiny, echo=FALSE}
+js4shiny::html_setup(stylize = c("fonts", "variables", "code"))
+```
+
+`r title_slide()`
+
+---
+name: first-demo
+class: fullscreen
+
+.panelset.sideways.pl2.h-100[
+
+```{r echo=FALSE}
+# this function was added to components.R
+# it creates two panels, one with a copy of the slide (found by name)
+# and another panel with the markdown source for the slide (as seen by remark)
+# (If the slide source is complicated, you can set source_panel = NULL and
+# manually add the source code in a panel.)
+slide_source_panels("fonts")
+```
+
+]
+
+---
+class: fullscreen
+
+.panelset.sideways.pl2.h-100[
+
+```{r echo=FALSE}
+slide_source_panels("html-resources")
+```
+
+.panel[.panel-name[Notes]
+
+## Good?
+
+## Bad?
+
+## What do you think?
+
+The slides are actually in the deck in a later section.
+I put them at the end in an "Appendix".
+
+The source is pulled from the compiled source, so you can't see R Markdown bits.
+
+]
+
+]
+
+---
+class: fullscreen
+
+.panelset.sideways.pl2.h-100[
+
+```{r echo=FALSE}
+slide_source_panels("break-javascript")
+```
+
+.panel[.panel-name[Notes]
+
+This slide doesn't look _perfect_ so somethings that rely on absolute positioning may be a little bit weird. Most basic xaringan stuff will probably look okay, though.
+
+]
+
+]
+
+---
+class: fullscreen
+
+.panelset.sideways.pl2.h-100[
+
+```{r echo=FALSE}
+slide_source_panels("first-demo", source_panel = NULL)
+```
+
+.panel[.panel-name[Source]
+
+This is where it gets **meta**.
+We're looking at a slide we saw earlier in the deck!
+
+This is the code I used to create that slide.
+
+````markdown
+---
+name: first-demo
+class: fullscreen
+
+.panelset.sideways.pl2.h-100[
+
+```{r echo=FALSE}`r ''`
+slide_source_panels("fonts")
+```
+
+]
+````
+
+I had to manually make this **Source** panel because it includes an Rmd chunk.
+
+]
+
+]
+---
+class: center middle
+
+# Appendix
+
+---
+class: break break-javascript
+name: break-javascript
+
+# JavaScript inspired break
+
+.absolute.top-1.left-1[break break-javascript]
+
+---
+name: fonts
+
+# Fonts
+
+.mh-auto.w-80.f5.mt4[
+.f-lato[Lato (body)] .fr.code[.f-lato]
+
+.f-nunito[Nunito Sans] .fr.code[.f-nunito]
+
+.f-marker[Marker] .fr.code[.f-marker]
+
+.f-source-code[Source Code Pro] .fr.code[.f-source-code]
+]
+
+---
+name: html-resources
+
+# HTML Resources
+
+* Mastering Shiny: Advanced UI
+ https://mastering-shiny.org/advanced-ui.html
+
+* FrontEnd Masters Handbook
+ https://frontendmasters.com/books/front-end-handbook/2019/
+
+* Interneting is Hard
+ https://internetingishard.com/
+
+* HTML Semantics Cheat Sheet
+ https://learn-the-web.algonquindesign.ca/topics/html-semantics-cheat-sheet/