From b6bccea0f3a2acb2826e2f80ef3d07759ae60da4 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 18 Mar 2026 08:35:33 +0000 Subject: [PATCH 1/4] Add accent colour to CTA button --- .../src/components/CallToActionAtom.tsx | 16 +++++++++++++--- .../src/layouts/HostedArticleLayout.tsx | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/dotcom-rendering/src/components/CallToActionAtom.tsx b/dotcom-rendering/src/components/CallToActionAtom.tsx index 6e7b768ce02..45fc876f6a4 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.tsx @@ -14,6 +14,7 @@ type CallToActionProps = { backgroundImage?: string; text?: string; buttonText?: string; + accentColour?: string; }; const overlayMaskGradientStyles = (angle: string, startPosition: number) => { @@ -116,6 +117,7 @@ export const CallToActionAtom = ({ backgroundImage, text, buttonText, + accentColour, }: CallToActionProps) => { return ( } theme={{ - textPrimary: sourcePalette.neutral[7], - backgroundPrimary: sourcePalette.neutral[100], - backgroundPrimaryHover: sourcePalette.neutral[86], + // We also still need to implement the dark mode based on the provided designs which should be the same as not providing an accent colour. + textPrimary: accentColour + ? sourcePalette.neutral[100] + : sourcePalette.neutral[0], + backgroundPrimary: + accentColour ?? sourcePalette.neutral[100], + //This is temporary as the behaviour we have in PROD is a lightbox when hover over the CTA. + backgroundPrimaryHover: transparentColour( + accentColour ?? sourcePalette.neutral[100], + 0.8, + ), }} > {buttonText} diff --git a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx index 6bc8e625394..95ea42a36a2 100644 --- a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx @@ -350,6 +350,9 @@ export const HostedArticleLayout = (props: WebProps | AppProps) => { backgroundImage={cta.image} text={cta.label} buttonText={cta.btnText} + accentColour={ + branding?.hostedCampaignColour + } /> )} From a9a21dac700de14dc18dfe63040faf0c90a34a43 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 18 Mar 2026 10:20:12 +0000 Subject: [PATCH 2/4] Add a new story with accent colour for CallToActionAtom --- .../components/CallToActionAtom.stories.tsx | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/dotcom-rendering/src/components/CallToActionAtom.stories.tsx b/dotcom-rendering/src/components/CallToActionAtom.stories.tsx index e8f7d67de08..9e8532eb3f6 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.stories.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.stories.tsx @@ -8,12 +8,26 @@ export default { export const Default = () => { return ( ); }; Default.storyName = 'default'; + +export const WithAccentColour = () => { + return ( + + ); +}; + +WithAccentColour.storyName = 'with accent colour'; From ef2cff39413251e110487b5b6cbf98952d5d8b86 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 18 Mar 2026 10:35:39 +0000 Subject: [PATCH 3/4] Remove anchor parent for CallToActionAtom and Button and instead used LinkButton --- .../src/components/CallToActionAtom.tsx | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/dotcom-rendering/src/components/CallToActionAtom.tsx b/dotcom-rendering/src/components/CallToActionAtom.tsx index 45fc876f6a4..d97f952d2d0 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.tsx @@ -6,7 +6,7 @@ import { textSansBold24, textSansBold28, } from '@guardian/source/foundations'; -import { Button, SvgExternal } from '@guardian/source/react-components'; +import { LinkButton, SvgExternal } from '@guardian/source/react-components'; import { transparentColour } from '../lib/transparentColour'; type CallToActionProps = { @@ -120,58 +120,51 @@ export const CallToActionAtom = ({ accentColour, }: CallToActionProps) => { return ( - - - {''} -
- {!!text &&

{text}

} - -
-
-
+ /> +
+ {!!text &&

{text}

} + } + theme={{ + // We also still need to implement the dark mode based on the provided designs which should be the same as not providing an accent colour. + textPrimary: accentColour + ? sourcePalette.neutral[100] + : sourcePalette.neutral[0], + backgroundPrimary: + accentColour ?? sourcePalette.neutral[100], + backgroundPrimaryHover: transparentColour( + accentColour ?? sourcePalette.neutral[100], + 0.8, + ), + }} + > + {buttonText} + +
+ ); }; From bc7c7bac5c26a23bfc22762de3a6f8c45991e8bc Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 18 Mar 2026 12:47:49 +0000 Subject: [PATCH 4/4] Updated unit tests and add new ones and added a comment for button hover --- .../components/CallToActionAtom.stories.tsx | 2 +- .../src/components/CallToActionAtom.test.tsx | 49 ++++++++++++++----- .../src/components/CallToActionAtom.tsx | 18 +++---- .../src/layouts/HostedArticleLayout.tsx | 4 +- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/dotcom-rendering/src/components/CallToActionAtom.stories.tsx b/dotcom-rendering/src/components/CallToActionAtom.stories.tsx index 9e8532eb3f6..60b07aae058 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.stories.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.stories.tsx @@ -25,7 +25,7 @@ export const WithAccentColour = () => { backgroundImage="https://media.guim.co.uk/2c2ad59a167c43496ff709d0d9a83e8d46c30674/0_0_1300_375/1300.jpg" text="Proactive security starts here" buttonText="Explore more" - accentColour="#d71920" + accentColor="#d71920" /> ); }; diff --git a/dotcom-rendering/src/components/CallToActionAtom.test.tsx b/dotcom-rendering/src/components/CallToActionAtom.test.tsx index 16f26b157f7..11a36269705 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.test.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.test.tsx @@ -3,21 +3,31 @@ import '@testing-library/jest-dom'; import { CallToActionAtom } from './CallToActionAtom'; describe('CallToActionAtom', () => { - it('should render with url and button text', () => { + it('should render with url and a default button text when not provided', () => { const { getByRole } = render( , ); - const link = getByRole('link'); + const link = getByRole('link', { name: 'Learn more' }); expect(link).toBeInTheDocument(); expect(link).toHaveAttribute('href', 'https://example.com'); + }); + + it('should display custom button text when provided', () => { + const { getByRole } = render( + , + ); - const button = getByRole('button', { name: 'Click here' }); - expect(button).toBeInTheDocument(); + const link = getByRole('link', { name: 'Click here' }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', 'https://example.com'); }); it('should display the label when provided', () => { @@ -47,21 +57,34 @@ describe('CallToActionAtom', () => { expect(heading).not.toBeInTheDocument(); }); - it('should have correct link wrapping the entire component', () => { + it('should apply the accent colour to the button when provided', () => { const { getByRole } = render( , ); - const link = getByRole('link'); - expect(link).toHaveAttribute('href', 'https://example.com'); + const link = getByRole('link', { name: 'Click here' }); + const computedStyle = window.getComputedStyle(link); + expect(computedStyle.color).toBe('rgb(255, 255, 255)'); + expect(computedStyle.backgroundColor).toBe('rgb(215, 25, 32)'); + }); + + it('should apply the default theme to the button when no accent colour is provided', () => { + const { getByRole } = render( + , + ); - // Check that the button is within the link - const button = getByRole('button', { name: 'Learn more' }); - expect(link).toContainElement(button); + const link = getByRole('link', { name: 'Click here' }); + const computedStyle = window.getComputedStyle(link); + expect(computedStyle.color).toBe('rgb(0, 0, 0)'); + expect(computedStyle.backgroundColor).toBe('rgb(255, 255, 255)'); }); }); diff --git a/dotcom-rendering/src/components/CallToActionAtom.tsx b/dotcom-rendering/src/components/CallToActionAtom.tsx index d97f952d2d0..28c1e5a6330 100644 --- a/dotcom-rendering/src/components/CallToActionAtom.tsx +++ b/dotcom-rendering/src/components/CallToActionAtom.tsx @@ -14,7 +14,7 @@ type CallToActionProps = { backgroundImage?: string; text?: string; buttonText?: string; - accentColour?: string; + accentColor?: string; }; const overlayMaskGradientStyles = (angle: string, startPosition: number) => { @@ -117,7 +117,7 @@ export const CallToActionAtom = ({ backgroundImage, text, buttonText, - accentColour, + accentColor, }: CallToActionProps) => { return ( } theme={{ // We also still need to implement the dark mode based on the provided designs which should be the same as not providing an accent colour. - textPrimary: accentColour + textPrimary: accentColor ? sourcePalette.neutral[100] : sourcePalette.neutral[0], backgroundPrimary: - accentColour ?? sourcePalette.neutral[100], - backgroundPrimaryHover: transparentColour( - accentColour ?? sourcePalette.neutral[100], - 0.8, - ), + accentColor ?? sourcePalette.neutral[100], + // This should be changed with `calculateHoverColour()` once we have the function available as DCR needs to upgrade Source to 12.1.0 to use it. + // Check https://github.com/guardian/csnx/blob/857116cf826dc700742f14c5a5f005bd6d39f1be/libs/%40guardian/source/CHANGELOG.md?plain=1#L20 + backgroundPrimaryHover: + accentColor ?? sourcePalette.neutral[100], }} > - {buttonText} + {buttonText ?? 'Learn more'} diff --git a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx index 95ea42a36a2..9c96108b0c4 100644 --- a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx @@ -350,9 +350,7 @@ export const HostedArticleLayout = (props: WebProps | AppProps) => { backgroundImage={cta.image} text={cta.label} buttonText={cta.btnText} - accentColour={ - branding?.hostedCampaignColour - } + accentColor={branding?.hostedCampaignColour} /> )}