| """A directive to generate a gallery of images from structured data. |
| |
| Generating a gallery of images that are all the same size is a common |
| pattern in documentation, and this can be cumbersome if the gallery is |
| generated programmatically. This directive wraps this particular use-case |
| in a helper-directive to generate it with a single YAML configuration file. |
| |
| It currently exists for maintainers of the pydata-sphinx-theme, |
| but might be abstracted into a standalone package if it proves useful. |
| """ |
|
|
| from pathlib import Path |
| from typing import Any, ClassVar, Dict, List |
|
|
| from docutils import nodes |
| from docutils.parsers.rst import directives |
| from sphinx.application import Sphinx |
| from sphinx.util import logging |
| from sphinx.util.docutils import SphinxDirective |
| from yaml import safe_load |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| TEMPLATE_GRID = """ |
| `````{{grid}} {columns} |
| {options} |
| |
| {content} |
| |
| ````` |
| """ |
|
|
| GRID_CARD = """ |
| ````{{grid-item-card}} {title} |
| {options} |
| |
| {content} |
| ```` |
| """ |
|
|
|
|
| class GalleryGridDirective(SphinxDirective): |
| """A directive to show a gallery of images and links in a Bootstrap grid. |
| |
| The grid can be generated from a YAML file that contains a list of items, or |
| from the content of the directive (also formatted in YAML). Use the parameter |
| "class-card" to add an additional CSS class to all cards. When specifying the grid |
| items, you can use all parameters from "grid-item-card" directive to customize |
| individual cards + ["image", "header", "content", "title"]. |
| |
| Danger: |
| This directive can only be used in the context of a Myst documentation page as |
| the templates use Markdown flavored formatting. |
| """ |
|
|
| name = "gallery-grid" |
| has_content = True |
| required_arguments = 0 |
| optional_arguments = 1 |
| final_argument_whitespace = True |
| option_spec: ClassVar[dict[str, Any]] = { |
| |
| "grid-columns": directives.unchanged, |
| "class-container": directives.unchanged, |
| "class-card": directives.unchanged, |
| } |
|
|
| def run(self) -> List[nodes.Node]: |
| """Create the gallery grid.""" |
| if self.arguments: |
| |
| |
| path_data_rel = Path(self.arguments[0]) |
| path_doc, _ = self.get_source_info() |
| path_doc = Path(path_doc).parent |
| path_data = (path_doc / path_data_rel).resolve() |
| if not path_data.exists(): |
| logger.info(f"Could not find grid data at {path_data}.") |
| nodes.text("No grid data found at {path_data}.") |
| return |
| yaml_string = path_data.read_text() |
| else: |
| yaml_string = "\n".join(self.content) |
|
|
| |
| |
| grid_items = [] |
| for item in safe_load(yaml_string): |
| |
| title = item.pop("title", "") |
|
|
| |
| header = f"{item.pop('header')} \n^^^ \n" if "header" in item else "" |
| image = f"}) \n" if "image" in item else "" |
| content = f"{item.pop('content')} \n" if "content" in item else "" |
|
|
| |
| if "class-card" in self.options: |
| item["class-card"] = self.options["class-card"] |
|
|
| loc_options_str = "\n".join(f":{k}: {v}" for k, v in item.items()) + " \n" |
|
|
| card = GRID_CARD.format( |
| options=loc_options_str, content=header + image + content, title=title |
| ) |
| grid_items.append(card) |
|
|
| |
| |
| class_ = "gallery-directive" + f' {self.options.get("class-container", "")}' |
| options = {"gutter": 2, "class-container": class_} |
| options_str = "\n".join(f":{k}: {v}" for k, v in options.items()) |
|
|
| |
| grid_directive = TEMPLATE_GRID.format( |
| columns=self.options.get("grid-columns", "1 2 3 4"), |
| options=options_str, |
| content="\n".join(grid_items), |
| ) |
|
|
| |
| container = nodes.container() |
| self.state.nested_parse([grid_directive], 0, container) |
|
|
| |
| return [container.children[0]] |
|
|
|
|
| def setup(app: Sphinx) -> Dict[str, Any]: |
| """Add custom configuration to sphinx app. |
| |
| Args: |
| app: the Sphinx application |
| |
| Returns: |
| the 2 parallel parameters set to ``True``. |
| """ |
| app.add_directive("gallery-grid", GalleryGridDirective) |
|
|
| return { |
| "parallel_read_safe": True, |
| "parallel_write_safe": True, |
| } |
|
|