Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add collapsible option to admonition directives #12507

Merged
merged 14 commits into from
Jan 29, 2025
106 changes: 83 additions & 23 deletions doc/_themes/sphinx13/static/sphinx13.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
--icon-warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 14h-2v-4h2m0 8h-2v-2h2M1 21h22L12 2 1 21z"/></svg>');
--icon-failure: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12 6.47 2 12 2m3.59 5L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41 15.59 7z"/></svg>');
--icon-spark: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.5 20l4.86-9.73H13V4l-5 9.73h3.5V20M12 2c2.75 0 5.1 1 7.05 2.95C21 6.9 22 9.25 22 12s-1 5.1-2.95 7.05C17.1 21 14.75 22 12 22s-5.1-1-7.05-2.95C3 17.1 2 14.75 2 12s1-5.1 2.95-7.05C6.9 3 9.25 2 12 2z"/></svg>');

/* icons used for details summaries */
--icon-details-open: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z"/></svg>');
}

body {
Expand Down Expand Up @@ -409,7 +412,7 @@ table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}

div.admonition, div.warning {
div.admonition, div.warning, details.admonition {
font-size: 0.9em;
margin: 1em 0 1em 0;
border: 1px solid #86989B;
Expand All @@ -418,16 +421,16 @@ div.admonition, div.warning {
padding: 1rem;
}

div.admonition > p, div.warning > p {
div.admonition > p, div.warning > p, details.admonition > p {
margin: 0;
padding: 0;
}

div.admonition > pre, div.warning > pre {
div.admonition > pre, div.warning > pre, details.admonition > pre {
margin: 0.4em 1em 0.4em 1em;
}

div.admonition > p.admonition-title {
div.admonition > p.admonition-title, details.admonition > summary.admonition-title {
position: relative;
font-weight: 500;
background-color: var(--color-admonition-bg);
Expand All @@ -436,33 +439,78 @@ div.admonition > p.admonition-title {
border-radius: var(--admonition-radius) var(--admonition-radius) 0 0;
}

details.admonition:not([open]) {
padding-bottom: 0;
}
details.admonition > summary.admonition-title {
list-style: none;
cursor: pointer;
padding-right: .5rem;
}
details.admonition > summary.admonition-title::after {
background-color: currentcolor;
content: "";
height: 1.2rem;
width: 1.2rem;
-webkit-mask-image: var(--icon-details-open);
mask-image: var(--icon-details-open);
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
transform: rotate(0deg);
transition: transform .25s;
float: right;
}
details.admonition[open] > summary.admonition-title::after {
transform: rotate(90deg);
}
details.admonition:not([open]) > summary.admonition-title {
margin-bottom: 0;
border-radius: var(--admonition-radius);
}

div.attention > p.admonition-title,
div.danger > p.admonition-title,
div.error > p.admonition-title {
div.error > p.admonition-title,
details.attention > summary.admonition-title,
details.danger > summary.admonition-title,
details.error > summary.admonition-title {
background-color: var(--colour-error-bg);
}

div.important > p.admonition-title,
div.caution > p.admonition-title,
div.warning > p.admonition-title {
div.warning > p.admonition-title,
details.important > summary.admonition-title,
details.caution > summary.admonition-title,
details.warning > summary.admonition-title {
background-color: var(--colour-warning-bg);
}

div.note > p.admonition-title {
div.note > p.admonition-title,
details.note > summary.admonition-title {
background-color: var(--colour-note-bg);
}

div.hint > p.admonition-title,
div.tip > p.admonition-title,
div.seealso > p.admonition-title {
div.seealso > p.admonition-title,
details.hint > summary.admonition-title,
details.tip > summary.admonition-title,
details.seealso > summary.admonition-title {
background-color: var(--colour-success-bg);
}

div.admonition-todo > p.admonition-title {
div.admonition-todo > p.admonition-title,
details.admonition-todo > summary.admonition-title {
background-color: var(--colour-todo-bg);
}

p.admonition-title::before {
p.admonition-title::before,
summary.admonition-title::before {
content: "";
height: 1rem;
left: .5rem;
Expand All @@ -472,69 +520,81 @@ p.admonition-title::before {
background-color: #5f5f5f;
}

div.admonition > p.admonition-title::before {
div.admonition > p.admonition-title::before,
details.admonition > summary.admonition-title::before {
background-color: var(--color-admonition-fg);
-webkit-mask-image: var(--icon-abstract);
mask-image: var(--icon-abstract);
}
div.attention > p.admonition-title::before {
div.attention > p.admonition-title::before,
details.attention > summary.admonition-title::before {
background-color: var(--colour-error-fg);
-webkit-mask-image: var(--icon-warning);
mask-image: var(--icon-warning);
}
div.caution > p.admonition-title::before {
div.caution > p.admonition-title::before,
details.caution > summary.admonition-title::before {
background-color: var(--colour-warning-fg);
-webkit-mask-image: var(--icon-spark);
mask-image: var(--icon-spark);
}
div.danger > p.admonition-title::before {
div.danger > p.admonition-title::before,
details.danger > summary.admonition-title::before {
background-color: var(--colour-error-fg);
-webkit-mask-image: var(--icon-spark);
mask-image: var(--icon-spark);
}
div.error > p.admonition-title::before {
div.error > p.admonition-title::before,
details.error > summary.admonition-title::before {
background-color: var(--colour-error-fg);
-webkit-mask-image: var(--icon-failure);
mask-image: var(--icon-failure);
}
div.hint > p.admonition-title::before {
div.hint > p.admonition-title::before,
details.hint > summary.admonition-title::before {
background-color: var(--colour-success-fg);
-webkit-mask-image: var(--icon-question);
mask-image: var(--icon-question);
}
div.important > p.admonition-title::before {
div.important > p.admonition-title::before,
details.important > summary.admonition-title::before {
background-color: var(--colour-warning-fg);
-webkit-mask-image: var(--icon-flame);
mask-image: var(--icon-flame);
}
div.note > p.admonition-title::before {
div.note > p.admonition-title::before,
details.note > summary.admonition-title::before {
background-color: var(--colour-note-fg);
-webkit-mask-image: var(--icon-pencil);
mask-image: var(--icon-pencil);
}
div.seealso > p.admonition-title::before {
div.seealso > p.admonition-title::before,
details.seealso > summary.admonition-title::before {
background-color: var(--colour-success-fg);
-webkit-mask-image: var(--icon-info);
mask-image: var(--icon-info);
}
div.tip > p.admonition-title::before {
div.tip > p.admonition-title::before,
details.tip > summary.admonition-title::before {
background-color: var(--colour-success-fg);
-webkit-mask-image: var(--icon-info);
mask-image: var(--icon-info);
}
div.admonition-todo > p.admonition-title::before {
div.admonition-todo > p.admonition-title::before,
details.admonition-todo > summary.admonition-title::before {
background-color: var(--colour-todo-fg);
-webkit-mask-image: var(--icon-pencil);
mask-image: var(--icon-pencil);
}
div.warning > p.admonition-title::before {
div.warning > p.admonition-title::before,
details.warning > summary.admonition-title::before {
background-color: var(--colour-warning-fg);
-webkit-mask-image: var(--icon-warning);
mask-image: var(--icon-warning);
}
div.caution,
div.important,
div.warning {
div.warning, details.warning {
border-color: var(--colour-warning-fg);
}
div.attention,
Expand Down
48 changes: 48 additions & 0 deletions doc/usage/restructuredtext/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,54 @@ and the generic :rst:dir:`admonition` directive.
Documentation for tar archive files, including GNU tar extensions.


.. _collapsible-admonitions:

.. rubric:: Collapsible text

Each admonition directive supports a ``:collapsible:`` option,
to make the content of the admonition collapsible
(where supported by the output format).
This can be useful for content that is not always relevant.
By default, collapsible admonitions are initially open,
but this can be controlled with the ``open`` and ``closed`` arguments
to the ``:collapsible:`` option, which change the default state.
In output formats that don't support collapsible content,
the text is always included.
For example:

.. code-block:: rst

.. note::
:collapsible:

This note is collapsible, and initially open by default.

.. admonition:: Example
:collapsible: open

This example is collapsible, and initially open.

.. hint::
:collapsible: closed

This hint is collapsible, but initially closed.

.. note::
:collapsible:

This note is collapsible, and initially open by default.

.. admonition:: Example
:collapsible: open

This example is collapsible, and initially open.

.. hint::
:collapsible: closed

This hint is collapsible, but initially closed.


Describing changes between versions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions sphinx/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
'sphinx.domains.rst',
'sphinx.domains.std',
'sphinx.directives',
'sphinx.directives.admonitions',
'sphinx.directives.code',
'sphinx.directives.other',
'sphinx.directives.patches',
Expand Down
107 changes: 107 additions & 0 deletions sphinx/directives/admonitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from docutils import nodes
from docutils.parsers.rst.directives.admonitions import BaseAdmonition

from sphinx import addnodes
from sphinx.util.docutils import SphinxDirective

if TYPE_CHECKING:
from typing import ClassVar

from docutils.nodes import Node

from sphinx.application import Sphinx
from sphinx.util.typing import ExtensionMetadata, OptionSpec


def _collapsible_arg(argument: str | None) -> str:
if argument is None:
return 'open'
if (value := argument.lower().strip()) in {'open', 'closed'}:
return value
msg = f'"{argument}" unknown; choose from "open" or "closed".'
raise ValueError(msg)


class SphinxAdmonition(BaseAdmonition, SphinxDirective):
option_spec: ClassVar[OptionSpec] = BaseAdmonition.option_spec.copy() # type: ignore[union-attr]
option_spec |= {
'collapsible': _collapsible_arg,
}

node_class: type[nodes.Admonition] = nodes.admonition
"""Subclasses must set this to the appropriate admonition node class."""

def run(self) -> list[Node]:
(admonition_node,) = super().run()
return [admonition_node]


class Admonition(SphinxAdmonition):
required_arguments = 1
node_class = nodes.admonition


class Attention(SphinxAdmonition):
node_class = nodes.attention


class Caution(SphinxAdmonition):
node_class = nodes.caution


class Danger(SphinxAdmonition):
node_class = nodes.danger


class Error(SphinxAdmonition):
node_class = nodes.error


class Hint(SphinxAdmonition):
node_class = nodes.hint


class Important(SphinxAdmonition):
node_class = nodes.important


class Note(SphinxAdmonition):
node_class = nodes.note


class Tip(SphinxAdmonition):
node_class = nodes.tip


class Warning(SphinxAdmonition):
node_class = nodes.warning


class SeeAlso(SphinxAdmonition):
"""An admonition mentioning things to look at as reference."""

node_class = addnodes.seealso


def setup(app: Sphinx) -> ExtensionMetadata:
app.add_directive('admonition', Admonition, override=True)
app.add_directive('attention', Attention, override=True)
app.add_directive('caution', Caution, override=True)
app.add_directive('danger', Danger, override=True)
app.add_directive('error', Error, override=True)
app.add_directive('hint', Hint, override=True)
app.add_directive('important', Important, override=True)
app.add_directive('note', Note, override=True)
app.add_directive('tip', Tip, override=True)
app.add_directive('warning', Warning, override=True)
app.add_directive('seealso', SeeAlso, override=True)

return {
'version': 'builtin',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
Loading
Loading