Skip to content

Commit ef13036

Browse files
feat: full footer with link list (#109)
1 parent b7b3f25 commit ef13036

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/Footer.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export type FooterProps = {
6262
>
6363
>;
6464
style?: CSSProperties;
65+
linkList?: FooterProps.LinkList.List;
6566
};
6667

6768
export namespace FooterProps {
@@ -87,6 +88,28 @@ export namespace FooterProps {
8788
};
8889
}
8990

91+
export namespace LinkList {
92+
export type List = [Column, Column?, Column?, Column?, Column?, Column?];
93+
export type Links = [
94+
LinkList.Link,
95+
LinkList.Link?,
96+
LinkList.Link?,
97+
LinkList.Link?,
98+
LinkList.Link?,
99+
LinkList.Link?,
100+
LinkList.Link?,
101+
LinkList.Link?
102+
];
103+
export interface Column {
104+
categoryName?: string;
105+
links: Links;
106+
}
107+
export interface Link {
108+
text: string;
109+
linkProps: RegisteredLinkProps;
110+
}
111+
}
112+
90113
export type PartnersLogos = PartnersLogos.MainOnly | PartnersLogos.SubOnly;
91114

92115
export namespace PartnersLogos {
@@ -128,6 +151,7 @@ export const Footer = memo(
128151
operatorLogo,
129152
license,
130153
style,
154+
linkList,
131155
...rest
132156
} = props;
133157

@@ -148,6 +172,52 @@ export const Footer = memo(
148172
style={style}
149173
{...rest}
150174
>
175+
{linkList !== undefined && (
176+
<div className={fr.cx("fr-footer__top")}>
177+
<div className={fr.cx("fr-container")}>
178+
<div
179+
className={fr.cx(
180+
"fr-grid-row",
181+
// "fr-grid-row--start", // why is this class used in dsfr doc?
182+
"fr-grid-row--gutters"
183+
)}
184+
>
185+
{linkList.map(
186+
column =>
187+
column !== undefined && (
188+
<div
189+
className={fr.cx(
190+
"fr-col-12",
191+
"fr-col-sm-3",
192+
"fr-col-md-2"
193+
)}
194+
>
195+
{column?.categoryName && (
196+
<h3 className={fr.cx("fr-footer__top-cat")}>
197+
{column?.categoryName}
198+
</h3>
199+
)}
200+
<ul className={fr.cx("fr-footer__top-list")}>
201+
{column?.links.map(linkItem => (
202+
<li>
203+
<Link
204+
{...linkItem?.linkProps}
205+
className={fr.cx(
206+
"fr-footer__top-link"
207+
)}
208+
>
209+
{linkItem?.text}
210+
</Link>
211+
</li>
212+
))}
213+
</ul>
214+
</div>
215+
)
216+
)}
217+
</div>
218+
</div>
219+
</div>
220+
)}
151221
<div className={fr.cx("fr-container")}>
152222
<div className={cx(fr.cx("fr-footer__body"), classes.body)}>
153223
<div

stories/Footer.stories.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ const { meta, getStory } = getStoryFactory({
5656
"license": {
5757
"description":
5858
"By default it's Etalab v2. [You can provide a custom React node](#with-custom-license)"
59+
},
60+
"linkList": {
61+
"controls": { "type": null }
5962
}
6063
}
6164
});
@@ -292,3 +295,36 @@ export const WithSubPartnersOnly = getStory({
292295
]
293296
}
294297
});
298+
299+
const links = new Array(8).fill({
300+
text: "Lien de navigation",
301+
linkProps: { href: "#" }
302+
}) as FooterProps.LinkList.Links;
303+
const linkList = new Array(6).fill({
304+
categoryName: "Nom de la catégorie",
305+
links
306+
}) as FooterProps.LinkList.List;
307+
308+
export const WithLinkList = getStory({
309+
"brandTop": (
310+
<>
311+
INTITULE
312+
<br />
313+
OFFICIEL
314+
</>
315+
),
316+
"accessibility": "fully compliant",
317+
"contentDescription": `
318+
Ce message est à remplacer par les informations de votre site.
319+
320+
Comme exemple de contenu, vous pouvez indiquer les informations
321+
suivantes : Le site officiel d’information administrative pour les entreprises.
322+
Retrouvez toutes les informations et démarches administratives nécessaires à la création,
323+
à la gestion et au développement de votre entreprise.
324+
`,
325+
"homeLinkProps": {
326+
"href": "/",
327+
"title": "Accueil - Nom de l’entité (ministère, secrétariat d‘état, gouvernement)"
328+
},
329+
linkList
330+
});

0 commit comments

Comments
 (0)