Skip to content

Commit

Permalink
✨ NEW: add version switcher (#436)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel McCloy <[email protected]>
Co-authored-by: ThuWangzw <[email protected]>
Co-authored-by: Xinran Xu <[email protected]>
Co-authored-by: MegChai <[email protected]>
Co-authored-by: Chris Holdgraf <[email protected]>
Co-authored-by: Joris Van den Bossche <[email protected]>
  • Loading branch information
6 people authored Dec 3, 2021
1 parent 102f741 commit af02a6a
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 2 deletions.
51 changes: 51 additions & 0 deletions docs/_static/switcher.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[
{
"name": "v0.7.1 (stable)",
"version": "0.7.1"
},
{
"version": "0.7.0"
},
{
"version": "0.6.3"
},
{
"version": "0.6.2"
},
{
"version": "0.6.1"
},
{
"version": "0.6.0"
},
{
"version": "0.5.2"
},
{
"version": "0.5.1"
},
{
"version": "0.5.0"
},
{
"version": "0.4.3"
},
{
"version": "0.4.2"
},
{
"version": "0.4.1"
},
{
"version": "0.4.0"
},
{
"version": "0.3.2"
},
{
"version": "0.3.1"
},
{
"version": "0.3.0"
}
]
11 changes: 9 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

import pydata_sphinx_theme

version = pydata_sphinx_theme.__version__.replace("dev0", "")
release = pydata_sphinx_theme.__version__
version = release.replace("dev0", "")

# -- General configuration ---------------------------------------------------

Expand Down Expand Up @@ -96,8 +97,14 @@
# "navbar_align": "left", # [left, content, right] For testing that the navbar items align properly
# "navbar_start": ["navbar-logo", "navbar-version"],
# "navbar_center": ["navbar-nav", "navbar-version"], # Just for testing
# "navbar_end": ["navbar-icon-links", "navbar-version"] # Just for testing
"navbar_end": ["version-switcher", "navbar-icon-links"],
# "footer_items": ["copyright", "sphinx-version", ""]
"switcher": {
# "json_url": "/_static/switcher.json",
"json_url": "https://pydata-sphinx-theme.readthedocs.io/en/latest/_static/switcher.json",
"url_template": "https://pydata-sphinx-theme.readthedocs.io/en/v{version}/",
"version_match": version,
},
}


Expand Down
192 changes: 192 additions & 0 deletions docs/user_guide/configuring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,198 @@ at the bottom. You can hide these buttons with the following configuration:
}
Add a dropdown to switch between docs versions
==============================================

You can add a button to your site that allows users to
switch between versions of your documentation. The links in the version
switcher will differ depending on which page of the docs is being viewed. For
example, on the page ``https://mysite.org/en/v2.0/changelog.html``, the
switcher links will go to ``changelog.html`` in the other versions of your
docs. When clicked, the switcher will check for the existence of that page, and
if it doesn't exist, redirect to the homepage of that docs version instead.

The switcher requires the following configuration steps:

1. Add a JSON file containing a list of the documentation versions that the
switcher should show on each page.

2. Add a configuration dictionary called ``switcher`` to the
``html_theme_options`` dict in ``conf.py``. ``switcher`` should have 3 keys:

- ``json_url``: the persistent location of the JSON file described above.
- ``url_template``: a template string used to generate the correct URLs for
the different documentation versions.
- ``version_match``: a string stating the version of the documentation that
is currently being browsed.

3. Specify where to place the switcher in your page layout. For example, add
the ``"version-switcher"`` template to one of the layout lists in
``html_theme_options`` (e.g., ``navbar_end``, ``footer_items``, etc).

Below is a more in-depth description of each of these configuration steps.


Add a JSON file to define your switcher's versions
--------------------------------------------------

First, write a JSON file stating which versions of your docs will be listed in
the switcher's dropdown menu. That file should contain a list of entries that
each have one or two fields:

- ``version``: a version string. This will be inserted into
``switcher['url_template']`` to create the links to other docs versions, and
also checked against ``switcher['version_match']`` to provide styling to the
switcher.
- ``name``: an optional name to display in the switcher dropdown instead of the
version string (e.g., "latest", "stable", "dev", etc).

Here is an example JSON file:

.. code:: json
[
{
"name": "v2.1 (stable)",
"version": "2.1"
},
{
"version": "2.0"
},
{
"version": "1.0"
},
]
See the discussion of ``switcher['json_url']`` (below) for options of where to
save the JSON file.


Configure ``switcher['json_url']``
----------------------------------

The JSON file needs to be at a stable, persistent, fully-resolved URL (i.e.,
not specified as a path relative to the sphinx root of the current doc build).
Each version of your documentation should point to the same URL, so that as new
versions are added to the JSON file all the older versions of the docs will
gain switcher dropdown entries linking to the new versions. This could be done
a few different ways:

- The location could be one that is always associated with the most recent
documentation build (i.e., if your docs server aliases "latest" to the most
recent version, it could point to a location in the build tree of version
"latest"). For example:

.. code:: python
html_theme_options = {
...,
"switcher": {
"json_url": "https://mysite.org/en/latest/_static/switcher.json",
}
}
In this case the JSON is versioned alongside the rest of the docs pages but
only the most recent version is ever loaded (even by older versions of the
docs).

- The JSON could be saved in a folder that is listed under your site's
``html_static_path`` configuration. See `the Sphinx static path documentation
<https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_static_path>`_
for more information.

- The JSON could be stored outside the doc build trees. This probably means it
would be outside the software repo, and would require you to add new version
entries to the JSON file manually as part of your release process. Example:

.. code:: python
html_theme_options = {
...,
"switcher": {
"json_url": "https://mysite.org/switcher.json",
}
}
Configure ``switcher['url_template']``
--------------------------------------

The switcher's links to other versions of your docs are made by combining the
*version strings* from the JSON file with a *template string* you provide in
``switcher['url_template']``. The template string must contain a placeholder
``{version}`` and otherwise be a fully-resolved URL. For example:

.. code:: python
html_theme_options = {
...,
"switcher": {
"url_template": "https://mysite.org/en/version-{version}/",
}
}
The example above will result in a link to
``https://mysite.org/en/version-1.0/`` for the JSON entry for version
``"1.0"``.


Configure ``switcher['version_match']``
---------------------------------------

This configuration value tells the switcher what docs version is currently
being viewed, and is used to style the switcher (i.e., to highlight the current
docs version in the switcher's dropdown menu, and to change the text displayed
on the switcher button).

Typically you can re-use one of the sphinx variables ``version``
or ``release`` as the value of ``switcher['version_match']``; which one you use
depends on how granular your docs versioning is. See
`the Sphinx "project info" documentation
<https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information>`__
for more information). Example:

.. code:: python
version = my_package_name.__version__.replace("dev0", "") # may differ
html_theme_options = {
...,
"switcher": {
"version_match": version,
}
}
Specify where to display the switcher
-------------------------------------

Finally, tell the theme where on your site's pages you want the switcher to
appear. There are many choices here: you can add ``"version-switcher"`` to one
of the locations in ``html_theme_options`` (e.g., ``navbar_end``,
``footer_items``, etc). For example:

.. code:: python
html_theme_options = {
...,
"navbar_end": ["version-switcher"]
}
Alternatively, you could override one of the other templates to include the
version switcher in a sidebar. For example, you could define
``_templates/sidebar-nav-bs.html`` as:

.. code:: jinja
{%- include 'version-switcher.html' -%}
{{ super() }}
to insert a version switcher at the top of the left sidebar, while still
keeping the default navigation below it. See :doc:`sections` for more
information.


Add an Edit this Page button
============================

Expand Down
1 change: 1 addition & 0 deletions docs/user_guide/sections.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ will be named accordingly).
- ``sidebar-ethical-ads.html``
- ``sidebar-nav-bs.html``
- ``sphinx-version.html``
- ``version-switcher.html``

Add your own HTML templates to theme sections
=============================================
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<div class="dropdown" id="version_switcher">
<button type="button" class="btn btn-primary btn-sm navbar-btn dropdown-toggle" id="version_switcher_button" data-toggle="dropdown">
{{ theme_switcher.get('version_match') }} <!-- this text may get changed later by javascript -->
<span class="caret"></span>
</button>
<div id="version_switcher_menu" class="dropdown-menu list-group-flush py-0" aria-labelledby="version_switcher_button">
<!-- dropdown will be populated by javascript on page load -->
</div>
</div>

<!-- NOTE: this JS must live here (not in our global JS file) because it relies
on being processed by Jinja before it is run (specifically for replacing
variables {{ pagename }} and {{ theme_switcher }}.
-->

<script type="text/javascript">
// Construct the target URL from the JSON components
function buildURL(entry) {
var template = "{{ theme_switcher.get('url_template') }}"; // supplied by jinja
template = template.replace("{version}", entry.version);
return template;
}

// Check if corresponding page path exists in other version of docs
// and, if so, go there instead of the homepage of the other docs version
function checkPageExistsAndRedirect(event) {
const currentFilePath = "{{ pagename }}.html",
tryUrl = event.target.getAttribute("href");
let otherDocsHomepage = tryUrl.replace(currentFilePath, "");
$.ajax({
type: 'HEAD',
url: tryUrl,
// if the page exists, go there
success: function() {
location.href = tryUrl;
}
}).fail(function() {
location.href = otherDocsHomepage;
});
// this prevents the browser from following the href of the clicked node
// (which is fine because this function takes care of redirecting)
return false;
}

// Populate the version switcher from the JSON config file
(function () {
$.getJSON("{{ theme_switcher.get('json_url') }}", function(data, textStatus, jqXHR) {
const currentFilePath = "{{ pagename }}.html";
// create links to the corresponding page in the other docs versions
$.each(data, function(index, entry) {
// if no custom name specified (e.g., "latest"), use version string
if (!("name" in entry)) {
entry.name = entry.version;
}
// create the node
const node = document.createElement("a");
node.setAttribute("class", "list-group-item list-group-item-action py-1");
node.textContent = `${entry.name}`;
// get the base URL for that doc version, add the current page's
// path to it, and set as `href`
entry.url = buildURL(entry);
node.setAttribute("href", `${entry.url}${currentFilePath}`);
// on click, AJAX calls will check if the linked page exists before
// trying to redirect, and if not, will redirect to the homepage
// for that version of the docs.
node.onclick = checkPageExistsAndRedirect;
$("#version_switcher_menu").append(node);
// 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 == "{{ theme_switcher.get('version_match') }}") {
node.classList.add("active");
$("#version_switcher_button").text(entry.name);
}
});
});
})();
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ navbar_center = navbar-nav.html
navbar_end = navbar-icon-links.html
footer_items = copyright.html, sphinx-version.html
page_sidebar_items = page-toc.html, edit-this-page.html
switcher =

0 comments on commit af02a6a

Please sign in to comment.