Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version warningbar #1354

Merged
merged 19 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/_static/switcher.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
{
"name": "0.13.3 (stable)",
"version": "stable",
"url": "https://pydata-sphinx-theme.readthedocs.io/en/stable/"
"url": "https://pydata-sphinx-theme.readthedocs.io/en/stable/",
"preferred": true
},
{
"name": "0.12.0",
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
"navbar_align": "left", # [left, content, right] For testing that the navbar items align properly
"navbar_center": ["version-switcher", "navbar-nav"],
"announcement": "https://raw.githubusercontent.com/pydata/pydata-sphinx-theme/main/docs/_templates/custom-template.html",
"show_version_warning_banner": True,
# "show_nav_level": 2,
# "navbar_start": ["navbar-logo"],
# "navbar_end": ["theme-switcher", "navbar-icon-links"],
Expand Down
31 changes: 31 additions & 0 deletions docs/user_guide/announcements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ By default, the value of your ``html_theme_options["announcement"]`` will be ins
For example, the following configuration adds a simple announcement.

.. code-block:: python
:caption: conf.py

html_theme_options = {
...
Expand All @@ -33,8 +34,38 @@ If the value of ``html_theme_options["announcement"]`` begins with **``http``**
For example, the following configuration tells the theme to load the ``custom-template.html`` example from this documentation's GitHub repository:

.. code-block:: python
:caption: conf.py

html_theme_options = {
...
"announcement": "https://github.com/pydata/pydata-sphinx-theme/raw/main/docs/_templates/custom-template.html",
}


.. _version-warning-banners:

Version warning banners
-----------------------

In addition to the general-purpose announcement banner, the theme includes a built-in banner to warn users when they are viewing versions of your docs other than the latest stable version. To use this feature, add the following to your ``conf.py``:

.. code-block:: python
:caption: conf.py

html_theme_options = {
...
"show_version_warning_banner": True,
}
.. warning::

This functionality relies on the :ref:`version switcher <version-dropdowns>` to determine the version number of the latest stable release.
*It will only work* if your version switcher ``.json`` has exactly one entry with property ``"preferred": true``
and a ``name`` property that begins with a version string that is parsable by the `compare-versions node module <https://www.npmjs.com/package/compare-versions>`__, for example:

.. code-block:: json

{
"name": "9.9.9 (current)",
"version": "stable",
drammock marked this conversation as resolved.
Show resolved Hide resolved
"url": "https://anything"
}
4 changes: 4 additions & 0 deletions docs/user_guide/version-dropdown.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _version-dropdowns:

Version switcher dropdowns
==========================

Expand Down Expand Up @@ -40,6 +42,8 @@ each can have the following fields:
- ``url``: the URL for this version.
- ``name``: an optional name to display in the switcher dropdown instead of the
version string (e.g., "latest", "stable", "dev", etc.).
- ``preferred``: an optional field that *should occur on at most one entry* in the JSON file.
It specifies which version is considered "latest stable", and is used to customize the message used on :ref:`version-warning-banners` (if they are enabled).

Here is an example JSON file:

Expand Down
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": "6.1.2",
"@popperjs/core": "^2.11.6",
"bootstrap": "^5.2.2"
"bootstrap": "^5.2.2",
"compare-versions": "^5.0.3"
}
}
1 change: 1 addition & 0 deletions src/pydata_sphinx_theme/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ def _remove_empty_templates(tname):
js = f"""
DOCUMENTATION_OPTIONS.theme_switcher_json_url = '{json_url}';
DOCUMENTATION_OPTIONS.theme_switcher_version_match = '{version_match}';
DOCUMENTATION_OPTIONS.show_version_warning_banner = {str(context["theme_show_version_warning_banner"]).lower()};
"""
app.add_js_file(None, body=js)

Expand Down
117 changes: 97 additions & 20 deletions src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Define the custom behavior of the page
import { documentReady } from "./mixin";
import { compare, validate } from "compare-versions";

import "../styles/pydata-sphinx-theme.scss";

Expand Down Expand Up @@ -299,48 +300,39 @@ function checkPageExistsAndRedirect(event) {
location.href = otherDocsHomepage;
});

// ensure we don't follow the initial link
// ↓ this prevents the browser from following the href of the clicked node
// ↓ (which is fine because this function takes care of redirecting)
event.preventDefault();
}

/**
* Check if the corresponding url is absolute and make a absolute path from root if necessary
* Load and parse the version switcher JSON file from an absolute or relative URL.
*
* @param {string} url the url to check
* @param {string} url The URL to load version switcher entries from.
*/
async function fetchVersionSwitcherJSON(url) {
// first check if it's a valid URL
try {
var result = new URL(url);
} catch (err) {
// if not, assume relative path and fix accordingly
if (err instanceof TypeError) {
// workaround for redirects like https://pydata-sphinx-theme.readthedocs.io
// fetch() automatically follows redirects so it should work in every builder
// (RDT, GitHub actions, etc)
const origin = await fetch(window.location.origin, {
method: "HEAD",
});
// assume we got a relative path, and fix accordingly. But first, we need to
// use `fetch()` to follow redirects so we get the correct final base URL
const origin = await fetch(window.location.origin, { method: "HEAD" });
result = new URL(url, origin.url);
} else {
// something unexpected happened
throw err;
}
}

// load and return the JSON
const response = await fetch(result);
const data = await response.json();
return data;
}

// Populate the version switcher from the JSON config file
var versionSwitcherBtns = document.querySelectorAll(
".version-switcher__button"
);

if (versionSwitcherBtns.length) {
const data = await fetchVersionSwitcherJSON(
DOCUMENTATION_OPTIONS.theme_switcher_json_url
);
// Populate the version switcher from the JSON data
function populateVersionSwitcher(data, versionSwitcherBtns) {
const currentFilePath = `${DOCUMENTATION_OPTIONS.pagename}.html`;
versionSwitcherBtns.forEach((btn) => {
// Set empty strings by default so that these attributes exist and can be used in CSS selectors
Expand Down Expand Up @@ -392,6 +384,70 @@ if (versionSwitcherBtns.length) {
});
}

/*******************************************************************************
* Warning banner when viewing non-stable version of the docs.
*/

/**
* Show a warning banner when viewing a non-stable version of the docs.
*
* adapted 2023-06 from https://mne.tools/versionwarning.js, which was
* originally adapted 2020-05 from https://scikit-learn.org/versionwarning.js
*
* @param {Array} data The version data used to populate the switcher menu.
*/
function showVersionWarningBanner(data) {
const version = DOCUMENTATION_OPTIONS.VERSION;
// figure out what latest stable version is
var preferredEntries = data.filter((entry) => entry.preferred);
if (preferredEntries.length !== 1) {
const howMany = preferredEntries.length == 0 ? "No" : "Multiple";
throw new Error(
`[PST] ${howMany} versions marked "preferred" found in versions JSON`
);
}
const preferredVersion = preferredEntries[0].version;
const preferredURL = preferredEntries[0].url;
// if already on preferred version, nothing to do
const versionsAreComparable = validate(version) && validate(preferredVersion);
if (versionsAreComparable && compare(version, preferredVersion, "=")) {
return;
}
// now construct the warning banner
var outer = document.createElement("div");
const middle = document.createElement("div");
const inner = document.createElement("div");
const bold = document.createElement("strong");
const button = document.createElement("a");
// these classes exist since pydata-sphinx-theme v0.10.0
outer.classList = "bd-header-version-warning container-fluid";
middle.classList = "bd-header-announcement__content";
inner.classList = "sidebar-message";
button.classList =
"sd-btn sd-btn-danger sd-shadow-sm sd-text-wrap font-weight-bold ms-3 my-1 align-baseline";
button.href = `${preferredURL}${DOCUMENTATION_OPTIONS.pagename}.html`;
button.innerText = "Switch to latest stable version";
button.onclick = checkPageExistsAndRedirect;
// add the version-dependent text
inner.innerText = "This is documentation for an ";
const isDev = version.includes("dev");
drammock marked this conversation as resolved.
Show resolved Hide resolved
const newerThanPreferred =
versionsAreComparable && compare(version, preferredVersion, ">");
if (isDev || newerThanPreferred) {
bold.innerText = "unstable development version";
} else if (versionsAreComparable && compare(version, preferredVersion, "<")) {
bold.innerText = `old version (${version})`;
} else {
bold.innerText = `version ${version}`;
}
outer.appendChild(middle);
middle.appendChild(inner);
inner.appendChild(bold);
inner.appendChild(document.createTextNode("."));
inner.appendChild(button);
document.body.prepend(outer);
}

/*******************************************************************************
* MutationObserver to move the ReadTheDocs button
*/
Expand Down Expand Up @@ -423,6 +479,27 @@ function initRTDObserver() {
observer.observe(document.body, config);
}

// fetch the JSON version data (only once), then use it to populate the version
// switcher and maybe show the version warning bar
var versionSwitcherBtns = document.querySelectorAll(
".version-switcher__button"
);
const hasSwitcherMenu = versionSwitcherBtns.length > 0;
const hasVersionsJSON = DOCUMENTATION_OPTIONS.hasOwnProperty(
"theme_switcher_json_url"
);
const wantsWarningBanner = DOCUMENTATION_OPTIONS.show_version_warning_banner;

if (hasVersionsJSON && (hasSwitcherMenu || wantsWarningBanner)) {
const data = await fetchVersionSwitcherJSON(
DOCUMENTATION_OPTIONS.theme_switcher_json_url
);
populateVersionSwitcher(data, versionSwitcherBtns);
if (wantsWarningBanner) {
showVersionWarningBanner(data);
}
}

/*******************************************************************************
* Call functions after document loading.
*/
Expand Down
16 changes: 14 additions & 2 deletions src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.bd-header-version-warning,
.bd-header-announcement {
min-height: 3rem;
width: 100%;
Expand All @@ -18,14 +19,12 @@
margin: 0;
}

// Bg color is now defined in the theme color palette - using our secondary color
&:after {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: var(--pst-color-secondary-bg);
content: "";
z-index: -1; // So it doesn't hover over the content
}
Expand All @@ -39,3 +38,16 @@
color: var(--pst-color-inline-code-links);
}
}

// Bg color is now defined in the theme color palette - using our secondary color
.bd-header-announcement {
&:after {
background-color: var(--pst-color-secondary-bg);
}
}

.bd-header-version-warning {
&:after {
background-color: var(--pst-color-danger-bg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ primary_sidebar_end = sidebar-ethical-ads.html
footer_start = copyright.html, sphinx-version.html
footer_end = theme-version.html
secondary_sidebar_items = page-toc.html, edit-this-page.html, sourcelink.html
show_version_warning_banner = False
12rambau marked this conversation as resolved.
Show resolved Hide resolved
announcement =

# DEPRECATE after 0.14
Expand Down