diff --git a/apps/website/screens/components/footer/code/FooterCodePage.tsx b/apps/website/screens/components/footer/code/FooterCodePage.tsx index a16ded6c4..e7eb69792 100644 --- a/apps/website/screens/components/footer/code/FooterCodePage.tsx +++ b/apps/website/screens/components/footer/code/FooterCodePage.tsx @@ -157,6 +157,30 @@ const sections = [ 0 + + variant + + 'branded' | 'neutral' + + + The available footer variants: + + Changing the variant only changes the footer's visual styling; its layout, content, and behavior remain + the same. + + + 'branded' + + ), diff --git a/packages/lib/src/footer/Footer.stories.tsx b/packages/lib/src/footer/Footer.stories.tsx index 73cfea535..38eabd939 100644 --- a/packages/lib/src/footer/Footer.stories.tsx +++ b/packages/lib/src/footer/Footer.stories.tsx @@ -196,19 +196,20 @@ const bottomLong = [ }, ]; -const Footer = () => ( +const FooterExamples = ({ variant }: { variant?: "branded" | "neutral" }) => ( <> - <DxcFooter /> + <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={ @@ -248,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." @@ -341,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} @@ -381,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} @@ -420,11 +424,11 @@ const Footer = () => ( </ExampleContainer> <ExampleContainer> <Title title="Reduced" theme="light" level={4} /> - <DxcFooter 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} /> @@ -436,14 +440,27 @@ const Footer = () => ( }, }} > - <DxcFooter /> - <DxcFooter mode="reduced" /> - <DxcFooter logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + <DxcFlex direction="column" gap="var(--spacing-gap-xl)"> + <DxcFooter variant={variant} /> + <DxcFooter variant={variant} mode="reduced" /> + <DxcFooter variant={variant} logo={{ src: woodenDockImage, alt: "Custom logo" }} /> + </DxcFlex> </HalstackProvider> </ExampleContainer> </> ); +const Footer = () => ( + <> + <Title title="Default" theme="light" level={3} /> + <FooterExamples /> + <Title title="Neutral" theme="light" level={3} /> + <FooterExamples variant="neutral" /> + </> +); + +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 @@ -667,6 +684,10 @@ export const Chromatic: Story = { render: Footer, }; +export const Neutral: Story = { + render: NeutralFooter, +}; + export const Responsive: Story = { render: Footer, parameters: { diff --git a/packages/lib/src/footer/Footer.test.tsx b/packages/lib/src/footer/Footer.test.tsx index 2cb34a346..00b90399c 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(); expect(getByTitle("DXC Logo")).toBeTruthy(); }); + test("Footer renders the reduced neutral logo in black", () => { + const { container } = render(); + expect(container.querySelector("svg path")?.getAttribute("fill")).toBe("#0E1020"); + }); test("Footer renders with social links", () => { const { getByRole } = render(); const socialIcon = getByRole("link"); @@ -109,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", () => { diff --git a/packages/lib/src/footer/Footer.tsx b/packages/lib/src/footer/Footer.tsx index 6bacca5f6..0edd31c5b 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 ? ( ) : ( - dxcSmallLogo + dxcSmallLogo(variant === "neutral" ? "#0E1020" : undefined) ); } - }, [mode, logo, themedLogos]); + }, [mode, logo, themedLogos, variant]); const footerRef = useRef(null); const width = useWidth(footerRef); @@ -285,7 +287,7 @@ const DxcFooter = ({ )} )} - + {mode === "default" && bottomLinks && ( {bottomLinks?.map((link, index) => ( diff --git a/packages/lib/src/footer/Icons.tsx b/packages/lib/src/footer/Icons.tsx index 5a6c6b197..2d8955ae5 100644 --- a/packages/lib/src/footer/Icons.tsx +++ b/packages/lib/src/footer/Icons.tsx @@ -77,11 +77,11 @@ export const dxcLogo = ( ); -export const dxcSmallLogo = ( +export const dxcSmallLogo = (color = "#F6F3F0") => ( ); diff --git a/packages/lib/src/footer/types.ts b/packages/lib/src/footer/types.ts index 857425607..99aa3a3cd 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 56c9f6d6e..67d75f638 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 = {