Skip to content

Commit 687d737

Browse files
authored
Add cloudy card modifier (#2143)
1 parent 8199022 commit 687d737

File tree

7 files changed

+151
-0
lines changed

7 files changed

+151
-0
lines changed

.changeset/fast-radios-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cloudfour/patterns': minor
3+
---
4+
5+
Add `c-card--cloudy` modifier for branded promotions

src/assets/clouds/all.svg

Lines changed: 11 additions & 0 deletions
Loading

src/assets/clouds/background.svg

Lines changed: 8 additions & 0 deletions
Loading

src/assets/clouds/foreground.svg

Lines changed: 5 additions & 0 deletions
Loading

src/components/card/card.scss

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@use '../../mixins/headings';
1212
@use '../../mixins/media-query';
1313
@use '../../mixins/ms';
14+
@use '../../mixins/spacing';
1415
@use '../../mixins/theme';
1516

1617
/// We can't use `grid-gap` exclusively due to some containers only being
@@ -39,6 +40,20 @@ $_cover-gap: ms.step(1, 1rem);
3940

4041
$_focus-overflow: (size.$edge-large * -1);
4142

43+
/// The cloudy modifier adds clouds to the bottom right corner and also applies
44+
/// some fluid padding to accommodate. The clouds feel best when they are sized
45+
/// just a _tad_ larger than this fluid padding.
46+
///
47+
/// @type Number
48+
/// @access private
49+
50+
$_cloud-height: fluid.fluid-clamp(
51+
size.$padding-container-vertical-min * 1.33,
52+
size.$padding-container-vertical-max * 1.33,
53+
breakpoint.$s,
54+
breakpoint.$m
55+
);
56+
4257
/**
4358
* The main card container
4459
*
@@ -127,6 +142,57 @@ $_focus-overflow: (size.$edge-large * -1);
127142
}
128143
}
129144

145+
/**
146+
* Cloudy modifier
147+
*
148+
* Chrome and Safari often introduce little subpixel artifacts between the edge
149+
* of a bottom-right image or positioned element that is sized responsively. To
150+
* minimize this, we assume that this modifier will be shown on a default/light
151+
* background, and we use a pseudo element for the cloud of the same color so
152+
* we can offset it slightly (which overlays any artifacting).
153+
*
154+
* 1. On the element itself we can include the "background" clouds. These are
155+
* lower contrast so the artifacting is less noticeable, and they do not
156+
* match light backgrounds so we can't offset them.
157+
* 2. We include more generous spacing to account for the clouds. It is still
158+
* theoretically possible for content to overlap the clouds, so this modifier
159+
* should be used carefully.
160+
*/
161+
162+
.c-card--cloudy {
163+
@include spacing.fluid-padding-block; /* 2 */
164+
@include spacing.fluid-padding-inline; /* 2 */
165+
background-image: svg-load('clouds/background.svg'); /* 1 */
166+
background-position: bottom right;
167+
background-repeat: no-repeat;
168+
background-size: auto $_cloud-height;
169+
}
170+
171+
/**
172+
* Pseudo element used to position the cloud matching the container background,
173+
* offset to obscure rounding artifacts.
174+
*
175+
* 1. Fluid sizing based on asset's natural dimensions, since we don't have an
176+
* `auto` width in this context.
177+
* 2. Offsetting to obscure artifacts.
178+
* 3. Prevent pointer events so that cloud can never block interactions (clicks,
179+
* text selection, etc.)
180+
*/
181+
182+
.c-card--cloudy::before {
183+
aspect-ratio: 580 / 220; /* 1 */
184+
background-image: svg-load('clouds/foreground.svg');
185+
background-position: bottom right;
186+
background-repeat: no-repeat;
187+
background-size: contain;
188+
block-size: $_cloud-height; /* 1 */
189+
content: '';
190+
inset-block-end: -1px; /* 2 */
191+
inset-inline-end: -1px; /* 2 */
192+
pointer-events: none; /* 3 */
193+
position: absolute;
194+
}
195+
130196
/**
131197
* Header area
132198
*

src/components/card/card.stories.mdx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import { Canvas, Meta, Story } from '@storybook/addon-docs';
22
import singleDemo from './demo/single.twig';
3+
// The '!!raw-loader!' syntax is a non-standard, Webpack-specific, syntax.
4+
// See: https://github.com/webpack-contrib/raw-loader#examples
5+
// For now, it seems likely Storybook is pretty tied to Webpack, therefore, we
6+
// are okay with the following Webpack-specific raw loader syntax. It's better
7+
// to leave the ESLint rule enabled globally, and only thoughtfully disable as
8+
// needed (e.g. within a Storybook docs page and not within an actual
9+
// component). This can be revisited in the future if Storybook no longer relies
10+
// on Webpack.
11+
// eslint-disable-next-line @cloudfour/import/no-webpack-loader-syntax
12+
import cloudyDemoSource from '!!raw-loader!./demo/cloudy.twig';
13+
import cloudyDemo from './demo/cloudy.twig';
314
const singleDemoProps = (args = {}, storyId) => {
415
const props = {
516
heading_id: args.heading_id || `${storyId}-heading`,
@@ -194,6 +205,25 @@ When the card is a focal point and more contrast is desired, you may also attach
194205
</Story>
195206
</Canvas>
196207

208+
## Cloudy
209+
210+
The `c-card--cloudy` modifier is meant to pair with `c-card--contained` and `t-dark`. It should only be used for very specific promotional content within light containers (so the white cloud blends into the background). Additional fluid white space is added to account for the clouds.
211+
212+
<Canvas>
213+
<Story
214+
name="Cloudy"
215+
parameters={{
216+
docs: {
217+
source: {
218+
code: cloudyDemoSource,
219+
},
220+
},
221+
}}
222+
>
223+
{cloudyDemo.bind({})}
224+
</Story>
225+
</Canvas>
226+
197227
## Template Properties
198228

199229
- `class` (string): Append a class to the root element.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% embed '@cloudfour/components/card/card.twig' with {
2+
tag_name: 'aside',
3+
class: 'c-card--contained c-card--cloudy t-dark'
4+
} only %}
5+
{% block content %}
6+
<div class="o-rhythm o-rhythm--compact has-big-font-size">
7+
{% include '@cloudfour/components/heading/heading.twig' with {
8+
content: 'We’re Cloud Four',
9+
level: 0,
10+
weight: 'light'
11+
} only %}
12+
<p>
13+
We’ve solved complex responsive web design and web development
14+
challenges for ecommerce, healthcare, fashion, B2B, SAAS and non-profit
15+
organizations.
16+
</p>
17+
</div>
18+
{% endblock %}
19+
{% block footer %}
20+
{% include '@cloudfour/components/button/button.twig' with {
21+
label: 'Hire our team',
22+
href: 'https://cloudfour.com/and-you/',
23+
class: 'c-button--primary'
24+
} only %}
25+
{% endblock %}
26+
{% endembed %}

0 commit comments

Comments
 (0)