diff --git a/cli/src/components/__tests__/choice-ad-banner.test.tsx b/cli/src/components/__tests__/choice-ad-banner.test.tsx new file mode 100644 index 000000000..b787c9770 --- /dev/null +++ b/cli/src/components/__tests__/choice-ad-banner.test.tsx @@ -0,0 +1,23 @@ +import { describe, expect, test } from 'bun:test' + +import { getAdDisplayLabel } from '../choice-ad-banner' + +describe('choice ad banner display label', () => { + test('uses the display domain when the ad has a URL', () => { + expect( + getAdDisplayLabel({ + title: 'Example Sponsor', + url: 'https://www.example.com/path', + }), + ).toEqual({ text: 'example.com', variant: 'domain' }) + }) + + test('uses the ad title when the ad has no URL', () => { + expect( + getAdDisplayLabel({ + title: 'Example Sponsor', + url: '', + }), + ).toEqual({ text: 'Example Sponsor', variant: 'title' }) + }) +}) diff --git a/cli/src/components/choice-ad-banner.tsx b/cli/src/components/choice-ad-banner.tsx index 7ca3f1d4a..7832dc3d2 100644 --- a/cli/src/components/choice-ad-banner.tsx +++ b/cli/src/components/choice-ad-banner.tsx @@ -25,7 +25,13 @@ function truncateToLines(text: string, lineWidth: number, maxLines: number): str return text.slice(0, maxChars - 1) + '…' } -const extractDomain = (url: string): string => { +function truncateToWidth(text: string, width: number): string { + if (width <= 0) return '' + if (text.length <= width) return text + return text.slice(0, width - 1) + '…' +} + +export const extractDomain = (url: string): string => { try { const parsed = new URL(url) return parsed.hostname.replace(/^www\./, '') @@ -34,6 +40,17 @@ const extractDomain = (url: string): string => { } } +export function getAdDisplayLabel( + ad: Pick, +): { text: string; variant: 'domain' | 'title' } { + const url = ad.url.trim() + if (url) { + return { text: extractDomain(url), variant: 'domain' } + } + + return { text: ad.title.trim() || 'Sponsored', variant: 'title' } +} + /** * Calculate evenly distributed column widths that sum exactly to availableWidth. * Distributes remainder pixels across the first N columns so there's no gap. @@ -89,8 +106,10 @@ export const ChoiceAdBanner: React.FC = ({ ads, onImpressio > {visibleAds.map((ad, i) => { const isHovered = hoveredIndex === i - const domain = extractDomain(ad.url) const ctaText = ad.cta || ad.title || 'Learn more' + const label = getAdDisplayLabel(ad) + const labelMaxWidth = Math.max(0, widths[i] - ctaText.length - 5) + const labelText = truncateToWidth(label.text, labelMaxWidth) return (