1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
from typing import Optional
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.application import Sphinx
from .icons import get_octicon
from .shared import SEMANTIC_COLORS, SdDirective, create_component, make_choice
def setup_article_info(app: Sphinx):
"""Setup the article information components."""
app.add_directive("article-info", ArticleInfoDirective)
class ArticleInfoDirective(SdDirective):
""" """
has_content = False
required_arguments = 0
optional_arguments = 0
option_spec = {
"avatar": directives.uri,
"avatar-alt": directives.unchanged,
"avatar-link": directives.uri,
"avatar-outline": make_choice(SEMANTIC_COLORS),
"author": directives.unchanged_required,
"date": directives.unchanged_required,
"read-time": directives.unchanged_required,
"class-container": directives.class_option,
"class-avatar": directives.class_option,
}
def _parse_text(
self, text: str, icon: Optional[nodes.Node] = None, parse: bool = False
) -> nodes.Node:
"""Parse the text."""
if not parse:
output = ([icon] if icon else []) + [nodes.Text(text)]
else:
text_nodes, _ = self.state.inline_text(text, self.lineno)
text_nodes = ([icon] if icon else []) + text_nodes
# note certain nodes (like references) need to be nested in a TextElement node
# (e.g. a pargraph)
para = nodes.paragraph("", "", *text_nodes, classes=["sd-p-0", "sd-m-0"])
self.set_source_info(para)
output = [para]
return output
def run_with_defaults(self) -> list[nodes.Node]: # noqa: PLR0915
parse_fields = True # parse field text
top_grid = create_component(
"grid-container",
[
"sd-container-fluid",
"sd-sphinx-override",
"sd-p-0",
"sd-mt-2",
"sd-mb-4",
*self.options.get("class-container", []),
],
)
self.set_source_info(top_grid)
top_row = create_component(
"grid-row",
["sd-row", "sd-row-cols-2", "sd-gx-2", "sd-gy-1"],
)
self.set_source_info(top_row)
top_grid += top_row
avatar_uri = self.options.get("avatar")
if avatar_uri:
# TODO only in html (hide in latex)
avatar_column = create_component(
"grid-item",
["sd-col", "sd-col-auto", "sd-d-flex-row", "sd-align-minor-center"],
)
self.set_source_info(avatar_column)
avatar_classes = ["sd-avatar-sm"]
if "avatar-outline" in self.options:
avatar_classes.append(f"sd-outline-{self.options['avatar-outline']}")
if "class-avatar" in self.options:
avatar_classes += self.options["class-avatar"]
avatar_image = nodes.image(
"",
uri=avatar_uri,
alt=self.options.get("avatar-alt", ""),
classes=avatar_classes,
)
self.set_source_info(avatar_image)
if self.options.get("avatar-link"):
avatar_link = nodes.reference(
"", "", refuri=self.options.get("avatar-link")
)
avatar_link += avatar_image
avatar_image = avatar_link
avatar_column += avatar_image
top_row += avatar_column
info_column = create_component(
"grid-item",
["sd-col", "sd-d-flex-row", "sd-align-minor-center"],
)
self.set_source_info(info_column)
top_row += info_column
info_grid = create_component(
"grid-container",
[
"sd-container-fluid",
"sd-sphinx-override",
],
)
self.set_source_info(info_grid)
info_column += info_grid
info_row = create_component(
"grid-row",
[
"sd-row",
"sd-row-cols-2",
"sd-row-cols-xs-2",
"sd-row-cols-sm-3",
"sd-row-cols-md-3",
"sd-row-cols-lg-3",
"sd-gx-3",
"sd-gy-1",
],
)
self.set_source_info(info_row)
info_grid += info_row
author_text = self.options.get("author")
if author_text:
author_column = create_component(
"grid-item",
["sd-col", "sd-col-auto", "sd-d-flex-row", "sd-align-minor-center"],
)
self.set_source_info(author_column)
author_nodes = self._parse_text(author_text, parse=parse_fields)
author_column.extend(author_nodes)
info_row += author_column
date_text = self.options.get("date")
if date_text:
date_column = create_component(
"grid-item",
["sd-col", "sd-col-auto", "sd-d-flex-row", "sd-align-minor-center"],
)
self.set_source_info(date_column)
date_icon = nodes.raw(
"",
nodes.Text(get_octicon("calendar", height="16px")),
classes=["sd-pr-2"],
format="html",
)
date_nodes = self._parse_text(date_text, icon=date_icon, parse=parse_fields)
date_column.extend(date_nodes)
info_row += date_column
read_time_text = self.options.get("read-time")
if read_time_text:
read_time_column = create_component(
"grid-item",
["sd-col", "sd-col-auto", "sd-d-flex-row", "sd-align-minor-center"],
)
self.set_source_info(read_time_column)
read_time_icon = nodes.raw(
"",
nodes.Text(get_octicon("clock", height="16px")),
classes=["sd-pr-2"],
format="html",
)
read_time_nodes = self._parse_text(
read_time_text, icon=read_time_icon, parse=parse_fields
)
read_time_column.extend(read_time_nodes)
info_row += read_time_column
return [top_grid]
|