Skip to content

Commit

Permalink
add files for first complete example book
Browse files Browse the repository at this point in the history
This includes:
- parts/chapters in _quarto.yml
- a DESCRIPTION file
- a GitHub Action
- a WebR example page
  • Loading branch information
widdowquinn committed Apr 22, 2024
1 parent 4091921 commit 3498e6a
Show file tree
Hide file tree
Showing 30 changed files with 2,861 additions and 12 deletions.
30 changes: 30 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# [A] SET PACKAGE NAME, BOOK TITLE AND VERSION
Package: PACKAGE_NAME
Title: BOOK_TITLE
Version: 0.1

# [B] SET AUTHOR NAMES AND EMAILS
Authors@R: c(
person("FORENAME1", "SURNAME1", , "[email protected]", role = c("aut", "cre")),
person("FORENAME2", "SURNAME2", , "[email protected]", role = c("aut", "cre"))
)

# [C] SET REPOSITORY URL
URL: https://github.com/sipbs-compbiol/REPOSITORY

# [D] SET REQUIRED PACKAGES IN R
Depends:
R (>= 3.1.0)
Imports:
tidyverse (>= 2.0.0),
ggplot2,
flextable,
kableExtra
Suggests:
knitr,
sessioninfo
Remotes: tidyverse/dplyr
Encoding: UTF-8

# [E] SET LICENCING INFORMATION
License: CC NC ND 4.0
428 changes: 428 additions & 0 deletions LICENCE

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# README.md sipbs-compbiol-book-template

This repository is a template, intended as a convenience to take some manual work out of setting the style for Quarto books used by SIPBS Computational Biology.

This version of the template includes:

- a GitHub Action (`.github/workflows/publish.yml`) that should update the GitHub Pages version of the book on each push to the `main` branch.
- an example WebR page

## How to use this template

### Setting Up

1. Click on the `Use This Template` button to create a new repository/project based on this template
2. Clone or download the project to your local development environment
3. Open the project folder and modify `_variables.yml` to change:
- `[A]` academic year
- `[B]` administrator name and contact information
- `[C]` GitHub URLs for the repository
4. Modify `_quarto.yml` to change:
- `[A]` book title
- `[B]` footer text
- `[C]` GitHub repository URL
- `[D]` author name and publication/presentation date
- `[E]` chapters and sections
5. Modify `DESCRIPTION` to change:
- `[A]` package name and book title
- `[B]` author names and emails
- `[C]` repository URL
- `[D]` required R packages
- `[E]` licensing information
6. Change or update the licence, if required
7. Add the `quarto-webr` extension (if necessary) using the command `quarto add coatless/quarto-webr`
8. Generate the book by issuing `quarto render` in the terminal, or using the `Render` button in `RStudio`
9. Commit your updates in the local development environment
10. Publish your book to GitHub Pages by issuing `quarto publish gh-pages` in the terminal

### General Usage

1. Make changes to the `.qmd` files, updating chapter information in `_quarto.yml`, as needed for your material
2. Commit your changes locally to the git repository
3. Push your changes to the GitHub repository
8 changes: 8 additions & 0 deletions _extensions/coatless/webr/_extension.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: webr
title: Embedded webr code cells
author: James Joseph Balamuta
version: 0.4.2-dev.4
quarto-required: ">=1.2.198"
contributes:
filters:
- webr.lua
274 changes: 274 additions & 0 deletions _extensions/coatless/webr/qwebr-cell-elements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
// Supported Evaluation Types for Context
globalThis.EvalTypes = Object.freeze({
Interactive: 'interactive',
Setup: 'setup',
Output: 'output',
});

// Function that obtains the font size for a given element
globalThis.qwebrCurrentFontSizeOnElement = function(element, cssProperty = 'font-size') {

const currentFontSize = parseFloat(
window
.getComputedStyle(element)
.getPropertyValue(cssProperty)
);

return currentFontSize;
}

// Function to determine font scaling
globalThis.qwebrScaledFontSize = function(div, qwebrOptions) {
// Determine if we should compute font-size using RevealJS's `--r-main-font-size`
// or if we can directly use the document's `font-size`.
const cssProperty = document.body.classList.contains('reveal') ?
"--r-main-font-size" : "font-size";

// Get the current font size on the div element
const elementFontSize = qwebrCurrentFontSizeOnElement(div, cssProperty);

// Determine the scaled font size value
const scaledFontSize = ((qwebrOptions['editor-font-scale'] ?? 1) * elementFontSize) ?? 17.5;

return scaledFontSize;
}


// Function that dispatches the creation request
globalThis.qwebrCreateHTMLElement = function (
cellData
) {

// Extract key components
const evalType = cellData.options.context;
const qwebrCounter = cellData.id;

// We make an assumption that insertion points are defined by the Lua filter as:
// qwebr-insertion-location-{qwebrCounter}
const elementLocator = document.getElementById(`qwebr-insertion-location-${qwebrCounter}`);

// Figure out the routine to use to insert the element.
let qwebrElement;
switch ( evalType ) {
case EvalTypes.Interactive:
qwebrElement = qwebrCreateInteractiveElement(qwebrCounter, cellData.options);
break;
case EvalTypes.Output:
qwebrElement = qwebrCreateNonInteractiveOutputElement(qwebrCounter, cellData.options);
break;
case EvalTypes.Setup:
qwebrElement = qwebrCreateNonInteractiveSetupElement(qwebrCounter, cellData.options);
break;
default:
qwebrElement = document.createElement('div');
qwebrElement.textContent = 'Error creating `quarto-webr` element';
}

// Insert the dynamically generated object at the document location.
elementLocator.appendChild(qwebrElement);
};

// Function that setups the interactive element creation
globalThis.qwebrCreateInteractiveElement = function (qwebrCounter, qwebrOptions) {

// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = 'qwebr-interactive-area-' + qwebrCounter;
mainDiv.className = `qwebr-interactive-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}

// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create toolbar div
var toolbarDiv = document.createElement('div');
toolbarDiv.className = 'qwebr-editor-toolbar';
toolbarDiv.id = 'qwebr-editor-toolbar-' + qwebrCounter;

// Create a div to hold the left buttons
var leftButtonsDiv = document.createElement('div');
leftButtonsDiv.className = 'qwebr-editor-toolbar-left-buttons';

// Create a div to hold the right buttons
var rightButtonsDiv = document.createElement('div');
rightButtonsDiv.className = 'qwebr-editor-toolbar-right-buttons';

// Create Run Code button
var runCodeButton = document.createElement('button');
runCodeButton.className = 'btn btn-default qwebr-button qwebr-button-run';
runCodeButton.disabled = true;
runCodeButton.type = 'button';
runCodeButton.id = 'qwebr-button-run-' + qwebrCounter;
runCodeButton.textContent = '🟡 Loading webR...';
runCodeButton.title = `Run code (Shift + Enter)`;

// Append buttons to the leftButtonsDiv
leftButtonsDiv.appendChild(runCodeButton);

// Create Reset button
var resetButton = document.createElement('button');
resetButton.className = 'btn btn-light btn-xs qwebr-button qwebr-button-reset';
resetButton.type = 'button';
resetButton.id = 'qwebr-button-reset-' + qwebrCounter;
resetButton.title = 'Start over';
resetButton.innerHTML = '<i class="fa-solid fa-arrows-rotate"></i>';

// Create Copy button
var copyButton = document.createElement('button');
copyButton.className = 'btn btn-light btn-xs qwebr-button qwebr-button-copy';
copyButton.type = 'button';
copyButton.id = 'qwebr-button-copy-' + qwebrCounter;
copyButton.title = 'Copy code';
copyButton.innerHTML = '<i class="fa-regular fa-copy"></i>';

// Append buttons to the rightButtonsDiv
rightButtonsDiv.appendChild(resetButton);
rightButtonsDiv.appendChild(copyButton);

// Create console area div
var consoleAreaDiv = document.createElement('div');
consoleAreaDiv.id = 'qwebr-console-area-' + qwebrCounter;
consoleAreaDiv.className = 'qwebr-console-area';

// Create editor div
var editorDiv = document.createElement('div');
editorDiv.id = 'qwebr-editor-' + qwebrCounter;
editorDiv.className = 'qwebr-editor';

// Create output code area div
var outputCodeAreaDiv = document.createElement('div');
outputCodeAreaDiv.id = 'qwebr-output-code-area-' + qwebrCounter;
outputCodeAreaDiv.className = 'qwebr-output-code-area';
outputCodeAreaDiv.setAttribute('aria-live', 'assertive');

// Create pre element inside output code area
var preElement = document.createElement('pre');
preElement.style.visibility = 'hidden';
outputCodeAreaDiv.appendChild(preElement);

// Create output graph area div
var outputGraphAreaDiv = document.createElement('div');
outputGraphAreaDiv.id = 'qwebr-output-graph-area-' + qwebrCounter;
outputGraphAreaDiv.className = 'qwebr-output-graph-area';

// Append buttons to the toolbar
toolbarDiv.appendChild(leftButtonsDiv);
toolbarDiv.appendChild(rightButtonsDiv);

// Append all elements to the main div
mainDiv.appendChild(toolbarDiv);
consoleAreaDiv.appendChild(editorDiv);
consoleAreaDiv.appendChild(outputCodeAreaDiv);
mainDiv.appendChild(consoleAreaDiv);
mainDiv.appendChild(outputGraphAreaDiv);

return mainDiv;
}

// Function that adds output structure for non-interactive output
globalThis.qwebrCreateNonInteractiveOutputElement = function(qwebrCounter, qwebrOptions) {
// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = 'qwebr-noninteractive-area-' + qwebrCounter;
mainDiv.className = `qwebr-noninteractive-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}

// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create a status container div
var statusContainer = createLoadingContainer(qwebrCounter);

// Create output code area div
var outputCodeAreaDiv = document.createElement('div');
outputCodeAreaDiv.id = 'qwebr-output-code-area-' + qwebrCounter;
outputCodeAreaDiv.className = 'qwebr-output-code-area';
outputCodeAreaDiv.setAttribute('aria-live', 'assertive');

// Create pre element inside output code area
var preElement = document.createElement('pre');
preElement.style.visibility = 'hidden';
outputCodeAreaDiv.appendChild(preElement);

// Create output graph area div
var outputGraphAreaDiv = document.createElement('div');
outputGraphAreaDiv.id = 'qwebr-output-graph-area-' + qwebrCounter;
outputGraphAreaDiv.className = 'qwebr-output-graph-area';

// Append all elements to the main div
mainDiv.appendChild(statusContainer);
mainDiv.appendChild(outputCodeAreaDiv);
mainDiv.appendChild(outputGraphAreaDiv);

return mainDiv;
};

// Function that adds a stub in the page to indicate a setup cell was used.
globalThis.qwebrCreateNonInteractiveSetupElement = function(qwebrCounter, qwebrOptions) {
// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = `qwebr-noninteractive-setup-area-${qwebrCounter}`;
mainDiv.className = `qwebr-noninteractive-setup-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}


// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create a status container div
var statusContainer = createLoadingContainer(qwebrCounter);

// Append status onto the main div
mainDiv.appendChild(statusContainer);

return mainDiv;
}


// Function to create loading container with specified ID
globalThis.createLoadingContainer = function(qwebrCounter) {

// Create a status container
const container = document.createElement('div');
container.id = `qwebr-non-interactive-loading-container-${qwebrCounter}`;
container.className = 'qwebr-non-interactive-loading-container qwebr-cell-needs-evaluation';

// Create an R project logo to indicate its a code space
const rProjectIcon = document.createElement('i');
rProjectIcon.className = 'fa-brands fa-r-project fa-3x qwebr-r-project-logo';

// Setup a loading icon from font awesome
const spinnerIcon = document.createElement('i');
spinnerIcon.className = 'fa-solid fa-spinner fa-spin fa-1x qwebr-icon-status-spinner';

// Add a section for status text
const statusText = document.createElement('p');
statusText.id = `qwebr-status-text-${qwebrCounter}`;
statusText.className = `qwebr-status-text qwebr-cell-needs-evaluation`;
statusText.innerText = 'Loading webR...';

// Incorporate an inner container
const innerContainer = document.createElement('div');

// Append elements to the inner container
innerContainer.appendChild(spinnerIcon);
innerContainer.appendChild(statusText);

// Append elements to the main container
container.appendChild(rProjectIcon);
container.appendChild(innerContainer);

return container;
}
Loading

0 comments on commit 3498e6a

Please sign in to comment.