Skip to content

Commit 573e6d6

Browse files
authored
feat(Equal heights): Build equal heights pattern (#5499)
* Equal heights prototype/POC * design review * parameterize image aspect ratio * reorder params, add custom image aspect ratios example * Support variable heading levels * Equal heights docs * design review * fix dead links * prettier
1 parent caed3ef commit 573e6d6

18 files changed

Lines changed: 950 additions & 1 deletion

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vanilla-framework",
3-
"version": "4.23.2",
3+
"version": "4.24.0",
44
"author": {
55
"email": "webteam@canonical.com",
66
"name": "Canonical Webteam"

releases.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
- version: 4.24.0
2+
features:
3+
- component: Equal heights
4+
url: /docs/patterns/equal-heights
5+
status: New
6+
notes: We've introduced the new equal heights pattern.
17
- version: 4.23.0
28
features:
39
- component: Pricing block

scss/_patterns_equal-height-row.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
Column:
1616
.p-equal-height-row__col:
1717
Column element within an equal height row.
18+
.p-equal-height-row__col.is-borderless:
19+
Column element within an equal height row with no top border.
1820
Item:
1921
.p-equal-height-row__item:
2022
Item element within an equal height row column.
@@ -68,6 +70,10 @@
6870
}
6971
}
7072

73+
.p-equal-height-row__col.is-borderless {
74+
border: none;
75+
}
76+
7177
// DIVIDERS
7278

7379
// For each row or column grid we only have access to two pseudo elements:

side-navigation.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113
- heading: Patterns
114114
ordering: alphabetical
115115
subheadings:
116+
- title: Equal heights
117+
url: /docs/patterns/equal-heights
116118
- title: Hero
117119
url: /docs/patterns/hero
118120
- title: Rich list (horizontal)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{#-
2+
Params
3+
- title_text (string) (required): The text to be displayed as the heading
4+
- subtitle_text (string) (optional): The text to be displayed as the subtitle
5+
- subtitle_heading_level (int) (optional): The heading level for the subtitle. Can be 4 or 5. Defaults to 5.
6+
- image_aspect_ratio_small (string) (optional): The aspect ratio for item images on small screens. Defaults to "square". Can be "square", "2-3", "3-2", "16-9", "cinematic". Defaults to "square".
7+
- image_aspect_ratio_medium (string) (optional): The aspect ratio for item images on medium screens. Defaults to "square". Can be "square", "2-3", "3-2", "16-9", "cinematic". Defaults to "square".
8+
- image_aspect_ratio_large (string) (optional): The aspect ratio for item images on large screens. Defaults to "2-3". Can be "square", "2-3", "3-2", "16-9", "cinematic". Defaults to "2-3".
9+
- items (array) (required): An array of items, each including 'image_html', 'title_text', 'description_html', and 'cta_html'.
10+
-#}
11+
{%- macro vf_equal_heights(
12+
title_text,
13+
subtitle_text="",
14+
subtitle_heading_level=5,
15+
image_aspect_ratio_small="square",
16+
image_aspect_ratio_medium="square",
17+
image_aspect_ratio_large="2-3",
18+
items=[]
19+
) -%}
20+
{% set has_subtitle = subtitle_text | trim | length > 0 %}
21+
{% set description_content = caller('description') | trim %}
22+
{% set has_description = description_content | length > 0 %}
23+
{% set cta_content = caller('cta') | trim %}
24+
{% set has_cta = cta_content | length > 0 %}
25+
26+
{% set has_two_top_cols = has_subtitle or has_description %}
27+
28+
{%- if subtitle_heading_level not in [4, 5] -%}
29+
{% set subtitle_heading_level=5 %}
30+
{%- endif -%}
31+
32+
<div class="p-section">
33+
<hr class="p-rule is-fixed-width"/>
34+
<div class="p-section--shallow">
35+
{%- if has_two_top_cols -%}
36+
<div class="row--50-50-on-large">
37+
<div class="col">
38+
{%- endif -%}
39+
<h2{% if not has_two_top_cols %} class="u-fixed-width"{% endif %}>{{ title_text }}</h2>
40+
{%- if has_two_top_cols -%}
41+
</div>
42+
{%- endif -%}
43+
{%- if has_two_top_cols -%}
44+
<div class="col">
45+
{%- if has_subtitle -%}
46+
<p class="p-heading--{{ subtitle_heading_level }}">{{ subtitle_text }}</p>
47+
{%- endif -%}
48+
{%- if has_description -%}
49+
{{- description_content -}}
50+
{%- endif -%}
51+
</div>
52+
{%- endif -%}
53+
{%- if has_two_top_cols -%}
54+
</div>
55+
{%- endif -%}
56+
</div>
57+
58+
<div class="row">
59+
<div class="{%- if items | length % 3 == 0 and items | length % 4 != 0 -%}col-9 col-start-large-4{%- else -%}col{%- endif -%}">
60+
<div class="p-equal-height-row--wrap">
61+
{%- for item in items -%}
62+
{% set image = item.get("image_html") | trim %}
63+
{% set title = item.get("title_text") | trim %}
64+
{% set description = item.get("description_html") or "" | trim %}
65+
{% set cta = item.get("cta_html") or "" | trim %}
66+
<div class="p-equal-height-row__col is-borderless">
67+
{#- Image item (required) -#}
68+
<div class="p-equal-height-row__item">
69+
<div
70+
class="p-image-container--{{ image_aspect_ratio_small }}-on-small p-image-container--{{ image_aspect_ratio_medium }}-on-medium p-image-container--{{ image_aspect_ratio_large }}-on-large is-cover">
71+
{#- The consumer must pass in an img.p-image-container__image for the image to be properly formatted -#}
72+
{{- image | safe -}}
73+
</div>
74+
</div>
75+
{#- Title item (required) -#}
76+
<div class="p-equal-height-row__item">
77+
<hr class="p-rule--highlight"/>
78+
<p class="p-heading--{{ subtitle_heading_level }}">{{- title -}}</p>
79+
</div>
80+
{#- Description item (optional) -#}
81+
<div class="p-equal-height-row__item">
82+
{{- description | safe -}}
83+
</div>
84+
{#- CTA item (optional) -#}
85+
<div class="p-equal-height-row__item">
86+
{%- if cta | length > 0 -%}
87+
<p>
88+
{{- cta | safe -}}
89+
</p>
90+
{%- endif -%}
91+
</div>
92+
</div>
93+
{%- endfor -%}
94+
</div>
95+
</div>
96+
</div>
97+
{%- if has_cta -%}
98+
<div class="row">
99+
<hr class="p-rule--muted">
100+
<div class="col-6 col-medium-3 col-start-large-7 col-start-medium-4">
101+
<p>
102+
{{- cta_content -}}
103+
</p>
104+
</div>
105+
</div>
106+
{%- endif -%}
107+
</div>
108+
{%- endmacro -%}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{% extends "_layouts/examples.html" %}
2+
{% from "_macros/vf_equal-heights.jinja" import vf_equal_heights %}
3+
{% block title %}Equal heights / 3 columns / Without CTA{% endblock %}
4+
5+
{% block standalone_css %}patterns_all{% endblock %}
6+
7+
{% block content %}
8+
9+
{% call(slot) vf_equal_heights(
10+
title_text="Keep this heading to 2 lines on large screens.",
11+
subtitle_text="Ensure the right hand side of this 50/50 split is taller than the left hand side (heading) on its left. This includes the subtitle and description.",
12+
items=[
13+
{
14+
"title_text": "A strong hardware ecosystem",
15+
"image_html": "<img src='https://assets.ubuntu.com/v1/ff6a068d-kernelt-vanilla-ehp-1.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
16+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
17+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
18+
},
19+
{
20+
"title_text": "A strong hardware ecosystem",
21+
"image_html": "<img src='https://assets.ubuntu.com/v1/7aa4ed28-kernelt-vanilla-ehp-2.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
22+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
23+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
24+
},
25+
{
26+
"title_text": "A strong hardware ecosystem",
27+
"image_html": "<img src='https://assets.ubuntu.com/v1/4936d43a-kernelt-vanilla-ehp-3.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
28+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
29+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
30+
}
31+
]
32+
) %}
33+
{% if slot == "description" %}
34+
<p>
35+
Ensure this block is taller than the heading on its left. Cloud types vary depending on who owns or
36+
operates
37+
them. It is also possible to use more than one cloud at a time in a hybrid or multi-cloud architecture. Cloud
38+
types vary depending on who owns or operates them. It is also possible to use more than one cloud at a time
39+
in
40+
a hybrid or multi-cloud architecture. Cloud types vary depending on who owns or operates them. It is also
41+
possible to use more than one cloud at a time in a hybrid or multi-cloud architecture.
42+
</p>
43+
{% endif %}
44+
{% endcall %}
45+
{% endblock %}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{% extends "_layouts/examples.html" %}
2+
{% from "_macros/vf_equal-heights.jinja" import vf_equal_heights %}
3+
{% block title %}Equal heights / 3 columns / Without description{% endblock %}
4+
5+
{% block standalone_css %}patterns_all{% endblock %}
6+
7+
{% block content %}
8+
9+
{% call(slot) vf_equal_heights(
10+
title_text="Keep this heading to 2 lines on large screens.",
11+
subtitle_text="Ensure the right hand side of this 50/50 split is taller than the left hand side (heading) on its left. This includes the subtitle and description.",
12+
items=[
13+
{
14+
"title_text": "A strong hardware ecosystem",
15+
"image_html": "<img src='https://assets.ubuntu.com/v1/ff6a068d-kernelt-vanilla-ehp-1.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
16+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
17+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
18+
},
19+
{
20+
"title_text": "A strong hardware ecosystem",
21+
"image_html": "<img src='https://assets.ubuntu.com/v1/7aa4ed28-kernelt-vanilla-ehp-2.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
22+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
23+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
24+
},
25+
{
26+
"title_text": "A strong hardware ecosystem",
27+
"image_html": "<img src='https://assets.ubuntu.com/v1/4936d43a-kernelt-vanilla-ehp-3.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
28+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
29+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
30+
}
31+
]
32+
) %}
33+
{% if slot == "cta" %}
34+
<a href="#" class="p-button">Learn more</a>
35+
<a href="#">Contact us&nbsp;&rsaquo;</a>
36+
{% endif %}
37+
{% endcall %}
38+
{% endblock %}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{% extends "_layouts/examples.html" %}
2+
{% from "_macros/vf_equal-heights.jinja" import vf_equal_heights %}
3+
{% block title %}Equal heights / 3 columns{% endblock %}
4+
5+
{% block standalone_css %}patterns_all{% endblock %}
6+
7+
{% block content %}
8+
9+
{% call(slot) vf_equal_heights(
10+
title_text="Keep this heading to 2 lines on large screens.",
11+
subtitle_text="Ensure the right hand side of this 50/50 split is taller than the left hand side (heading) on its left. This includes the subtitle and description.",
12+
items=[
13+
{
14+
"title_text": "A strong hardware ecosystem",
15+
"image_html": "<img src='https://assets.ubuntu.com/v1/ff6a068d-kernelt-vanilla-ehp-1.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
16+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
17+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
18+
},
19+
{
20+
"title_text": "A strong hardware ecosystem",
21+
"image_html": "<img src='https://assets.ubuntu.com/v1/7aa4ed28-kernelt-vanilla-ehp-2.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
22+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
23+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
24+
},
25+
{
26+
"title_text": "A strong hardware ecosystem",
27+
"image_html": "<img src='https://assets.ubuntu.com/v1/4936d43a-kernelt-vanilla-ehp-3.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
28+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
29+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
30+
},
31+
{
32+
"title_text": "A strong hardware ecosystem",
33+
"image_html": "<img src='https://assets.ubuntu.com/v1/ff6a068d-kernelt-vanilla-ehp-1.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
34+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
35+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
36+
},
37+
{
38+
"title_text": "A strong hardware ecosystem",
39+
"image_html": "<img src='https://assets.ubuntu.com/v1/7aa4ed28-kernelt-vanilla-ehp-2.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
40+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
41+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
42+
},
43+
{
44+
"title_text": "A strong hardware ecosystem",
45+
"image_html": "<img src='https://assets.ubuntu.com/v1/4936d43a-kernelt-vanilla-ehp-3.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
46+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
47+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
48+
}
49+
]
50+
) %}
51+
{% if slot == "description" %}
52+
<p>
53+
Ensure this block is taller than the heading on its left. Cloud types vary depending on who owns or
54+
operates
55+
them. It is also possible to use more than one cloud at a time in a hybrid or multi-cloud architecture. Cloud
56+
types vary depending on who owns or operates them. It is also possible to use more than one cloud at a time
57+
in
58+
a hybrid or multi-cloud architecture. Cloud types vary depending on who owns or operates them. It is also
59+
possible to use more than one cloud at a time in a hybrid or multi-cloud architecture.
60+
</p>
61+
{% endif %}
62+
{% if slot == "cta" %}
63+
<a href="#" class="p-button">Learn more</a>
64+
<a href="#">Contact us&nbsp;&rsaquo;</a>
65+
{% endif %}
66+
{% endcall %}
67+
{% endblock %}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{% extends "_layouts/examples.html" %}
2+
{% from "_macros/vf_equal-heights.jinja" import vf_equal_heights %}
3+
{% block title %}Equal heights / 4 columns / Custom aspect ratios{% endblock %}
4+
5+
{% block standalone_css %}patterns_all{% endblock %}
6+
7+
{% block content %}
8+
9+
{% call(slot) vf_equal_heights(
10+
title_text="Keep this heading to 2 lines on large screens.",
11+
subtitle_text="Ensure the right hand side of this 50/50 split is taller than the left hand side (heading) on its left. This includes the subtitle and description.",
12+
image_aspect_ratio_small="3-2",
13+
image_aspect_ratio_medium="16-9",
14+
image_aspect_ratio_large="cinematic",
15+
items=[
16+
{
17+
"title_text": "A strong hardware ecosystem",
18+
"image_html": "<img src='https://assets.ubuntu.com/v1/ff6a068d-kernelt-vanilla-ehp-1.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
19+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
20+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
21+
},
22+
{
23+
"title_text": "A strong hardware ecosystem",
24+
"image_html": "<img src='https://assets.ubuntu.com/v1/7aa4ed28-kernelt-vanilla-ehp-2.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
25+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
26+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
27+
},
28+
{
29+
"title_text": "A strong hardware ecosystem",
30+
"image_html": "<img src='https://assets.ubuntu.com/v1/4936d43a-kernelt-vanilla-ehp-3.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
31+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
32+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
33+
},
34+
{
35+
"title_text": "A strong hardware ecosystem",
36+
"image_html": "<img src='https://assets.ubuntu.com/v1/bbe7b062-kernelt-vanilla-ehp-4.png' class='p-image-container__image' width='284' height='426' alt='Kernelt' />",
37+
"description_html": "<p>We enable Ubuntu Core with the best ODMs and silicon vendors in the world. We continuously test it on leading IoT and edge devices and hardware.</p>",
38+
"cta_html": "<a href='#'>Browse all certified hardware&nbsp;&rsaquo;</a>"
39+
}
40+
]
41+
) %}
42+
{% if slot == "description" %}
43+
<p>
44+
Ensure this block is taller than the heading on its left. Cloud types vary depending on who owns or
45+
operates
46+
them. It is also possible to use more than one cloud at a time in a hybrid or multi-cloud architecture. Cloud
47+
types vary depending on who owns or operates them. It is also possible to use more than one cloud at a time
48+
in
49+
a hybrid or multi-cloud architecture. Cloud types vary depending on who owns or operates them. It is also
50+
possible to use more than one cloud at a time in a hybrid or multi-cloud architecture.
51+
</p>
52+
{% endif %}
53+
{% if slot == "cta" %}
54+
<a href="#" class="p-button">Learn more</a>
55+
<a href="#">Contact us&nbsp;&rsaquo;</a>
56+
{% endif %}
57+
{% endcall %}
58+
{% endblock %}

0 commit comments

Comments
 (0)