Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4d524c0
Introduce user_manual.
trexfeathers Dec 12, 2025
cabd701
Reader-level restructure.
trexfeathers Dec 19, 2025
619827d
Add sphinx-needs to dependencies.
trexfeathers Dec 30, 2025
917139c
Add licence header to user_manual_directives.py.
trexfeathers Dec 30, 2025
b85ce62
Merge remote-tracking branch 'upstream/main' into diataxis
trexfeathers Dec 30, 2025
5ab8bfc
Address Sphinx warnings.
trexfeathers Dec 30, 2025
3ca882f
Populate the explanation and how-to directories.
trexfeathers Dec 30, 2025
b6123e2
Populate the reference and tutorial directories.
trexfeathers Dec 30, 2025
39526bd
Fix some references I missed before.
trexfeathers Dec 31, 2025
293131f
Refactor of get_started.
trexfeathers Dec 31, 2025
8b3ee35
Remove defunct IEP directory.
trexfeathers Dec 31, 2025
122f4c2
Itemise all of Iris public API.
trexfeathers Dec 31, 2025
cbf0630
Rendering improvements.
trexfeathers Jan 2, 2026
adf85ca
Itemise all of the Iris docs pages.
trexfeathers Jan 2, 2026
c146081
Itemise all of the Gallery pages.
trexfeathers Jan 2, 2026
ae8e1d9
Topic descriptions.
trexfeathers Jan 6, 2026
fd88e68
user_manual_directives.py code quality.
trexfeathers Jan 6, 2026
a7adaa8
Merge remote-tracking branch 'upstream/main' into diataxis
trexfeathers Jan 6, 2026
3e4ac28
Needs item validation routine.
trexfeathers Jan 9, 2026
cac5e12
Remove column titles.
trexfeathers Jan 9, 2026
9199a06
Fix doctests.
trexfeathers Jan 9, 2026
eddc28b
Merge remote-tracking branch 'upstream/main' into diataxis
trexfeathers Jan 9, 2026
bb8cd62
Implement redirects.
trexfeathers Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/src/_templates/tags_links.need
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{# Render plain clickable text links for each tag #}
{% if tags %}
:strong:`Tags:` {{ " " }} {%- for t in tags -%}
{%- if t and t.startswith('topic_') -%}
:ref:`{{ t }} <{{ t }}>`
{%- else -%}
{{ t }}
{%- endif -%}
{%- if not loop.last %} | {% endif -%}
{%- endfor %}
{% endif %}
56 changes: 56 additions & 0 deletions docs/src/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ def _dotv(version):
"sphinx_gallery.gen_gallery",
"matplotlib.sphinxext.mathmpl",
"matplotlib.sphinxext.plot_directive",
"sphinx_needs",
"user_manual_directives",
]

if skip_api == "1":
Expand Down Expand Up @@ -441,3 +443,57 @@ def reset_modules(gallery_conf, fname):
"section": "Section %s",
"table": "Table %s",
}

# -- sphinx-needs config ------------------------------------------------------
# See https://sphinx-needs.readthedocs.io/en/latest/configuration.html

# TODO: namespace these types as Diataxis for max clarity?
needs_types = [
{
"directive": "tutorial",
"title": "Tutorial",
"prefix": "",
"color": "",
"style": "node",
},
{
"directive": "how-to",
"title": "How To",
"prefix": "",
"color": "",
"style": "node",
},
{
"directive": "explanation",
"title": "Explanation",
"prefix": "",
"color": "",
"style": "node",
},
{
"directive": "reference",
"title": "Reference",
"prefix": "",
"color": "",
"style": "node",
},
]
# The layout whenever a 'need item' directive is used. I.e. at the top of each
# user manual page.
needs_default_layout = "focus"
# IDs must be used in needtables, as the only way to link to the item. Using
# the title makes for the most readable / least jarring links.
needs_id_from_title = True
# The `tags_links` jinja template displays a list of tags where every topic_*
# tag is a link to the relevant section in user_manual/index.rst.
needs_template_folder = "_templates"
needs_global_options = {
"post_template": {"default": "tags_links"},
}

from sphinx_needs.data import NeedsCoreFields

# Known bug in sphinx-needs pre v6.0.
# https://github.com/useblocks/sphinx-needs/issues/1420
if "allow_default" not in NeedsCoreFields["post_template"]:
NeedsCoreFields["post_template"]["allow_default"] = "str"
24 changes: 0 additions & 24 deletions docs/src/further_topics/index.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/src/further_topics/ux_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Reviewing the Iris User Experience
**********************************

.. todo:: https://github.com/SciTools/iris/issues/6511; this page belongs in 'Explanation'
.. todo:: https://github.com/SciTools/iris/issues/6867; this page belongs in 'Get Involved'

Often, improving and updating the existing user experience can fall behind fixing create new features,
or quashing pesky bugs. To combat this, we plan to have regular development discussions to ensure
Expand Down
19 changes: 5 additions & 14 deletions docs/src/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ For more information see :ref:`why_iris`.
plotting and more.

+++
.. button-ref:: user_guide_index
.. button-ref:: user_manual_index
:ref-type: ref
:color: primary
:outline:
:expand:

User Guide
User Manual

.. grid-item-card::
:text-align: center
Expand Down Expand Up @@ -159,12 +159,12 @@ The legacy support resources:


.. toctree::
:caption: User Guide
:caption: User Manual
:maxdepth: 1
:name: userguide_index
:name: user_manual
:hidden:

userguide/index
user_manual/index


.. toctree::
Expand All @@ -176,15 +176,6 @@ The legacy support resources:
developers_guide/contributing_getting_involved


.. toctree::
:caption: Community
:maxdepth: 1
:name: community_index
:hidden:

Community <community/index>


.. toctree::
:caption: What's New in Iris
:maxdepth: 1
Expand Down
145 changes: 145 additions & 0 deletions docs/src/sphinxext/user_manual_directives.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Copyright Iris contributors
#
# This file is part of Iris and is released under the BSD license.
# See LICENSE in the root of the repository for full licensing details.
# TODO: header
# TODO: docstrings/comments. How to document an extension/directive?
# TODO: linting

# TODO: include a validation routine, calling to sphinx-needs to confirm that
# all User Manual pages have the minimum metadata.
# - sphinx-need directive
# - :tags: including a topic_xxx tag
# - think sphinx-needs will already insist on a valid type?
# - think sphinx-needs will already insist on a title?
# - think sphinx-needs will already insist on a description?
# - as it stands this would exclude all section indexes, unless the section
# indexes get their own Diataxis tab.

from pathlib import Path
import enum
import re

from docutils import nodes # type: ignore[import-untyped]
from docutils.parsers.rst import Directive # type: ignore[import-untyped]
from docutils.statemachine import StringList # type: ignore[import-untyped]


class Diataxis(enum.StrEnum):
# TODO: should user manual section indexes also get their own Diataxis tab?
# This would allow topic-based filtering, and allow all pages to be found
# through the same route.

ALL = "all"
TUTORIAL = "tutorial"
HOW_TO = "how-to"
REFERENCE = "reference"
EXPLANATION = "explanation"


DIATAXIS_CAPTIONS = {
Diataxis.TUTORIAL: "Guided lessons for understanding a topic. (Supports **study**, via **action**)",
Diataxis.HOW_TO: "Step by step instructions for achieving a specific goal. (Supports **work**, via **action**)",
Diataxis.EXPLANATION: "In-depth discussion for understanding concepts. (Supports **study**, via **theory**)",
Diataxis.REFERENCE: "Concise information to look up when needed. (Supports **work**, via **theory**)",
}


class DiataxisDirective(Directive):
has_content = True

@staticmethod
def _indent(text: str) -> str:
indented = [" " + line for line in text.splitlines()]
return "\n".join(indented)

def _needtable(self, types: Diataxis, tags: str) -> str:
options = [
':columns: id as "Link";title;content as " "',
":colwidths: 10;30;60",
":style: table",
":filter_warning: No pages for this filter.",
]
# TODO: should the table somehow include what section the page belongs
# to? This isn't standard sphinx-needs metadata so would need
# `needs_extra_options` in conf.py.
if types is not Diataxis.ALL:
options.append(f":types: {types}")
# TODO: is looking for `topic_all` brittle hard-coding?
if tags != "topic_all":
options.append(f":tags: {tags}")
options_str = "\n".join(options)
needtable = "\n".join([
".. needtable::",
self._indent(options_str),
])
return needtable

def _tab_item(self, diataxis: Diataxis, tags: str) -> str:
needtable = self._needtable(types=diataxis, tags=tags)
tab_item_title = diataxis.capitalize()
# TODO: should there be a caption for ALL as well? Even if that's just
# for visual consistency.
caption = DIATAXIS_CAPTIONS.get(diataxis, "")
if diataxis is not Diataxis.ALL:
tab_item_title += "s"
content = [
f":sync: {diataxis}",
"",
caption,
"",
needtable,
]
content_str = "\n".join(content)
tab_item = "\n".join([
f".. tab-item:: {tab_item_title}",
self._indent(content_str),
])
return tab_item

def run(self):
rst_path = Path(self.state.document['source'])
# user_manual.index.rst
if not (rst_path.parent.name == "user_manual" and rst_path.name == "index.rst"):
message = "Expected directive to only be used in user_manual/index.rst"
error = self.state_machine.reporter.error(
message, line=self.lineno
)
return [error]
label_pattern = re.compile(r"^\.\. _(topic_.+):$", re.MULTILINE)
topic_labels = label_pattern.findall(rst_path.read_text())
badges = {
label: "bdg-ref-primary" if label == self.content[0] else "bdg-ref-primary-line"
for label in topic_labels
}
# Parse the badges as RST.
node = nodes.Element()
self.state.nested_parse(
StringList([f":{badge}:`{label}`" for label, badge in badges.items()]),
self.content_offset,
node
)

tab_items = [
self._tab_item(diataxis=diataxis, tags=self.content[0])
for diataxis in Diataxis
]
tab_items_str = "\n\n".join(tab_items)
tab_set = "\n".join([
".. tab-set::",
"",
self._indent(tab_items_str),
])
# Parse the tab set as RST.
self.state.nested_parse(
StringList(tab_set.splitlines()),
self.content_offset,
node
)

return node.children


def setup(app):
app.add_directive("diataxis-page-list", DiataxisDirective)
return {"version": "0.1"}
83 changes: 83 additions & 0 deletions docs/src/user_manual/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.. comment:
now that User Manual is the official top-level, and the User Guide is a
sub-section, the original labels have been relocated here.

.. _user_guide_index:
.. _user_guide_introduction:
.. _user_manual_index:

User Manual
===========

Welcome to the Iris User Manual!

We encourage exploring our User Manual pages using the tabbed sections below,
which combine the `Diataxis`_ framework and topic-based filters to find content
best suited to your purpose today. Alternatively, you can use the sidebar to
navigate by section.

.. todo:
Should the sections also be offered as another Diataxis tab? This would allow
topic-based filtering, and allow all pages to be found through the same
route.

.. comment:
The tree structure for user_manual is specified here. As mentioned in the
text, we prefer readers to use the tabbed sections below, so the toctree is
hidden - not rendered in the text, only in the sidebar. This toctree is
expected to be exclusively section_indexes/* pages; with those pages
providing the remaining sub-structure.


.. toctree::
:maxdepth: 1
:hidden:

section_indexes/userguide
section_indexes/dask_best_practices
section_indexes/mesh_support
section_indexes/metadata_arithmetic
section_indexes/community
section_indexes/general

.. _topic_all:

All
---

.. diataxis-page-list:: topic_all

By Topic
--------

.. _topic_data_model:

topic: ``data_model``
^^^^^^^^^^^^^^^^^^^^^

Pages about the :class:`~iris.cube.Cube` class and its associated components
such as :class:`~iris.coords.Coord` and :class:`~iris.mesh.Mesh`.

.. diataxis-page-list:: topic_data_model

.. _topic_load_save:

topic: ``load_save``
^^^^^^^^^^^^^^^^^^^^

Pages about reading from files into the data model, and writing from the data
model to files.

.. diataxis-page-list:: topic_load_save

.. _topic_lazy_data:

topic: ``lazy_data``
^^^^^^^^^^^^^^^^^^^^

Pages about Iris' implementation of parallel and out-of-core data handling, via
Dask. See :term:`Lazy Data`.

.. diataxis-page-list:: topic_lazy_data

.. _Diataxis: https://diataxis.fr/
Loading
Loading