From c4980b0f1e5c9f480bd96c6db5c4a53411a2618e Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso Date: Fri, 2 Oct 2026 12:10:08 +0200 Subject: [PATCH 1/4] New branding changes on Footer component --- .../components/footer/code/FooterCodePage.tsx | 20 +++++++++++++++++++ packages/lib/src/footer/Footer.stories.tsx | 16 ++++++++++++--- packages/lib/src/footer/Footer.test.tsx | 4 ++++ packages/lib/src/footer/Footer.tsx | 12 ++++++----- packages/lib/src/footer/Icons.tsx | 4 ++-- packages/lib/src/footer/types.ts | 4 ++++ packages/lib/src/footer/utils.ts | 2 +- 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/apps/website/screens/components/footer/code/FooterCodePage.tsx b/apps/website/screens/components/footer/code/FooterCodePage.tsx index a16ded6c47..5a24b40e13 100644 --- a/apps/website/screens/components/footer/code/FooterCodePage.tsx +++ b/apps/website/screens/components/footer/code/FooterCodePage.tsx @@ -157,6 +157,26 @@ const sections = [ 0 + + variant + + 'branded' | 'neutral' + + + The available footer variants: + + + + 'branded' + + ), diff --git a/packages/lib/src/footer/Footer.stories.tsx b/packages/lib/src/footer/Footer.stories.tsx index 73cfea535b..0308f39063 100644 --- a/packages/lib/src/footer/Footer.stories.tsx +++ b/packages/lib/src/footer/Footer.stories.tsx @@ -202,6 +202,10 @@ const Footer = () => ( <DxcFooter /> </ExampleContainer> + <ExampleContainer> + <Title title="Neutral" theme="light" level={4} /> + <DxcFooter variant="neutral" bottomLinks={bottom} /> + </ExampleContainer> <ExampleContainer> <Title title="With custom logo" theme="light" level={4} /> <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> @@ -422,6 +426,10 @@ const Footer = () => ( <Title title="Reduced" theme="light" level={4} /> <DxcFooter mode="reduced" /> </ExampleContainer> + <ExampleContainer> + <Title title="Neutral Reduced" theme="light" level={4} /> + <DxcFooter variant="neutral" mode="reduced" /> + </ExampleContainer> <ExampleContainer> <Title title="Reduced with custom logo" theme="light" level={4} /> <DxcFooter mode="reduced" logo={{ src: woodenDockImage, alt: "Custom logo" }} /> @@ -436,9 +444,11 @@ const Footer = () => ( }, }} > - <DxcFooter /> - <DxcFooter mode="reduced" /> - <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + <DxcFlex direction="column" gap="var(--spacing-gap-xl)"> + <DxcFooter /> + <DxcFooter mode="reduced" /> + <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + </DxcFlex> </HalstackProvider> </ExampleContainer> </> diff --git a/packages/lib/src/footer/Footer.test.tsx b/packages/lib/src/footer/Footer.test.tsx index 2cb34a346f..f0363e3bc5 100644 --- a/packages/lib/src/footer/Footer.test.tsx +++ b/packages/lib/src/footer/Footer.test.tsx @@ -28,6 +28,10 @@ describe("Footer component tests", () => { const { getByTitle } = render(<DxcFooter />); expect(getByTitle("DXC Logo")).toBeTruthy(); }); + test("Footer renders the reduced neutral logo in black", () => { + const { container } = render(<DxcFooter mode="reduced" variant="neutral" />); + expect(container.querySelector("svg path")?.getAttribute("fill")).toBe("#0E1020"); + }); test("Footer renders with social links", () => { const { getByRole } = render(<DxcFooter socialLinks={social} />); const socialIcon = getByRole("link"); diff --git a/packages/lib/src/footer/Footer.tsx b/packages/lib/src/footer/Footer.tsx index 6bacca5f6b..0edd31c5bc 100644 --- a/packages/lib/src/footer/Footer.tsx +++ b/packages/lib/src/footer/Footer.tsx @@ -127,13 +127,14 @@ const SocialIconContainer = styled.div` } `; -const BottomContainer = styled.div<{ textColor: string; width: number }>` +const BottomContainer = styled.div<{ textColor: string; width: number; variant: FooterPropsType["variant"] }>` width: 100%; min-height: var(--height-xl); display: grid; grid-template-columns: 60% var(--spacing-gap-ml) 1fr; align-items: center; - background-color: var(--color-bg-primary-strong); + background-color: ${({ variant }) => (variant === "branded" ? "var(--color-bg-primary-strong)" : "var(--color-bg-primary-lightest)")}; + border-top: ${({ variant }) => (variant === "branded" ? "" : "var(--border-width-s) var(--border-style-default) var(--border-color-primary-stronger)")}; color: ${({ textColor }) => textColor}; padding: var(--spacing-padding-none) var(--spacing-padding-xl); box-sizing: border-box; @@ -213,6 +214,7 @@ const DxcFooter = ({ mode = "default", rightContent, socialLinks, + variant = "branded", tabIndex = 0, }: FooterPropsType): JSX.Element => { const translatedLabels = use(HalstackLanguageContext).labels; @@ -233,10 +235,10 @@ const DxcFooter = ({ ) : themedLogos?.footerReducedLogo ? ( <LogoImg mode={mode} alt={"Footer logo"} src={themedLogos.footerReducedLogo} title={"Footer logo"} /> ) : ( - dxcSmallLogo + dxcSmallLogo(variant === "neutral" ? "#0E1020" : undefined) ); } - }, [mode, logo, themedLogos]); + }, [mode, logo, themedLogos, variant]); const footerRef = useRef<HTMLDivElement>(null); const width = useWidth(footerRef); @@ -285,7 +287,7 @@ const DxcFooter = ({ )} </MainContainer> )} - <BottomContainer ref={bottomContainerRef} textColor={textColor} width={width}> + <BottomContainer ref={bottomContainerRef} variant={variant} textColor={textColor} width={width}> {mode === "default" && bottomLinks && ( <BottomLinks textColor={textColor} width={width}> {bottomLinks?.map((link, index) => ( diff --git a/packages/lib/src/footer/Icons.tsx b/packages/lib/src/footer/Icons.tsx index 5a6c6b1977..2d8955ae59 100644 --- a/packages/lib/src/footer/Icons.tsx +++ b/packages/lib/src/footer/Icons.tsx @@ -77,11 +77,11 @@ export const dxcLogo = ( </svg> ); -export const dxcSmallLogo = ( +export const dxcSmallLogo = (color = "#F6F3F0") => ( <svg xmlns="http://www.w3.org/2000/svg" width="57" height="16" viewBox="0 0 57 16" fill="none"> <path d="M14.585 4.05054C16.7623 4.05054 18.5344 5.82924 18.5345 8.01646C18.5345 10.2037 16.7623 11.9823 14.585 11.9823H4.04297V10.3637H14.585C15.8752 10.3637 16.9251 9.31046 16.9251 8.01646C16.9251 6.72239 15.8752 5.6693 14.585 5.6693H4.04297V4.05054H14.585ZM52.8906 5.66923H42.3486C41.0584 5.66923 40.0085 6.72239 40.0085 8.01646C40.0085 9.31046 41.0584 10.3636 42.3486 10.3636H52.8906V11.9823H42.3486C40.1704 11.9823 38.3992 10.2036 38.3991 8.01646C38.3991 5.82924 40.1714 4.05048 42.3486 4.05048H52.8906V5.66923ZM36.858 5.66923C35.1351 5.66924 33.9253 6.43576 32.6444 7.24706C32.2289 7.51079 31.8077 7.77646 31.3684 8.01359C31.8076 8.25066 32.2289 8.51626 32.6444 8.78006C33.9253 9.59132 35.1351 10.3579 36.858 10.3579V11.9766C34.6703 11.9766 33.1386 11.0063 31.7868 10.1503C30.6631 9.43899 29.6928 8.82386 28.5038 8.82386C27.3147 8.82386 26.3444 9.43806 25.2207 10.1503C23.8689 11.0063 22.3372 11.9766 20.1495 11.9766V10.3579C21.8724 10.3579 23.0822 9.59132 24.3631 8.78006C24.7786 8.51626 25.2 8.25066 25.6392 8.01359C25.2 7.77646 24.7786 7.51079 24.3631 7.24706C23.0822 6.43576 21.8724 5.66923 20.1495 5.66923V4.05048C22.3372 4.05048 23.8689 5.02078 25.2207 5.87776C26.3444 6.58904 27.3147 7.20419 28.5038 7.20419V7.20319C29.6928 7.20319 30.6631 6.58908 31.7868 5.87684C33.1386 5.02082 34.6703 4.05049 36.858 4.05048V5.66923Z" - fill="#F6F3F0" + fill={color} /> </svg> ); diff --git a/packages/lib/src/footer/types.ts b/packages/lib/src/footer/types.ts index 8574256078..99aa3a3cd9 100644 --- a/packages/lib/src/footer/types.ts +++ b/packages/lib/src/footer/types.ts @@ -76,6 +76,10 @@ type FooterPropsType = { * inside the leftContent and rightContent. */ tabIndex?: number; + /** + * Visual variant of the footer. + */ + variant?: "branded" | "neutral"; }; export default FooterPropsType; diff --git a/packages/lib/src/footer/utils.ts b/packages/lib/src/footer/utils.ts index 56c9f6d6e9..67d75f6389 100644 --- a/packages/lib/src/footer/utils.ts +++ b/packages/lib/src/footer/utils.ts @@ -30,7 +30,7 @@ function getLuminance(color: string): number { export const getContrastColor = (bgColor: string) => { const luminance = getLuminance(bgColor); - return luminance > 0.179 ? "var(--color-fg-neutral-dark)" : "var(--color-fg-neutral-bright)"; + return luminance > 0.179 ? "var(--color-fg-primary-stronger)" : "var(--color-fg-neutral-bright)"; }; export const getResponsiveStyles = { From 05f89a508818c5528e1eeaddc62c3c20babde107 Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso <pfelguerosogalguera@gmail.com> Date: Mon, 5 Oct 2026 16:12:49 +0200 Subject: [PATCH 2/4] Fix test --- packages/lib/src/footer/Footer.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/lib/src/footer/Footer.test.tsx b/packages/lib/src/footer/Footer.test.tsx index f0363e3bc5..00b90399cd 100644 --- a/packages/lib/src/footer/Footer.test.tsx +++ b/packages/lib/src/footer/Footer.test.tsx @@ -113,11 +113,11 @@ describe("Footer component tests", () => { }); describe("getContrastColor function", () => { - test("should return black color for light backgrounds", () => { - expect(getContrastColor("#FFFFFF")).toBe("var(--color-fg-neutral-dark)"); - expect(getContrastColor("#F5F5F5")).toBe("var(--color-fg-neutral-dark)"); - expect(getContrastColor("rgb(255, 255, 255)")).toBe("var(--color-fg-neutral-dark)"); - expect(getContrastColor("rgb(245, 245, 245)")).toBe("var(--color-fg-neutral-dark)"); + test("should return primary stronger for light backgrounds", () => { + expect(getContrastColor("#FFFFFF")).toBe("var(--color-fg-primary-stronger)"); + expect(getContrastColor("#F5F5F5")).toBe("var(--color-fg-primary-stronger)"); + expect(getContrastColor("rgb(255, 255, 255)")).toBe("var(--color-fg-primary-stronger)"); + expect(getContrastColor("rgb(245, 245, 245)")).toBe("var(--color-fg-primary-stronger)"); }); test("should return white color for dark backgrounds", () => { From 73b7c66b7bb645953d49e5a1a4fa23804bc37a24 Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso <pfelguerosogalguera@gmail.com> Date: Tue, 6 Oct 2026 17:25:39 +0200 Subject: [PATCH 3/4] fixes based on comments --- .../components/footer/code/FooterCodePage.tsx | 8 +++-- packages/lib/src/footer/Footer.stories.tsx | 36 ++++++++++--------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/apps/website/screens/components/footer/code/FooterCodePage.tsx b/apps/website/screens/components/footer/code/FooterCodePage.tsx index 5a24b40e13..e7eb69792b 100644 --- a/apps/website/screens/components/footer/code/FooterCodePage.tsx +++ b/apps/website/screens/components/footer/code/FooterCodePage.tsx @@ -166,12 +166,16 @@ const sections = [ The available footer variants: <ul> <li> - <strong>branded</strong>: Footer with branded styling. + <strong>branded</strong>: Footer with branded styling, using the primary brand background and + contrasting content colors. </li> <li> - <strong>neutral</strong>: Footer with neutral styling. + <strong>neutral</strong>: Footer with neutral styling, using a neutral background and content colors + instead of the branded treatment. </li> </ul> + Changing the variant only changes the footer's visual styling; its layout, content, and behavior remain + the same. </td> <td> <TableCode>'branded'</TableCode> diff --git a/packages/lib/src/footer/Footer.stories.tsx b/packages/lib/src/footer/Footer.stories.tsx index 0308f39063..576461704e 100644 --- a/packages/lib/src/footer/Footer.stories.tsx +++ b/packages/lib/src/footer/Footer.stories.tsx @@ -196,23 +196,20 @@ const bottomLong = [ }, ]; -const Footer = () => ( +const FooterExamples = ({ variant }: { variant?: "branded" | "neutral" }) => ( <> <ExampleContainer> <Title title="Default" theme="light" level={4} /> - <DxcFooter /> - </ExampleContainer> - <ExampleContainer> - <Title title="Neutral" theme="light" level={4} /> - <DxcFooter variant="neutral" bottomLinks={bottom} /> + <DxcFooter variant={variant} /> </ExampleContainer> <ExampleContainer> <Title title="With custom logo" theme="light" level={4} /> - <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + <DxcFooter variant={variant} logo={{ src: woodenDockImage, alt: "Custom logo" }} /> </ExampleContainer> <ExampleContainer> <Title title="With children, copyright, bottom links and social links" theme="light" level={4} /> <DxcFooter + variant={variant} socialLinks={social} bottomLinks={bottom} leftContent={ @@ -252,6 +249,7 @@ const Footer = () => ( <ExampleContainer> <Title title="With long content" theme="light" level={4} /> <DxcFooter + variant={variant} socialLinks={social} bottomLinks={bottomLong} copyright="This is a long copyright text, this is a long copyright text, this is a long copyright text, this is a long copyright text, this is a long copyright text, this is a long copyright text, this is a long copyright text." @@ -345,6 +343,7 @@ const Footer = () => ( <ExampleContainer> <Title title="With children, copyright, bottom links and social links from material" theme="light" level={4} /> <DxcFooter + variant={variant} copyright="Copyright" socialLinks={socialMaterialIcons} bottomLinks={bottom} @@ -385,6 +384,7 @@ const Footer = () => ( <ExampleContainer pseudoState="pseudo-focus"> <Title title="Focused bottom and social links" theme="light" level={4} /> <DxcFooter + variant={variant} copyright="Copyright" socialLinks={social} bottomLinks={bottom} @@ -424,15 +424,11 @@ const Footer = () => ( </ExampleContainer> <ExampleContainer> <Title title="Reduced" theme="light" level={4} /> - <DxcFooter mode="reduced" /> - </ExampleContainer> - <ExampleContainer> - <Title title="Neutral Reduced" theme="light" level={4} /> - <DxcFooter variant="neutral" mode="reduced" /> + <DxcFooter variant={variant} mode="reduced" /> </ExampleContainer> <ExampleContainer> <Title title="Reduced with custom logo" theme="light" level={4} /> - <DxcFooter mode="reduced" logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + <DxcFooter variant={variant} mode="reduced" logo={{ src: woodenDockImage, alt: "Custom logo" }} /> </ExampleContainer> <ExampleContainer> <Title title="Themed footer" theme="light" level={4} /> @@ -445,15 +441,19 @@ const Footer = () => ( }} > <DxcFlex direction="column" gap="var(--spacing-gap-xl)"> - <DxcFooter /> - <DxcFooter mode="reduced" /> - <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + <DxcFooter variant={variant} /> + <DxcFooter variant={variant} mode="reduced" /> + <DxcFooter variant={variant} logo={{ src: woodenDockImage, alt: "Custom logo" }} /> </DxcFlex> </HalstackProvider> </ExampleContainer> </> ); +const Footer = () => <FooterExamples />; + +const NeutralFooter = () => <FooterExamples variant="neutral" />; + const dxcLogo = ( <svg xmlns="http://www.w3.org/2000/svg" width="73" height="40" viewBox="0 0 73 40"> <title>DXC Logo @@ -677,6 +677,10 @@ export const Chromatic: Story = { render: Footer, }; +export const Neutral: Story = { + render: NeutralFooter, +}; + export const Responsive: Story = { render: Footer, parameters: { From b6007be3d228014b60e140f10ed171b98db46421 Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso Date: Wed, 7 Oct 2026 09:01:12 +0200 Subject: [PATCH 4/4] Remove unwanted storybook page --- packages/lib/src/footer/Footer.stories.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/lib/src/footer/Footer.stories.tsx b/packages/lib/src/footer/Footer.stories.tsx index 576461704e..38eabd939d 100644 --- a/packages/lib/src/footer/Footer.stories.tsx +++ b/packages/lib/src/footer/Footer.stories.tsx @@ -450,7 +450,14 @@ const FooterExamples = ({ variant }: { variant?: "branded" | "neutral" }) => ( ); -const Footer = () => ; +const Footer = () => ( + <> + + <FooterExamples /> + <Title title="Neutral" theme="light" level={3} /> + <FooterExamples variant="neutral" /> + </> +); const NeutralFooter = () => <FooterExamples variant="neutral" />;