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
5 changes: 5 additions & 0 deletions .changeset/swift-avocados-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cloudfour/patterns': minor
---

Add `c-card--contained` modifier
21 changes: 21 additions & 0 deletions src/components/card/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@use '../../mixins/media-query';
@use '../../mixins/ms';
@use '../../mixins/ratio-box';
@use '../../mixins/theme';

/// We can't use `grid-gap` exclusively due to some containers only being
/// present some of the time, so we re-use this value to define the space
Expand Down Expand Up @@ -65,6 +66,15 @@ $_focus-overflow: (size.$edge-large * -1);
); /* 3 */
}

.c-card--contained {
border-radius: size.$border-radius-large;
padding: ms.step(1);

@include theme.unthemed-styles() {
background-color: var(--theme-color-background-secondary);
}
}

/**
* Responsive horizontal modifiers
*
Expand Down Expand Up @@ -154,6 +164,17 @@ $_focus-overflow: (size.$edge-large * -1);
right: $_focus-overflow;
top: $_focus-overflow;
z-index: 1;

/**
* Do not overflow when the card's edges are distinct
*/

.c-card--contained & {
bottom: 0;
left: 0;
right: 0;
top: 0;
}
}

/**
Expand Down
45 changes: 43 additions & 2 deletions src/components/card/card.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const singleDemoStory = (args) => {
const props = {
href: args.href,
};
const classNames = [];
const modifiers = [];
if (args.show.length > 0) {
for (const block of args.show) {
Expand All @@ -13,8 +14,17 @@ const singleDemoStory = (args) => {
if (args.horizontal !== 'none') {
modifiers.push(`horizontal${args.horizontal}`);
}
if (args.contained) {
modifiers.push('contained');
}
if (modifiers.length > 0) {
props.class = modifiers.map((modifier) => `c-card--${modifier}`).join(' ');
classNames.push(...modifiers.map((modifier) => `c-card--${modifier}`));
}
if (args.theme !== 'none') {
classNames.push(`t-${args.theme}`);
}
if (classNames.length > 0) {
props.class = classNames.join(' ');
}
return singleDemo(props);
};
Expand All @@ -35,6 +45,12 @@ const singleDemoStory = (args) => {
control: { type: 'inline-radio', options: ['none', '@m', '@l', '@xl'] },
defaultValue: 'none',
},
contained: { type: { name: 'boolean' } },
theme: {
type: { name: 'string' },
control: { type: 'inline-radio', options: ['none', 'light', 'dark'] },
defaultValue: 'none',
},
}}
/>

Expand Down Expand Up @@ -92,7 +108,32 @@ If a card with a cover is meant to occupy its full container width, it may be pr

Horizontal cards will attempt to span all available columns of a CSS Grid Layout. This comes in handy when displaying them [in a Deck](/docs/objects-deck--horizontal-card#with-horizontal-cards).

## Contained

A card with the `c-card--contained` class will gain a background color, padding and rounded corners. This can be helpful for offsetting the card visually from its surroundings.

<Canvas>
<Story
name="Contained"
args={{ href: '#', horizontal: '@m', contained: true }}
>
{singleDemoStory.bind({})}
</Story>
</Canvas>

When the card is a focal point and more contrast is desired, you may also attach a [theme class](/docs/design-themes--light) to the card. In this example, the card has a class of `t-light` within a `t-dark` container:

<Canvas>
<Story
name="Themed"
parameters={{ theme: 't-dark' }}
args={{ href: '#', horizontal: '@m', contained: true, theme: 'light' }}
>
{singleDemoStory.bind({})}
</Story>
</Canvas>

## Coming soon

- Progressive enhancement based on CSS Grid support
- Contained and themed cards for PWA Stats use case
- Distinctly contained footers for PWA Stats (if necessary)
12 changes: 9 additions & 3 deletions src/design/demo/theme.twig
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<h1>t-{{theme}}</h1>
{% include '@cloudfour/design/typography/demo/inline-elements.twig' only %}
{% include '@cloudfour/components/button/demo/styles.twig' only %}
{# TODO: Replace padding and corner modifiers once card component can
handle these variations natively #}
{% set _card_class = 'c-card--horizontal@m u-pad-1 u-rounded' %}
{% set _card_class = 'c-card--horizontal@m c-card--contained' %}
{% include '@cloudfour/components/card/demo/single.twig' with {
class: _card_class,
href: '#',
show_heading: true,
show_content: true,
show_cover: true,
show_footer: true
} only %}
{% if theme == 'light' %}
{% set _card_class = _card_class ~ ' t-dark' %}
{% else %}
Expand Down
10 changes: 10 additions & 0 deletions src/mixins/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ $default-theme: light;
}
}

/// Apply these styles only if this element is a container without an explicit
/// theme. Useful for patterns that are only optionally a container, such as
/// 'c-card'.
/// @content
@mixin unthemed-styles() {
&:not([class^='t-']):not([class*=' t-']) {
@content;
}
}

/// Establish the minimal rules needed for a theme's root element, specifically
/// a `background-color` and default text color. Without this, the theme root
/// won't be visually offset from its parent and its contents may not be very
Expand Down
1 change: 1 addition & 0 deletions src/tokens/size/border.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"radius": {
"small": { "value": "0.125em" },
"medium": { "value": "0.25em" },
"large": { "value": "0.5em" },
"full": {
"value": "9999px",
"comment": "A value of 50% would be more intuitive, but results in unexpectedly oblong rounding for non-square shapes. We use `px` to save the browser the trouble of recalculating the stupidly large value."
Expand Down