Skip to content

Commit

Permalink
✨ NEW: Add card-carousel directive (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjsewell authored Aug 4, 2021
1 parent 10d21dc commit db15bff
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 11 deletions.
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

0 comments on commit db15bff

Please sign in to comment.