diff --git a/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.scss b/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.scss index 9b4e5dd520b..8e2a8f29f13 100644 --- a/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.scss +++ b/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.scss @@ -165,11 +165,22 @@ 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 { display: flex; gap: $grid-unit-05; - margin: 0; - padding: 0; /* Allow vendor link to "punch through" the "whole card clickable" trick: */ position: relative; } @@ -181,6 +192,10 @@ text-decoration: none; } + &__sponsored-label { + color: $gray-700; + } + &__description { display: -webkit-box; -webkit-box-orient: vertical; diff --git a/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx b/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx index 3d740c1375f..d746b0eaddf 100644 --- a/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx +++ b/plugins/woocommerce-admin/client/marketplace/components/product-card/product-card.tsx @@ -24,6 +24,9 @@ export interface ProductCardProps { } 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 query = useQuery(); // Get the product if provided; if not provided, render a skeleton loader @@ -33,6 +36,8 @@ function ProductCard( props: ProductCardProps ): JSX.Element { vendorName: '', vendorUrl: '', icon: '', + label: null, + primary_color: null, url: '', price: 0, image: '', @@ -40,6 +45,24 @@ function ProductCard( props: ProductCardProps ): JSX.Element { 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 ) { const tracksData = props.tracksData; @@ -104,11 +127,16 @@ function ProductCard( props: ProductCardProps ): JSX.Element { { 'is-loading': isLoading, 'is-small': props.small, + 'is-sponsored': isSponsored(), } ); return ( - +
{ isTheme && (
@@ -158,12 +186,33 @@ function ProductCard( props: ProductCardProps ): JSX.Element { { isLoading && ( -

+

+ +

) } - { ! isLoading && productVendor && ( -

- { __( 'By ', 'woocommerce' ) } - { productVendor } + { ! isLoading && ( +

+ { productVendor && ( + + + { __( 'By ', 'woocommerce' ) } + + { productVendor } + + ) } + { productVendor && isSponsored() && ( + + ) } + { isSponsored() && ( + + { __( 'Sponsored', 'woocommerce' ) } + + ) }

) }
diff --git a/plugins/woocommerce-admin/client/marketplace/components/product-list-content/product-list-content.tsx b/plugins/woocommerce-admin/client/marketplace/components/product-list-content/product-list-content.tsx index 91028817c34..9111923f3e8 100644 --- a/plugins/woocommerce-admin/client/marketplace/components/product-list-content/product-list-content.tsx +++ b/plugins/woocommerce-admin/client/marketplace/components/product-list-content/product-list-content.tsx @@ -73,6 +73,8 @@ export default function ProductListContent( props: { image: product.image, type: product.type, icon: product.icon, + label: product.label, + primary_color: product.primary_color, vendorName: product.vendorName, vendorUrl: product.vendorUrl ? appendURLParams( product.vendorUrl, [ diff --git a/plugins/woocommerce-admin/client/marketplace/components/product-list/types.ts b/plugins/woocommerce-admin/client/marketplace/components/product-list/types.ts index dcf675cd49f..1626e469df2 100644 --- a/plugins/woocommerce-admin/client/marketplace/components/product-list/types.ts +++ b/plugins/woocommerce-admin/client/marketplace/components/product-list/types.ts @@ -39,6 +39,7 @@ export interface Product { averageRating?: number | null; reviewsCount?: number | null; label?: string; + primary_color?: string; group?: string; searchTerm?: string; category?: string; diff --git a/plugins/woocommerce/changelog/45684-add-woocom19612-identify-sponsored-products b/plugins/woocommerce/changelog/45684-add-woocom19612-identify-sponsored-products new file mode 100644 index 00000000000..d62ddd69521 --- /dev/null +++ b/plugins/woocommerce/changelog/45684-add-woocom19612-identify-sponsored-products @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Made sponsored product listings in the Extensions marketplace easier to identify. \ No newline at end of file