Skip to content

Commit e6bbcea

Browse files
author
Sam Partee
committed
Use a different sphinx theme
1 parent b9a5d8e commit e6bbcea

22 files changed

+761
-66
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
"""A directive to generate a gallery of images from structured data.
2+
3+
Generating a gallery of images that are all the same size is a common
4+
pattern in documentation, and this can be cumbersome if the gallery is
5+
generated programmatically. This directive wraps this particular use-case
6+
in a helper-directive to generate it with a single YAML configuration file.
7+
8+
It currently exists for maintainers of the pydata-sphinx-theme,
9+
but might be abstracted into a standalone package if it proves useful.
10+
"""
11+
from pathlib import Path
12+
from typing import Any, Dict, List
13+
14+
from docutils import nodes
15+
from docutils.parsers.rst import directives
16+
from sphinx.application import Sphinx
17+
from sphinx.util import logging
18+
from sphinx.util.docutils import SphinxDirective
19+
from yaml import safe_load
20+
21+
logger = logging.getLogger(__name__)
22+
23+
24+
TEMPLATE_GRID = """
25+
`````{{grid}} {grid_columns}
26+
{container_options}
27+
28+
{content}
29+
30+
`````
31+
"""
32+
33+
GRID_CARD = """
34+
````{{grid-item-card}} {title}
35+
{card_options}
36+
37+
{content}
38+
````
39+
"""
40+
41+
42+
class GalleryDirective(SphinxDirective):
43+
"""A directive to show a gallery of images and links in a grid."""
44+
45+
name = "gallery-grid"
46+
has_content = True
47+
required_arguments = 0
48+
optional_arguments = 1
49+
final_argument_whitespace = True
50+
option_spec = {
51+
# A class to be added to the resulting container
52+
"grid-columns": directives.unchanged,
53+
"class-container": directives.unchanged,
54+
"class-card": directives.unchanged,
55+
}
56+
57+
def run(self) -> List[nodes.Node]:
58+
if self.arguments:
59+
# If an argument is given, assume it's a path to a YAML file
60+
# Parse it and load it into the directive content
61+
path_data_rel = Path(self.arguments[0])
62+
path_doc, _ = self.get_source_info()
63+
path_doc = Path(path_doc).parent
64+
path_data = (path_doc / path_data_rel).resolve()
65+
if not path_data.exists():
66+
logger.warn(f"Could not find grid data at {path_data}.")
67+
nodes.text("No grid data found at {path_data}.")
68+
return
69+
yaml_string = path_data.read_text()
70+
else:
71+
yaml_string = "\n".join(self.content)
72+
73+
# Read in YAML so we can generate the gallery
74+
grid_data = safe_load(yaml_string)
75+
76+
grid_items = []
77+
for item in grid_data:
78+
# Grid card parameters
79+
options = {}
80+
if "website" in item:
81+
options["link"] = item["website"]
82+
83+
if "class-card" in self.options:
84+
options["class-card"] = self.options["class-card"]
85+
86+
if "img-background" in item:
87+
options["img-background"] = item["img-background"]
88+
89+
if "img-top" in item:
90+
options["img-top"] = item["img-top"]
91+
92+
if "img-bottom" in item:
93+
options["img-bottom"] = item["img-bottom"]
94+
95+
options_str = "\n".join(f":{k}: {v}" for k, v in options.items()) + "\n\n"
96+
97+
# Grid card content
98+
content_str = ""
99+
if "header" in item:
100+
content_str += f"{item['header']}\n\n^^^\n\n"
101+
102+
if "image" in item:
103+
content_str += f"![Gallery image]({item['image']})\n\n"
104+
105+
if "content" in item:
106+
content_str += f"{item['content']}\n\n"
107+
108+
if "footer" in item:
109+
content_str += f"+++\n\n{item['footer']}\n\n"
110+
111+
title = item.get("title", "")
112+
content_str += "\n"
113+
grid_items.append(
114+
GRID_CARD.format(
115+
card_options=options_str, content=content_str, title=title
116+
)
117+
)
118+
119+
# Parse the template with Sphinx Design to create an output
120+
container = nodes.container()
121+
# Prep the options for the template grid
122+
container_options = {"gutter": 2, "class-container": "gallery-directive"}
123+
if "class-container" in self.options:
124+
container_options[
125+
"class-container"
126+
] += f' {self.options["class-container"]}'
127+
container_options_str = "\n".join(
128+
f":{k}: {v}" for k, v in container_options.items()
129+
)
130+
131+
# Create the directive string for the grid
132+
grid_directive = TEMPLATE_GRID.format(
133+
grid_columns=self.options.get("grid-columns", "1 2 3 4"),
134+
container_options=container_options_str,
135+
content="\n".join(grid_items),
136+
)
137+
# Parse content as a directive so Sphinx Design processes it
138+
self.state.nested_parse([grid_directive], 0, container)
139+
# Sphinx Design outputs a container too, so just use that
140+
container = container.children[0]
141+
142+
# Add extra classes
143+
if self.options.get("container-class", []):
144+
container.attributes["classes"] += self.options.get("class", [])
145+
return [container]
146+
147+
148+
def setup(app: Sphinx) -> Dict[str, Any]:
149+
"""Add custom configuration to sphinx app.
150+
151+
Args:
152+
app: the Sphinx application
153+
Returns:
154+
the 2 parallel parameters set to ``True``.
155+
"""
156+
app.add_directive("gallery-grid", GalleryDirective)
157+
158+
return {
159+
"parallel_read_safe": True,
160+
"parallel_write_safe": True,
161+
}
41.2 KB
Loading
188 KB
Loading

docs/_static/apple-touch-icon.png

38.5 KB
Loading

docs/_static/css/custom.css

Whitespace-only changes.

docs/_static/favicon-16x16.png

817 Bytes
Loading

docs/_static/favicon-32x32.png

2.23 KB
Loading

docs/_static/favicon.ico

15 KB
Binary file not shown.

docs/_static/site.webmanifest

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

docs/_templates/layout.html

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)