diff --git a/package.json b/package.json
index 857d0b8b0..2287fe264 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vanilla-framework",
- "version": "4.55.1",
+ "version": "4.56.0",
"author": {
"email": "webteam@canonical.com",
"name": "Canonical Webteam"
diff --git a/releases.yml b/releases.yml
index 19e687fb0..9ff572c96 100644
--- a/releases.yml
+++ b/releases.yml
@@ -1,3 +1,9 @@
+- version: 4.56.0
+ features:
+ - component: Product card
+ url: /docs/patterns/product-card
+ status: New
+ notes: Added a new Product card pattern
- version: 4.55.1
features:
- component: CheckboxInput
diff --git a/scss/_patterns_product-card.scss b/scss/_patterns_product-card.scss
new file mode 100644
index 000000000..930ed2272
--- /dev/null
+++ b/scss/_patterns_product-card.scss
@@ -0,0 +1,46 @@
+@import 'settings';
+
+@mixin vf-p-product-card {
+ // Product card(s) in the blog article sidebar, above the newsletter card.
+ // The whole card is an anchor (no CTA link), so render it as a block and
+ // match the newsletter card's border hover transition.
+ .p-card--product {
+ @extend %vf-card;
+ @extend %vf-is-bordered;
+
+ border-color: $colors--theme--border-low-contrast;
+ display: block;
+
+ @include vf-transition(border-color, brisk);
+
+ &:hover {
+ border-color: $colors--theme--border-high-contrast;
+ // Don't underline the whole card; the border highlight is the affordance.
+ text-decoration: none;
+ }
+
+ // The whole card is a link; don't apply the visited colour to its text.
+ &:visited {
+ color: $colors--theme--text-default;
+ }
+
+ // Arrow icon at the end of each card, in place of the removed CTA link.
+ // A recolourable mask, so the colour lives here rather than in inline SVG
+ // markup repeated in the template.
+ .product-card__arrow {
+ background-color: $color-brand;
+ display: inline-block;
+ height: $default-icon-size;
+ mask: url('data:image/svg+xml,')
+ no-repeat center / contain;
+ width: $default-icon-size;
+
+ @include vf-transition(transform, snap);
+ }
+
+ // Nudge the arrow to the right on hover.
+ &:hover .product-card__arrow {
+ transform: translateX($sp-small);
+ }
+ }
+}
diff --git a/scss/_vanilla.scss b/scss/_vanilla.scss
index 4cfcb7d1c..aceb316ba 100644
--- a/scss/_vanilla.scss
+++ b/scss/_vanilla.scss
@@ -44,6 +44,7 @@
@import 'patterns_notifications';
@import 'patterns_pagination';
@import 'patterns_pricing-block';
+@import 'patterns_product-card';
@import 'patterns_newsletter-signup';
@import 'patterns_pull-quotes';
@import 'patterns_resources-block';
@@ -152,6 +153,7 @@
@include vf-p-pagination;
@include vf-p-pricing-block;
@include vf-p-pull-quotes;
+ @include vf-p-product-card;
@include vf-p-resources-block;
@include vf-p-rule;
@include vf-p-search-and-filter;
diff --git a/side-navigation.yaml b/side-navigation.yaml
index 89b2a61f9..7f0427077 100644
--- a/side-navigation.yaml
+++ b/side-navigation.yaml
@@ -153,6 +153,8 @@
url: /docs/patterns/resources
- title: Card
url: /docs/patterns/content-card
+ - title: Product card
+ url: /docs/patterns/product-card
- heading: Utilities
ordering: alphabetical
subheadings:
diff --git a/templates/_macros/vf_product-card.jinja b/templates/_macros/vf_product-card.jinja
new file mode 100644
index 000000000..1a2b45727
--- /dev/null
+++ b/templates/_macros/vf_product-card.jinja
@@ -0,0 +1,7 @@
+{%- macro vf_product_card(url, heading, content, class_name="") -%}
+
+ {{ heading }} {{ content|safe }}
h5-styled heading text |
+| Content | p description text, rendered as raw HTML |
+| Arrow | Decorative arrow icon indicating the card is actionable |
+
+## Default
+
+The default product card renders a bordered card that links to the provided
+URL, with a heading, description, and trailing arrow.
+
+
+
+## Jinja Macro
+
+The `vf_product_card` Jinja macro can be used to generate a product card pattern. The API for the macro is shown below.
+
+### Parameters
+
+| Name | +Required? | +Type | +Default | +Description | +
|---|---|---|---|---|
+ url
+ |
+ + Yes + | +
+ string
+ |
+
+ ''
+ |
+ + Destination the card links to + | +
+ heading
+ |
+ + Yes + | +
+ string
+ |
+
+ ''
+ |
+
+ Heading text displayed at the top of the card, using h5 styling
+ |
+
+ content
+ |
+ + Yes + | +
+ string
+ |
+
+ ''
+ |
+ + Description text displayed below the heading; rendered as raw HTML + | +
+ class_name
+ |
+ + No + | +
+ string
+ |
+
+ ''
+ |
+ + Additional CSS class(es) appended to the card element + | +