diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 800cecda4..0070f87e3 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -2,7 +2,7 @@ .button-primary, .button-alt, -div.sphx-glr-download a { +.napari-gallery-downloads .sphx-glr-download a { background-image: none !important; border-radius: 4px; text-align: center; @@ -15,14 +15,14 @@ div.sphx-glr-download a { } /* Allow border override to show through on example buttons */ -div.sphx-glr-download a { +.napari-gallery-downloads .sphx-glr-download a { border: 1px solid transparent; display: inline-block; padding: 0.45rem 0.8rem; } /* force sphinx-gallery download code to inherit text color */ -div.sphx-glr-download a code.download { +.napari-gallery-downloads .sphx-glr-download a code.download { color: inherit !important; } @@ -39,28 +39,36 @@ div.sphx-glr-download a code.download { margin: 0; } +/* Remove the sphinx-gallery downloads note and buttons */ +.sphx-glr-download-link-note, +.sphx-glr-download-jupyter, +.sphx-glr-download-python, +.sphx-glr-download-zip { + display: none; +} + html[data-theme="light"] .button-primary, -html[data-theme="light"] div.sphx-glr-download a { +html[data-theme="light"] .napari-gallery-downloads .sphx-glr-download a { background-color: var(--napari-primary-blue) !important; border-color: var(--napari-primary-blue) !important; color: var(--napari-color-text-base) !important; } html[data-theme="dark"] .button-primary, -html[data-theme="dark"] div.sphx-glr-download a { +html[data-theme="dark"] .napari-gallery-downloads .sphx-glr-download a { background-color: var(--napari-purple) !important; border-color: var(--napari-purple) !important; color: var(--napari-color-text-base) !important; } html[data-theme="light"] .button-primary:hover, -html[data-theme="light"] div.sphx-glr-download a:hover { +html[data-theme="light"] .napari-gallery-downloads .sphx-glr-download a:hover { background-color: color-mix(in srgb, var(--napari-primary-blue), transparent 25%) !important; text-decoration: underline; } html[data-theme="dark"] .button-primary:hover, -html[data-theme="dark"] div.sphx-glr-download a:hover { +html[data-theme="dark"] .napari-gallery-downloads .sphx-glr-download a:hover { background-color: color-mix(in srgb, var(--napari-purple), transparent 25%) !important; text-decoration: underline; } @@ -239,4 +247,4 @@ html[data-theme="dark"] .homepage-quicklinks a { html[data-theme="dark"] img#homepage-featured-example-image { background-color: var(--pst-color-background) !important; -} \ No newline at end of file +} diff --git a/docs/conf.py b/docs/conf.py index 569b5b0da..581ae0907 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -396,6 +396,53 @@ def napari_scraper(block, block_vars, gallery_conf): return scrapers.figure_rst(img_paths, gallery_conf['src_dir']) +GALLERY_METADATA_END_RE = re.compile( + r'^\.\. GENERATED FROM PYTHON SOURCE LINES \d+-\d+\s*$', re.MULTILINE +) + + +def add_gallery_download_buttons(app, docname, source): + """Add compact download links near the top of generated gallery examples. + + Sphinx-Gallery emits the example title first, followed by the short + description and tags, and only then the ``GENERATED FROM PYTHON SOURCE`` + marker. Insert the links just before that first marker so they stay below + the description metadata without overriding Sphinx-Gallery templates. + """ + if not docname.startswith('gallery/'): + return + if docname.endswith('/index') or docname.endswith('sg_execution_times'): + return + + content = source[0] + if 'THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.' not in content: + return + + example_name = Path(docname).name + metadata_end_match = GALLERY_METADATA_END_RE.search(content) + if metadata_end_match is None: + return + + download_block = f""" +.. only:: html + + .. container:: napari-gallery-downloads + + .. container:: sphx-glr-download + + :download:`Python (.py) <{example_name}.py>` + + .. container:: sphx-glr-download + + :download:`Notebook (.ipynb) <{example_name}.ipynb>` +""" + source[0] = ( + content[: metadata_end_match.start()] + + download_block + + content[metadata_end_match.start() :] + ) + + gen_rst.EXAMPLE_HEADER = """ .. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. @@ -403,15 +450,6 @@ def napari_scraper(block, block_vars, gallery_conf): .. "{0}" .. LINE NUMBERS ARE GIVEN BELOW. -.. only:: html - - .. note:: - :class: sphx-glr-download-link-note - - :ref:`Go to the end ` - to download the full example as a Python script or as a - Jupyter notebook.{2} - .. rst-class:: sphx-glr-example-title .. _sphx_glr_{1}: @@ -549,6 +587,7 @@ def setup(app): """ app.registry.source_suffix.pop('.ipynb', None) app.connect('source-read', add_google_calendar_secrets) + app.connect('source-read', add_gallery_download_buttons) app.connect('linkcheck-process-uri', rewrite_github_anchor) app.connect('autodoc-process-docstring', qt_docstrings) diff --git a/docs/gallery.md b/docs/gallery.md index c14dfa8a4..961d8d394 100644 --- a/docs/gallery.md +++ b/docs/gallery.md @@ -4,9 +4,17 @@ Examples of napari usage. -All examples in this gallery can be downloaded as Python scripts or Jupyter -notebooks to be executed locally. Check out [](launch-jupyter) for more details -on using napari in Jupyter notebooks. +Each example page includes downloads for both the source `.py` file and a +generated Jupyter notebook. If you download the Python script, you can run it +with `napari path/to/my_example.py` or drag the `.py` file onto a running napari viewer +to execute it there. Some examples may require additional dependencies beyond +napari itself, so be sure to check the example's source code for any additional +requirements if you see an error when trying to run it. +Check out [](launch-jupyter) for more details on using +napari in Jupyter notebooks. + +Use the tag index below to browse examples by topic, or jump straight into the +gallery grid. ```{note}