Add styling to marketplace to identify sponsored products (#45684)

* Pass 'Sponsored' detail down to product cards from API

* Style a "Sponsored" label

* Stripe on top of sponsored products

* Add 'blob' next to sponsored listings

* Fix indentation bug

* Add changefile(s) from automation for the following project(s): woocommerce

* Update plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx

Co-authored-by: Remi Corson <remicorson@gmail.com>

* Update plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx

Co-authored-by: Remi Corson <remicorson@gmail.com>

* Update plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx

Co-authored-by: Remi Corson <remicorson@gmail.com>

* Apply suggestions from code review

Co-authored-by: Remi Corson <remicorson@gmail.com>

* Add missing close parenthesis following linter changes

* Make linter happier about hex colors (still needs variablising)

* Fix margins around vendor name

* Fixed height of product stripe

* Linting

* Moved color to variable and calculated alpha using Sass functions

* Update plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.scss

* Update plugins/woocommerce-admin/client/marketplace/stylesheets/_variables.scss

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Remi Corson <remicorson@gmail.com>
This commit is contained in:
Dan Q 2024-03-19 18:10:34 +00:00 committed by GitHub
parent 99853c19bf
commit b0ea77326f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 79 additions and 8 deletions

View File

@ -165,11 +165,22 @@
position: relative; position: relative;
} }
&__vendor-details {
display: flex;
gap: $grid-unit-10;
margin: 0;
padding: 0;
&__separator {
color: $gray-300;
font-size: 28px;
line-height: 16px;
}
}
&__vendor { &__vendor {
display: flex; display: flex;
gap: $grid-unit-05; gap: $grid-unit-05;
margin: 0;
padding: 0;
/* Allow vendor link to "punch through" the "whole card clickable" trick: */ /* Allow vendor link to "punch through" the "whole card clickable" trick: */
position: relative; position: relative;
} }
@ -181,6 +192,10 @@
text-decoration: none; text-decoration: none;
} }
&__sponsored-label {
color: $gray-700;
}
&__description { &__description {
display: -webkit-box; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;

View File

@ -24,6 +24,9 @@ export interface ProductCardProps {
} }
function ProductCard( props: ProductCardProps ): JSX.Element { function ProductCard( props: ProductCardProps ): JSX.Element {
const SPONSORED_PRODUCT_LABEL = 'promoted'; // what product.label indicates a sponsored placement
const SPONSORED_PRODUCT_STRIPE_SIZE = '5px'; // unfortunately can't be defined in CSS - height of "stripe"
const { isLoading, type } = props; const { isLoading, type } = props;
const query = useQuery(); const query = useQuery();
// Get the product if provided; if not provided, render a skeleton loader // Get the product if provided; if not provided, render a skeleton loader
@ -33,6 +36,8 @@ function ProductCard( props: ProductCardProps ): JSX.Element {
vendorName: '', vendorName: '',
vendorUrl: '', vendorUrl: '',
icon: '', icon: '',
label: null,
primary_color: null,
url: '', url: '',
price: 0, price: 0,
image: '', image: '',
@ -40,6 +45,24 @@ function ProductCard( props: ProductCardProps ): JSX.Element {
reviewsCount: null, reviewsCount: null,
}; };
function isSponsored(): boolean {
return SPONSORED_PRODUCT_LABEL === product.label;
}
/**
* Sponsored products with a primary_color set have that color applied as a dynamically-colored stripe at the top of the card.
* In an ideal world this could be set in a data- attribute and we'd use CSS calc() and attr() to get it, but
* attr() doesn't have very good support yet, so we need to apply some inline CSS to stripe sponsored results.
*/
function inlineCss(): object {
if ( ! isSponsored() || ! product.primary_color ) {
return {};
}
return {
background: `linear-gradient(${ product.primary_color } 0, ${ product.primary_color } ${ SPONSORED_PRODUCT_STRIPE_SIZE }, white ${ SPONSORED_PRODUCT_STRIPE_SIZE }, white)`,
};
}
function recordTracksEvent( event: string, data: ExtraProperties ) { function recordTracksEvent( event: string, data: ExtraProperties ) {
const tracksData = props.tracksData; const tracksData = props.tracksData;
@ -104,11 +127,16 @@ function ProductCard( props: ProductCardProps ): JSX.Element {
{ {
'is-loading': isLoading, 'is-loading': isLoading,
'is-small': props.small, 'is-small': props.small,
'is-sponsored': isSponsored(),
} }
); );
return ( return (
<Card className={ classNames } aria-hidden={ isLoading }> <Card
className={ classNames }
aria-hidden={ isLoading }
style={ inlineCss() }
>
<div className="woocommerce-marketplace__product-card__content"> <div className="woocommerce-marketplace__product-card__content">
{ isTheme && ( { isTheme && (
<div className="woocommerce-marketplace__product-card__image"> <div className="woocommerce-marketplace__product-card__image">
@ -158,12 +186,33 @@ function ProductCard( props: ProductCardProps ): JSX.Element {
</a> </a>
</h2> </h2>
{ isLoading && ( { isLoading && (
<p className="woocommerce-marketplace__product-card__vendor" /> <p className="woocommerce-marketplace__product-card__vendor-details">
<span className="woocommerce-marketplace__product-card__vendor" />
</p>
) } ) }
{ ! isLoading && productVendor && ( { ! isLoading && (
<p className="woocommerce-marketplace__product-card__vendor"> <p className="woocommerce-marketplace__product-card__vendor-details">
<span>{ __( 'By ', 'woocommerce' ) }</span> { productVendor && (
{ productVendor } <span className="woocommerce-marketplace__product-card__vendor">
<span>
{ __( 'By ', 'woocommerce' ) }
</span>
{ productVendor }
</span>
) }
{ productVendor && isSponsored() && (
<span
aria-hidden="true"
className="woocommerce-marketplace__product-card__vendor-details__separator"
>
·
</span>
) }
{ isSponsored() && (
<span className="woocommerce-marketplace__product-card__sponsored-label">
{ __( 'Sponsored', 'woocommerce' ) }
</span>
) }
</p> </p>
) } ) }
</div> </div>

View File

@ -73,6 +73,8 @@ export default function ProductListContent( props: {
image: product.image, image: product.image,
type: product.type, type: product.type,
icon: product.icon, icon: product.icon,
label: product.label,
primary_color: product.primary_color,
vendorName: product.vendorName, vendorName: product.vendorName,
vendorUrl: product.vendorUrl vendorUrl: product.vendorUrl
? appendURLParams( product.vendorUrl, [ ? appendURLParams( product.vendorUrl, [

View File

@ -39,6 +39,7 @@ export interface Product {
averageRating?: number | null; averageRating?: number | null;
reviewsCount?: number | null; reviewsCount?: number | null;
label?: string; label?: string;
primary_color?: string;
group?: string; group?: string;
searchTerm?: string; searchTerm?: string;
category?: string; category?: string;

View File

@ -0,0 +1,4 @@
Significance: patch
Type: enhancement
Made sponsored product listings in the Extensions marketplace easier to identify.