Skip to content
Merged
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
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,12 @@ Use autoprefixer when compiling SASS (see <https://getbootstrap.com/docs/5.0/get

horizontal card (grid row inside card, picture on left)

horizontally scrollable cards: (see <https://stackoverflow.com/questions/35993300/horizontally-scrollable-list-of-cards-in-bootstrap>)

subtitle for card (see <https://material.io/components/cards#anatomy>)

paragraph and tab-set in grid-item

rtd PRs not working

size octicons to 1rem etc

empty grid item

[github-ci]: https://github.com/executablebooks/sphinx-design/workflows/continuous-integration/badge.svg?branch=main
[github-link]: https://github.com/executablebooks/sphinx-design
[codecov-badge]: https://codecov.io/gh/executablebooks/sphinx-design/branch/main/graph/badge.svg
Expand Down
43 changes: 43 additions & 0 deletions docs/cards.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,49 @@ Content
Content
:::

(cards:carousel)=

## Card carousels

The `card-carousel` directive can be used to create a single row of fixed width, scrollable cards.
The argument should be a number between 1 and 12, to denote the number of cards to display.

When scrolling a carousel, the scroll will snap to the start of the nearest card:

::::{card-carousel} 2

:::{card} card 1
content
:::
:::{card} card 2
Longer

content
:::
:::{card} card 3
:::
:::{card} card 4
:::
:::{card} card 5
:::
:::{card} card 6
:::
::::

`````{dropdown} Syntax
:icon: code
:color: light

````{tab-set-code}
```{literalinclude} ./snippets/myst/card-carousel.txt
:language: markdown
```
```{literalinclude} ./snippets/rst/card-carousel.txt
:language: rst
```
````
`````

(cards:options)=

## `card` options
Expand Down
19 changes: 19 additions & 0 deletions docs/snippets/myst/card-carousel.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
::::{card-carousel} 2

:::{card} card 1
content
:::
:::{card} card 2
Longer

content
:::
:::{card} card 3
:::
:::{card} card 4
:::
:::{card} card 5
:::
:::{card} card 6
:::
::::
19 changes: 19 additions & 0 deletions docs/snippets/rst/card-carousel.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.. card-carousel:: 2

.. card:: card 1

content

.. card:: card 2

Longer

content

.. card:: card 3

.. card:: card 4

.. card:: card 5

.. card:: card 6
5 changes: 5 additions & 0 deletions docs/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ Content 2

::::::

## `tab-set` options

class
: Additional CSS classes for the container element.

## `tab-item` options

selected
Expand Down
47 changes: 46 additions & 1 deletion sphinx_design/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,30 @@
from sphinx import addnodes
from sphinx.application import Sphinx
from sphinx.util.docutils import SphinxDirective
from sphinx.util.logging import getLogger

from .shared import (
WARNING_TYPE,
PassthroughTextElement,
create_component,
is_component,
make_choice,
margin_option,
text_align,
)

LOGGER = getLogger(__name__)

DIRECTIVE_NAME_CARD = "card"
DIRECTIVE_NAME_CAROUSEL = "card-carousel"
REGEX_HEADER = re.compile(r"^\^{3,}\s*$")
REGEX_FOOTER = re.compile(r"^\+{3,}\s*$")


def setup_cards(app: Sphinx) -> None:
"""Setup the card components."""
app.add_directive(DIRECTIVE_NAME_CARD, CardDirective)
app.add_directive(DIRECTIVE_NAME_CAROUSEL, CardCarouselDirective)


class CardContent(NamedTuple):
Expand Down Expand Up @@ -61,7 +68,6 @@ class CardDirective(SphinxDirective):
}

def run(self) -> List[nodes.Node]:
self.assert_has_content()
return [self.create_card(self, self.arguments, self.options)]

@classmethod
Expand Down Expand Up @@ -214,3 +220,42 @@ def add_card_child_classes(node):
# title["classes"] = ([] if "classes" not in title else title["classes"]) + [
# "sd-card-title"
# ]


class CardCarouselDirective(SphinxDirective):
"""A component, which is a container for cards in a single scrollable row."""

has_content = True
required_arguments = 1 # columns
optional_arguments = 0
option_spec = {
"class": directives.class_option,
}

def run(self) -> List[nodes.Node]:
"""Run the directive."""
self.assert_has_content()
try:
cols = make_choice([str(i) for i in range(1, 13)])(
self.arguments[0].strip()
)
except ValueError as exc:
raise self.error(f"Invalid directive argument: {exc}")
container = create_component(
"card-carousel",
["sd-sphinx-override", "sd-cards-carousel", f"sd-card-cols-{cols}"]
+ self.options.get("class", []),
)
self.set_source_info(container)
self.state.nested_parse(self.content, self.content_offset, container)
for item in container.children:
if not is_component(item, "card"):
LOGGER.warning(
"All children of a 'card-carousel' "
f"should be 'card' [{WARNING_TYPE}.card]",
location=item,
type=WARNING_TYPE,
subtype="card",
)
break
return [container]
2 changes: 1 addition & 1 deletion sphinx_design/compiled/style.min.css

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions sphinx_design/grids.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,12 @@ class GridDirective(SphinxDirective):

def run(self) -> List[nodes.Node]:
"""Run the directive."""
column_classes = row_columns_option(self.arguments[0]) if self.arguments else []
try:
column_classes = (
row_columns_option(self.arguments[0]) if self.arguments else []
)
except ValueError as exc:
raise self.error(f"Invalid directive argument: {exc}")
self.assert_has_content()
# container-fluid is 100% width for all breakpoints,
# rather than the fixed width of the breakpoint (like container)
Expand Down Expand Up @@ -170,7 +175,6 @@ class GridItemDirective(SphinxDirective):

def run(self) -> List[nodes.Node]:
"""Run the directive."""
self.assert_has_content()
if not is_component(self.state_machine.node, "grid-row"):
LOGGER.warning(
f"The parent of a 'grid-item' should be a 'grid-row' [{WARNING_TYPE}.grid]",
Expand Down Expand Up @@ -223,7 +227,6 @@ class GridItemCardDirective(SphinxDirective):

def run(self) -> List[nodes.Node]:
"""Run the directive."""
self.assert_has_content()
if not is_component(self.state_machine.node, "grid-row"):
LOGGER.warning(
f"The parent of a 'grid-item' should be a 'grid-row' [{WARNING_TYPE}.grid]",
Expand Down
41 changes: 41 additions & 0 deletions style/_cards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright 2011-2019 The Bootstrap Authors
// Copyright 2011-2019 Twitter, Inc.
// Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
@use 'sass:math';

.sd-card {
background-clip: border-box;
Expand Down Expand Up @@ -114,3 +115,43 @@
border-bottom-left-radius: calc(0.25rem - 1px);
border-bottom-right-radius: calc(0.25rem - 1px);
}

// sd-cards-carousel is not part of bootstrap
// it is intended to create a single row of scrollable cards
// with a standard width for each card

.sd-cards-carousel {
width: 100%;
display: flex;
flex-wrap: nowrap;
-ms-flex-direction: row;
flex-direction: row;
overflow-x: hidden;
scroll-snap-type: x mandatory;
}

// use to always show the scroll bar
.sd-cards-carousel.sd-show-scrollbar {
overflow-x: auto;
}

.sd-cards-carousel:hover, .sd-cards-carousel:focus {
overflow-x: auto;
}

.sd-cards-carousel > .sd-card {
flex-shrink: 0;
scroll-snap-align: start;
}

.sd-cards-carousel > .sd-card:not(:last-child) {
margin-right: 3px;
}

@for $i from 1 through 12 {
.sd-card-cols-#{$i} > .sd-card {
// we use less than 100% here, so that the (i+1)th card will be slightly visible,
// so the user is aware that there are more cards available
width: math.div(90%, $i);
}
}
35 changes: 35 additions & 0 deletions tests/test_snippets/snippet_post_card-carousel.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<document source="index">
<section ids="heading" names="heading">
<title>
Heading
<container classes="sd-sphinx-override sd-cards-carousel sd-card-cols-2" design_component="card-carousel" is_div="True">
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 1
<paragraph classes="sd-card-text">
content
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 2
<paragraph classes="sd-card-text">
Longer
<paragraph classes="sd-card-text">
content
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 3
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 4
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 5
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 6
35 changes: 35 additions & 0 deletions tests/test_snippets/snippet_pre_card-carousel.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<document source="index">
<section ids="heading" names="heading">
<title>
Heading
<container classes="sd-sphinx-override sd-cards-carousel sd-card-cols-2" design_component="card-carousel" is_div="True">
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 1
<paragraph classes="sd-card-text">
content
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 2
<paragraph classes="sd-card-text">
Longer
<paragraph classes="sd-card-text">
content
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 3
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 4
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 5
<container classes="sd-card sd-sphinx-override sd-mb-3 sd-shadow-sm" design_component="card" is_div="True">
<container classes="sd-card-body" design_component="card-body" is_div="True">
<container classes="sd-card-title sd-font-weight-bold" design_component="card-title" is_div="True">
card 6