From 55f0d6e7dde5104d0cbd4a86ec88e0e99e1bbe00 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 20 Jun 2023 09:30:50 -0500 Subject: [PATCH 01/19] update supporting files --- docs/_static/switcher.json | 3 ++- docs/conf.py | 1 + package.json | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/_static/switcher.json b/docs/_static/switcher.json index a70e93c3d..2cb3bea3e 100644 --- a/docs/_static/switcher.json +++ b/docs/_static/switcher.json @@ -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", diff --git a/docs/conf.py b/docs/conf.py index b86bec3f5..aeab715c4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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"], diff --git a/package.json b/package.json index f615c4a97..f992c9a7a 100644 --- a/package.json +++ b/package.json @@ -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" } } From 4139bb68925753b60e6b5b5cb68e2cc6873b7f8a Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 20 Jun 2023 09:34:54 -0500 Subject: [PATCH 02/19] improve code comments --- .../assets/scripts/pydata-sphinx-theme.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index 463ab9fc2..ee491d6a8 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -299,34 +299,32 @@ 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; From e492ae28edf61427f4f2b8384fea86e8566f09ec Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 20 Jun 2023 09:35:56 -0500 Subject: [PATCH 03/19] do switcher loading as a function; add warning banner function --- .../assets/scripts/pydata-sphinx-theme.js | 94 +++++++++++++++++-- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index ee491d6a8..f70c3a8e7 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -1,5 +1,6 @@ // Define the custom behavior of the page import { documentReady } from "./mixin"; +import { compare } from "compare-versions"; import "../styles/pydata-sphinx-theme.scss"; @@ -330,15 +331,8 @@ async function fetchVersionSwitcherJSON(url) { 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 @@ -371,6 +365,7 @@ if (versionSwitcherBtns.length) { anchor.classList.add("active"); versionSwitcherBtns.forEach((btn) => { btn.innerText = entry.name; + entry.name; btn.dataset["activeVersionName"] = entry.name; btn.dataset["activeVersion"] = entry.version; }); @@ -390,6 +385,66 @@ 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 + if (!version.includes("dev") && 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 "; + if (version.includes("dev") || compare(version, preferredVersion, ">")) { + inner.innerText += "the "; + bold.innerText = "unstable development version"; + } else { + inner.innerText += "an "; + bold.innerText = `old 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 */ @@ -421,6 +476,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 = themeSwitchBtns.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. */ From 4fc87d0e6cc3054c802b6d54279a32e0ec61eff1 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 20 Jun 2023 10:18:38 -0500 Subject: [PATCH 04/19] fix variable rename --- src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index f70c3a8e7..fa8632360 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -481,7 +481,7 @@ function initRTDObserver() { var versionSwitcherBtns = document.querySelectorAll( ".version-switcher__button" ); -const hasSwitcherMenu = themeSwitchBtns.length > 0; +const hasSwitcherMenu = versionSwitcherBtns.length > 0; const hasVersionsJSON = DOCUMENTATION_OPTIONS.hasOwnProperty( "theme_switcher_json_url" ); From 9be7964ea0f78cc6af394def11f21a3141a37c70 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Mon, 3 Jul 2023 13:29:23 -0500 Subject: [PATCH 05/19] cleanup after rebase --- src/pydata_sphinx_theme/__init__.py | 1 + src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js | 1 - src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pydata_sphinx_theme/__init__.py b/src/pydata_sphinx_theme/__init__.py index 0c9c97741..1418fec6e 100644 --- a/src/pydata_sphinx_theme/__init__.py +++ b/src/pydata_sphinx_theme/__init__.py @@ -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) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index fa8632360..a7b400693 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -365,7 +365,6 @@ function populateVersionSwitcher(data, versionSwitcherBtns) { anchor.classList.add("active"); versionSwitcherBtns.forEach((btn) => { btn.innerText = entry.name; - entry.name; btn.dataset["activeVersionName"] = entry.name; btn.dataset["activeVersion"] = entry.version; }); diff --git a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf index eb750f318..0b2685086 100644 --- a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf +++ b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf @@ -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 announcement = # DEPRECATE after 0.14 From d4f3364efcf77b858323f75bdffaae28a95680f1 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Mon, 3 Jul 2023 13:30:07 -0500 Subject: [PATCH 06/19] banner background color --- .../assets/styles/sections/_announcement.scss | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss b/src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss index 524f2ec91..843c4be7f 100644 --- a/src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss +++ b/src/pydata_sphinx_theme/assets/styles/sections/_announcement.scss @@ -1,3 +1,4 @@ +.bd-header-version-warning, .bd-header-announcement { min-height: 3rem; width: 100%; @@ -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 } @@ -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); + } +} From 124b761a797433c1d5bacb5385854b4c5636ea17 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Mon, 3 Jul 2023 13:42:31 -0500 Subject: [PATCH 07/19] docs --- docs/user_guide/announcements.rst | 28 ++++++++++++++++++++++++++++ docs/user_guide/version-dropdown.rst | 2 ++ 2 files changed, 30 insertions(+) diff --git a/docs/user_guide/announcements.rst b/docs/user_guide/announcements.rst index 2d71417d9..9ee2a63b2 100644 --- a/docs/user_guide/announcements.rst +++ b/docs/user_guide/announcements.rst @@ -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 = { ... @@ -33,8 +34,35 @@ 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 +----------------------- + +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 ` 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 `__, for example: + + .. code-block:: json + + { + "name": "9.9.9 (current)", + "version": "stable", + "url": "https://anything" + } diff --git a/docs/user_guide/version-dropdown.rst b/docs/user_guide/version-dropdown.rst index 2502a99c4..f245c3877 100644 --- a/docs/user_guide/version-dropdown.rst +++ b/docs/user_guide/version-dropdown.rst @@ -1,3 +1,5 @@ +.. _version-dropdowns: + Version switcher dropdowns ========================== From 6aa43a6c97dfc2a55dec24045a9d4900b935a4b2 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Mon, 3 Jul 2023 13:42:49 -0500 Subject: [PATCH 08/19] add TODO --- src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index a7b400693..eeb2b8f2b 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -408,6 +408,9 @@ function showVersionWarningBanner(data) { } const preferredVersion = preferredEntries[0].version; const preferredURL = preferredEntries[0].url; + // TODO: make the below logic more forgiving: + // - don't fail if version string not semVer-parsable + // - if not semVer parsable make message more generic // if already on preferred version, nothing to do if (!version.includes("dev") && compare(version, preferredVersion, "=")) { return; From f6a3a4f968906dc3d35d3ba049d92a2abd823a10 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 4 Jul 2023 11:47:25 -0500 Subject: [PATCH 09/19] be forgiving about version specs --- .../assets/scripts/pydata-sphinx-theme.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index eeb2b8f2b..16a6bbf7f 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -1,6 +1,6 @@ // Define the custom behavior of the page import { documentReady } from "./mixin"; -import { compare } from "compare-versions"; +import { compare, validate } from "compare-versions"; import "../styles/pydata-sphinx-theme.scss"; @@ -408,11 +408,9 @@ function showVersionWarningBanner(data) { } const preferredVersion = preferredEntries[0].version; const preferredURL = preferredEntries[0].url; - // TODO: make the below logic more forgiving: - // - don't fail if version string not semVer-parsable - // - if not semVer parsable make message more generic // if already on preferred version, nothing to do - if (!version.includes("dev") && compare(version, preferredVersion, "=")) { + const versionsAreComparable = validate(version) && validate(preferredVersion); + if (versionsAreComparable && compare(version, preferredVersion, "=")) { return; } // now construct the warning banner @@ -431,13 +429,16 @@ function showVersionWarningBanner(data) { button.innerText = "Switch to latest stable version"; button.onclick = checkPageExistsAndRedirect; // add the version-dependent text - inner.innerText = "This is documentation for "; - if (version.includes("dev") || compare(version, preferredVersion, ">")) { - inner.innerText += "the "; + inner.innerText = "This is documentation for an "; + const isDev = version.includes("dev"); + const newerThanPreferred = + versionsAreComparable && compare(version, preferredVersion, ">"); + if (isDev || newerThanPreferred) { bold.innerText = "unstable development version"; - } else { - inner.innerText += "an "; + } else if (versionsAreComparable && compare(version, preferredVersion, "<")) { bold.innerText = `old version (${version})`; + } else { + bold.innerText = `version ${version}`; } outer.appendChild(middle); middle.appendChild(inner); From 0e6d02e30ce7e0867b35d368186d67d948fcee92 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 4 Jul 2023 11:47:38 -0500 Subject: [PATCH 10/19] update package-lock --- package-lock.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 89c5c3906..474c42cd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "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" }, "devDependencies": { "axe-core": "^4.6.3", @@ -993,6 +994,11 @@ "node": ">= 6" } }, + "node_modules/compare-versions": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" + }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", @@ -5293,6 +5299,11 @@ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true }, + "compare-versions": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" + }, "copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", From 0c0c38669b992ea825774ce06029eed46a2b2370 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 4 Jul 2023 11:52:55 -0500 Subject: [PATCH 11/19] more documentation --- docs/user_guide/announcements.rst | 3 +++ docs/user_guide/version-dropdown.rst | 2 ++ 2 files changed, 5 insertions(+) diff --git a/docs/user_guide/announcements.rst b/docs/user_guide/announcements.rst index 9ee2a63b2..ac8acdae7 100644 --- a/docs/user_guide/announcements.rst +++ b/docs/user_guide/announcements.rst @@ -41,6 +41,9 @@ For example, the following configuration tells the theme to load the ``custom-te "announcement": "https://github.com/pydata/pydata-sphinx-theme/raw/main/docs/_templates/custom-template.html", } + +.. _version-warning-banners: + Version warning banners ----------------------- diff --git a/docs/user_guide/version-dropdown.rst b/docs/user_guide/version-dropdown.rst index f245c3877..299ab678e 100644 --- a/docs/user_guide/version-dropdown.rst +++ b/docs/user_guide/version-dropdown.rst @@ -42,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: From 01c41721c044ba846aaa92ef4b3cff8e2e1d3146 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Thu, 6 Jul 2023 13:14:13 -0500 Subject: [PATCH 12/19] handle more prerelease indicators in version strings --- .../assets/scripts/pydata-sphinx-theme.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index 16a6bbf7f..e3c00a797 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -430,7 +430,10 @@ function showVersionWarningBanner(data) { button.onclick = checkPageExistsAndRedirect; // add the version-dependent text inner.innerText = "This is documentation for an "; - const isDev = version.includes("dev"); + const isDev = + version.includes("dev") || + version.includes("rc") || + version.includes("pre"); const newerThanPreferred = versionsAreComparable && compare(version, preferredVersion, ">"); if (isDev || newerThanPreferred) { From cfdb9fd39a80ad43ed880be4724a8d123d17aaf0 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Thu, 6 Jul 2023 13:14:39 -0500 Subject: [PATCH 13/19] Update docs/user_guide/announcements.rst --- docs/user_guide/announcements.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/user_guide/announcements.rst b/docs/user_guide/announcements.rst index ac8acdae7..ccddeb709 100644 --- a/docs/user_guide/announcements.rst +++ b/docs/user_guide/announcements.rst @@ -67,5 +67,6 @@ In addition to the general-purpose announcement banner, the theme includes a bui { "name": "9.9.9 (current)", "version": "stable", + "preferred": true, "url": "https://anything" } From c7c48a0dea822164643c1f80ae7d505ed184ad80 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 11 Jul 2023 17:34:34 -0500 Subject: [PATCH 14/19] add HTML snippet to docs --- docs/user_guide/announcements.rst | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/user_guide/announcements.rst b/docs/user_guide/announcements.rst index ccddeb709..02df44f80 100644 --- a/docs/user_guide/announcements.rst +++ b/docs/user_guide/announcements.rst @@ -56,17 +56,30 @@ In addition to the general-purpose announcement banner, the theme includes a bui ... "show_version_warning_banner": True, } -.. warning:: + +.. important:: This functionality relies on the :ref:`version switcher ` 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 `__, for example: + and your entries have ``version`` properties that are parsable by the `compare-versions node module `__, for example: .. code-block:: json { - "name": "9.9.9 (current)", - "version": "stable", - "preferred": true, - "url": "https://anything" + "name": "stable", + "version": "9.9.9", + "url": "https://anything", + "preferred": true } + +If you want similar functionality for *older* versions of your docs (i.e. those built before the ``show_version_warning_banner`` configuration option was available), you can manually add a banner by prepending the following HTML to all pages (be sure to replace ``URL_OF_STABLE_VERSION_OF_PROJECT`` with a valid URL, and adjust styling as desired): + +.. code-block:: html + +
+
+
This is documentation for an old version. + Switch to stable version +
+
+
From e108aa7d2de3b37707236daf1bb7249fbad4cb67 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 11 Jul 2023 17:34:49 -0500 Subject: [PATCH 15/19] unrelated formatting fix --- docs/user_guide/announcements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide/announcements.rst b/docs/user_guide/announcements.rst index 02df44f80..d86abb295 100644 --- a/docs/user_guide/announcements.rst +++ b/docs/user_guide/announcements.rst @@ -29,7 +29,7 @@ You can specify an arbitrary URL that will be used as the HTML source for your a When the page is loaded, JavaScript will attempt to fetch this HTML and insert it as-is into the announcement banner. This allows you to define a single HTML announcement that you can pull into multiple documentation sites or versions. -If the value of ``html_theme_options["announcement"]`` begins with **``http``** it will be treated as a URL to remote HTML. +If the value of ``html_theme_options["announcement"]`` begins with ``http`` it will be treated as a URL to remote HTML. For example, the following configuration tells the theme to load the ``custom-template.html`` example from this documentation's GitHub repository: From 891f680997587562d4ce576dc82434994c1cbd62 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Wed, 12 Jul 2023 00:01:48 -0500 Subject: [PATCH 16/19] disambiguate button message --- src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index e3c00a797..c5582ec1b 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -426,7 +426,7 @@ function showVersionWarningBanner(data) { 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.innerText = "Switch to stable version"; button.onclick = checkPageExistsAndRedirect; // add the version-dependent text inner.innerText = "This is documentation for an "; From e15f47f11e5755962ee1e0f9925853edc8a88c54 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Wed, 12 Jul 2023 00:03:06 -0500 Subject: [PATCH 17/19] use parsable version string for stable entry in JSON --- docs/_static/switcher.json | 5 ++--- docs/conf.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/_static/switcher.json b/docs/_static/switcher.json index 2cb3bea3e..6d4f0a912 100644 --- a/docs/_static/switcher.json +++ b/docs/_static/switcher.json @@ -1,12 +1,11 @@ [ { - "name": "dev", - "version": "latest", + "version": "dev", "url": "https://pydata-sphinx-theme.readthedocs.io/en/latest/" }, { "name": "0.13.3 (stable)", - "version": "stable", + "version": "v0.13.3", "url": "https://pydata-sphinx-theme.readthedocs.io/en/stable/", "preferred": true }, diff --git a/docs/conf.py b/docs/conf.py index aeab715c4..54537a096 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,7 @@ # For local development, infer the version to match from the package. release = pydata_sphinx_theme.__version__ if "dev" in release or "rc" in release: - version_match = "latest" + version_match = "dev" # We want to keep the relative reference if we are in dev mode # but we want the whole url if we are effectively in a released version json_url = "_static/switcher.json" From f9aef360943d93461e596a41f2eea0e80b659295 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Wed, 12 Jul 2023 00:03:38 -0500 Subject: [PATCH 18/19] update test for new color palette --- tests/test_a11y.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_a11y.py b/tests/test_a11y.py index 7259056bd..71b09f345 100644 --- a/tests/test_a11y.py +++ b/tests/test_a11y.py @@ -127,4 +127,6 @@ def test_version_switcher_highlighting(page: Page, url_base: str) -> None: assert entries.count() == 2 # make sure they're highlighted for entry in entries.all(): - expect(entry).to_have_css("color", "rgb(10, 125, 145)") + light_mode = "rgb(39, 107, 233)" + # dark_mode = "rgb(121, 163, 142)" + expect(entry).to_have_css("color", light_mode) From af158fe1fa22dab11c8e272e31ef08ccf0d98696 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 18 Jul 2023 16:36:38 -0500 Subject: [PATCH 19/19] handle Bokeh case elegantly --- .../assets/scripts/pydata-sphinx-theme.js | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js index c5582ec1b..c29b8a04d 100644 --- a/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js +++ b/src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js @@ -339,12 +339,28 @@ function populateVersionSwitcher(data, versionSwitcherBtns) { btn.dataset["activeVersionName"] = ""; btn.dataset["activeVersion"] = ""; }); - // create links to the corresponding page in the other docs versions - data.forEach((entry) => { + // in case there are multiple entries with the same version string, this helps us + // decide which entry's `name` to put on the button itself. Without this, it would + // always be the *last* version-matching entry; now it will be either the + // version-matching entry that is also marked as `"preferred": true`, or if that + // doesn't exist: the *first* version-matching entry. + data = data.map((entry) => { + // does this entry match the version that we're currently building/viewing? + entry.match = + entry.version == DOCUMENTATION_OPTIONS.theme_switcher_version_match; + entry.preferred = entry.preferred || false; // if no custom name specified (e.g., "latest"), use version string if (!("name" in entry)) { entry.name = entry.version; } + return entry; + }); + const hasMatchingPreferredEntry = data + .map((entry) => entry.preferred && entry.match) + .some(Boolean); + var foundMatch = false; + // create links to the corresponding page in the other docs versions + data.forEach((entry) => { // create the node const anchor = document.createElement("a"); anchor.setAttribute("class", "list-group-item list-group-item-action py-1"); @@ -357,17 +373,20 @@ function populateVersionSwitcher(data, versionSwitcherBtns) { // to apply CSS styling based on this information. anchor.dataset["versionName"] = entry.name; anchor.dataset["version"] = entry.version; - // replace dropdown button text with the preferred display name of - // this version, rather than using sphinx's {{ version }} variable. - // also highlight the dropdown entry for the currently-viewed - // version's entry - if (entry.version == DOCUMENTATION_OPTIONS.theme_switcher_version_match) { + // replace dropdown button text with the preferred display name of the + // currently-viewed version, rather than using sphinx's {{ version }} variable. + // also highlight the dropdown entry for the currently-viewed version's entry + let matchesAndIsPreferred = hasMatchingPreferredEntry && entry.preferred; + let matchesAndIsFirst = + !hasMatchingPreferredEntry && !foundMatch && entry.match; + if (matchesAndIsPreferred || matchesAndIsFirst) { anchor.classList.add("active"); versionSwitcherBtns.forEach((btn) => { btn.innerText = entry.name; btn.dataset["activeVersionName"] = entry.name; btn.dataset["activeVersion"] = entry.version; }); + foundMatch = true; } // There may be multiple version-switcher elements, e.g. one // in a slide-over panel displayed on smaller screens.