diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..e8ad847b8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,11 @@ +// container instruction for codespace users +{ + "name": "Python 3", + "image": "mcr.microsoft.com/devcontainers/python:1-3.10-bullseye", + "features": { + "ghcr.io/devcontainers-contrib/features/nox:2": {}, + "ghcr.io/devcontainers-contrib/features/pre-commit:2": {}, + "ghcr.io/rocker-org/devcontainer-features/pandoc:1": {} + }, + "postCreateCommand": "pre-commit install" +} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b1d514cc8..fe88d592f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -137,6 +137,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + # waiting for https://github.com/nikeee/setup-pandoc/pull/8 + # using 12rambau fork until then + - uses: 12rambau/setup-pandoc@test - name: Setup Python uses: actions/setup-python@v4 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b5e3aa41..cf0f3e0f2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,3 +38,8 @@ repos: rev: v1.1.1 hooks: - id: doc8 + + - repo: "https://github.com/kynan/nbstripout" + rev: "0.5.0" + hooks: + - id: nbstripout diff --git a/docs/community/setup.md b/docs/community/setup.md index 6b0747666..309e53ece 100644 --- a/docs/community/setup.md +++ b/docs/community/setup.md @@ -42,6 +42,7 @@ To simplify this process, we use a few helper tools: - [The Sphinx Theme Builder](https://sphinx-theme-builder.readthedocs.io/en/latest/) compiles web assets in an automated way. - [pre-commit](https://pre-commit.com/) for automatically enforcing code standards and quality checks before commits. - [nox](https://nox.thea.codes/) for automating common development tasks. +- [pandoc](https://pandoc.org/) the universal document converter. In particular, `nox` can be used to automatically create isolated local development environments with all the correct packages installed to work on the theme. The rest of this guide focuses on using `nox` to start with a basic environment. diff --git a/docs/community/topics/manual-dev.md b/docs/community/topics/manual-dev.md index 35964d5cc..2b05d5888 100644 --- a/docs/community/topics/manual-dev.md +++ b/docs/community/topics/manual-dev.md @@ -12,22 +12,26 @@ This is optional, but it's best to start with a fresh development environment so To do so, use a tool like [conda](https://docs.conda.io/en/latest/), [mamba](https://github.com/mamba-org/mamba), or [virtualenv](https://virtualenv.pypa.io/). -## Clone the repository locally +## Install dependencies -First clone this repository from the `pydata` organization, or from a fork that you have created: +You must install `sphinx-theme-builder` and Pandoc. + +We use the `sphinx-theme-builder` to install `nodejs` locally and to compile all CSS and JS assets needed for the theme. +Install it like so (note the `cli` option so that we can run it from the command line): ```console -$ git clone https://github.com/pydata/pydata-sphinx-theme -$ cd pydata-sphinx-theme +$ pip install "sphinx-theme-builder[cli]" ``` -## Install the `sphinx-theme-builder` +We use `nbsphinx` to support notebook (.ipynb) files in the documentation, which requires [installing Pandoc](https://pandoc.org/installing.html) at a system level (or within a Conda environment). -We use the `sphinx-theme-builder` to install `nodejs` locally and to compile all CSS and JS assets needed for the theme. -Install it like so (note the `cli` option so that we can run it from the command line): +## Clone the repository locally + +First clone this repository from the `pydata` organization, or from a fork that you have created: ```console -$ pip install sphinx-theme-builder[cli] +$ git clone https://github.com/pydata/pydata-sphinx-theme +$ cd pydata-sphinx-theme ``` ## Install this theme locally @@ -35,7 +39,7 @@ $ pip install sphinx-theme-builder[cli] Next, install this theme locally so that we have the necessary dependencies to build the documentation and testing suite: ```console -$ pip install -e .[dev] +$ pip install -e ".[dev]" ``` Note that the `sphinx-theme-builder` will automatically install a local copy of `nodejs` for building the theme's assets. diff --git a/docs/conf.py b/docs/conf.py index 572cff558..8501b0210 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,15 +34,15 @@ "sphinx_design", "sphinx_copybutton", "autoapi.extension", + # custom extentions "_extension.gallery_directive", "_extension.component_directive", # For extension examples and demos + "myst_parser", "ablog", "jupyter_sphinx", - "matplotlib.sphinxext.plot_directive", - "myst_nb", "sphinxcontrib.youtube", - # "nbsphinx", # Uncomment and comment-out MyST-NB for local testing purposes. + "nbsphinx", "numpydoc", "sphinx_togglebutton", "jupyterlite_sphinx", @@ -67,11 +67,6 @@ sitemap_locales = [None] sitemap_url_scheme = "{link}" -# -- Internationalization ---------------------------------------------------- - -# specifying the natural language populates some key tags -language = "en" - # -- MyST options ------------------------------------------------------------ # This allows us to use ::: to denote directives, useful for admonitions @@ -79,6 +74,11 @@ myst_heading_anchors = 2 myst_substitutions = {"rtd": "[Read the Docs](https://readthedocs.org/)"} +# -- Internationalization ---------------------------------------------------- + +# specifying the natural language populates some key tags +language = "en" + # -- Ablog options ----------------------------------------------------------- blog_path = "examples/blog/index" @@ -100,19 +100,21 @@ # Define the version we use for matching in the version switcher. version_match = os.environ.get("READTHEDOCS_VERSION") +release = pydata_sphinx_theme.__version__ # If READTHEDOCS_VERSION doesn't exist, we're not on RTD # If it is an integer, we're in a PR build and the version isn't correct. # If it's "latest" → change to "dev" (that's what we want the switcher to call it) if not version_match or version_match.isdigit() or version_match == "latest": # 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 = "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" else: - version_match = "v" + release + version_match = f"v{release}" +elif version_match == "stable": + version_match = f"v{release}" html_theme_options = { "external_links": [ @@ -160,28 +162,28 @@ "logo": { "text": "PyData Theme", "image_dark": "_static/logo-dark.svg", - "alt_text": "PyData Theme", }, "use_edit_page_button": True, "show_toc_level": 1, "navbar_align": "left", # [left, content, right] For testing that the navbar items align properly - "navbar_center": ["version-switcher", "navbar-nav"], + # "show_nav_level": 2, "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_center": ["version-switcher", "navbar-nav"], # "navbar_start": ["navbar-logo"], # "navbar_end": ["theme-switcher", "navbar-icon-links"], # "navbar_persistent": ["search-button"], - # "primary_sidebar_end": ["custom-template.html", "sidebar-ethical-ads.html"], - # "article_footer_items": ["test.html", "test.html"], - # "content_footer_items": ["test.html", "test.html"], - "footer_start": ["copyright.html"], - "footer_center": ["sphinx-version.html"], - # "secondary_sidebar_items": ["page-toc.html"], # Remove the source buttons + # "primary_sidebar_end": ["custom-template", "sidebar-ethical-ads"], + # "article_footer_items": ["test", "test"], + # "content_footer_items": ["test", "test"], + "footer_start": ["copyright"], + "footer_center": ["sphinx-version"], + # "secondary_sidebar_items": ["page-toc"], # Remove the source buttons "switcher": { "json_url": json_url, "version_match": version_match, }, + "navigation_with_keys": False, # "search_bar_position": "navbar", # TODO: Deprecated - remove in future version } diff --git a/docs/examples/gallery.md b/docs/examples/gallery.md index e344ee969..888b6d416 100644 --- a/docs/examples/gallery.md +++ b/docs/examples/gallery.md @@ -43,4 +43,6 @@ Thanks for your support! link: https://docs.pyvista.org - title: Pastas link: https://pastas.readthedocs.io/ +- title: DecentralChain + link: https://docs.decentralchain.io/en/master/ ``` diff --git a/docs/examples/pydata.ipynb b/docs/examples/pydata.ipynb new file mode 100644 index 000000000..742a0b7c3 --- /dev/null +++ b/docs/examples/pydata.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PyData Library Styles\n", + "\n", + "This theme has built-in support and special styling for several major visualization libraries in the PyData ecosystem.\n", + "This ensures that the images and output generated by these libraries looks good for both light and dark modes.\n", + "Below are examples of each that we use as a benchmark for reference.\n", + "\n", + "## Pandas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import string\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "rng = np.random.default_rng()\n", + "data = rng.standard_normal((100, 26))\n", + "df = pd.DataFrame(data, columns=list(string.ascii_lowercase))\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.scatter(df[\"a\"], df[\"b\"], c=df[\"b\"], s=3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rng = np.random.default_rng()\n", + "data = rng.standard_normal((3, 100))\n", + "fig, ax = plt.subplots()\n", + "ax.scatter(data[0], data[1], c=data[2], s=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotly\n", + "\n", + "The HTML below shouldn't display, but it uses RequireJS to make sure that all\n", + "works as expected. If the widgets don't show up, RequireJS may be broken." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.io as pio\n", + "import plotly.express as px\n", + "import plotly.offline as py\n", + "\n", + "pio.renderers.default = \"notebook\"\n", + "\n", + "df = px.data.iris()\n", + "fig = px.scatter(df, x=\"sepal_width\", y=\"sepal_length\", color=\"species\", size=\"sepal_length\")\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Xarray\n", + "\n", + "Here we demonstrate `xarray` to ensure that it shows up properly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import xarray as xr\n", + "data = xr.DataArray(\n", + " np.random.randn(2, 3),\n", + " dims=(\"x\", \"y\"),\n", + " coords={\"x\": [10, 20]}, attrs={\"foo\": \"bar\"}\n", + " )\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ipyleaflet\n", + "\n", + "`ipyleaflet` is a **Jupyter**/**Leaflet** bridge enabling interactive maps in the Jupyter notebook environment. this demonstrate how you can integrate maps in your documentation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipyleaflet import Map, basemaps\n", + "\n", + "# display a map centered on France\n", + "m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[46.21, 2.21])\n", + "m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/examples/pydata.md b/docs/examples/pydata.md deleted file mode 100644 index e31a90905..000000000 --- a/docs/examples/pydata.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -file_format: mystnb -kernelspec: - name: python3 - display_name: Python 3 ---- - -% To test this file with nbsphinx we need to convert to ipynb. To do this: -% - Run this command: jupytext docs/examples/pydata.md --to ipynb -% - _Temporarily_ delete the pydata.md file -% - Uncomment `nbsphinx` and comment `myst_nb` in "extensions" in our conf.py file -% - Build the docs and test that the results look OK -% - Undo everything in this list to make sure we revert back to the old structure - -# PyData Library Styles - -This theme has built-in support and special styling for several major visualization libraries in the PyData ecosystem. -This ensures that the images and output generated by these libraries looks good for both light and dark modes. -Below are examples of each that we use as a benchmark for reference. - -## Pandas - -```{code-cell} -import string - -import numpy as np -import pandas as pd - -rng = np.random.default_rng() -data = rng.standard_normal((100, 26)) -df = pd.DataFrame(data, columns=list(string.ascii_lowercase)) -df -``` - -## Matplotlib - -```{sidebar} -Here's a sidebar to test that the code cells behave as we'd expect when there is content to the right. The code cell should be displayed to the left and with no overlap. -``` - -```{code-cell} -import matplotlib.pyplot as plt - -fig, ax = plt.subplots() -ax.scatter(df["a"], df["b"], c=df["b"], s=3) -``` - -and with the Matplotlib `plot` directive: - -```{eval-rst} -.. plot:: - - import matplotlib.pyplot as plt - import numpy as np - rng = np.random.default_rng() - data = rng.standard_normal((3, 100)) - fig, ax = plt.subplots() - ax.scatter(data[0], data[1], c=data[2], s=3) -``` - -## Plotly - -The HTML below shouldn't display, but it uses RequireJS to make sure that all -works as expected. If the widgets don't show up, RequireJS may be broken. - -```{code-cell} -import plotly.io as pio -import plotly.express as px -import plotly.offline as py - -pio.renderers.default = "notebook" - -df = px.data.iris() -fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species", size="sepal_length") -fig -``` - -## Xarray - -Here we demonstrate `xarray` to ensure that it shows up properly. - -```{code-cell} -import xarray as xr -data = xr.DataArray( - np.random.randn(2, 3), - dims=("x", "y"), - coords={"x": [10, 20]}, attrs={"foo": "bar"} - ) -data -``` - -## ipyleaflet - -`ipyleaflet` is a **Jupyter**/**Leaflet** bridge enabling interactive maps in the Jupyter notebook environment. this demonstrate how you can integrate maps in your documentation. - -```{code-cell} -from ipyleaflet import Map, basemaps - -# display a map centered on France -m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[46.21, 2.21]) -m -``` diff --git a/docs/user_guide/branding.rst b/docs/user_guide/branding.rst index 43402e8b6..40ba7b2d2 100644 --- a/docs/user_guide/branding.rst +++ b/docs/user_guide/branding.rst @@ -77,40 +77,67 @@ To reference an external website, make sure your link starts with ``http``: } } -Customize logo alternative text +Logo title and alternative text ------------------------------- -You may set a custom ``alt text`` for your logo to replace the default ``"logo image"`` generic description. -Adding a descriptive ``alt text`` can help make your documentation more accessible to readers using screen readers or another assistive tech. - -To do so, customize the ``html_theme_options["logo"]["alt_text"]`` configuration option as in the following example: +If you provide a logo image, it replaces ``project`` or ``html_title`` in the +header nav bar. If you want to display both your site's logo and title (or any +other text) next to the logo, you provide it with the ``text`` property like so: .. code-block:: python :caption: conf.py html_theme_options = { "logo": { - # Because the logo is also a homepage link, including "home" in the alt text is good practice - "alt_text": "My Project Name - Home", + "text": "My awesome documentation", + "image_light": "_static/logo-light.png", + "image_dark": "_static/logo-dark.png", } } -Add a logo title ----------------- - -To add a title in the brand section of your documentation, define a value for ``html_theme_options.logo["text"]``. -This title will appear next to the logo image if set. +But if you only want to display the logo and not the site title, then it's good +practice to provide alt text, which helps blind visitors and others who rely on +screen readers: .. code-block:: python + :caption: conf.py html_theme_options = { "logo": { - "text": "My awesome documentation", + # Because the logo is also a homepage link, including "home" in the + # alt text is good practice + "alt_text": "My awesome documentation - Home", + "image_light": "_static/logo-light.png", + "image_dark": "_static/logo-dark.png", } } -.. note:: The ``html_title`` field will work as well if no logo images are specified. +In most cases, you will provide either ``text`` or ``alt_text``, not both, but +there are some circumstances in which it may make sense to provide both: + +.. code-block:: python + :caption: conf.py + + html_theme_options = { + "logo": { + # In a left-to-right context, screen readers will read the alt text + # first, then the text, so this example will be read as "P-G-G-P-Y + # (short pause) Home A pretty good geometry package" + "alt_text": "PggPy - Home", + "text": "A pretty good geometry package", + "image_light": "_static/logo-light.png", + "image_dark": "_static/logo-dark.png", + } + } +If you do not provide ``text`` or ``alt_text``, the theme will provide some +default alt text (otherwise, your homepage link would appear to assistive tech +as something like "Unlabeled image"). The default alt text is "`docstitle +`_ - +Home", but if you provide a logo title (``text``) the default alt text will be an +empty string (the assumption is that if you provide a logo title, the title is +probably doing the work of the alt text, and as shown above, you can override +this assumption by supplying both ``text`` and ``alt_text``). Add favicons ============ diff --git a/docs/user_guide/keyboard-shortcuts.md b/docs/user_guide/keyboard-shortcuts.md index c163d47d4..42bfeb93e 100644 --- a/docs/user_guide/keyboard-shortcuts.md +++ b/docs/user_guide/keyboard-shortcuts.md @@ -3,18 +3,3 @@ ## Trigger the search bar You can trigger the search bar pop-up with {kbd}`Ctrl`/{kbd}`⌘` + {kbd}`K`. - -## Change pages - -By default, you can move to the previous/next page using the {octicon}`arrow-left` (left arrow) and {octicon}`arrow-right` (right arrow) keys on a keyboard. -To disable this behavior, use the following configuration: - -```py -html_theme_options = { - "navigation_with_keys": False -} -``` - -```{attention} -Keep in mind that many readers use their keyboards and other assistive technology to interact with web documents. If you disable the keyboard navigation, you might be making your documentaion inaccessible to many readers. -``` diff --git a/docs/user_guide/theme-elements.md b/docs/user_guide/theme-elements.md index 919be251d..06e905224 100644 --- a/docs/user_guide/theme-elements.md +++ b/docs/user_guide/theme-elements.md @@ -161,7 +161,7 @@ In Python you can {python}`import sphinx`. ## Code execution This theme has support for Jupyter execution libraries so that you can programmatically update your documentation with each build. -For examples, see [](../examples/pydata.md). +For examples, see [](../examples/pydata.ipynb). ## Admonition sidebars diff --git a/docs/user_guide/web-components.rst b/docs/user_guide/web-components.rst index 54bae0db5..7a96cb355 100644 --- a/docs/user_guide/web-components.rst +++ b/docs/user_guide/web-components.rst @@ -17,8 +17,8 @@ Below you can find some examples of the components created with the :code:`sphin .. _badges-buttons: -Badges and buttons -================== +Badges and button-links +======================= Here are some of the available badges: @@ -29,7 +29,7 @@ Here are some of the available badges: :bdg-secondary-line:`secondary outline` :bdg-success-line:`success outline` -Here are some of the available buttons, also using semantic colors: +Here are some of the available button-style links, also using semantic colors: .. grid:: auto @@ -96,6 +96,16 @@ Here are some of the available buttons, also using semantic colors: Dark +.. note:: + + `Sphinx Design buttons + `__ + are actually links, meaning they are rendered in HTML with ```` tags + instead of ``