|
7 | 7 | from sphinx import addnodes |
8 | 8 | from sphinx.application import Sphinx |
9 | 9 | from sphinx.util.docutils import SphinxDirective |
| 10 | +from sphinx.util.logging import getLogger |
10 | 11 |
|
11 | 12 | from .shared import ( |
| 13 | + WARNING_TYPE, |
12 | 14 | PassthroughTextElement, |
13 | 15 | create_component, |
| 16 | + is_component, |
14 | 17 | make_choice, |
15 | 18 | margin_option, |
16 | 19 | text_align, |
17 | 20 | ) |
18 | 21 |
|
| 22 | +LOGGER = getLogger(__name__) |
| 23 | + |
19 | 24 | DIRECTIVE_NAME_CARD = "card" |
| 25 | +DIRECTIVE_NAME_CAROUSEL = "card-carousel" |
20 | 26 | REGEX_HEADER = re.compile(r"^\^{3,}\s*$") |
21 | 27 | REGEX_FOOTER = re.compile(r"^\+{3,}\s*$") |
22 | 28 |
|
23 | 29 |
|
24 | 30 | def setup_cards(app: Sphinx) -> None: |
25 | 31 | """Setup the card components.""" |
26 | 32 | app.add_directive(DIRECTIVE_NAME_CARD, CardDirective) |
| 33 | + app.add_directive(DIRECTIVE_NAME_CAROUSEL, CardCarouselDirective) |
27 | 34 |
|
28 | 35 |
|
29 | 36 | class CardContent(NamedTuple): |
@@ -61,7 +68,6 @@ class CardDirective(SphinxDirective): |
61 | 68 | } |
62 | 69 |
|
63 | 70 | def run(self) -> List[nodes.Node]: |
64 | | - self.assert_has_content() |
65 | 71 | return [self.create_card(self, self.arguments, self.options)] |
66 | 72 |
|
67 | 73 | @classmethod |
@@ -214,3 +220,42 @@ def add_card_child_classes(node): |
214 | 220 | # title["classes"] = ([] if "classes" not in title else title["classes"]) + [ |
215 | 221 | # "sd-card-title" |
216 | 222 | # ] |
| 223 | + |
| 224 | + |
| 225 | +class CardCarouselDirective(SphinxDirective): |
| 226 | + """A component, which is a container for cards in a single scrollable row.""" |
| 227 | + |
| 228 | + has_content = True |
| 229 | + required_arguments = 1 # columns |
| 230 | + optional_arguments = 0 |
| 231 | + option_spec = { |
| 232 | + "class": directives.class_option, |
| 233 | + } |
| 234 | + |
| 235 | + def run(self) -> List[nodes.Node]: |
| 236 | + """Run the directive.""" |
| 237 | + self.assert_has_content() |
| 238 | + try: |
| 239 | + cols = make_choice([str(i) for i in range(1, 13)])( |
| 240 | + self.arguments[0].strip() |
| 241 | + ) |
| 242 | + except ValueError as exc: |
| 243 | + raise self.error(f"Invalid directive argument: {exc}") |
| 244 | + container = create_component( |
| 245 | + "card-carousel", |
| 246 | + ["sd-sphinx-override", "sd-cards-carousel", f"sd-card-cols-{cols}"] |
| 247 | + + self.options.get("class", []), |
| 248 | + ) |
| 249 | + self.set_source_info(container) |
| 250 | + self.state.nested_parse(self.content, self.content_offset, container) |
| 251 | + for item in container.children: |
| 252 | + if not is_component(item, "card"): |
| 253 | + LOGGER.warning( |
| 254 | + "All children of a 'card-carousel' " |
| 255 | + f"should be 'card' [{WARNING_TYPE}.card]", |
| 256 | + location=item, |
| 257 | + type=WARNING_TYPE, |
| 258 | + subtype="card", |
| 259 | + ) |
| 260 | + break |
| 261 | + return [container] |
0 commit comments