Skip to content

Commit

Permalink
Add a loading spinner for TryExamples directive. (#133)
Browse files Browse the repository at this point in the history
* Remove unused config variable

* Add a spinner

* Add link for example css

* Dynamically adjust spinner position

* Adjust spinner position

* Add spinners for other jupyterlite-sphinx directives
steppi authored Feb 2, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent e084a6f commit 2582889
Showing 4 changed files with 63 additions and 48 deletions.
8 changes: 4 additions & 4 deletions docs/directives/try_examples.md
Original file line number Diff line number Diff line change
@@ -137,8 +137,8 @@ Here's an example with some options set
We've also added the ``blue-bottom`` class, the button should appear as blue,
below the examples, and on the left side of the screen.
See ``try_examples.css`` in the Repository to see how we achieved this via
custom css.
See `try_examples.css <https://github.com/jupyterlite/jupyterlite-sphinx/blob/main/docs/_static/try_examples.css>`_
to see how we achieved this via custom css.
```

and here is the result
@@ -159,8 +159,8 @@ and here is the result
We've also added the ``blue-bottom`` class, the button should appear as blue,
below the examples, and on the left side of the screen.
See ``try_examples.css`` in the Repository to see how we achieved this via
custom css.
See `try_examples.css <https://github.com/jupyterlite/jupyterlite-sphinx/blob/main/docs/_static/try_examples.css>`_
to see how we achieved this via custom css.
```


56 changes: 19 additions & 37 deletions jupyterlite_sphinx/jupyterlite_sphinx.css
Original file line number Diff line number Diff line change
@@ -38,47 +38,29 @@
box-shadow: 0 0.2rem 0.5rem #d8d8d8;
}

.jupyterlite_sphinx_iframe_container:hover .jupyterlite_sphinx_try_it_button_unclicked {
-webkit-animation:grow 0.2s ease-in-out;
animation:grow 0.2s ease-in-out;
transform: translateY(-50%) translateX(-50%) scale(1.2);
}

.jupyterlite_sphinx_try_it_button_clicked {
-webkit-animation:grow 1s infinite alternate;
animation:grow 1s infinite alternate;
transform: translateY(-50%) translateX(-50%) scale(1.2);
}

@keyframes grow {
from {
transform: translateY(-50%) translateX(-50%) scale(1);
}
to {
transform: translateY(-50%) translateX(-50%) scale(1.2);
}
}

@-webkit-keyframes grow {
from {
transform: translateY(-50%) translateX(-50%) scale(1);
}
to {
transform: translateY(-50%) translateX(-50%) scale(1.2);
}
}

.try_examples_iframe_container {
position: relative;
cursor: pointer;
}


.try_examples_outer_container {
position: relative;
}


.hidden {
display: none;
}

.jupyterlite_sphinx_spinner {
/* From https://css-loaders.com/spinner/ */
position: absolute;
z-index: 0;
top: 50%;
left: 50%;
width: 50px;
aspect-ratio: 1;
border-radius: 50%;
background:
radial-gradient(farthest-side,#ffa516 94%,#0000) top/8px 8px no-repeat,
conic-gradient(#0000 30%,#ffa516);
-webkit-mask: radial-gradient(farthest-side,#0000 calc(100% - 8px),#000 0);
animation: l13 1s infinite linear;
}
@keyframes l13{
100%{transform: rotate(1turn)}
}
44 changes: 39 additions & 5 deletions jupyterlite_sphinx/jupyterlite_sphinx.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
window.jupyterliteShowIframe = (tryItButtonId, iframeSrc) => {
const tryItButton = document.getElementById(tryItButtonId);
const iframe = document.createElement('iframe');
const buttonRect = tryItButton.getBoundingClientRect();

const spinner = document.createElement('div');
// hardcoded spinner height and width needs to match what is in css.
const spinnerHeight = 50; // px
const spinnerWidth = 50; // px
spinner.classList.add('jupyterlite_sphinx_spinner');
spinner.style.display = 'none';
// Add negative margins to center the spinner
spinner.style.marginTop = `-${spinnerHeight/2}px`;
spinner.style.marginLeft = `-${spinnerWidth/2}px`;

iframe.src = iframeSrc;
iframe.width = iframe.height = '100%';
iframe.classList.add('jupyterlite_sphinx_iframe');

tryItButton.style.display = 'none';
spinner.style.display = 'block';

tryItButton.parentNode.appendChild(spinner);
tryItButton.parentNode.appendChild(iframe);
tryItButton.innerText = 'Loading ...';
tryItButton.classList.remove('jupyterlite_sphinx_try_it_button_unclicked');
tryItButton.classList.add('jupyterlite_sphinx_try_it_button_clicked');
}

window.jupyterliteConcatSearchParams = (iframeSrc, params) => {
@@ -50,9 +62,17 @@ window.tryExamplesShowIframe = (
const iframeContainer = document.getElementById(iframeContainerId);
var height;

let iframe = iframeContainer.querySelector('iframe.jupyterlite_sphinx_raw_iframe');
let iframe = iframeContainer.querySelector('iframe.jupyterlite_sphinx_iframe');

if (!iframe) {
// Add spinner
const spinner = document.createElement('div');
// hardcoded spinner width needs to match what is in css.
const spinnerHeight = 50; // px
const spinnerWidth = 50; // px
spinner.classList.add('jupyterlite_sphinx_spinner');
iframeContainer.appendChild(spinner);

const examples = examplesContainer.querySelector('.try_examples_content');
iframe = document.createElement('iframe');
iframe.src = iframeSrc;
@@ -62,9 +82,23 @@ window.tryExamplesShowIframe = (
} else {
height = Math.max(tryExamplesGlobalMinHeight, examples.offsetHeight);
}

/* Get spinner position. It will be centered in the iframe, unless the
* iframe extends beyond the viewport, in which case it will be centered
* between the top of the iframe and the bottom of the viewport.
*/
const examplesTop = examples.getBoundingClientRect().top;
const viewportBottom = window.innerHeight;
const spinnerTop = 0.5 * Math.min((viewportBottom - examplesTop), height);
spinner.style.top = `${spinnerTop}px`;
// Add negative margins to center the spinner
spinner.style.marginTop = `-${spinnerHeight/2}px`;
spinner.style.marginLeft = `-${spinnerWidth/2}px`;

iframe.style.height = `${height}px`;
iframe.classList.add('jupyterlite_sphinx_raw_iframe');
iframe.classList.add('jupyterlite_sphinx_iframe');
examplesContainer.classList.add("hidden");

iframeContainer.appendChild(iframe);
} else {
examplesContainer.classList.add("hidden");
3 changes: 1 addition & 2 deletions jupyterlite_sphinx/jupyterlite_sphinx.py
Original file line number Diff line number Diff line change
@@ -436,7 +436,7 @@ def run(self):
iframe_parent_container_div_end = "</div>"
iframe_container_div = (
f'<div id="{iframe_div_id}" '
f'class="try_examples_iframe_container">'
f'class="jupyterlite_sphinx_iframe_container">'
f"</div>"
)

@@ -498,7 +498,6 @@ def _process_autodoc_docstrings(app, what, name, obj, options, lines):
try_examples_options = {
"theme": app.config.try_examples_global_theme,
"button_text": app.config.try_examples_global_button_text,
"example_class": app.config.try_examples_global_example_class,
}
try_examples_options = {
key: value for key, value in try_examples_options.items() if value is not None

0 comments on commit 2582889

Please sign in to comment.