Skip to content

Commit 39176b5

Browse files
authored
Logo component (#2152)
* Add logo component * Adjust card eyebrow spacing
1 parent 6bf8f7b commit 39176b5

File tree

14 files changed

+237
-16
lines changed

14 files changed

+237
-16
lines changed

.changeset/five-eggs-destroy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cloudfour/patterns': patch
3+
---
4+
5+
Adjust space between Card component heading and eyebrow

.changeset/thick-wombats-hammer.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 Logo component for consistent project logo sizing and alignment

src/components/card/card.scss

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ $_content-gap: ms.step(-1, 1rem);
3131

3232
$_cover-gap: ms.step(1, 1rem);
3333

34-
/// We add more space between the eyebrow and heading so they won't feel as
35-
/// crowded if the eyebrow contains visual elements.
36-
///
37-
/// @type Number
38-
/// @access private
39-
40-
$_eyebrow-gap: ms.step(1, 1rem);
41-
4234
/// The focus outline feels a little snug directly on the outer edge, but we
4335
/// don't want to extend _too_ far out for fear of colliding with adjacent
4436
/// content. Doubling the size of the focus edge felt like a nice compromise.
@@ -212,7 +204,7 @@ $_cloud-height: fluid.fluid-clamp(
212204

213205
.c-card__header {
214206
display: grid; /* 1 */
215-
gap: $_eyebrow-gap; /* 1 */
207+
gap: $_content-gap; /* 1 */
216208
grid-area: header;
217209

218210
/**

src/components/card/card.stories.mdx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const singleDemoStory = (args) => {
4949
};
5050
const singleDemoBlockExamples = {
5151
heading: 'Lorem ipsum dolor sit amet',
52-
eyebrow: `<img src="/media/logos/pleasantest.svg" alt="Pleasantest" width="180" height="58">`,
52+
eyebrow: `{% include '@cloudfour/components/logo/logo.twig' with { } only %}`,
5353
cover: `<img src="/media/feature-ozzie-wide.jpg" alt="">`,
5454
content: `<p>Consectetur adipiscing elit...</p>`,
5555
footer: `<p>{{'now'|date('M j, Y')}}</p>`,
@@ -151,14 +151,15 @@ An optional `cover` block may be provided containing an image or other visual ob
151151

152152
## With eyebrow
153153

154-
If a card includes a heading, you may want to include additional elements that precede the heading visually without disrupting the element's outline. For example, a customer's logo in a card that links to a case study. Similar to [the Article Header object](/?path=/docs/objects-article-header--example), the contents of the `eyebrow` block will render below the heading in the DOM, but display above the heading visually.
154+
If a card includes a heading, you may want to include additional elements that precede the heading visually without disrupting the element's outline. For example, a [Logo component](/docs/components-logo--basic-options) in a card that links to a case study. Similar to [the Article Header object](/?path=/docs/objects-article-header--example), the contents of the `eyebrow` block will render below the heading in the DOM, but display above the heading visually.
155155

156156
<Canvas>
157157
<Story
158158
name="Eyebrow"
159159
args={{
160160
href: '#',
161-
show: ['heading', 'eyebrow', 'content'],
161+
horizontal: '@m',
162+
show: ['heading', 'eyebrow', 'cover', 'content'],
162163
}}
163164
>
164165
{singleDemoStory.bind({})}

src/components/card/demo/div.twig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
{% endblock %}
88
{% block eyebrow %}
99
{%- if show_eyebrow -%}
10-
<img src="/media/logos/pleasantest.svg" alt="Pleasantest" width="180" height="58">
10+
{% include '@cloudfour/components/logo/logo.twig' with {
11+
src: '/media/logos/pleasantest.svg',
12+
alt: 'Pleasantest',
13+
width: 180,
14+
height: 58,
15+
scale: 1.25,
16+
align: 'end'
17+
} only %}
1118
{%- endif -%}
1219
{% endblock %}
1320
{% block cover %}

src/components/card/demo/single.twig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
{% endblock %}
77
{% block eyebrow %}
88
{%- if show_eyebrow -%}
9-
<img src="/media/logos/pleasantest.svg" alt="Pleasantest" width="180" height="58">
9+
{% include '@cloudfour/components/logo/logo.twig' with {
10+
src: '/media/logos/pleasantest.svg',
11+
alt: 'Pleasantest',
12+
width: 180,
13+
height: 58,
14+
scale: 1.25,
15+
align: 'end'
16+
} only %}
1017
{%- endif -%}
1118
{% endblock %}
1219
{% block cover %}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@use '../../../compiled/tokens/scss/color';
2+
@use 'sass:math';
3+
4+
$_line-color: color.$base-fuchsia-lighter;
5+
$_line-size: 1px;
6+
7+
._demo-c-logo-alignment {
8+
background-image: linear-gradient(
9+
to bottom,
10+
transparent calc(50% - math.div($_line-size, 2)),
11+
$_line-color calc(50% - math.div($_line-size, 2)),
12+
$_line-color calc(50% + math.div($_line-size, 2)),
13+
transparent calc(50% + math.div($_line-size, 2))
14+
);
15+
border: 0 solid $_line-color;
16+
border-width: $_line-size 0;
17+
display: grid;
18+
gap: 1em;
19+
grid-template-columns: repeat(3, 1fr);
20+
justify-content: space-between;
21+
22+
> * {
23+
border: inherit;
24+
border-width: 0 $_line-size;
25+
}
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<figure>
2+
<div class="_demo-c-logo-alignment">
3+
{% include '@cloudfour/components/logo/logo.twig' with {
4+
src: '/media/logos/walmart.svg',
5+
alt: 'Walmart',
6+
width: 176,
7+
height: 42
8+
} only %}
9+
{% include '@cloudfour/components/logo/logo.twig' with {
10+
src: '/media/logos/obama.svg',
11+
alt: 'Obama ’08',
12+
width: 171,
13+
height: 30,
14+
scale: align ? 0.8
15+
} only %}
16+
{% include '@cloudfour/components/logo/logo.twig' with {
17+
src: '/media/logos/pleasantest.svg',
18+
alt: 'Pleasantest',
19+
width: 180,
20+
height: 58,
21+
scale: align ? 1.25,
22+
align: align ? 'end'
23+
} only %}
24+
</div>
25+
<figcaption>
26+
Logos with {% if not align %}no{% endif %} alignment options set.
27+
</figcaption>
28+
</figure>

src/components/logo/logo.scss

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@use '../../compiled/tokens/scss/size';
2+
3+
/// Logo component
4+
///
5+
/// 1. By default, we assume that we want to vertically center the logo. This is
6+
/// only really apparent if the asset is scaled.
7+
/// 2. Justification is inherited by default, so a centered flex container (such
8+
/// as a Logo Group) will automatically have centered logos.
9+
.c-logo {
10+
align-items: var(--logo-align, center); // 1
11+
block-size: size.$height-logo-default;
12+
display: flex;
13+
justify-content: var(--logo-justify, inherit); // 2
14+
}
15+
16+
/// Logo content, presumably an `img` but possibly an `svg` or other element.
17+
///
18+
/// 1. Set the container size. We use `block-size` instead of `scale` so that it
19+
/// will impact the `inline-size`. This allows scale adjustments greater than
20+
/// 1.0 without overflowing the container.
21+
/// 2. Respect the logo's natural width up to the container width.
22+
/// 3. The combination of `block-size` and `max-inline-size` can cause the logo
23+
/// to be squashed at smaller sizes. This prevents the image contents from
24+
/// being distorted or clipped.
25+
.c-logo > *,
26+
.c-logo > picture > img {
27+
block-size: calc(100% * var(--logo-scale, 1)); // 1
28+
inline-size: auto; // 2
29+
max-inline-size: 100%; // 2
30+
object-fit: contain; // 3
31+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Canvas, Meta, Story } from '@storybook/addon-docs';
2+
import logoTemplate from './logo.twig';
3+
import alignmentDemo from './demo/alignment.twig';
4+
import './demo/alignment.scss';
5+
const alignOptions = ['start', 'center', 'end'];
6+
7+
<!--
8+
This component's options rely on CSS custom properties, which are currently
9+
broken in the library we use for inlining Storybook stories. Until that issue
10+
is resolved, we must fallback to iframes for these stories. 🙈️
11+
12+
@see https://github.com/aknuds1/html-to-react/issues/144
13+
-->
14+
15+
<Meta title="Components/Logo" parameters={{ docs: { inlineStories: false } }} />
16+
17+
# Logo
18+
19+
The logo component enforces a consistent height for logos, promoting alignment and consistency for content that summarizes branded projects, client work and case studies.
20+
21+
To showcase several logos together, see [the Logo Group object](/docs/objects-logo-group--default-story).
22+
23+
<Canvas>
24+
<Story
25+
name="Basic Options"
26+
argTypes={{
27+
src: { control: { type: 'text' } },
28+
alt: { control: { type: 'text' } },
29+
class: { control: { type: 'text' } },
30+
width: { control: { type: 'number' } },
31+
height: { control: { type: 'number' } },
32+
scale: { control: { type: 'number' } },
33+
align: {
34+
options: alignOptions,
35+
control: { type: 'inline-radio' },
36+
},
37+
justify: {
38+
options: alignOptions,
39+
control: { type: 'inline-radio' },
40+
},
41+
}}
42+
args={{
43+
src: '/media/logos/pleasantest.svg',
44+
alt: 'Pleasantest',
45+
width: 180,
46+
height: 58,
47+
}}
48+
>
49+
{(args) => logoTemplate(args)}
50+
</Story>
51+
</Canvas>
52+
53+
## Alignment
54+
55+
Different brands are usually designed in isolation, so it's common for logos to feel inconsistently sized when displayed in a row or a grid. The logo component includes `scale`, `align` and `justify` options for fine-tuning the alignment of logos relative to others nearby.
56+
57+
The following stories show three logos before and after alignment options are set. In the second example, the middle logo has a `scale` lower than `1`, whereas the rightmost logo has a `scale` higher than `1` and an `align` value of `end`.
58+
59+
<Canvas isColumn>
60+
<Story name="Before Alignment">{alignmentDemo.bind({})}</Story>
61+
<Story name="After Alignment" args={{ align: true }}>
62+
{alignmentDemo.bind({})}
63+
</Story>
64+
</Canvas>
65+
66+
## Template Options
67+
68+
<!--
69+
Because `ArgsTable` doesn't work very well for non-inline stories, we have to
70+
manually document the options available to this template.
71+
-->
72+
73+
- `align` (Default: `center`): Specify the block (vertical) alignment.
74+
- `alt`: A description of the image. For logos, this is typically the name of the brand.
75+
- `class`: Append additional class names to the element.
76+
- `content` (block): Specify the `img` or image-like element to display directly.
77+
- `height`: The height of the image in pixels.
78+
- `justify` (Default: `inherit`): Specify the inline (horizontal) alignment.
79+
- `scale`: Scale the logo up or down within its container.
80+
- `src`: The URL of the image to display.
81+
- `width`: The width of the image in pixels.
82+
83+
## CSS Custom Properties
84+
85+
- `--logo-align` (Default: `center`): Specify the block (vertical) alignment.
86+
- `--logo-justify` (Default: `inherit`): Specify the inline (horizontal) alignment.
87+
- `--logo-scale`: Scale the logo up or down within its container.

0 commit comments

Comments
 (0)