diff --git a/_extensions/closeread/closeread.js b/_extensions/closeread/closeread.js
index 5a47ddd..0156033 100644
--- a/_extensions/closeread/closeread.js
+++ b/_extensions/closeread/closeread.js
@@ -47,6 +47,15 @@ document.addEventListener("DOMContentLoaded", () => {
console.error("Warning: Quarto OJS module not found")
}
+ // expand hlz option into highlight and zoom-to
+ const allHlzTriggers = Array.from(document.querySelectorAll('[data-hlz]'));
+ console.log(">> allHlzTriggers", allHlzTriggers)
+ allHlzTriggers.forEach(trigger => {
+ const hlzValue = trigger.getAttribute('data-hlz');
+ trigger.setAttribute('data-zoom-to', hlzValue);
+ trigger.setAttribute('data-highlight', hlzValue);
+ });
+
// collect all sticky elements
const allStickies = Array.from(document.querySelectorAll(".sticky"));
@@ -54,6 +63,7 @@ document.addEventListener("DOMContentLoaded", () => {
// === Set up scrolling event listeners === //
// scrollama() is accessible because scrollama.min.js is attached via closeread.lua
+ // primary scroller
const triggerScroller = scrollama();
triggerScroller
.setup({
@@ -81,6 +91,7 @@ document.addEventListener("DOMContentLoaded", () => {
});
+ // secondary scroller used for making progress blocks
const progressBlockScroller = scrollama();
progressBlockScroller
.setup({
@@ -127,7 +138,7 @@ document.addEventListener("DOMContentLoaded", () => {
});
-// === Hotkey Listeners === //
+// === Other Hotkey Listeners === //
// toggle presentation mode
document.addEventListener('keydown', (event) => {
@@ -145,11 +156,12 @@ document.addEventListener('keydown', (event) => {
-//===========//
-// Functions //
-//===========//
+//===============//
+// Focus effects //
+//===============//
+// A collection of functions that apply focus effects to stickies
- /* updateStickies: triggers effects and transformations of the focused sticky */
+// updateStickies: triggers effects on the focused sticky
function updateStickies(allStickies, focusedStickyName, trigger) {
const focusedSticky = document.querySelectorAll("[id=" + focusedStickyName)[0];
@@ -159,15 +171,25 @@ function updateStickies(allStickies, focusedStickyName, trigger) {
// apply additional effects
transformSticky(focusedSticky, trigger.element);
+ highlightSpans(focusedSticky, trigger.element);
- if (focusedSticky.classList.contains("cr-poem")) {
- scalePoemFull(focusedSticky);
+ if ( // scale-to-fill only takes effect if there are no other transforms
+ focusedSticky.classList.contains("scale-to-fill") &&
+ !trigger.element.hasAttribute("data-zoom-to") &&
+ !trigger.element.hasAttribute("data-pan-to") &&
+ !trigger.element.hasAttribute("data-scale-by")
+ ) {
+ scaleToFill(focusedSticky);
}
-
- highlightSpans(focusedSticky, trigger.element);
}
+
+//==============//
+// Highlighting //
+//==============//
+
+// highlights line number spans in line blocks and code, and id'ed spans in line blocks
function highlightSpans(focusedSticky, triggerEl) {
// remove any previous highlighting
@@ -182,10 +204,34 @@ function highlightSpans(focusedSticky, triggerEl) {
return;
}
- // turn a range of line numbers into a series
+ // dim enclosing block
+ focusedSticky.classList.add("cr-hl-within");
+
+ // add highlight class to appropriate spans
+ highlightIds = rangeToSeries(highlightIds);
+ highlightIds.split(',').forEach(highlightId => {
+
+ // build selector
+ const spanSelector = idToSpanSelector(focusedSticky, highlightId);
+ // find span
+ const highlightSpan = focusedSticky.querySelector(spanSelector);
+
+ // apply effect
+ if (highlightSpan !== null) {
+ highlightSpan.classList.add("cr-hl");
+ } else {
+ // Handle the case where the ID does not correspond to a span
+ console.warn(`While highlighting, could not find span with corresponding to an ID of '${highlightId}'. Please ensure the ID is correct.`);
+ }
+ });
+
+}
+
+// turn a range of line numbers into a series
+function rangeToSeries(ids) {
isRange = /\b(\d+)\s*-\s*(\d+)\b/;
- if (isRange.test(highlightIds)) {
- const match = highlightIds.match(isRange);
+ if (isRange.test(ids)) {
+ const match = ids.match(isRange);
if (match) {
const start = parseInt(match[1], 10);
@@ -196,227 +242,149 @@ function highlightSpans(focusedSticky, triggerEl) {
numbers.push(i);
}
- highlightIds = numbers.join(',');
- } else {
- return '';
+ ids = numbers.join(',');
}
}
- // dim enclosing block
- focusedSticky.classList.add("cr-hl-within");
+ return ids;
+}
+
+// convert id to appropriate span selector
+function idToSpanSelector(focusedSticky, id) {
+ id.trim();
+ let spanSelector = "";
- // add highlight class to appropriate spans
- highlightIds.split(',').forEach(highlightId => {
- const trimmedId = highlightId.trim();
- let spanSelector = "";
+ // determine the right spanSelector
+ // for line numbers
+ if (!isNaN(id)) {
- // determine the right spanSelector
- // for line numbers
- if (!isNaN(trimmedId)) {
-
- // that are in line blocks
- if (focusedSticky.querySelector('.line-block') !== null) {
- spanSelector = `span[id^="lb"][id*="-${trimmedId}"]`;
- }
- // or in code cells
- if (focusedSticky.querySelector('.cell') !== null) {
- spanSelector = `span[id^="cb"][id*="-${trimmedId}"]`;
- }
-
- // and for span ids
- } else {
- spanSelector = `span[id="${trimmedId}"]`;
+ // that are in line blocks
+ if (focusedSticky.querySelector('.line-block') !== null) {
+ spanSelector = `span[id^="lb"][id*="-${id}"]`;
}
-
- const highlightSpan = focusedSticky.querySelector(spanSelector);
-
- if (highlightSpan !== null) {
- highlightSpan.classList.add("cr-hl");
- } else {
- // Handle the case where the ID does not correspond to a span
- console.warn(`While highlighting, could not find span with corresponding to an ID of '${trimmedId}'. Please ensure the ID is correct.`);
+ // or in code cells
+ if (focusedSticky.querySelector('.cell') !== null || focusedSticky.querySelector('.sourceCode') !== null) {
+ spanSelector = `span[id^="cb"][id*="-${id}"]`;
}
- });
+
+ // and for span ids
+ } else {
+ spanSelector = `span[id="${id}"]`;
+ }
+ return spanSelector;
}
-function highlightans(focusedSticky, triggerEl) {
- // remove any previous highlighting from sticky
- focusedSticky.querySelectorAll("span[id]").forEach(d => d.classList.remove("cr-hl"));
- focusedSticky.classList.remove("cr-hl-within");
+//==============//
+// Transforming //
+//==============//
+// use the flexible `transform` attribute to trigger effects associated with
+// zoom-to, pan-to, scale-by, .scale-to-fill, and (indirectly) hlz
+
+function transformSticky(focusedSticky, trigger) {
- // get hightlighted spans from trigger
- let highlightIds = triggerEl.getAttribute("data-highlight-spans");
+ // initialize empty strings
+ let translateStr = "";
+ let scaleStr = "";
+ let transformStr = "";
- // exit function if there's no highlighting
- if (highlightIds === null) {
- return;
+ // determine type of transform
+ if (trigger.hasAttribute("data-pan-to")) {
+ // get translate attributes from trigger
+ translateStr = "translate(" + trigger.getAttribute("data-pan-to") + ")";
}
- // dim enclosing block
- focusedSticky.classList.add("cr-hl-within");
-
- // add highlight class to appropriate spans
- highlightIds.split(',').forEach(highlightId => {
- const trimmedId = highlightId.trim();
- const highlightSpan = focusedSticky.querySelector(`#${trimmedId}`);
- if (highlightSpan !== null) {
- highlightSpan.classList.add("cr-hl");
- } else {
- // Handle the case where the ID does not correspond to a span
- console.warn(`Could not find span with ID '${trimmedId}'. Please ensure the ID is correct.`);
- }
- });
+ if (trigger.hasAttribute("data-scale-by")) {
+ // get scale attributes from trigger
+ scaleStr = "scale(" + trigger.getAttribute("data-scale-by") + ")";
+ }
- if (focusedSticky.classList.contains("cr-poem")) {
- // scale to span using transform
- scalePoemToSpan(focusedSticky, highlightIds);
+ if (trigger.hasAttribute("data-zoom-to")) {
+ transformStr = zoomToTransform(focusedSticky, trigger);
}
-}
-
-
-// make the given element active. if it's a poem, rescale it
-function updateActivePoem(el, priorSteps) {
-
- const elId = el.getAttribute("data-cr-id")
-
- // active highlight is the most recent step with `cr-in` of this sticky
-
- const activeHighlight = priorSteps
- .filter(d => d.getAttribute("data-cr-in") == elId)
- .at(-1)
- ?.getAttribute("data-cr-highlight")
-
- // no active highlight?
- if (activeHighlight === undefined) {
- rescaleElement(el);
- } else {
- // Split the `activeHighlight` value on commas to support multiple IDs
- const highlightIds = activeHighlight.split(',');
-
- // Call rescaleElement with the first found id for focusing,
- // or without a specific focus if no ids are found
- if (highlightIds) {
- rescaleElement(el, highlightIds);
- } else {
- rescaleElement(el);
+ // zooming will override pan-to and scale-by
+ if (!transformStr) {
+ if (translateStr && scaleStr) {
+ transformStr = translateStr + " " + scaleStr;
+ } else if (translateStr) {
+ transformStr = translateStr;
+ } else if (scaleStr) {
+ transformStr = scaleStr;
}
}
-}
-
-/* rescaleElement:
- given a poem element `el` (and potentially a contained ids `highlightIds`),
- resets the focus status of a poem's highlight spans, then rescales (and
- potentially translates) the poem so that either the whole thing is visible
- or the line containing `highlightIds` is visible and centerd */
-function rescaleElement(el, highlightIds) {
-
- // find ALL spans within the `el` and remove `.cr-hl`
- el.querySelectorAll("span[id]").forEach(d => d.classList.remove("cr-hl"))
- if (highlightIds == undefined) {
- scalePoemFull(el)
- } else {
- scalePoemToSpan(el, highlightIds)
- }
+ // use the string to transform the sticky
+ focusedSticky.style.transform = transformStr;
+
}
-/* scalePoemFull:
- given an element `el`, rescales it to fill its containing .sticky-col-stack */
-function scalePoemFull(el, paddingX = 75, paddingY = 50) {
-
- console.log("Focusing on whole poem")
-
- el.classList.remove("cr-hl-within")
-
- // get dimensions of element and its container
- const container = el.closest(".sticky-col-stack")
+function zoomToTransform(focusedSticky, trigger) {
- const elHeight = el.scrollHeight
- const elWidth = el.scrollWidth
- const containerHeight = container.offsetHeight - (paddingY * 2)
- const containerWidth = container.offsetWidth - (paddingX * 2)
-
- const scaleHeight = elHeight / containerHeight
- const scaleWidth = elWidth / containerWidth
- const scale = 1 / Math.max(scaleHeight, scaleWidth)
+ const paddingX = 75;
+ const paddingY = 50;
- const centerDeltaY = (elHeight - el.offsetHeight) * scale / -2
-
- // apply styles
- el.style.setProperty("transform",
- `matrix(${scale}, 0, 0, ${scale}, 0, ${centerDeltaY})`)
-}
-
-/* scalePoemToSpan:
- given a sticky and a span `focusEl` within it, rescales and translates
- sticky so that `focusEl` is vertically centerd and its line fills the
- containing .sticky-col-stack */
-function scalePoemToSpan(focusedSticky, highlightIds, paddingX = 75, paddingY = 50) {
+ // get zoom-to spans from trigger
+ let zoomToIds = trigger.getAttribute("data-zoom-to");
+ zoomToIds = rangeToSeries(zoomToIds);
- // for now just get first span
- const focusedSpan = focusedSticky.querySelector(`#${highlightIds.trim()}`);
+ // for now, exit function if user provides more than one span / line
+ const zoomToArray = zoomToIds.split(',');
+ if (zoomToArray.length > 1) {
+ console.warn(`zoom-to currently only supports a single line number or span id.`);
+ return;
+ }
- // get dimensions of element and its container
- const container = focusedSticky.closest(".sticky-col-stack")
+ // build selector
+ const spanSelector = idToSpanSelector(focusedSticky, zoomToIds);
+ // find span
+ const focusedSpan = focusedSticky.querySelector(spanSelector);
+ // measurements needed for translation
const focusedStickyHeight = focusedSticky.scrollHeight
const focusedStickyWidth = focusedSticky.scrollWidth
- const containerHeight = container.offsetHeight - (paddingY * 2)
- const containerWidth = container.offsetWidth - (paddingX * 2)
-
const focusHeight = focusedSpan.offsetHeight
+ focusedSpan.offsetTop;
const focusTop = focusedSpan.offsetTop
const focusCenterY = focusTop + (focusHeight / 2)
+ const centerDeltaY = (focusCenterY - (focusedSticky.offsetHeight / 2)) * -1
+ // measurements needed for scaling
+ const container = focusedSticky.closest(".sticky-col-stack")
+ const containerHeight = container.offsetHeight - (paddingY * 2)
+ const containerWidth = container.offsetWidth - (paddingX * 2)
// note scaleWidth uses the whole line, not just the span width
const scaleWidth = focusedStickyWidth / containerWidth
const scaleHeight = focusHeight / containerHeight
- const scale = 1 / Math.max(scaleHeight, scaleWidth)
+ const scaleFactor = 1 / Math.max(scaleHeight, scaleWidth)
- const centerDeltaY = (focusCenterY - (focusedSticky.offsetHeight / 2)) * -1
-
- // apply styles
- focusedSticky.style.setProperty("transform",
- `matrix(${scale}, 0, 0, ${scale}, 0, ${centerDeltaY})`)
+ // form matrix transform string
+ const transformStr = `matrix(${scaleFactor}, 0, 0, ${scaleFactor}, 0, ${centerDeltaY})`;
+
+ return transformStr
}
+// given an element `el`, rescales it to fill its containing .sticky-col-stack
+function scaleToFill(el, paddingX = 75, paddingY = 50) {
-//==================//
-// Transform Sticky //
-//==================//
-
-function transformSticky(sticky, step) {
-
- // initialize empty strings
- let translateStr = "";
- let scaleStr = "";
- let transformStr = "";
-
- if (step.hasAttribute("data-pan-to")) {
- // get translate attributes from step
- translateStr = "translate(" + step.getAttribute("data-pan-to") + ")";
- }
-
- if (step.hasAttribute("data-scale-by")) {
- // get scale attributes from step
- scaleStr = "scale(" + step.getAttribute("data-scale-by") + ")";
- }
-
- // form transform string
- if (translateStr && scaleStr) {
- transformStr = translateStr + " " + scaleStr;
- } else if (translateStr) {
- transformStr = translateStr;
- } else if (scaleStr) {
- transformStr = scaleStr;
- }
+ // get dimensions of element and its container
+ const container = el.closest(".sticky-col-stack")
- // and use it to scale the sticky
- sticky.style.transform = transformStr;
+ const elHeight = el.scrollHeight
+ const elWidth = el.scrollWidth
+ const containerHeight = container.offsetHeight - (paddingY * 2)
+ const containerWidth = container.offsetWidth - (paddingX * 2)
+
+ const scaleHeight = elHeight / containerHeight
+ const scaleWidth = elWidth / containerWidth
+ const scale = 1 / Math.max(scaleHeight, scaleWidth)
+ const centerDeltaY = (elHeight - el.offsetHeight) * scale / -2
+
+ // apply styles
+ el.style.setProperty("transform",
+ `matrix(${scale}, 0, 0, ${scale}, 0, ${centerDeltaY})`)
}
/* getBooleanConfig: checks for a with named attribute `cr-[metaFlag]`
diff --git a/docs/gallery/demos/_poem-2/index.qmd b/docs/gallery/demos/_poem-2/index.qmd
deleted file mode 100644
index 63e5e58..0000000
--- a/docs/gallery/demos/_poem-2/index.qmd
+++ /dev/null
@@ -1,56 +0,0 @@
----
-description: Text zooming using font scaling
-format:
- closeread-html:
- css: nytimes.css
- remove-header-space: true
----
-
-:::{.cr-section}
-
-:::{focus-on="musee"}
-# A Poem (and a Painting) About the Suffering That Hides in Plain Sight
-
-By Elisa Gabbert March 6, 2002
-:::
-
-I’ve been reading this short, wry poem about suffering for more than 20 years.
-
-:::{focus-on="musee" highlight-spans="suffering"}
-How nice that it tells you in the first two words what it’s about.
-:::
-
-No matter how familiar a poem is, rereading it always gives me a sense of first encounter, as though I’ve gone back to sleep and re-entered the dream through a different door.
-
-
-:::{#cr-musee .cr-poem2}
-
-| **MUSÉE DES BEAUX ARTS**
-| *by W.H. Auden*
-|
-| [About suffering]{#cr-suffering} they were never wrong,
-| The old Masters: how well they understood
-| Its human position: how it takes place
-| While someone else is eating or opening a window
-| or just walking dully along;
-| How, when the aged are reverently, passionately waiting
-| For the miraculous birth, there always must be
-| Children who did not specially want it to happen, skating
-| On a pond at the edge of the wood:
-| They never forgot
-| That even the dreadful martyrdom must run its course
-| Anyhow in a corner, some untidy spot
-| Where the dogs go on with their doggy life and the torturer's horse
-| Scratches its innocent behind on a tree.
-|
-| In Breughel's *Icarus*, for instance: how everything turns away
-| Quite leisurely from the disaster; the ploughman may
-| Have heard the splash, the forsaken cry,
-| But for him it was not an important failure; the sun shone
-| As it had to on the white legs disappearing into the green
-| Water, and the expensive delicate ship that must have seen
-| Something amazing, a boy falling out of the sky,
-| Had somewhere to get to and sailed calmly on.
-:::
-
-:::
diff --git a/docs/gallery/demos/sticky-block-types/blue-desktop.png b/docs/gallery/demos/_sticky-block-types/blue-desktop.png
similarity index 100%
rename from docs/gallery/demos/sticky-block-types/blue-desktop.png
rename to docs/gallery/demos/_sticky-block-types/blue-desktop.png
diff --git a/docs/gallery/demos/sticky-block-types/index.qmd b/docs/gallery/demos/_sticky-block-types/index.qmd
similarity index 100%
rename from docs/gallery/demos/sticky-block-types/index.qmd
rename to docs/gallery/demos/_sticky-block-types/index.qmd
diff --git a/docs/gallery/demos/sticky-block-types/pink-desktop.png b/docs/gallery/demos/_sticky-block-types/pink-desktop.png
similarity index 100%
rename from docs/gallery/demos/sticky-block-types/pink-desktop.png
rename to docs/gallery/demos/_sticky-block-types/pink-desktop.png
diff --git a/docs/gallery/demos/highlighting/index.qmd b/docs/gallery/demos/highlighting/index.qmd
index 14cba10..70a09e7 100644
--- a/docs/gallery/demos/highlighting/index.qmd
+++ b/docs/gallery/demos/highlighting/index.qmd
@@ -1,18 +1,20 @@
---
title: Highlighting
+image: limerick.png
+description: "Highlight lines or spans of code or line blocks."
format:
closeread-html:
code-tools: true
---
-Closeread enables the highlighting of both code and text using a similar syntax.
+Closeread enables the [highlighting](../../../guide/focus-effects.html#highlighting) of both code and text using a similar syntax.
To highlight particular lines of code for your reader, you can add an attribute to your trigger called `highlight`. To highlight lines of code, you can either use a series of line numbers separated by commas or a range separate by a hyphen. Some examples:
- `highlight="1,5"`: highlight lines 1 and 5
- `highlight="1-5"`: highlight lines 1 through 5
-The following section demonstrates that functionality.
+The following section demonstrates that functionality. Note that all stickies use `.scale-to-fill`
:::{.cr-section}
We'll show an example that demonstrates the use of the `dplyr` R package for data wrangling.
@@ -23,7 +25,7 @@ In the first two lines we load the `dplyr` package and the `palmerpenguins` pack
The main block of code is referred as a pipeline or chain. Each line starts with a function and ends with a pipe, `|>`. [@cr-dplyr]{highlight="4-8"}
-:::{#cr-dplyr}
+:::{#cr-dplyr .scale-to-fill}
```{r}
#| echo: true
#| message: false
@@ -55,7 +57,7 @@ The end of the first two lines of a Limerick must rhyme. [@cr-limerick]{highligh
The end of the third and fourth line also rhyme and are nudged in a bit. [@cr-limerick]{highlight="3-4"}
-| {#cr-limerick}
+| {#cr-limerick .scale-to-fill}
| There was a young rustic named [Mallory]{#cr-mallory},
| who drew but a very small [salary]{#cr-salary}.
| When he went to the show,
diff --git a/docs/gallery/demos/highlighting/limerick.png b/docs/gallery/demos/highlighting/limerick.png
new file mode 100644
index 0000000..3017a05
Binary files /dev/null and b/docs/gallery/demos/highlighting/limerick.png differ
diff --git a/docs/gallery/demos/ojs-map/globe.png b/docs/gallery/demos/ojs-variables/globe.png
similarity index 100%
rename from docs/gallery/demos/ojs-map/globe.png
rename to docs/gallery/demos/ojs-variables/globe.png
diff --git a/docs/gallery/demos/ojs-map/index.qmd b/docs/gallery/demos/ojs-variables/index.qmd
similarity index 99%
rename from docs/gallery/demos/ojs-map/index.qmd
rename to docs/gallery/demos/ojs-variables/index.qmd
index 49e445b..7316500 100644
--- a/docs/gallery/demos/ojs-map/index.qmd
+++ b/docs/gallery/demos/ojs-variables/index.qmd
@@ -1,5 +1,5 @@
---
-title: "Spinning Globe"
+title: "OJS Variables"
image: "globe.png"
description: "Smoothly transition interactive OJS graphics."
format:
diff --git a/docs/gallery/demos/ojs-map/naturalearth-land-110m.geojson b/docs/gallery/demos/ojs-variables/naturalearth-land-110m.geojson
similarity index 100%
rename from docs/gallery/demos/ojs-map/naturalearth-land-110m.geojson
rename to docs/gallery/demos/ojs-variables/naturalearth-land-110m.geojson
diff --git a/docs/gallery/demos/poem-1/nytimes.css b/docs/gallery/demos/poem-1/nytimes.css
deleted file mode 100644
index 6fe93a6..0000000
--- a/docs/gallery/demos/poem-1/nytimes.css
+++ /dev/null
@@ -1,53 +0,0 @@
-@import url("https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap");
-#quarto-document-content {
- font-family: Georgia, "Times New Roman", Times, serif;
- font-size: 15pt;
-}
-#quarto-document-content h1 {
- font-family: "Cormorant Garamond", "Times New Roman", Times, serif;
- font-weight: 500;
- font-size: 2.8em;
- line-height: 1;
-}
-
-.cr-section .narrative-col {
- background-color: rgb(17, 17, 17);
- color: white;
- min-width: 400px;
- /* Override the padding for the first block */
-}
-.cr-section .narrative-col > *:first-child {
- padding-block-start: 10svh;
-}
-
-/* mobile sizing (bootstrap: xs) is always overlay-center */
-@media (max-width: 575.98px) {
- .cr-section.sidebar-left .narrative-col,
- .cr-section.sidebar-right .narrative-col,
- .cr-section.overlay-left .narrative-col,
- .cr-section.overlay-right .narrative-col,
- .cr-section.overlay-center .narrative-col {
- background-color: transparent;
- }
- .cr-section.sidebar-left .narrative-col .narrative > *,
- .cr-section.sidebar-right .narrative-col .narrative > *,
- .cr-section.overlay-left .narrative-col .narrative > *,
- .cr-section.overlay-right .narrative-col .narrative > *,
- .cr-section.overlay-center .narrative-col .narrative > * {
- background-color: rgba(17, 17, 17, 0.85);
- padding: 5px;
- border-radius: 5px;
- }
-}
-.cr-section.overlay-left .narrative-col,
-.cr-section.overlay-center .narrative-col,
-.cr-section.overlay-right .narrative-col {
- background-color: transparent;
-}
-.cr-section.overlay-left .narrative-col .narrative,
-.cr-section.overlay-center .narrative-col .narrative,
-.cr-section.overlay-right .narrative-col .narrative {
- background-color: rgba(17, 17, 17, 0.7);
-}
-
-/*# sourceMappingURL=nytimes.css.map */
diff --git a/docs/gallery/demos/poem-1/nytimes.css.map b/docs/gallery/demos/poem-1/nytimes.css.map
deleted file mode 100644
index c290b09..0000000
--- a/docs/gallery/demos/poem-1/nytimes.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sourceRoot":"","sources":["nytimes.scss"],"names":[],"mappings":"AACQ;AAGR;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;AAEA;;AACA;EACE;;;AAKN;AAEA;EAOI;AAAA;AAAA;AAAA;AAAA;IACE;;EAIE;AAAA;AAAA;AAAA;AAAA;IACE;IACA;IACA;;;AAUR;AAAA;AAAA;EACE;;AAEA;AAAA;AAAA;EACE","file":"nytimes.css"}
\ No newline at end of file
diff --git a/docs/gallery/demos/poem-1/nytimes.scss b/docs/gallery/demos/poem-1/nytimes.scss
deleted file mode 100644
index 8e4947c..0000000
--- a/docs/gallery/demos/poem-1/nytimes.scss
+++ /dev/null
@@ -1,65 +0,0 @@
-
-@import url("https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap");
-
-
-#quarto-document-content {
- font-family: Georgia, "Times New Roman", Times, serif;
- font-size: 15pt;
-
- h1 {
- font-family: "Cormorant Garamond", "Times New Roman", Times, serif;
- font-weight: 500;
- font-size: 2.8em;
- line-height: 1;
- }
-}
-
-.cr-section {
-
- .narrative-col {
- background-color: rgba(17, 17, 17, 1);
- color: white;
- min-width: 400px;
-
- /* Override the padding for the first block */
- > *:first-child {
- padding-block-start: 10svh;
- }
- }
-}
-
-/* mobile sizing (bootstrap: xs) is always overlay-center */
-//@media (max-width: 575.98px) {
-@media (max-width: 575.98px) {
- .cr-section.sidebar-left,
- .cr-section.sidebar-right,
- .cr-section.overlay-left,
- .cr-section.overlay-right,
- .cr-section.overlay-center {
-
- .narrative-col {
- background-color: transparent;
-
- .narrative {
-
- > * {
- background-color: rgba(17, 17, 17, .85);
- padding: 5px;
- border-radius: 5px;
- }
- }
- }
- }
-}
-
-.cr-section.overlay-left,
-.cr-section.overlay-center,
-.cr-section.overlay-right {
- .narrative-col {
- background-color: transparent;
-
- .narrative {
- background-color: rgba(17, 17, 17, .7);
- }
- }
-}
diff --git a/docs/gallery/demos/zooming/index.qmd b/docs/gallery/demos/zooming/index.qmd
new file mode 100644
index 0000000..24c18f0
--- /dev/null
+++ b/docs/gallery/demos/zooming/index.qmd
@@ -0,0 +1,127 @@
+---
+title: Zooming
+format:
+ closeread-html:
+ code-tools: true
+---
+
+Closeread enables the reader to zoom in on particular bits of both code and text using a similar syntax to highlighting
+
+To zoom to particular lines of code for your reader, you can add an attribute to your trigger called `zoom-to`. To zoom to a line of code, you can either use a line number or a span id.
+
+- `zoom-to="3"`: zoom to line 3
+- `zoom-to="cr-love`: zoom to the line containing the span `cr-love`
+
+The following section demonstrates that functionality.
+
+:::{.cr-section}
+
+The limerick is a form of poetry composed of five lines.
+
+Here is the first limerick appearing in the written record, from the *Saint John Daily News* in 1880. @cr-limerick
+
+The end of the first two lines of a Limerick must rhyme. [@cr-limerick]{zoom-to="1"}
+
+The end third and fourth line also rhyme and are nudged in a bit. [@cr-limerick]{zoom-to="14"}
+
+The end third and fourth line also rhyme and are nudged in a bit. [@cr-limerick]{zoom-to="cr-salary"}
+
+
+:::{#cr-limerick .scale-to-fill}
+| There was a young rustic named Mallory,
+| who drew but a very small [salary]{#cr-salary}.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+:::
+
+:::
+
+Now here is some code zooming.
+
+:::{.cr-section}
+
+The limerick is a form of poetry composed of five lines.
+
+Here is the first limerick appearing in the written record, from the *Saint John Daily News* in 1880. @cr-dplyr
+
+The end of the first two lines of a Limerick must rhyme. [@cr-dplyr]{zoom-to="18"}
+
+The end third and fourth line also rhyme and are nudged in a bit. [@cr-dplyr]{zoom-to="3"}
+
+
+:::{#cr-dplyr .scale-to-fill}
+```r
+library(dplyr)
+
+mtcars |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp) |>
+ select(mpg, hp)
+```
+
+:::
+
+:::
+
+`hlz` is a short-cut that you can use when you want to zoom into on a line while also highlighting it (or a span within the line).
+
+:::{.cr-section}
+Let's revisit the limerick. @cr-limerick2
+
+Let's focus on this line. [@cr-limerick2]{hlz="15"}
+
+Or this phrase. [@cr-limerick2]{hlz="cr-salary"}
+
+:::{#cr-limerick2 .scale-to-fill}
+| There was a young rustic named Mallory
+| who drew but a very small [salary]{#cr-salary}.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+:::
+:::
+
+
diff --git a/docs/gallery/examples/auden-poem/gabbert.png b/docs/gallery/examples/auden-poem/gabbert.png
new file mode 100644
index 0000000..9474734
Binary files /dev/null and b/docs/gallery/examples/auden-poem/gabbert.png differ
diff --git a/docs/gallery/demos/poem-1/index.qmd b/docs/gallery/examples/auden-poem/index.qmd
similarity index 78%
rename from docs/gallery/demos/poem-1/index.qmd
rename to docs/gallery/examples/auden-poem/index.qmd
index 708ce3e..9debadf 100644
--- a/docs/gallery/demos/poem-1/index.qmd
+++ b/docs/gallery/examples/auden-poem/index.qmd
@@ -1,5 +1,7 @@
---
-description: Text zooming using transforms
+title: "A Poem (and a Painting) About the Suffering That Hides in Plain Sight"
+image: gabbert.png
+author: Elisa Gabbert
format:
closeread-html:
css: nytimes.css
@@ -17,14 +19,12 @@ By Elisa Gabbert March 6, 2002
I’ve been reading this short, wry poem about suffering for more than 20 years.
-:::{focus-on="cr-musee" highlight-spans="cr-suffering"}
-How nice that it tells you in the first two words what it’s about.
-:::
+How nice that it tells you in the first two words what it’s about. [@cr-musee]{hlz="cr-suffering"}
No matter how familiar a poem is, rereading it always gives me a sense of first encounter, as though I’ve gone back to sleep and re-entered the dream through a different door.
-:::{#cr-musee .cr-poem}
+:::{#cr-musee .scale-to-fill}
| **MUSÉE DES BEAUX ARTS**
| *by W.H. Auden*
@@ -56,3 +56,9 @@ No matter how familiar a poem is, rereading it always gives me a sense of first
:::
:::
+
+\
+\
+\
+
+This is an excerpt of the first three lines of *A Poem (and a Painting) About the Suffering That Hides in Plain Sight* by Elisa Gabbert, appearing in *The New York Times* on March 6, 2022 ()
\ No newline at end of file
diff --git a/docs/gallery/demos/_poem-2/nytimes.css b/docs/gallery/examples/auden-poem/nytimes.css
similarity index 100%
rename from docs/gallery/demos/_poem-2/nytimes.css
rename to docs/gallery/examples/auden-poem/nytimes.css
diff --git a/docs/gallery/demos/_poem-2/nytimes.css.map b/docs/gallery/examples/auden-poem/nytimes.css.map
similarity index 100%
rename from docs/gallery/demos/_poem-2/nytimes.css.map
rename to docs/gallery/examples/auden-poem/nytimes.css.map
diff --git a/docs/gallery/demos/_poem-2/nytimes.scss b/docs/gallery/examples/auden-poem/nytimes.scss
similarity index 100%
rename from docs/gallery/demos/_poem-2/nytimes.scss
rename to docs/gallery/examples/auden-poem/nytimes.scss
diff --git a/docs/gallery/demos/minard-zoom/cr-tufte.css b/docs/gallery/examples/minards-map/cr-tufte.css
similarity index 100%
rename from docs/gallery/demos/minard-zoom/cr-tufte.css
rename to docs/gallery/examples/minards-map/cr-tufte.css
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot b/docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot
rename to docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg b/docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg
rename to docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf b/docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf
rename to docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff b/docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff
rename to docs/gallery/examples/minards-map/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot b/docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot
rename to docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg b/docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg
rename to docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf b/docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf
rename to docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff b/docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff
rename to docs/gallery/examples/minards-map/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot b/docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg b/docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf b/docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff b/docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot b/docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg b/docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf b/docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff b/docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff
rename to docs/gallery/examples/minards-map/et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot b/docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot
rename to docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.eot
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.svg b/docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.svg
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.svg
rename to docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.svg
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf b/docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf
rename to docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.ttf
diff --git a/docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff b/docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff
similarity index 100%
rename from docs/gallery/demos/minard-zoom/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff
rename to docs/gallery/examples/minards-map/et-book/et-book-semi-bold-old-style-figures/et-book-semi-bold-old-style-figures.woff
diff --git a/docs/gallery/demos/minard-zoom/index.qmd b/docs/gallery/examples/minards-map/index.qmd
similarity index 97%
rename from docs/gallery/demos/minard-zoom/index.qmd
rename to docs/gallery/examples/minards-map/index.qmd
index bae87ac..aade891 100644
--- a/docs/gallery/demos/minard-zoom/index.qmd
+++ b/docs/gallery/examples/minards-map/index.qmd
@@ -1,5 +1,6 @@
---
-title: "Minard's Map"
+title: "The Visual Display of Quantitative Information"
+author: Edward Tufte
format:
closeread-html:
css: cr-tufte.css
@@ -9,13 +10,10 @@ format:
description: Revisiting a classic of data visualization
---
-# Mindard's Map
-
:::{.epigraph}
> [The Visual Display of Quantitative Information](https://www.edwardtufte.com/tufte/books_vdqi) by Edward Tufte is a seminal text in the field of data visualization. On page 40, the text walks the reader through the complexity of a graphic by Charles Minard[^map] that depicts Napoleon's disastrous military campaign in Russia. An excerpt from that chapter is printed below, with permission[^text].
:::
-
## Narrative Graphics of Space and Time
An especially effective device for enhancing the explanatory power of time-series displays is to add spatial dimensions to the design of the graphic, so that the data are moving over space (in two or three dimensions) as well as over time. Three excellent space-time-story graphics illustrate here how multivariate complexity can be subtly integrated into graphical architecture, integrated so gently and unobtrusively that viewers are hardly aware that they are looking into a world of four or five dimensions. Occasionally graphics are belligerently multivariate, advertising the technique rather than the data. But not these three.
diff --git a/docs/gallery/demos/minard-zoom/minard-large.png b/docs/gallery/examples/minards-map/minard-large.png
similarity index 100%
rename from docs/gallery/demos/minard-zoom/minard-large.png
rename to docs/gallery/examples/minards-map/minard-large.png
diff --git a/docs/gallery/demos/minard-zoom/minard-map.png b/docs/gallery/examples/minards-map/minard-map.png
similarity index 100%
rename from docs/gallery/demos/minard-zoom/minard-map.png
rename to docs/gallery/examples/minards-map/minard-map.png
diff --git a/docs/gallery/index.qmd b/docs/gallery/index.qmd
index 2ab58b6..3694ffb 100644
--- a/docs/gallery/index.qmd
+++ b/docs/gallery/index.qmd
@@ -1,15 +1,27 @@
---
title: Gallery
listing:
- - id: demo-listings
- contents: demos
+ - id: examples-listings
+ contents: examples
sort: "date desc"
type: grid
+ fields: [image, title, author]
+ - id: demo-listings
+ contents: demos
+ sort-ui: false
+ filter-ui: false
+ type: table
+ fields: [title, description]
+ field-display-names:
+ title: "Feature"
---
-### Demos
+:::{#examples-listings}
+:::
+
+### Feature Demos
-Demonstrations of Closeread functionality.
+A series of short closeread documents that each demonstrate one feature of the closeread custom format.
:::{#demo-listings}
:::
\ No newline at end of file
diff --git a/docs/guide/focus-effects.qmd b/docs/guide/focus-effects.qmd
index a973706..9702e61 100644
--- a/docs/guide/focus-effects.qmd
+++ b/docs/guide/focus-effects.qmd
@@ -2,9 +2,13 @@
title: Focus Effects
---
-Focus effects are used to closely guide your readers attention to particular aspects of your stickies. They are all supplied as [attributes](https://quarto.org/docs/authoring/markdown-basics.html#ordering-of-attributes), which follow a `attribute="value"` syntax where the value must be quoted and where `=` separates the value from the attribute with no spaces.
+Focus effects are used to closely guide your readers attention to particular aspects of your stickies. They are all supplied as [attributes](https://quarto.org/docs/authoring/markdown-basics.html#ordering-of-attributes), which follow a `attribute="value"` syntax where the value must be quoted and where `=` separates the value from the attribute with no spaces.
-## Highlighting
+All of these effects will remain on the sticky until there is a new trigger block scrolls into the viewport. You can "reset" the effects on a given sticky by following the focus effect trigger with a trigger without any focus effects.
+
+# Types of Focus Effects
+
+## Highlighting {#highlighting}
You can highlight parts of the code and text of your sticky using the following syntax.
@@ -56,19 +60,93 @@ Highlighting spans of code within a line is currently not possible.
### Line Block Examples
-To do.
+This will highlight lines 3 and 4.
+
+````markdown
+The end of the third and fourth line also rhyme and are nudged in a bit. [@cr-limerick]{highlight="3-4"}
+
+| {#cr-limerick}
+| There was a young rustic named [Mallory]{#cr-mallory},
+| who drew but a very small [salary]{#cr-salary}.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+````
+
+This will highlight spans `cr-mallory` and `cr-salary`.
+
+````markdown
+The end of the first two lines of a Limerick must rhyme. [@cr-limerick]{highlight="cr-mallory,cr-salary"}
+
+| {#cr-limerick}
+| There was a young rustic named [Mallory]{#cr-mallory},
+| who drew but a very small [salary]{#cr-salary}.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+````
+
+Note that closeread extends the native pandoc processing of line blocks. Instead of wrapping line blocks in a fenced divs and providing and id and classes there, you can provide them on the first line of the line block in curly braces as demonstrated above. The functionality is identical; the goal of the feature is to simplify the syntax.
+
+
+## Zooming
+
+You can zoom to parts of the code and text of your sticky using the following syntax.
+
+1. `zoom-to="3"`: zoom to line 3
+2. `zoom-to="cr-span1"`: zoom to the line with the span with id `cr-span1`
+
+Zooming works for both code blocks and line blocks but currently only supports a single line or span. When you trigger a zoom to a line, it will zoom such that the line occupies most of the horizontal space in the viewport and is roughly centered vertically.
## Panning
-To do.
+You can pan across any sticky element (often an image) by using the `pan-to` attribute. It supports several different units:
+- `pan-to="25%,-50%: pan the sticky 25% of its width to the right and 50% of its height up.
+- `pan-to="-30px, 30px": pan the sticky 30 pixels to the left and 30 pixels down.
+
+`pan-to` accepts a string that corresponds to any of the options in the analogous [`translate()`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate) CSS function.
## Scaling
-To do.
+You can scale a sticky element up or down by using the `scale-by()` attribute and providing a numerical scaling factor. For example:
+- `scale-by=".5"`: shrinks a sticky to 50% its original size
+- `scale-by="3"`: triples the size of a sticky.
-## Zooming
+`scale-by` accepts a string that corresponds to any of the options in the analogous [`scale()`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale) CSS function.
+
+# Combining Focus Effects
+
+You can combine multiple focus effects on a single trigger. For example:
+
+- `[@cr-sticky]{pan-to="50%,50%" scale-by="1.5"}`: pan the sticky down and to the right why increasing its size by 50%.
+
+One exception is the `zoom-to` attribute. Since it performs both panning and zooming, it will override those options if they're included on the same trigger.
+
+## Highlight - Zoom
+
+It is common if want to zoom into a line or span of code or text while also highlighting. There is an additional attribute called `hlz` for this purpose.
+
+- `hlz="cr-love": highlight the span `cr-love` while zooming in on the line that contains it.
+- `hlz="4"`: highlight line 4 while zooming in on the line that contains it.
+
+Because this focus effect translates into `highlight` and `zoom-to`, the latter constrains it to only working for single spans or lines at the moment.
+
+# Other Features
+
+You can scale a sticky to fill the viewport without distortion or cropping by adding the `scale-to-fill` class. For example:
+
+````markdown
+This is the first limerick ever recorded. @cr-limerick
+
+| {#cr-limerick .scale-to-fill}
+| There was a young rustic named [Mallory]{#cr-mallory},
+| who drew but a very small [salary]{#cr-salary}.
+| When he went to the show,
+| his purse made him go
+| to a seat in the uppermost gallery.
+````
-To do.
+When this sticky is triggered, it will fade in and transform such that it fills the viewport. This class can be applied to a wide range of sticky types.