diff --git a/dotcom-rendering/src/components/ListenToArticle.importable.tsx b/dotcom-rendering/src/components/ListenToArticle.importable.tsx index 81ede9e00f0..e32add1f161 100644 --- a/dotcom-rendering/src/components/ListenToArticle.importable.tsx +++ b/dotcom-rendering/src/components/ListenToArticle.importable.tsx @@ -1,9 +1,6 @@ import { log } from '@guardian/libs'; import { useEffect, useState } from 'react'; -import { - getListenToArticleClient, - getNativeABTestingClient, -} from '../lib/bridgetApi'; +import { getListenToArticleClient } from '../lib/bridgetApi'; import { useIsBridgetCompatible } from '../lib/useIsBridgetCompatible'; import { ListenToArticleButton } from './ListenToArticleButton'; @@ -28,48 +25,28 @@ export const formatAudioDuration = ( }; export const ListenToArticle = ({ articleId }: Props) => { - const [showButton, setShowButton] = useState(false); + const [showButton, setShowButton] = useState(true); const [audioDurationSeconds, setAudioDurationSeconds] = useState< number | undefined - >(undefined); + >(314); const isBridgetCompatible = useIsBridgetCompatible('8.7.0'); useEffect(() => { if (isBridgetCompatible) { Promise.all([ - // AB TESTING native - getNativeABTestingClient().getParticipations(), getListenToArticleClient().isAvailable(articleId), getListenToArticleClient().isPlaying(articleId), getListenToArticleClient().getAudioDurationSeconds(articleId), ]) - .then( - ([ - abParticipations, - isAvailable, - isPlaying, - durationSeconds, - ]) => { - // AB TESTING native start - const variant = abParticipations.get( - 'l2a_article_button_test', - ); - if (variant === 'no-button') { - setShowButton(false); - } else if (variant === 'with-duration') { - setAudioDurationSeconds( - typeof durationSeconds === 'number' && - durationSeconds > 0 - ? durationSeconds - : undefined, - ); - setShowButton(isAvailable && !isPlaying); - } else if (variant === 'without-duration') { - setShowButton(isAvailable && !isPlaying); - } - // AB TESTING native ends - }, - ) + .then(([isAvailable, isPlaying, durationSeconds]) => { + setAudioDurationSeconds( + typeof durationSeconds === 'number' && + durationSeconds > 0 + ? durationSeconds + : undefined, + ); + setShowButton(isAvailable && !isPlaying); + }) .catch((error) => { console.error( 'Error fetching article audio status: ', diff --git a/dotcom-rendering/src/components/ListenToArticleButton.stories.tsx b/dotcom-rendering/src/components/ListenToArticleButton.stories.tsx index 44cff51c5ea..25f5e34e343 100644 --- a/dotcom-rendering/src/components/ListenToArticleButton.stories.tsx +++ b/dotcom-rendering/src/components/ListenToArticleButton.stories.tsx @@ -13,7 +13,7 @@ type Story = StoryObj; export const ListenToArticleWithDurationButton = { args: { onClickHandler: () => undefined, - audioDuration: '3:02', + audioDuration: '5:14', }, } satisfies Story; diff --git a/dotcom-rendering/src/components/ListenToArticleButton.tsx b/dotcom-rendering/src/components/ListenToArticleButton.tsx index 3c24d4f6d02..014bc95eabc 100644 --- a/dotcom-rendering/src/components/ListenToArticleButton.tsx +++ b/dotcom-rendering/src/components/ListenToArticleButton.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/react'; -import { height, space } from '@guardian/source/foundations'; +import { height, neutral, space } from '@guardian/source/foundations'; +import type { ThemeIcon } from '@guardian/source/react-components'; import { Button, SvgMediaControlsPlay, @@ -18,12 +19,12 @@ const buttonCss = (audioDuration: string | undefined) => css` } margin-bottom: ${space[4]}px; margin-left: ${space[2]}px; - padding-left: ${space[2]}px; + padding-left: ${space[3]}px; padding-right: ${audioDuration === undefined ? space[4] : space[3]}px; padding-bottom: 0px; font-size: 15px; - height: ${height.ctaSmall}px; - min-height: ${height.ctaSmall}px; + height: ${height.ctaXsmall}px; + min-height: ${height.ctaXsmall}px; .src-button-space { width: 0px; @@ -36,15 +37,46 @@ const dividerCss = css` opacity: 0.5; border-left: 1px solid ${palette('--follow-icon-background')}; margin-left: ${space[2]}px; - margin-right: ${space[2]}px; `; -const durationCss = css` - font-weight: 300; +const themeIcon: ThemeIcon = { + fill: palette('--follow-icon-background'), +}; + +const waveFormContainerCss = css` + height: ${space[12]}px; + border-top: 1px solid ${neutral[86]}; `; -const baselineCss = css` - padding-bottom: 2px; +const generateWaveformGradients = (barCount: number): string => { + const barWidth = 2; + const spacing = 1; + const gradients: string[] = []; + let lastBarHeight = Math.floor(Math.random() * 60) + 25; // Initial random height + + for (let i = 0; i < barCount; i++) { + const variation = lastBarHeight * 0.5; // keep within 50% of last bar height + const minHeight = Math.max(50, lastBarHeight - variation); + const maxHeight = Math.min(70, lastBarHeight + variation); + const barHeight = + Math.floor(Math.random() * (maxHeight - minHeight + 1)) + minHeight; + lastBarHeight = barHeight; + const position = i * (barWidth + spacing); + gradients.push( + `linear-gradient(to top, ${neutral[86]} 0 ${barHeight}%, transparent ${barHeight}%) ${position}px 50% / ${barWidth}px 100%`, + ); + } + + return gradients.join(',\n\t\t'); +}; + +const waveFormCss = css` + background: ${generateWaveformGradients(250)}; + background-repeat: no-repeat; + height: inherit; + display: block; + width: 100%; + padding-top: ${space[2]}px; `; type ButtonProps = { @@ -55,19 +87,22 @@ export const ListenToArticleButton = ({ onClickHandler, audioDuration, }: ButtonProps) => ( - +
+
+ +
+
);