e768098d0e
Flake8 Lint / flake8 (push) Waiting to run
Spell check CI / Spell_Check (push) Waiting to run
tools_continuous_delivery / Private PyPI non-main branch release (push) Has been skipped
tools_continuous_delivery / Private PyPI main branch release (push) Failing after 2m42s
Publish Promptflow Doc / Build (push) Has been cancelled
Publish Promptflow Doc / Deploy (push) Has been cancelled
140 lines
4.8 KiB
Python
140 lines
4.8 KiB
Python
"""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 yaml import safe_load
|
|
from typing import List
|
|
from pathlib import Path
|
|
|
|
from docutils import nodes
|
|
from docutils.parsers.rst import directives
|
|
from sphinx.util.docutils import SphinxDirective
|
|
from sphinx.util import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
TEMPLATE_GRID = """
|
|
`````{{grid}} {grid_columns}
|
|
{container_options}
|
|
{content}
|
|
`````
|
|
"""
|
|
|
|
GRID_CARD = """
|
|
````{{grid-item-card}} {title}
|
|
{card_options}
|
|
{content}
|
|
````
|
|
"""
|
|
|
|
|
|
class GalleryDirective(SphinxDirective):
|
|
"""A directive to show a gallery of images and links in a grid."""
|
|
|
|
name = "gallery-grid"
|
|
has_content = True
|
|
required_arguments = 0
|
|
optional_arguments = 1
|
|
final_argument_whitespace = True
|
|
option_spec = {
|
|
# A class to be added to the resulting container
|
|
"grid-columns": directives.unchanged,
|
|
"class-container": directives.unchanged,
|
|
"class-card": directives.unchanged,
|
|
}
|
|
|
|
def run(self) -> List[nodes.Node]: # noqa: C901
|
|
if self.arguments:
|
|
# If an argument is given, assume it's a path to a YAML file
|
|
# Parse it and load it into the directive content
|
|
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.warn(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)
|
|
|
|
# Read in YAML so we can generate the gallery
|
|
grid_data = safe_load(yaml_string)
|
|
|
|
grid_items = []
|
|
for item in grid_data:
|
|
# Grid card parameters
|
|
options = {}
|
|
if "website" in item:
|
|
options["link"] = item["website"]
|
|
|
|
if "class-card" in self.options:
|
|
options["class-card"] = self.options["class-card"]
|
|
|
|
if "img-background" in item:
|
|
options["img-background"] = item["img-background"]
|
|
|
|
if "img-top" in item:
|
|
options["img-top"] = item["img-top"]
|
|
|
|
if "img-bottom" in item:
|
|
options["img-bottom"] = item["img-bottom"]
|
|
|
|
options_str = "\n".join(f":{k}: {v}" for k, v in options.items()) + "\n\n"
|
|
|
|
# Grid card content
|
|
content_str = ""
|
|
if "header" in item:
|
|
content_str += f"{item['header']}\n\n^^^\n\n"
|
|
|
|
if "image" in item:
|
|
content_str += f"\n\n"
|
|
|
|
if "content" in item:
|
|
content_str += f"{item['content']}\n\n"
|
|
|
|
if "footer" in item:
|
|
content_str += f"+++\n\n{item['footer']}\n\n"
|
|
|
|
title = item.get("title", "")
|
|
content_str += "\n"
|
|
grid_items.append(
|
|
GRID_CARD.format(
|
|
card_options=options_str, content=content_str, title=title
|
|
)
|
|
)
|
|
|
|
# Parse the template with Sphinx Design to create an output
|
|
container = nodes.container()
|
|
# Prep the options for the template grid
|
|
container_options = {"gutter": 2, "class-container": "gallery-directive"}
|
|
if "class-container" in self.options:
|
|
container_options[
|
|
"class-container"
|
|
] += f' {self.options["class-container"]}'
|
|
container_options_str = "\n".join(
|
|
f":{k}: {v}" for k, v in container_options.items()
|
|
)
|
|
|
|
# Create the directive string for the grid
|
|
grid_directive = TEMPLATE_GRID.format(
|
|
grid_columns=self.options.get("grid-columns", "1 2 3 4"),
|
|
container_options=container_options_str,
|
|
content="\n".join(grid_items),
|
|
)
|
|
# Parse content as a directive so Sphinx Design processes it
|
|
self.state.nested_parse([grid_directive], 0, container)
|
|
# Sphinx Design outputs a container too, so just use that
|
|
container = container.children[0]
|
|
|
|
# Add extra classes
|
|
if self.options.get("container-class", []):
|
|
container.attributes["classes"] += self.options.get("class", [])
|
|
return [container]
|