From cdf636568fa3aa481d8672d9f967b615f404e0d0 Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Mon, 21 Sep 2026 11:29:12 +0200 Subject: [PATCH] fix: render sponsor strip logos as images --- .../monetization/sponsorStrip/SponsorLogo.tsx | 64 +++---------------- .../sponsorStrip/SponsorStrip.spec.tsx | 38 ++++++----- .../sponsorStrip/SponsorStrip.tsx | 9 --- .../sponsorStrip/sponsorLogoSizing.ts | 5 +- .../sponsorStrip/sponsorStripCreative.ts | 6 +- 5 files changed, 32 insertions(+), 90 deletions(-) diff --git a/packages/shared/src/features/monetization/sponsorStrip/SponsorLogo.tsx b/packages/shared/src/features/monetization/sponsorStrip/SponsorLogo.tsx index bd7b43e915..efb81298c2 100644 --- a/packages/shared/src/features/monetization/sponsorStrip/SponsorLogo.tsx +++ b/packages/shared/src/features/monetization/sponsorStrip/SponsorLogo.tsx @@ -1,6 +1,5 @@ import type { CSSProperties, ReactElement } from 'react'; import React, { useMemo } from 'react'; -import classNames from 'classnames'; import { AdPixel } from '../../../components/cards/ad/common/AdPixel'; import { getViewedPixels } from '../../../components/cards/ad/common/getViewedPixels'; import { anchorSponsoredRel } from '../../../lib/strings'; @@ -28,17 +27,8 @@ interface SponsorLogoProps { * the gold slot takes its natural width instead. */ boxWidth?: number; - /** - * Draw the mark as a single-colour silhouette that takes the surrounding - * text colour, instead of the file's own inks. This is what makes a wall of - * marks from a dozen advertisers read as one row in both themes — full - * colour there is a patchwork, and half the marks die against one ground. - * The gold slot is the exception: its brand colour is what was sold. - */ - monochrome?: boolean; /** Height ceiling in px, so a mark cannot outgrow the row it sits in. */ maxHeight?: number; - className?: string; } export const SponsorLogo = ({ @@ -47,9 +37,7 @@ export const SponsorLogo = ({ cap, exactHeight, boxWidth, - monochrome = false, maxHeight, - className, }: SponsorLogoProps): ReactElement => { const { ref, isViewable, onClick } = useSponsorSlotLog({ sponsor, @@ -76,17 +64,7 @@ export const SponsorLogo = ({ const size: CSSProperties = { height: `${height}px`, - // A mask paints whatever box it is handed, and a boxed wall slot has to - // stay a predictable width, so both take the width the ratio implies. A - // bare `` carries its own ratio, and with no dimensions on the wire - // the file beats the stand-in: the gold slot is sized by height and lets - // the width follow, which is what the slot was sold as. Handing it the - // stand-in width instead would letterbox a wide lockup down to two thirds - // of the height the row reserves for it. - width: - monochrome || boxWidth - ? `${Math.round(height * sponsor.ratio)}px` - : 'auto', + width: boxWidth ? `${Math.round(height * sponsor.ratio)}px` : 'auto', }; return ( @@ -97,41 +75,15 @@ export const SponsorLogo = ({ rel={anchorSponsoredRel} title={sponsor.company} onClick={onClick} - className={classNames( - 'relative flex shrink-0 items-center justify-center', - className, - )} + className="relative flex shrink-0 items-center justify-center" style={boxWidth ? { width: `${boxWidth}px` } : undefined} > - {monochrome ? ( - - ) : ( - {sponsor.company} - )} + {sponsor.company} {/* No `fireOnMount`: the ad server should count the impression when the mark reaches the viewport, which is how every other placement counts it. Only the viewable re-fire below is already gated by then. */} diff --git a/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.spec.tsx b/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.spec.tsx index 5fb9e8b325..78d18e1d9d 100644 --- a/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.spec.tsx +++ b/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.spec.tsx @@ -238,11 +238,6 @@ it('should log an impression per logo with its tier and slot', async () => { ); }); -// The wire sends no dimensions, so every mark carries the stand-in ratio. A -// masked wall mark needs a box computed from it — a mask paints whatever box it -// gets — but the gold slot is an `` with its own ratio, and handing it the -// stand-in width letterboxes a wide lockup to two thirds of the height the row -// reserves for the one slot somebody paid for. it('should let the gold mark take its own width', async () => { renderStrip(); await settle(); @@ -254,18 +249,27 @@ it('should let the gold mark take its own width', async () => { expect(gold).toHaveStyle({ height: '20px', width: 'auto' }); }); -it('should give a masked wall mark a box to paint into', async () => { - renderStrip(); - await settle(); - - // Whichever premium mark the deck dealt, not a named one: the pool is - // shuffled per page load and holds more creatives than the row has slots, - // so naming one picks a mark that is only usually there. - const company = shownLogos().find((name) => PREMIUM.includes(name)) as string; - const wall = within(screen.getByTitle(company)).getByLabelText(company); - - expect(wall).toHaveStyle({ height: '17px', width: '60px' }); -}); +it.each([ + { companies: PREMIUM, height: '17px', width: '60px' }, + { companies: COMMUNITY, height: '15px', width: '53px' }, +])( + 'should render a wall logo image at height $height', + async ({ companies, height, width }) => { + renderStrip(); + await settle(); + + // Whichever mark the deck dealt, not a named one: the pool is + // shuffled per page load and holds more creatives than the row has slots, + // so naming one picks a mark that is only usually there. + const company = shownLogos().find((name) => + companies.includes(name), + ) as string; + const wall = within(screen.getByTitle(company)).getByAltText(company); + + expect(wall).toHaveAttribute('src', `icon-${company}`); + expect(wall).toHaveStyle({ height, width }); + }, +); it('should open air time for every logo on the row', async () => { renderStrip(); diff --git a/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.tsx b/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.tsx index ce0fb10576..1882899037 100644 --- a/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.tsx +++ b/packages/shared/src/features/monetization/sponsorStrip/SponsorStrip.tsx @@ -77,16 +77,11 @@ const SponsorRow = ({ Made possible by - {/* The gold mark is the one slot that keeps its own inks and its - own size: one coloured mark at full height against a silhouetted - wall is the whole hierarchy of the row, without a hover effect - on top. */} {gold && ( )} @@ -114,8 +109,6 @@ const SponsorRow = ({ cap={PREMIUM_CAP} boxWidth={SLOT_WIDTH} maxHeight={WALL_MAX_HEIGHT} - monochrome - className="text-text-secondary transition-colors hover:text-text-primary" /> ))} {community.map((sponsor, index) => ( @@ -129,8 +122,6 @@ const SponsorRow = ({ cap={COMMUNITY_CAP} boxWidth={SLOT_WIDTH} maxHeight={WALL_MAX_HEIGHT} - monochrome - className="text-text-tertiary transition-colors hover:text-text-primary" /> ))} diff --git a/packages/shared/src/features/monetization/sponsorStrip/sponsorLogoSizing.ts b/packages/shared/src/features/monetization/sponsorStrip/sponsorLogoSizing.ts index 662246135d..95f160bf79 100644 --- a/packages/shared/src/features/monetization/sponsorStrip/sponsorLogoSizing.ts +++ b/packages/shared/src/features/monetization/sponsorStrip/sponsorLogoSizing.ts @@ -3,15 +3,14 @@ * That normalising exists to stop a dozen unrelated wall marks fighting each * other, and it works by trading height for width, so it punishes exactly the * wide mark-plus-wordmark lockup a paid slot is most likely to supply: the - * lockup came out shorter than the tallest silhouette beside it, which is the + * lockup came out shorter than the tallest mark beside it, which is the * opposite of what the slot is sold as. One known creative in one slot does * not need normalising, it needs to be the biggest thing on the row. * * It is the box height, not the cap height, and a lockup that is all wordmark * spends nearly all of that box on letterforms where a mark-plus-wordmark * spends it on the mark. Sized for the former: matching the wall's ceiling in - * height, it still leads the row on width and on being the one slot in - * colour. + * height, it still leads the row on width. */ export const GOLD_HEIGHT = 20; /** The wall's two tiers differ by a hair of ink, not by a wash of opacity. */ diff --git a/packages/shared/src/features/monetization/sponsorStrip/sponsorStripCreative.ts b/packages/shared/src/features/monetization/sponsorStrip/sponsorStripCreative.ts index 03d97b97dd..9e226cd074 100644 --- a/packages/shared/src/features/monetization/sponsorStrip/sponsorStripCreative.ts +++ b/packages/shared/src/features/monetization/sponsorStrip/sponsorStripCreative.ts @@ -91,11 +91,7 @@ export const parseSponsors = (raw: unknown): SponsorStripCreative[] => { }; /** - * The bar ships one flat asset per advertiser and no dimensions, so both the - * themed pair and the measured ratio the row was built around are gone. The - * wall masks its marks to the row's text colour, which is what lets one file - * serve either ground; the gold slot keeps the file's own inks, so a mark drawn - * for a single theme is on its own there. + * The bar ships one flat asset per advertiser and no dimensions. * * Every mark therefore takes the ratio the optical sizing is calibrated around, * which makes `opticalHeight` hand back the cap exactly and leaves `contain` to