@purpurds/footer 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LICENSE.txt +59 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/footer-navigation.d.ts +22 -0
- package/dist/footer-navigation.d.ts.map +1 -0
- package/dist/footer-social-link.d.ts +11 -0
- package/dist/footer-social-link.d.ts.map +1 -0
- package/dist/footer.cjs.js +34 -0
- package/dist/footer.cjs.js.map +1 -0
- package/dist/footer.d.ts +66 -0
- package/dist/footer.d.ts.map +1 -0
- package/dist/footer.es.js +965 -0
- package/dist/footer.es.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +65 -0
- package/src/constants.ts +1 -0
- package/src/footer-navigation.tsx +102 -0
- package/src/footer-social-link.tsx +28 -0
- package/src/footer.mixins.scss +9 -0
- package/src/footer.module.scss +303 -0
- package/src/footer.stories.tsx +192 -0
- package/src/footer.test.tsx +192 -0
- package/src/footer.tsx +202 -0
- package/src/global.d.ts +4 -0
- package/src/types.ts +5 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import { facebook, instagram, linkedin, x, youtube } from "@purpurds/icon";
|
|
3
|
+
import { Link } from "@purpurds/link";
|
|
4
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
+
|
|
6
|
+
import "@purpurds/link/styles";
|
|
7
|
+
import "@purpurds/grid/styles";
|
|
8
|
+
import "@purpurds/accordion/styles";
|
|
9
|
+
import "@purpurds/icon/styles";
|
|
10
|
+
import "@purpurds/heading/styles";
|
|
11
|
+
import { Footer } from "./footer";
|
|
12
|
+
|
|
13
|
+
const meta = {
|
|
14
|
+
title: "Components/Footer",
|
|
15
|
+
component: Footer,
|
|
16
|
+
parameters: {
|
|
17
|
+
design: [
|
|
18
|
+
{
|
|
19
|
+
name: "Footer",
|
|
20
|
+
type: "figma",
|
|
21
|
+
url: "https://www.figma.com/design/XEaIIFskrrxIBHMZDkIuIg/Purpur-DS---Component-library-%26-guidelines?node-id=58165-9763",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
} satisfies Meta<typeof Footer>;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof Footer>;
|
|
29
|
+
|
|
30
|
+
type CustomTestLinkProps = {
|
|
31
|
+
children?: React.ReactNode;
|
|
32
|
+
href?: string;
|
|
33
|
+
target?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const CustomTestLink = forwardRef(({ children, href, target, ...props }: CustomTestLinkProps) => {
|
|
37
|
+
return (
|
|
38
|
+
<a href={href} target={target} {...props}>
|
|
39
|
+
{children}
|
|
40
|
+
</a>
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const navigationLinks = [
|
|
45
|
+
{
|
|
46
|
+
heading: "Recommended",
|
|
47
|
+
links: [
|
|
48
|
+
{ text: "iPhone 16", href: "https://telia.se" },
|
|
49
|
+
{ text: "Samsung Galaxy s24", href: "https://telia.se" },
|
|
50
|
+
{ text: "Premier League", href: "https://telia.se" },
|
|
51
|
+
{ text: "SHL", href: "https://telia.se" },
|
|
52
|
+
{ text: "Mobile Phones", href: "https://telia.se" },
|
|
53
|
+
{ text: "Broadband", href: "https://telia.se" },
|
|
54
|
+
{ text: "Fiber", href: "https://telia.se" },
|
|
55
|
+
{ text: "TV and Streaming", href: "https://telia.se" },
|
|
56
|
+
{ text: "Black Friday", href: "https://telia.se" },
|
|
57
|
+
{ text: "Telia's Offers", href: "https://telia.se" },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
heading: "This is Telia",
|
|
62
|
+
links: [
|
|
63
|
+
{ text: "About Telia", href: "https://telia.se" },
|
|
64
|
+
{ text: "Press", href: "https://telia.se" },
|
|
65
|
+
{ text: "Network of the Future", href: "https://telia.se" },
|
|
66
|
+
{ text: "Telia's Networks and Cables", href: "https://telia.se" },
|
|
67
|
+
{ text: "Jobs at Telia", href: "https://telia.se" },
|
|
68
|
+
{ text: "5G", href: "https://telia.se" },
|
|
69
|
+
{ text: "2G/3G Phase-out", href: "https://telia.se" },
|
|
70
|
+
{ text: "Management Team", href: "https://telia.se" },
|
|
71
|
+
{ text: "Privacy Policy", href: "https://telia.se" },
|
|
72
|
+
{ text: "About the Website", href: "https://telia.se" },
|
|
73
|
+
{ text: "Cookies", href: "https://telia.se" },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
heading: "Shop at Telia",
|
|
78
|
+
links: [
|
|
79
|
+
{ text: "Support", href: "https://telia.se" },
|
|
80
|
+
{ text: "Contact Us", href: "https://telia.se" },
|
|
81
|
+
{ text: "Operational Information", href: "https://telia.se" },
|
|
82
|
+
{ text: "Purchase Information", href: "https://telia.se" },
|
|
83
|
+
{ text: "Terms and Conditions", href: "https://telia.se" },
|
|
84
|
+
{ text: "Prices", href: "https://telia.se" },
|
|
85
|
+
{ text: "Telia Stores", href: "https://telia.se" },
|
|
86
|
+
{ text: "Reports and Violations", href: "https://telia.se" },
|
|
87
|
+
{ text: "Coverage Maps", href: "https://telia.se" },
|
|
88
|
+
{ text: "Email to Telia", href: "https://telia.se" },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
heading: "Sustainability",
|
|
93
|
+
links: [
|
|
94
|
+
{ text: "Recycle Your Phone", href: "https://telia.se" },
|
|
95
|
+
{ text: "Used Phones", href: "https://telia.se" },
|
|
96
|
+
{ text: "Repair Your Phone", href: "https://telia.se" },
|
|
97
|
+
{ text: "Sustainability Work", href: "https://telia.se" },
|
|
98
|
+
{ text: "Environmental Work", href: "https://telia.se" },
|
|
99
|
+
{ text: "Eco-rating", href: "https://telia.se" },
|
|
100
|
+
{ text: "Social Sustainability", href: "https://telia.se" },
|
|
101
|
+
{ text: "Surf Safely", href: "https://telia.se" },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const socialLinks = [
|
|
107
|
+
{ href: "https://telia.se", icon: instagram, "aria-label": "Link to Telia's Instagram page" },
|
|
108
|
+
{ href: "https://telia.se", icon: linkedin, "aria-label": "Link to Telia's LinkedIn page" },
|
|
109
|
+
{ href: "https://telia.se", icon: facebook, "aria-label": "Link to Telia's Facebook page" },
|
|
110
|
+
{ href: "https://telia.se", icon: youtube, "aria-label": "Link to Telia's YouTube page" },
|
|
111
|
+
{ href: "https://telia.se", icon: x, "aria-label": "Link to Telia's X page" },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const contacts = {
|
|
115
|
+
copyright: "© Telia Company 2024",
|
|
116
|
+
address: {
|
|
117
|
+
content: (
|
|
118
|
+
<>
|
|
119
|
+
Address line 1<br />
|
|
120
|
+
Address line 2<br />
|
|
121
|
+
Address line 3<br />
|
|
122
|
+
Org number
|
|
123
|
+
</>
|
|
124
|
+
),
|
|
125
|
+
addressProps: { "aria-label": "Telia Company address" },
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const legalLinks = [
|
|
130
|
+
{ text: "link 1", href: "https://telia.se" },
|
|
131
|
+
{ text: "link 2", href: "https://telia.se" },
|
|
132
|
+
{ text: "link 3", href: "https://telia.se" },
|
|
133
|
+
{ text: "link 4", href: "https://telia.se" },
|
|
134
|
+
{ text: "link 5", href: "https://telia.se" },
|
|
135
|
+
{ text: "link 6", href: "https://telia.se" },
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const additionalContent = (
|
|
139
|
+
<Link variant="standalone" negative href="https://www.telia.lt/privatiems">
|
|
140
|
+
Additional content
|
|
141
|
+
</Link>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const paymentImages = [
|
|
145
|
+
{
|
|
146
|
+
src: "https://www.mastercard.com/content/dam/public/brandcenter/assets/images/logos/mclogo-for-footer.svg",
|
|
147
|
+
alt: "MasterCard",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
src: "https://upload.wikimedia.org/wikipedia/commons/5/5e/Visa_Inc._logo.svg",
|
|
151
|
+
alt: "Visa",
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
export const Showcase: Story = {
|
|
156
|
+
args: {
|
|
157
|
+
navigation: {
|
|
158
|
+
customLink: CustomTestLink,
|
|
159
|
+
links: navigationLinks,
|
|
160
|
+
sectionProps: {
|
|
161
|
+
"aria-label": "Navigation links",
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
social: {
|
|
165
|
+
links: socialLinks,
|
|
166
|
+
sectionProps: {
|
|
167
|
+
"aria-label": "Social media links",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
contacts: {
|
|
171
|
+
...contacts,
|
|
172
|
+
sectionProps: {
|
|
173
|
+
"aria-label": "Contact information",
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
legal: { links: legalLinks, sectionProps: { "aria-label": "Legal links" } },
|
|
177
|
+
additional: {
|
|
178
|
+
content: additionalContent,
|
|
179
|
+
sectionProps: { "aria-label": "Additional content" },
|
|
180
|
+
},
|
|
181
|
+
payments: {
|
|
182
|
+
images: paymentImages,
|
|
183
|
+
sectionProps: {
|
|
184
|
+
"aria-label": "Payment methods",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const Empty: Story = {
|
|
191
|
+
args: {},
|
|
192
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { facebook, linkedin } from "@purpurds/icon";
|
|
3
|
+
import * as matchers from "@testing-library/jest-dom/matchers";
|
|
4
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { Footer } from "./footer";
|
|
8
|
+
|
|
9
|
+
expect.extend(matchers);
|
|
10
|
+
|
|
11
|
+
describe("Footer", () => {
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
cleanup();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should render empty footer", () => {
|
|
17
|
+
render(<Footer />);
|
|
18
|
+
|
|
19
|
+
const sections = screen.queryAllByRole("region");
|
|
20
|
+
expect(sections).toHaveLength(0);
|
|
21
|
+
|
|
22
|
+
const teliaLogo = screen.getByRole("presentation");
|
|
23
|
+
expect(teliaLogo).toBeInTheDocument();
|
|
24
|
+
expect(teliaLogo).toHaveAttribute("alt", "Telia logo");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should render footer with social links", () => {
|
|
28
|
+
render(
|
|
29
|
+
<Footer
|
|
30
|
+
social={{
|
|
31
|
+
links: [
|
|
32
|
+
{ icon: facebook, href: "https://facebook.com", "aria-label": "link to facebook page" },
|
|
33
|
+
{ icon: linkedin, href: "https://linkedin.com", "aria-label": "link to linkedin page" },
|
|
34
|
+
],
|
|
35
|
+
sectionProps: { "aria-label": "Social links" },
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
// Due to the fact that the social links are rendered for both mobile and desktop the length is doubled
|
|
40
|
+
const sections = screen.queryAllByRole("region");
|
|
41
|
+
expect(sections).toHaveLength(2);
|
|
42
|
+
expect(sections[0]).toHaveAttribute("aria-label", "Social links");
|
|
43
|
+
expect(sections[1]).toHaveAttribute("aria-label", "Social links");
|
|
44
|
+
|
|
45
|
+
const socialLinks = screen.queryAllByRole("link");
|
|
46
|
+
expect(socialLinks).toHaveLength(4);
|
|
47
|
+
|
|
48
|
+
const facebookSocialLinks = screen.queryAllByLabelText("link to facebook page");
|
|
49
|
+
expect(facebookSocialLinks).toHaveLength(2);
|
|
50
|
+
|
|
51
|
+
const linkedinSocialLinks = screen.queryAllByLabelText("link to linkedin page");
|
|
52
|
+
expect(linkedinSocialLinks).toHaveLength(2);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should render footer with navigation links", () => {
|
|
56
|
+
render(
|
|
57
|
+
<Footer
|
|
58
|
+
navigation={{
|
|
59
|
+
links: [
|
|
60
|
+
{
|
|
61
|
+
heading: "Section 1",
|
|
62
|
+
links: [
|
|
63
|
+
{ text: "link 1", href: "https://telia.se" },
|
|
64
|
+
{ text: "link 2", href: "https://telia.se" },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
heading: "Section 2",
|
|
69
|
+
links: [
|
|
70
|
+
{ text: "link 3", href: "https://telia.se" },
|
|
71
|
+
{ text: "link 4", href: "https://telia.se" },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
sectionProps: { "aria-label": "Navigation links" },
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Due to the fact that the navigation is rendered for both mobile and desktop the length is doubled
|
|
81
|
+
const sections = screen.queryAllByRole("region");
|
|
82
|
+
expect(sections).toHaveLength(2);
|
|
83
|
+
expect(sections[0]).toHaveAttribute("aria-label", "Navigation links");
|
|
84
|
+
expect(sections[1]).toHaveAttribute("aria-label", "Navigation links");
|
|
85
|
+
|
|
86
|
+
expect(screen.queryAllByRole("heading")).toHaveLength(4);
|
|
87
|
+
|
|
88
|
+
// Links in accordion are not rendered in the test
|
|
89
|
+
const links = screen.queryAllByRole("link");
|
|
90
|
+
expect(links).toHaveLength(4);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should render footer with payments", () => {
|
|
94
|
+
render(
|
|
95
|
+
<Footer
|
|
96
|
+
payments={{
|
|
97
|
+
images: [
|
|
98
|
+
{
|
|
99
|
+
src: "https://www.mastercard.com/content/dam/public/brandcenter/assets/images/logos/mclogo-for-footer.svg",
|
|
100
|
+
alt: "MasterCard",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
src: "https://upload.wikimedia.org/wikipedia/commons/5/5e/Visa_Inc._logo.svg",
|
|
104
|
+
alt: "Visa",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
sectionProps: { "aria-label": "Payment methods available in Telia" },
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const sections = screen.getByRole("region");
|
|
113
|
+
expect(sections).toBeInTheDocument();
|
|
114
|
+
expect(sections).toHaveAttribute("aria-label", "Payment methods available in Telia");
|
|
115
|
+
|
|
116
|
+
const paymentImages = screen.queryAllByRole("img");
|
|
117
|
+
expect(paymentImages).toHaveLength(2);
|
|
118
|
+
|
|
119
|
+
expect(screen.getByAltText("MasterCard")).toBeInTheDocument();
|
|
120
|
+
expect(screen.getByAltText("Visa")).toBeInTheDocument();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should render footer with contacts", () => {
|
|
124
|
+
render(
|
|
125
|
+
<Footer
|
|
126
|
+
contacts={{
|
|
127
|
+
copyright: "© Telia Company 2024",
|
|
128
|
+
address: {
|
|
129
|
+
content: (
|
|
130
|
+
<>
|
|
131
|
+
Address line 1 <br />
|
|
132
|
+
Address line 2 <br />
|
|
133
|
+
Address line 3 <br />
|
|
134
|
+
Org number
|
|
135
|
+
</>
|
|
136
|
+
),
|
|
137
|
+
addressProps: { "aria-label": "Telia Company address" },
|
|
138
|
+
},
|
|
139
|
+
sectionProps: { "aria-label": "Contact information" },
|
|
140
|
+
}}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const sections = screen.getByRole("region");
|
|
145
|
+
expect(sections).toBeInTheDocument();
|
|
146
|
+
expect(sections).toHaveAttribute("aria-label", "Contact information");
|
|
147
|
+
|
|
148
|
+
expect(screen.getByText("© Telia Company 2024")).toBeInTheDocument();
|
|
149
|
+
|
|
150
|
+
const address = document.querySelector("address");
|
|
151
|
+
expect(address).toHaveTextContent("Address line 1 Address line 2 Address line 3 Org number");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should render footer with legal links", () => {
|
|
155
|
+
render(
|
|
156
|
+
<Footer
|
|
157
|
+
legal={{
|
|
158
|
+
links: [{ text: "link 1", href: "https://telia.se", target: "_blank" }],
|
|
159
|
+
sectionProps: {
|
|
160
|
+
"aria-label": "Legal links",
|
|
161
|
+
},
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const sections = screen.getByRole("region");
|
|
167
|
+
expect(sections).toBeInTheDocument();
|
|
168
|
+
|
|
169
|
+
const links = screen.getByRole("link");
|
|
170
|
+
expect(links).toBeInTheDocument();
|
|
171
|
+
expect(links).toHaveTextContent("link 1");
|
|
172
|
+
expect(links).toHaveAttribute("href", "https://telia.se");
|
|
173
|
+
expect(links).toHaveAttribute("target", "_blank");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should render footer with additional content", () => {
|
|
177
|
+
render(
|
|
178
|
+
<Footer
|
|
179
|
+
additional={{
|
|
180
|
+
content: <div data-testid="additional-content">Additional content</div>,
|
|
181
|
+
sectionProps: { "aria-label": "Additional content section" },
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const sections = screen.getByRole("region");
|
|
187
|
+
expect(sections).toBeInTheDocument();
|
|
188
|
+
|
|
189
|
+
expect(screen.getByTestId("additional-content")).toBeInTheDocument();
|
|
190
|
+
expect(screen.getByTestId("additional-content")).toHaveTextContent("Additional content");
|
|
191
|
+
});
|
|
192
|
+
});
|
package/src/footer.tsx
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React, { HTMLAttributes, ReactElement } from "react";
|
|
2
|
+
import { Grid } from "@purpurds/grid";
|
|
3
|
+
import { Link, LinkProps } from "@purpurds/link";
|
|
4
|
+
import c from "classnames/bind";
|
|
5
|
+
|
|
6
|
+
import { rootClassName } from "./constants";
|
|
7
|
+
import styles from "./footer.module.scss";
|
|
8
|
+
import {
|
|
9
|
+
CustomLinkType,
|
|
10
|
+
FooterNavigation,
|
|
11
|
+
FooterNavigationItem,
|
|
12
|
+
FooterNavigationItemLink,
|
|
13
|
+
} from "./footer-navigation.tsx";
|
|
14
|
+
import { FooterSocialLink, FooterSocialLinkProps } from "./footer-social-link.tsx";
|
|
15
|
+
import { DataAttributes } from "./types";
|
|
16
|
+
const cx = c.bind(styles);
|
|
17
|
+
|
|
18
|
+
type LegalLink = FooterNavigationItemLink &
|
|
19
|
+
Omit<LinkProps, "href" | "variant" | "negative" | "children">;
|
|
20
|
+
|
|
21
|
+
export type FooterProps = DataAttributes &
|
|
22
|
+
HTMLAttributes<HTMLElement> & {
|
|
23
|
+
className?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Navigation section of the footer.
|
|
26
|
+
*/
|
|
27
|
+
navigation?: {
|
|
28
|
+
customLink?: CustomLinkType;
|
|
29
|
+
links: FooterNavigationItem[];
|
|
30
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Social links section of the footer.
|
|
34
|
+
*/
|
|
35
|
+
social?: {
|
|
36
|
+
links: FooterSocialLinkProps[];
|
|
37
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Contacts section of the footer.
|
|
41
|
+
*/
|
|
42
|
+
contacts?: {
|
|
43
|
+
copyright?: string;
|
|
44
|
+
address?: {
|
|
45
|
+
content: ReactElement;
|
|
46
|
+
addressProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
47
|
+
};
|
|
48
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Legal links section of the footer.
|
|
52
|
+
*/
|
|
53
|
+
legal?: {
|
|
54
|
+
links: LegalLink[];
|
|
55
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Additional content section of the footer.
|
|
59
|
+
*/
|
|
60
|
+
additional?: {
|
|
61
|
+
content: ReactElement;
|
|
62
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Payment images section of the footer.
|
|
66
|
+
*/
|
|
67
|
+
payments?: {
|
|
68
|
+
images: { src: string; alt: string }[];
|
|
69
|
+
sectionProps?: DataAttributes & HTMLAttributes<HTMLElement>;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Footer = ({
|
|
74
|
+
className,
|
|
75
|
+
navigation,
|
|
76
|
+
social,
|
|
77
|
+
contacts,
|
|
78
|
+
legal,
|
|
79
|
+
additional,
|
|
80
|
+
payments,
|
|
81
|
+
...props
|
|
82
|
+
}: FooterProps) => {
|
|
83
|
+
const classes = cx([className, rootClassName]);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<footer {...props} className={classes}>
|
|
87
|
+
<Grid>
|
|
88
|
+
<div className={cx(`${rootClassName}__container`)}>
|
|
89
|
+
<div className={cx(`${rootClassName}__logo`)}>
|
|
90
|
+
<img
|
|
91
|
+
src="https://cdn.voca.teliacompany.com/logo/Telia-secondary-default-v2.svg"
|
|
92
|
+
alt="Telia logo"
|
|
93
|
+
role="presentation"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
{social && (
|
|
97
|
+
<section
|
|
98
|
+
{...social.sectionProps}
|
|
99
|
+
className={cx(
|
|
100
|
+
`${rootClassName}__social`,
|
|
101
|
+
`${rootClassName}__social--md`,
|
|
102
|
+
social.sectionProps?.className
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
{social.links.map(({ icon, href, ...props }, i) => (
|
|
106
|
+
<FooterSocialLink {...props} icon={icon} href={href} key={i} />
|
|
107
|
+
))}
|
|
108
|
+
</section>
|
|
109
|
+
)}
|
|
110
|
+
{navigation && (
|
|
111
|
+
<FooterNavigation
|
|
112
|
+
customLink={navigation.customLink}
|
|
113
|
+
navigationLinks={navigation.links}
|
|
114
|
+
sectionProps={navigation.sectionProps}
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
{payments && (
|
|
118
|
+
<section
|
|
119
|
+
{...payments.sectionProps}
|
|
120
|
+
className={cx(`${rootClassName}__payments`, payments.sectionProps?.className)}
|
|
121
|
+
>
|
|
122
|
+
{payments.images.map((payment, i) => (
|
|
123
|
+
<img
|
|
124
|
+
className={cx(`${rootClassName}__payments-image`)}
|
|
125
|
+
src={payment.src}
|
|
126
|
+
alt={payment.alt}
|
|
127
|
+
key={i}
|
|
128
|
+
/>
|
|
129
|
+
))}
|
|
130
|
+
</section>
|
|
131
|
+
)}
|
|
132
|
+
{contacts && (
|
|
133
|
+
<section
|
|
134
|
+
{...contacts.sectionProps}
|
|
135
|
+
className={cx(`${rootClassName}__contacts`, contacts.sectionProps?.className)}
|
|
136
|
+
>
|
|
137
|
+
{contacts.copyright && (
|
|
138
|
+
<div className={cx(`${rootClassName}__contacts-copyright`)}>
|
|
139
|
+
{contacts.copyright}
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
{contacts.address && (
|
|
143
|
+
<address
|
|
144
|
+
{...contacts.address.addressProps}
|
|
145
|
+
className={cx(
|
|
146
|
+
`${rootClassName}__contacts-address`,
|
|
147
|
+
contacts.address.addressProps?.className
|
|
148
|
+
)}
|
|
149
|
+
>
|
|
150
|
+
{contacts.address.content}
|
|
151
|
+
</address>
|
|
152
|
+
)}
|
|
153
|
+
</section>
|
|
154
|
+
)}
|
|
155
|
+
{(additional || legal) && (
|
|
156
|
+
<div className={cx(`${rootClassName}__legal`)}>
|
|
157
|
+
{additional && (
|
|
158
|
+
<section
|
|
159
|
+
{...additional.sectionProps}
|
|
160
|
+
className={cx(
|
|
161
|
+
`${rootClassName}__additional-content`,
|
|
162
|
+
additional.sectionProps?.className
|
|
163
|
+
)}
|
|
164
|
+
>
|
|
165
|
+
{additional.content}
|
|
166
|
+
</section>
|
|
167
|
+
)}
|
|
168
|
+
{legal && (
|
|
169
|
+
<section
|
|
170
|
+
{...legal.sectionProps}
|
|
171
|
+
className={cx(`${rootClassName}__legal-links`, legal.sectionProps?.className)}
|
|
172
|
+
>
|
|
173
|
+
{legal?.links?.map(({ href, text, ...props }, i) => (
|
|
174
|
+
<Link {...props} variant="standalone" negative href={href} key={i}>
|
|
175
|
+
{text}
|
|
176
|
+
</Link>
|
|
177
|
+
))}
|
|
178
|
+
</section>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
{social && (
|
|
183
|
+
<section
|
|
184
|
+
{...social.sectionProps}
|
|
185
|
+
className={cx(
|
|
186
|
+
`${rootClassName}__social`,
|
|
187
|
+
`${rootClassName}__social--sm`,
|
|
188
|
+
social.sectionProps?.className
|
|
189
|
+
)}
|
|
190
|
+
>
|
|
191
|
+
{social.links.map(({ icon, href, ...props }, i) => (
|
|
192
|
+
<FooterSocialLink {...props} icon={icon} href={href} key={i} />
|
|
193
|
+
))}
|
|
194
|
+
</section>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
</Grid>
|
|
198
|
+
</footer>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
Footer.displayName = "Footer";
|
package/src/global.d.ts
ADDED