Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

## Unreleased

- ✨ NEW: Card headers and footers now have dedicated, parser-portable
`card-header` / `card-footer` directives (plus inline `:header:` / `:footer:`
options for one-liners), which are hoisted into their slots. The whole card
body is parsed in a single pass, so error messages point at the right line.
The legacy `^^^` / `+++` separators — which scan the card's raw source lines
— remain on by default behind the new `sd_card_legacy_separators` option,
emitting a suppressible `design.card_legacy` deprecation warning once per
document; both syntaxes produce identical doctrees. Note that the single-parse
robustness — correct line numbers, and a stray `^^^` / `+++` (e.g. inside a
code block) no longer mis-splitting the card — is only fully realized once the
legacy separators are disabled with `sd_card_legacy_separators = False`
(planned to become the default at 1.0). One behaviour change: an *empty*
`card-header` / `card-footer` directive now errors (`Content block expected`),
where an empty legacy chunk produced an empty slot. See the cards
documentation for the mechanical migration ({pr}`294`)
- ♻️ REFACTOR: The private `CardDirective._create_component` helper is renamed
to `_create_slot`; a back-compatible alias is kept for one release for
downstream extensions that call it ({pr}`294`)
- ♻️ IMPROVE: Replace the Sass/Node build with a dependency-free Python CSS
generator (`tools/generate_css.py` driven by `style/design.toml` and
hand-authored `style/*.css`); `package.json` is gone. The compiled
Expand Down
192 changes: 174 additions & 18 deletions docs/cards.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,25 @@ See the [Material Design](https://material.io/components/cards) and [Bootstrap c
````
`````

All content before the first occurrence of three or more `^^^` is considered as a header,
and all content after the final occurrence of three or more `+++` is considered as a footer:
## Card headers and footers

:::{card} Card Title
Add a header and/or footer to a card with the `card-header` and `card-footer` directives.
They always render in their slots — the header at the top and the footer at the bottom of
the card — regardless of where they appear within the card body (the recommended order is
header, then body, then footer):

::::{card} Card Title

:::{card-header}
Header
^^^
:::

Card content
+++

:::{card-footer}
Footer
:::
::::

`````{dropdown-syntax}

Expand All @@ -48,26 +57,46 @@ Footer
````
`````

For a single line of content, the `header` and `footer` options are a convenient
short-hand (they accept inline markup, and compose with the card body):

:::{card} Card Title
:header: A **header**
:footer: A footer

Card content
:::

When using cards in grids (see [`grid-item-card`](./grids.md)) footers can be aligned.

::::{grid} 2
:::{grid-item-card} Card Title
::::::{grid} 2
:::::{grid-item-card} Card Title

::::{card-header}
Header
^^^
::::

Card content
+++

::::{card-footer}
Footer
:::
:::{grid-item-card} Card Title
::::
:::::
:::::{grid-item-card} Card Title

::::{card-header}
Header
^^^
::::

Longer

Card content
+++

::::{card-footer}
Footer
:::
::::
:::::
::::::

## Card images

Expand All @@ -91,22 +120,30 @@ Text
:img-top: images/particle_background.jpg
:img-alt: your desired alt text

:::{card-header}
Header
^^^
:::

Content
+++

:::{card-footer}
Footer
:::
::::

::::{grid-item-card} Title
:img-bottom: images/particle_background.jpg
:img-alt: your desired alt text

:::{card-header}
Header
^^^
:::

Content
+++

:::{card-footer}
Footer
:::
::::

:::::
Expand Down Expand Up @@ -288,6 +325,14 @@ link-alt
shadow
: The size of the shadow below the card: `none`, `sm` (default), `md`, `lg`.

header
: Inline-markup short-hand for a single-line header
(equivalent to a `card-header` directive; the two are mutually exclusive).

footer
: Inline-markup short-hand for a single-line footer
(equivalent to a `card-footer` directive; the two are mutually exclusive).

class-card
: Additional CSS classes for the card container element.

Expand All @@ -308,3 +353,114 @@ class-img-top

class-img-bottom
: Additional CSS classes for the bottom image (if present).

(legacy-separator-syntax)=

## Legacy separator syntax

:::{deprecated} 0.8
Prefer the `card-header` / `card-footer` directives (above).
The `^^^` / `+++` separators are **deprecated**: they scan the card's raw source
lines, so a `^^^` or `+++` line inside nested content (for example a code block)
is mistaken for a separator, and they have no meaning to non-Python MyST tools.
:::

Historically, a card header and footer were delimited within the body itself:
all content before the first line of three-or-more `^^^` became the header,
and all content after the final line of three-or-more `+++` became the footer.

::::{card} Card Title
Header
^^^
Card content
+++
Footer
::::

This syntax is still recognised by default, but emits a deprecation warning
(once per document). The rewrite is mechanical:

| Legacy separators | Header / footer directives |
| --- | --- |
| `Header` above a `^^^` line | a `card-header` directive |
| `Footer` below a `+++` line | a `card-footer` directive |

`````{tab-set}
````{tab-item} MyST
```markdown
:::{card} Card Title
Header
^^^
Body
+++
Footer
:::
```
becomes
```markdown
::::{card} Card Title

:::{card-header}
Header
:::

Body

:::{card-footer}
Footer
:::
::::
```
````
````{tab-item} reStructuredText
```rst
.. card:: Card Title

Header
^^^
Body
+++
Footer
```
becomes
```rst
.. card:: Card Title

.. card-header::

Header

Body

.. card-footer::

Footer
```
````
`````

:::{important} Migrate, then flip the flag
While the legacy separators are enabled (the default), the raw-line scan runs
on **every** card, so a stray column-0 `^^^` or `+++` — even inside a code
block, and even in a card that has already migrated to the `card-header` /
`card-footer` directives — is still treated as a separator (mis-splitting the
card and emitting a mixed-syntax warning). The single-parse robustness is only
realized once the separators are turned off.

The recommended order is therefore **migrate first, then flip the flag**:
convert every card to the directives, then set
`sd_card_legacy_separators = False` in your `conf.py`.
:::

With `sd_card_legacy_separators = False`, `^^^` / `+++` lines are no longer
scanned — but they do **not** reliably render as literal text, so migrate
before flipping:

- in MyST, a bare `+++` line is a block break and silently disappears;
- in reStructuredText, a `^^^` / `++++` line can raise a docutils `CRITICAL`
"Unexpected section title or transition" error.

To keep the legacy syntax on but silence the deprecation warning, add
`"design.card_legacy"` to the Sphinx `suppress_warnings` list.

**Timeline**: deprecated now (default on) → default off at `1.0` → removed at `2.0`.
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
]

# suppresses the warning for builders with no fontawesome support (e.g. man)
suppress_warnings = ["design.fa-build"]
# "design.card_legacy" is suppressed because the cards page intentionally
# demonstrates the deprecated ^^^/+++ separator syntax in its migration section
suppress_warnings = ["design.fa-build", "design.card_legacy"]
sd_fontawesome_latex = "fontawesome5"
# pdflatex errors on emoji (e.g. in the changelog); xelatex only warns for
# missing glyphs. makeindex replaces xindy, which CI TeX images lack.
Expand Down
11 changes: 8 additions & 3 deletions docs/snippets/myst/card-head-foot.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
:::{card} Card Title
::::{card} Card Title

:::{card-header}
Header
^^^
:::

Card content
+++

:::{card-footer}
Footer
:::
::::
16 changes: 12 additions & 4 deletions docs/snippets/myst/card-images.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,29 @@ Text
:img-top: images/particle_background.jpg
:img-alt:

:::{card-header}
Header
^^^
:::

Content
+++

:::{card-footer}
Footer
:::
::::

::::{grid-item-card} Title
:img-bottom: images/particle_background.jpg

:::{card-header}
Header
^^^
:::

Content
+++

:::{card-footer}
Footer
:::
::::

:::::
12 changes: 8 additions & 4 deletions docs/snippets/rst/card-head-foot.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
.. card:: Card Title

Header
^^^
.. card-header::

Header

Card content
+++
Footer

.. card-footer::

Footer
24 changes: 16 additions & 8 deletions docs/snippets/rst/card-images.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,25 @@
:img-top: images/particle_background.jpg
:img-alt:

Header
^^^
.. card-header::

Header

Content
+++
Footer

.. card-footer::

Footer

.. grid-item-card:: Title
:img-bottom: images/particle_background.jpg

Header
^^^
.. card-header::

Header

Content
+++
Footer

.. card-footer::

Footer
Loading
Loading