``
This approach is preferable when your usage of a particular style is
systematic rather than *ad hoc*.
The sections on :ref:`summary_detail` and :ref:`custom_tooltips` give examples where
the ``span`` role can be useful.
Use of JavaScript, CSS and font assets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The version of jQuery used is 3.3.1. The version of Bootstrap used is 3.3.7.
These are loaded from CDN, as are the fonts. No additional external assets
beyond these are used, though you can add some in the usual way to a specific
project -- see the section :ref:`custom` for more details.
Styling Lists using Font Awesome
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can style bulleted lists using Font Awesome. For example, the following
list:
.. cssclass:: styled-list using-star
* Arcturus
* Betelgeuse
* VY Canis Majoris
was produced using this markup:
.. code-block:: rst
.. cssclass:: styled-list using-star
* Arcturus
* Betelgeuse
* VY Canis Majoris
A class starting with ``using-`` is used to style the list, with ``using-`` being
replaced by ``fa-`` in the actual style applied.
You can override individual items with specific icons. For example,
.. cssclass:: styled-list using-star
* :fa:`star-o` Arcturus
* :fa:`star-half-o` Betelgeuse
* VY Canis Majoris
was produced by this markup:
.. code-block:: rst
.. cssclass:: styled-list using-star
* :fa:`star-o` Arcturus
* :fa:`star-half-o` Betelgeuse
* VY Canis Majoris
.. _summary_detail:
Summary-Detail Lists
~~~~~~~~~~~~~~~~~~~~
HTML5 has a handy feature - summary-detail lists, which are marked up like this:
.. code-block:: html
The summary goes here.
The detail goes here.
The idea is that the whole thing can be closed (when only the summary is
visible) or open (when both the summary and detail parts are visible). However,
browser support is patchy and inconsistent, and styling options are limited.
Here's how the element looks when open and closed in Firefox and Chrome:
.. cssclass:: table table-bordered
===================================== =================================== ========================================= ======================================
Closed (Firefox) Open (Firefox) Closed (Chrome) Open (Chrome)
===================================== =================================== ========================================= ======================================
.. image:: _static/img/ff-closed.png .. image:: _static/img/ff-open.png .. image:: _static/img/chrome-closed.png .. image:: _static/img/chrome-open.png
===================================== =================================== ========================================= ======================================
Of course, docutils and Sphinx don't offer any reStructuredText markup which
maps to this HTML5 element. With the Sizzle theme, you can achieve a similar
effect like this:
.. code-block:: rst
.. cssclass:: summary-detail
* :span:`The summary goes here.`
The detail goes here.
The Sizzle theme code looks for this specific CSS class and arranges for it to
be shown like this:
.. cssclass:: summary-detail
* :span:`The summary goes here.`
The detail goes here.
.. _custom:
Custom Styles and JavaScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have custom styles and/or JavaScript, you can install them in one of
two ways, depending on the version of Sphinx you're using. If you're using
Sphinx 1.8 or later, you should use configuration options in :file:`conf.py`
like this:
.. code-block:: python
html_css_files = ['css/project.css']
html_js_files = ['js/project.js']
.. superseded:
If you're using an earlier Sphinx version than 1.8, then in your
:file:`conf.py`, have code something like this:
.. code-block:: python
def setup(app):
app.add_stylesheet('css/project.css')
app.add_javascript('js/project.js')
The CSS file will be loaded *after* Sizzle's own CSS, allowing you to tweak
styles where needed. The JavaScript file will be added after all other external
JavaScript files. Bear in mind that the Sizzle theme arranges to first add a
JavaScript object to the DOM using a jQuery call:
.. code-block:: javascript
$(document).data('sizzle', {on_load: []}); // code in the Sizzle theme
This is done *before* your custom JavaScript is included. If you want to have
some JavaScript code of yours called after the entire document is loaded, you
can do something like
.. code-block:: javascript
function my_custom_function() {
// whatever
}
var sizzle = $(document).data('sizzle');
sizzle.on_load.push(my_custom_function);
in your custom JavaScript file. When the document has loaded, the Sizzle
theme's code calls any functions pushed onto the ``on_load`` array:
.. code-block:: javascript
$(document).ready(function() { // code in the Sizzle theme
// other stuff omitted ...
var sizzle = $(document).data('sizzle');
if (sizzle.on_load) {
sizzle.on_load.forEach(function(f) {
f();
});
}
// other stuff omitted ...
}
So your ``my_custom_function`` should get called once the document has loaded.
.. _style-cols:
Example -- styling columns in a table
+++++++++++++++++++++++++++++++++++++
Here's an example function which I implemented for a project, using the
functionality described above:
.. code-block:: javascript
function add_column_styles() {
$('table').each(function() {
$(this).find('tr').each(function() {
$(this).find('td, th').each(function(i) {
$(this).addClass('col-' + i);
});
});
});
}
This adds a ``col-N`` class to every cell in the Nth column of every table,
including header rows. By judicious application of CSS, you might be able to
use this approach to style tables in your content as you wish. For instance,
.. code-block:: css
/* centre all columns except the first */
#some-table td:not(.col-0), #some-table th:not(.col-0) {
text-align: center;
}
/* apply padding to the first column only */
#some-table td.col-0, #some-table th.col-0 {
padding-left: 6px;
}
Device-Friendliness
~~~~~~~~~~~~~~~~~~~
The theme adapts well to smaller screens, as shown in the following images.
.. cssclass:: table table-bordered
==================================== ===================================
Appearance on a small screen Navigation menu on a small screen
==================================== ===================================
.. image:: _static/img/mobile_1.png .. image:: _static/img/mobile_2.png
==================================== ===================================
Navigation Improvements
~~~~~~~~~~~~~~~~~~~~~~~
In larger documentation sets, the list of items in the navigator is quite long -
if you use it to navigate to a different page, then the navigator would normally
be positioned at the top, rather than in the vicinity of the element you clicked
to get to that page. The Sizzle theme JavaScript code tries to position the link
which led you to a particular part of the documentation to near the vertical
centre of the navigator, or at least in the visible portion of the navigator.
Glossary Improvements
~~~~~~~~~~~~~~~~~~~~~
Starting with version 0.0.9, there have been some improvements to Sphinx
glossary functionality.
Tooltips
++++++++
By default, you can see tooltips when you hover over a glossary term in
documentation. You can try them out in the `Supervisor documentation set
`_: there are some glossary terms at
the top of the home page - just hover over them to see the tooltips with the
glossary definitions of those terms.
You can disable tooltips by setting ``enable_tooltips`` to ``False`` in the
theme options.
.. versionadded:: 0.0.9
The tooltip functionality was added and applied to glossary terms.
Permalinks
++++++++++
In the glossary, the term headings have a hover-over permalink which allows
you to bookmark them by right-clicking -- the same as headings.
You can disable glossary permalinks by setting ``glossary_permalinks`` to
``False`` in the theme options.
Code Block Improvements
~~~~~~~~~~~~~~~~~~~~~~~
Starting with version 0.0.9, code blocks with captions get a little button
which, when clicked, copies the contents of the code block to the clipboard.
The idea was shamelessly borrowed from recent Django documentation! Here's an
example:
.. code-block:: python3
:caption: dump_node.py
def dump_node(node, level=0, file=sys.stdout): # used for debugging only
print('%s%r' %(' ' * level, node), file=file)
for child in node.children:
dump_node(child, level + 1, file=file)
.. versionadded:: 0.0.9
The code block copy functionality was added.
.. _api_tooltips:
Providing API Tooltips
~~~~~~~~~~~~~~~~~~~~~~
Starting with version 0.1.2, you can add tooltips derived from docstrings in your module code. To do this, you need to
set up a JSON file containing the HTML snippets for your tooltips, and make use of it in your ``conf.py``. Before
discussing how to do that in more detail, you might want to see the effect in built documentation. An example of
documentation with API tooltips can be seen for |example-link| --- follow the link (it should open in a new tab) and
then, *in the linked page*, hover over the links in the paragraph for ``Identity``, ``encrypt()``, ``decrypt()``,
``sign()`` and ``verify()``. You should see tooltips for the corresponding code elements.
.. |example-link| raw:: html
the pagesign
project
To achieve the same effect in your documentation, you need to take the following steps.
#. Create a JSON file which maps fully-qualified API endpoints to HTML snippets to be displayed in the tooltips for
those endpoints. An example of such a file (from the ``pagesign`` project) is as follows.
.. code-block:: json
:caption: hover.json
{
"pagesign.CryptException": "\n
\nclass\nCryptException(builtins.Exception):\n\n \n
\n
Base class of all exceptions defined in this module.
\n
\n
",
"pagesign.Identity": "\n
\nclass\nIdentity:\n\n \n
\n
This class represents both remote identities (used for encryption and verification\nonly) and local identities (used for all functions - encryption, decryption,\nsigning and verification).
\n
\n
",
"pagesign.Identity.encoding": "\n
\nencoding = 'utf-8'\n
\n
",
"pagesign.Identity.export": "\n
\ndef\nexport(self):\n
\n
Export this instance. Only public attributes are preserved in the export - it\nis meant for sending to someone securely.
\n
\n
",
"pagesign.Identity.imported": "\n
\n
@classmethod
\n
def\n
imported(cls, d, name):\n
\n
Return a remote identity instance created from d and with local name name.\nThe dictionary must contain the public attributes created, crypt_public,\nsign_public and sign_id (which will be present in dictionaries created\nusing the export
method). Names are case-sensitive.
\n
\n
",
"pagesign.Identity.save": "\n
\ndef\nsave(self, name):\n
\n
Save this instance with the specified name, which cannot be blank or\nNone
. Names are case-sensitive.
\n
\n
",
"pagesign.clear_identities": "\n
\ndef\nclear_identities():\n
\n
Clear all identities saved locally.
\n
\n
",
"pagesign.decrypt": "\n
\ndef\ndecrypt(path, identities, outpath=None):\n
\n
Decrypt the data at path which is intended for recipients named in identities\nand save the decrypted data at outpath. If outpath is not specified and path\nends with '.age'
, then outpath will be set to path with that suffix\nstripped. Otherwise, it will be set to path with '.dec'
appended.
\n
Arguments:
\n
\n- path (str): The path to the data to be decrypted.
\n- identities (str|list[str]): The name(s) of the recipient(s) of the data.
\n- outpath (str): The path to which the decrypted data should be written.
\n
\n
Returns:
\n
\nstr: The value of outpath is returned.
\n
\n
\n
",
"pagesign.decrypt_mem": "\n
\ndef\ndecrypt_mem(data, identities):\n
\n
Decrypt the in-memory data for recipients whose names are in identities. The\ndecrypted data is returned as bytes.
\n
Arguments:
\n
\n- data (str|bytes): The data to decrypt.
\n- identities (str|list[str]): The name(s) of the recipient(s) of the data.
\n
\n
Returns:
\n
\nbytes: The decrypted data.
\n
\n
\n
",
"pagesign.encrypt": "\n
\ndef\nencrypt(path, recipients, outpath=None, armor=False):\n
\n
Encrypt the file at path for identities whose names are in recipients and\nsave the encrypted data in outpath. The output data is ASCII-armored if armor\nis true, else it is binary. If outpath isn't specified, it will be set to path\nwith '.age'
appended.
\n
Arguments:
\n
\n- path (str): The path to the data to be encrypted.
\n- recipients (str|list[str]): The name(s) of the recipient(s) of the data.
\n- outpath (str): The path to which the encrypted data should be written.
\n- armor (bool): Whether the output is to be ASCII-armored.
\n
\n
Returns:
\n
\nstr: The value of outpath is returned.
\n
\n
\n
",
"pagesign.encrypt_and_sign": "\n
\ndef\nencrypt_and_sign(path, recipients, signer, armor=False, outpath=None, sigpath=None):\n
\n
Encrypt the data at path for identities named in recipients and sign it with\nthe identity named by signer. If armor is true, use ASCII armor for the\nencrypted data, else save it as binary. Write the encrypted data to outpath and\nthe signature to sigpath. If outpath isn't specified, it will be set to path\nwith '.age'
appended. If not specified, sigpath is set to outpath with\n'.sig'
appended.
\n
Note that you'll need to call verify_and_decrypt
to reverse this process.
\n
Arguments:
\n
\n- recipients (str|list[str]): The name(s) of the recipient(s) of the encrypted data.
\n- signer (str): The name of the signer identity.
\n- armor (bool): Whether the result is ASCII-armored.
\n- outpath (str): The output path to which the encrypted data should be written,
\n- sigpath (str): The path to which the signature should be written.
\n
\n
Returns:
\n
\ntuple(str, str): A tuple of outpath and sigpath is returned.
\n
\n
\n
",
"pagesign.encrypt_mem": "\n
\ndef\nencrypt_mem(data, recipients, armor=False):\n
\n
Encrypt the in-memory data for identities whose names are in recipients. The\noutput data is ASCII-armored if armor is true, else it is binary. The encrypted\ndata is returned as bytes.
\n
Arguments:
\n
\n- data (str|bytes): The data to be encrypted.
\n- recipients (str|list[str]): The name(s) of the recipient(s) of the data.
\n- armor (bool): Whether the output is to be ASCII-armored.
\n
\n
Returns:
\n
\nbytes: The encrypted data.
\n
\n
\n
",
"pagesign.list_identities": "\n
\ndef\nlist_identities():\n
\n
Return an iterator over the locally stored identities, as name-value 2-tuples.
\n
\n
",
"pagesign.remove_identities": "\n
\ndef\nremove_identities(*args):\n
\n
Remove the identities stored locally whose names are in args. Names are\ncase-sensitive.
\n
Arguments:
\n
\n- args (list[str]): The list of identities to remove.
\n
\n
\n
",
"pagesign.sign": "\n
\ndef\nsign(path, identity, outpath=None):\n
\n
Sign the data at path with the named identity and save the signature in\noutpath. If not specified, outpath is set to path with '.sig'
appended.
\n
Arguments:
\n
\n- path (str): The path to the data to be signed.
\n- identity (str): The name of the signer's identity.
\n- outpath (str): The path to which the signature is to be written.
\n
\n
Returns:
\n
\nstr: The value of outpath is returned.
\n
\n
\n
",
"pagesign.verify": "\n
\ndef\nverify(path, identity, sigpath=None):\n
\n
Verify that the data at path was signed with the identity named identity, where\nthe signature is at sigpath. If not specified, sigpath is set to path with\n'.sig'
appended. If verification fails, an exception is raised, otherwise this\nfunction returns None
.
\n
Arguments:
\n
\n- path (str): The path to the data to be verified.
\n- identity (str): The name of the signer's identity.
\n- sigpath (str): The path where the signature is stored.
\n
\n
\n
",
"pagesign.verify_and_decrypt": "\n
\ndef\nverify_and_decrypt(path, recipients, signer, outpath=None, sigpath=None):\n
\n
Verify the encrypted and signed data at path as having been signed by the\nidentity named by signer and intended for identities named in recipients.\nThe signature for path is in sigpath. If not specified, it will be set to\npath with '.sig'
appended. If verification or decryption fails, an exception\nwill be raised. Otherwise, the decrypted data will be stored at outpath. If\nnot specified, it will be set to path with the suffix stripped (if it ends in\n'.age'
) or with '.dec'
appended.
\n
The function returns outpath.
\n
Note that the file inputs to this function should have been created using\nencrypt_and_sign
.
\n
Arguments:
\n
\n- path (str): The path to the encrypted and signed data.
\n- recipients (str|list[str]): The name(s) of the recipient(s) of the encrypted data.
\n- signer (str): The name of the signer identity.
\n- outpath (str): The output path to which the decrypted data should be written,
\n- sigpath (str): The path in which the signature is to be found.
\n
\n
Returns:
\n
\nstr: The value of outpath is returned.
\n
\n
\n
"
}
You can use whatever tools you want to create this file --- we used the `pdoc `_ project, using
``pdoc`` as a library, to create the above file. Note that the APIs are fully-qualified. The following step assumes
that this file will be adjacent to your documentation's ``conf.py``.
#. Update your ``conf.py`` using the following code from the ``pagesign`` project as a guide:
.. code-block:: python
HTML_THEME_OPTIONS = {
'sizzle': {
'sitemap_url': 'https://docs.red-dove.com/pagesign/'
},
# You can add options for other themes here
}
html_theme = os.environ.get('DOCS_THEME', 'default')
if html_theme == 'sizzle' and os.path.isfile('hover.json'):
import json
with open('hover.json', encoding='utf-8') as f:
HTML_THEME_OPTIONS['sizzle']['custom_data'] = {'hovers': json.load(f) }
if html_theme in HTML_THEME_OPTIONS:
html_theme_options = HTML_THEME_OPTIONS[html_theme]
The above code ensures that the tooltip snippets are stored under the theme options' ``custom_data`` key, and as
all of ``custom_data`` will be made available to JavaScript code for the theme, it will be used there to set up the
tooltips appropriately.
#. Optionally, add or update custom CSS to style your tooltips according to your requirements. You can use the CSS
class on the top-level ``div`` in your HTML tooltip snippets to make the styles specific to your tooltips.
You can see the source docstrings for those tooltips `here
`__. Although that project uses docstrings formatted in the
Google style, you aren't restricted to this, as long as any tool you use for creating the snippet JSON supports your
preferred style (for example, ``pdoc`` supports docstrings in Markdown, reStructuredText, NumPy or Google formats).
.. versionadded:: 0.1.2
API tooltip functionality was added.
.. _custom_tooltips:
Providing Customized Tooltips
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with version 0.0.9, you can provide customized tooltips. For example, here's
an info icon with a customized tooltip: :fa:`info-circle,tc-infotip,tci-ver-0.0.9`
:span:`tc-info|` If you hover over it, you'll see a tooltip saying something like
"This feature was added in version 0.0.9." This was achieved using the following
steps:
* Have a span with a CSS class ``tc-infotip`` and another CSS class starting with ``tci-``,
where the suffix is treated as a key to use when finding the tooltip's HTML. In the
above example, that's done using the markup
``:fa:`info-circle,tc-infotip,tci-ver-0.0.9```. The ``tc-infotip`` class is used to
style the content with the tip (by default, it just indicates via the cursor that
help is available).
* Immediately following that, have a span which has the ``tc-info`` class. In the above
example, that's just ``:span:`tc-info|``` (the span here has no text; it simply
serves as a marker for the preceding element. But it's fine to have text, too, as in
the examples below).
* In :file:`conf.py`, the ``custom_data`` theme option was set to have some pertinent
information, like this:
.. code-block:: python
'custom_data': {
'info-tips': {
'ver-0.0.9': 'This feature was added in version 0.0.9.',
'win-only': 'This doodad only works on Windows.',
'linux-only': 'This thingummy is for Linux only.',
},
}
When the documentation is built, Python code in the Sizzle theme ensures that the
contents of ``custom_data`` are made available to the JavaScript code in the built
documentation. When the page is loaded, JavaScript code in the Sizzle theme looks for
elements with class ``tc-info`` and for each of them, if an element is found
immediately preceding it with a class beginning with ``tci-``, that prefix is stripped
off to provide a key (in this case, it would be ``ver-0.0.9``. If that key is found in
the ``info-tips`` mapping, the corresponding value is treated as HTML to appear in the
tooltip. (If the key is not found, e.g. because missing or misspelt in
``custom_data['info-tips']``, then no tooltip will appear.)
Of course, Sphinx has ``versionadded`` and ``versionchanged`` directives to provide
this type of information in the body of the document. But this example is just for the
purposes of illustration -- in practice, this feature could be used to provide
info-tips which are about platform-specific or product-specific features, with a
suitable icon to draw attention to them. For example, to mark something as only
working on :fa:`windows,tc-infotip,tci-win-only` :span:`tc-info|Windows`, or something else as
only working on :fa:`linux,tc-infotip,tci-linux-only` :span:`tc-info|Linux`.
.. versionadded:: 0.0.9
Customized tooltip functionality was added.
Change Log
~~~~~~~~~~
.. cssclass:: summary-detail
* :span:`Changes for recent releases are shown here (click the arrow at left to
expand).`
.. cssclass:: table table-striped
+------------+------------+----------------------------------------------------+
|Version |Released on |Changes |
+============+============+====================================================+
|0.1.4 |Not yet. | |
+------------+------------+----------------------------------------------------+
|0.1.3 |31 Aug 2023 |Fix manifest to include theme.conf. |
| | | |
| | |Fix failures which show up under Sphinx 7 and the |
| | |Whoosh documentation. |
+------------+------------+----------------------------------------------------+
|0.1.2 |05 May 2023 |Add table padding styles. |
| | | |
| | |Add logic for code tooltips. |
| | | |
| | |Support for Sphinx older than 5.3.0 dropped. |
+------------+------------+----------------------------------------------------+
|0.1.1 |03 May 2022 |Add metatags to layout, so that the meta directive |
| | |can be used. |
| | | |
| | |Change size constraints on header elements. |
| | | |
| | |Add build date tooltip to footer. |
| | | |
| | |Handle empty field bodies correctly. |
| | | |
| | |Make TOC input box stick to near top of browser |
| | |window. |
| | | |
| | |Add support for Iconify icons. |
| | | |
| | |Update client-side libraries. |
| | | |
+------------+------------+----------------------------------------------------+
|0.1.0 |03 May 2022 |Released, but yanked due to a search bug. |
+------------+------------+----------------------------------------------------+
|0.0.9 |17 Apr 2020 |Add glossary improvements (allowing permalinks to |
| | |terms, providing tooltips for term definitions). |
| | | |
| | |Allow code blocks with captions to be copied with a |
| | |click. |
| | | |
| | |Provide a means of showing customized tooltips. |
+------------+------------+----------------------------------------------------+
|0.0.8 |16 Oct 2019 |Improved documentation. |
| | | |
| | |Fixed some minor styling nits (e.g. equation |
| | |colors). |
| | | |
| | |Added the 'linktags' block to the layout. |
| | | |
| | |Allowed keyboard navigation without having to click |
| | |on the page first. |
+------------+------------+----------------------------------------------------+
|0.0.7 |10 May 2019 |Improved tarball generation. |
| | | |
| | |Updated documentation, layout, styles and logic. |
+------------+------------+----------------------------------------------------+
|0.0.6 |07 May 2019 |Removed unused files when building documentation. |
| | | |
| | |Improved navigation logic further. |
+------------+------------+----------------------------------------------------+
|0.0.5 |18 Apr 2019 |Updated styles and layout. |
| | | |
| | |Improved navigation logic. |
+------------+------------+----------------------------------------------------+
|0.0.4 |12 Apr 2019 |Updated README. |
| | | |
| | |Added documentation and prepared to dogfood theme. |
| | | |
| | |Made changes to styles, layout and JavaScript code. |
| | | |
| | |Announced on sphinx-users, feedback solicited. |
+------------+------------+----------------------------------------------------+
|0.0.3 |09 Apr 2019 |Made style, layout and JavaScript changes. |
| | | |
| | |Added LICENSE file. |
| | | |
| | |Switched to SCSS for style source. |
+------------+------------+----------------------------------------------------+
|0.0.2 |07 Apr 2019 |Updated README. |
+------------+------------+----------------------------------------------------+
|0.0.1 |07 Apr 2019 |Initial release. |
+------------+------------+----------------------------------------------------+