From 2040ac2beb60f26b193d4fafd9da09279baf7637 Mon Sep 17 00:00:00 2001 From: Celeste Robert <robert.m.celeste@gmail.com> Date: Mon, 10 Oct 2022 11:17:08 +0000 Subject: [PATCH] refactor: improve code readability doc: added naming conventions --- README.md | 6 +++ doc/components.md | 20 ++++++++-- docusaurus.config.js | 2 +- src/components/{ => Carousel}/Carousel.js | 6 +-- .../{ => Carousel}/CarouselLibre.js | 2 +- src/components/Features/Features.js | 24 ++++++++++++ .../{ => Features}/HomepageFeatures.js | 26 +++---------- src/components/HomepagePromises.module.css | 9 ----- .../{ => Promises}/HomepagePromises.js | 37 +++++++------------ src/components/Promises/Promises.js | 17 +++++++++ .../{ => Results}/HomepageResults.js | 23 ++---------- .../{ => Results}/HomepageResults.module.css | 0 src/components/Results/Results.js | 17 +++++++++ src/css/carousel.css | 8 ++-- src/css/custom.css | 27 +++++++++----- .../features.css} | 22 ++++------- src/css/footer.css | 4 +- src/css/results.css | 11 ++++++ src/pages/{dummy_page.mdx => dummy-page.mdx} | 2 +- src/pages/faq.md | 2 +- src/pages/index.js | 12 +++--- ...entions_legales.md => mentions-legales.md} | 0 src/theme/Footer/index.js | 12 +++--- 23 files changed, 163 insertions(+), 126 deletions(-) rename src/components/{ => Carousel}/Carousel.js (94%) rename src/components/{ => Carousel}/CarouselLibre.js (99%) create mode 100644 src/components/Features/Features.js rename src/components/{ => Features}/HomepageFeatures.js (64%) delete mode 100644 src/components/HomepagePromises.module.css rename src/components/{ => Promises}/HomepagePromises.js (52%) create mode 100644 src/components/Promises/Promises.js rename src/components/{ => Results}/HomepageResults.js (72%) rename src/components/{ => Results}/HomepageResults.module.css (100%) create mode 100644 src/components/Results/Results.js rename src/{components/HomepageFeatures.module.css => css/features.css} (67%) create mode 100644 src/css/results.css rename src/pages/{dummy_page.mdx => dummy-page.mdx} (95%) rename src/pages/{mentions_legales.md => mentions-legales.md} (100%) diff --git a/README.md b/README.md index 227e2b8..7667ecd 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,12 @@ More details on Project structure: * `/static/` - Any contents inside here will be copied into the root of the final `build` directory * `/docusaurus.config.js` - This is the equivalent of `siteConfig.js` in Docusaurus v1 +## Naming conventions + +- *Components* files and folders must be named using camel case (e.g `Hello world component` = `HelloWorldComponent`) +- *Page* files must be named using kebab case, all lower cases (e.g `Hello world page` = `hello-world-page`) +- *Style classes* must be name using kebab case as well, all lower cases (e.g `Hello world title` = `hello-world-title`) + ## Image organisation Static assets are arranged in a certain way, all images are contained in subfolders within the `img` folder, the subfolder depends on how they are used. The name must be the same. Following this structure: diff --git a/doc/components.md b/doc/components.md index 6827ae2..97cb4c0 100644 --- a/doc/components.md +++ b/doc/components.md @@ -28,11 +28,25 @@ Afin que les logos de FLOSS unis (par exemple blancs ou noirs) restent bien visi ### HomepagePromises.js Le composant **HomepagePromises** est utilisé sur la page d'accueil pour afficher les promesses de Froggit (section **À vous de faire la différence**). +Il renvoie une section constituée d'un titre central puis d'une liste React (**PromiseList**) affichée en ligne avec le composant **Promises**. -il renvoie une section constituée d'un titre central puis d'une liste React (**PromiseList**) affichée en ligne. +### Promises.js -Les éléments **Promise** de la liste sont affichés en colonne et sont composés d'un titre, une image SVG et une description. Le composant **Promise** prendra respectivement les props `Svg`, `title` et `description`. +Le composant **Promises** permet de générer une carte affichée en colonne et composée d'un titre, une image SVG et une description. Le composant **Promises** prendra respectivement les props `Svg`, `alt`, `title` et `description`. ### HomepageFeatures.js -Le composant **HomepageFeatures** affiche les fonctionnalités de Froggit sur la page d'accueil. +Le composant **HomepageFeatures** affiche les fonctionnalités de Froggit sur la page d'accueil (section **Optimisez votre manière de façonner vos applications**) sous forme d'onglets à l'aide du composant **Features**. + +### Features.js + +Le composant **Features** génère des onglets, chaque onglet est représenté par un titre et une fois ouvert, il affiche une image accompagnée d'un court texte. Il prend respectivement les props `title`, `svg` et `description`. + +### HomepageResults + +Le composant **HomepageResults** affiche les résultats à attendre de Froggit sur la page d'accueil (section **Obtenez de meilleurs résultats…** ). Il utilise des cartes retournées par le composant **Results**. + +### Results.js + +Le composant **Results** retourne une carte composée d'une colone textuelle avec un titre et une image, ainsi qu'une colone illustratrice composée d'une image. La colone textuelle se situe à gauche pour les enfants impairs et à droite pour les enfants pairs. +Il prend respectivement les props `title`, `description`, `img` et `alt`. diff --git a/docusaurus.config.js b/docusaurus.config.js index 27707e9..c1129d9 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -102,7 +102,7 @@ module.exports = { }, { label: "Mentions légales", - to: "/mentions_legales", + to: "/mentions-legales", }, { label: "📜 CGV", diff --git a/src/components/Carousel.js b/src/components/Carousel/Carousel.js similarity index 94% rename from src/components/Carousel.js rename to src/components/Carousel/Carousel.js index 8540b92..c0b0cc7 100644 --- a/src/components/Carousel.js +++ b/src/components/Carousel/Carousel.js @@ -9,7 +9,7 @@ function Logo({img, svg, alt}) { if (img) { return ( <> - <img src={useBaseUrl(img)} alt={alt} className="carousel_img" /> + <img src={useBaseUrl(img)} alt={alt} className="carousel-img" /> </> ); } @@ -24,7 +24,7 @@ function Logo({img, svg, alt}) { function CarouselElement({name, img, svg, link, alt}) { return ( - <div className="carousel_box"> + <div className="carousel-box"> {(() => { if (link) { return ( @@ -42,7 +42,7 @@ function CarouselElement({name, img, svg, link, alt}) { {(() => { if (name) { return ( - <h6 className="carousel_title">{name}</h6> + <h6 className="carousel-title">{name}</h6> ); } })()} diff --git a/src/components/CarouselLibre.js b/src/components/Carousel/CarouselLibre.js similarity index 99% rename from src/components/CarouselLibre.js rename to src/components/Carousel/CarouselLibre.js index a77a5f5..4501082 100644 --- a/src/components/CarouselLibre.js +++ b/src/components/Carousel/CarouselLibre.js @@ -57,7 +57,7 @@ const CarouselList = [ export default function CarouselLibre() { return ( - <div className="homepage_section"> + <div className="homepage-section"> <section className="sections container"> <h2 className={clsx("text--center")}>Restez libres ! </h2> diff --git a/src/components/Features/Features.js b/src/components/Features/Features.js new file mode 100644 index 0000000..2e33931 --- /dev/null +++ b/src/components/Features/Features.js @@ -0,0 +1,24 @@ +import React from "react"; +import clsx from "clsx"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +/* eslint-disable react/prop-types */ +export default function Features(props) { + return ( + <div> + <Tabs className="tabs-element"> + {props.list.map((em, idx) => ( + <TabItem key={idx} className={clsx("text--center")} value={em.title} label={em.title}> + <div className="tab-row-display"> + <img src={useBaseUrl("img/components/HomepageFeatures/" + em.svg)} alt={em.alt} className="tab-images"/> + <p className="tab-text-display"> {em.description} </p> + </div> + </TabItem> + ))} + </Tabs> + </div> + ); + +} diff --git a/src/components/HomepageFeatures.js b/src/components/Features/HomepageFeatures.js similarity index 64% rename from src/components/HomepageFeatures.js rename to src/components/Features/HomepageFeatures.js index e6e2225..f5e8cf8 100644 --- a/src/components/HomepageFeatures.js +++ b/src/components/Features/HomepageFeatures.js @@ -1,9 +1,7 @@ import React from "react"; import clsx from "clsx"; -import styles from "./HomepageFeatures.module.css"; -import useBaseUrl from "@docusaurus/useBaseUrl"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Features from "./Features"; + const FeatureList = [ { @@ -53,30 +51,18 @@ const FeatureList = [ export default function HomepageFeatures() { return ( - <div className="homepage_section"> + <div className="homepage-section"> <section className="sections container" id="features"> <h2 className={clsx("text--center")}>Optimisez votre manière de façonner vos applications </h2> - <div className={styles.featuresSubtitle}> + <div className="padding-top--md"> <p className={"text--center"}>De la planification au déploiement en passant par le testing… <br/> </p> - <p className={"text--center margin-bottom--lg"}> Réunissez vos équipes sur la même plateforme DevOps, pensée pour améliorer vos performances, vos résultats et réduire votre empreinte écologique. + <p className={"text--center"}> Réunissez vos équipes sur la même plateforme DevOps, pensée pour améliorer vos performances, vos résultats et réduire votre empreinte écologique. </p> </div> - <div> - <Tabs className={styles.tabsElement}> - {FeatureList.map((em) => ( - <TabItem key={em.id} className={clsx("text--center")} value={em.title} label={em.title}> - <div className={styles.rowDisplay}> - <img src={useBaseUrl("img/components/HomepageFeatures/" + em.svg)} alt={em.alt} className={styles.tabImages}/> - <p className={styles.textDisplay}> {em.description} </p> - </div> - </TabItem> - ))} - </Tabs> - </div> + <Features list={FeatureList}/> </section> </div> - ); } diff --git a/src/components/HomepagePromises.module.css b/src/components/HomepagePromises.module.css deleted file mode 100644 index ffa77d2..0000000 --- a/src/components/HomepagePromises.module.css +++ /dev/null @@ -1,9 +0,0 @@ -/* stylelint-disable docusaurus/copyright-header */ -.promiseSvg { - height: 64px; - width: auto; -} - -.rowOverflow { - overflow:hidden; -} diff --git a/src/components/HomepagePromises.js b/src/components/Promises/HomepagePromises.js similarity index 52% rename from src/components/HomepagePromises.js rename to src/components/Promises/HomepagePromises.js index 115c25b..4773c17 100644 --- a/src/components/HomepagePromises.js +++ b/src/components/Promises/HomepagePromises.js @@ -1,11 +1,15 @@ import React from "react"; -import clsx from "clsx"; -import styles from "./HomepagePromises.module.css"; +import bouclier from "@site/static/img/components/HomepagePromises/bouclier.svg"; +import rgpd from "@site/static/img/components/HomepagePromises/rgpd.svg"; +import liberte from "@site/static/img/components/HomepagePromises/liberte.svg"; +import Promises from "./Promises"; + +const PromiseSectionTitle = "Faites la différence"; const PromiseList = [ { title: "Sécurisé", - Svg: require("../../static/img/components/HomepagePromises/bouclier.svg").default, + Svg: bouclier, alt: "Icône d'un bouclier bleu", description: ( <> @@ -15,7 +19,7 @@ const PromiseList = [ }, { title: "Souverain", - Svg: require("../../static/img/components/HomepagePromises/rgpd.svg").default, + Svg: rgpd, alt: "Icône d'un cadenas avec inscrit RGPD", description: ( <> @@ -25,7 +29,7 @@ const PromiseList = [ }, { title: "Libre", - Svg: require("../../static/img/components/HomepagePromises/liberte.svg").default, + Svg: liberte, alt: "Icône de menottes brisées", description: ( <> @@ -35,29 +39,14 @@ const PromiseList = [ }, ]; -// eslint-disable-next-line -function Promise({Svg, alt, title, description}) { - return ( - <div className={clsx("col col--4")}> - <div className="text--center"> - <Svg className={styles.promiseSvg} alt={alt} /> - </div> - <div className="text--center padding-horiz--md"> - <h3>{title}</h3> - <p>{description}</p> - </div> - </div> - ); -} - export default function HomepagePromises() { return ( - <div className={styles.rowOverflow+" homepage_section"}> - <section className="section-promises"> - <h2 className="promise-title margin-bottom--lg">Faites la différence</h2> + <div className="row-overflow homepage-section"> + <h2 className="text--center"> {PromiseSectionTitle} </h2> + <section className="section-promises"> <div className="row"> {PromiseList.map((props, idx) => ( - <Promise key={idx} {...props} /> + <Promises key={idx} {...props} /> ))} </div> </section> diff --git a/src/components/Promises/Promises.js b/src/components/Promises/Promises.js new file mode 100644 index 0000000..6b625e9 --- /dev/null +++ b/src/components/Promises/Promises.js @@ -0,0 +1,17 @@ +import React from "react"; +import clsx from "clsx"; + +// eslint-disable-next-line +export default function Promises({Svg, alt, title, description}) { + return ( + <div className={clsx("col col--4")}> + <div className="text--center"> + <Svg className="promise-svg" alt={alt} /> + </div> + <div className="text--center padding-horiz--md"> + <h3>{title}</h3> + <p>{description}</p> + </div> + </div> + ); +} diff --git a/src/components/HomepageResults.js b/src/components/Results/HomepageResults.js similarity index 72% rename from src/components/HomepageResults.js rename to src/components/Results/HomepageResults.js index 3afbde2..ecd8497 100644 --- a/src/components/HomepageResults.js +++ b/src/components/Results/HomepageResults.js @@ -1,10 +1,9 @@ import React from "react"; +import Results from "./Results"; import environment from "@site/static/img/components/HomepageResults/environment.png"; import advance from "@site/static/img/components/HomepageResults/advance.png"; import conversation from "@site/static/img/components/HomepageResults/conversation.png"; -import styles from "./HomepageResults.module.css"; - const ResultsList = [ { title: "Alliez compétitivité et respect de l’environnement", @@ -40,27 +39,11 @@ const ResultsList = [ }, ]; -// eslint-disable-next-line -function Results({title, description, img, alt}) { - return ( - <div className="sectionsReverse row"> - <div className={"col col--5 " + styles.resultsCenter}> - <img className={styles.resultsImage} src={img} alt={alt}/> - </div> - <div className="col col--5"> - <h3>{title}</h3> - <p>{description}</p> - </div> - </div> - - ); -} - export default function HomepageResults() { return ( - <div className="homepage_section"> + <div className="homepage-section"> <section className="sections container" id="results"> - <h2 className="promise-title">Obtenez de meilleurs résultats, <br/>et pas seulement au niveau du code !</h2> + <h2 className="text--center">Obtenez de meilleurs résultats, <br/>et pas seulement au niveau du code !</h2> <div> {ResultsList.map((props, idx) => ( <Results key={idx} {...props} /> diff --git a/src/components/HomepageResults.module.css b/src/components/Results/HomepageResults.module.css similarity index 100% rename from src/components/HomepageResults.module.css rename to src/components/Results/HomepageResults.module.css diff --git a/src/components/Results/Results.js b/src/components/Results/Results.js new file mode 100644 index 0000000..8468617 --- /dev/null +++ b/src/components/Results/Results.js @@ -0,0 +1,17 @@ +import React from "react"; + +// eslint-disable-next-line +export default function Results({title, description, img, alt}) { + return ( + <div className="sections-reverse row"> + <div className="col col--5 results-center"> + <img className="results-image" src={img} alt={alt}/> + </div> + <div className="col col--5"> + <h3>{title}</h3> + <p>{description}</p> + </div> + </div> + + ); +} diff --git a/src/css/carousel.css b/src/css/carousel.css index a2023f0..83c8bf3 100644 --- a/src/css/carousel.css +++ b/src/css/carousel.css @@ -1,5 +1,5 @@ /* CAROUSEL */ -.carousel_box { +.carousel-box { display: flex; flex-direction: column; justify-content: space-between; @@ -9,17 +9,17 @@ height: 122px; } -.carousel_img, .carousel_box svg { +.carousel-img, .carousel-box svg { padding: 8px; width: 90px; height: 90px; /* text-align: center; */ } -.carousel_box svg { +.carousel-box svg { fill: var(--ifm-font-color-base); } -.carousel_title { +.carousel-title { display: flex; justify-content: center; } diff --git a/src/css/custom.css b/src/css/custom.css index 6d6ea9c..5320462 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -6,7 +6,8 @@ @import url("matomo.css"); @import url("tarifs.css"); @import url("carousel.css"); - +@import url("features.css"); +@import url("results.css"); html, body { margin: 0; @@ -115,11 +116,11 @@ ul { } /****** HERO TITLE ******/ -.hero__title { +.hero-title { color: var(--ifm-color-white); } -.hero__subtitle { +.hero-subtitle { color: var(--ifm-color-white); width: 90%; text-align: center; @@ -127,6 +128,12 @@ ul { padding-bottom: 20px; } +/**** HORIZONTAL OVERFLOW ****/ +.row-overflow { + overflow:hidden; +} + + /******* MAIN ELEM *******/ .section-promises { padding: 4rem 0; @@ -137,7 +144,7 @@ ul { padding: 4rem 0; width: var(--ifm-container-max-width); } -.sectionsReverse { +.sections-reverse { margin: 0 16px 0 16px; padding: 4rem 0; display: flex; @@ -146,7 +153,7 @@ ul { text-align: end; } -.sectionsReverse:nth-of-type(odd) { +.sections-reverse:nth-of-type(odd) { flex-direction: row-reverse; text-align: start; } @@ -207,7 +214,7 @@ ul { } /* background color on homepage */ -.homepage_section:nth-child(even) { +.homepage-section:nth-child(even) { background-color: var(--section-background); } @@ -218,8 +225,8 @@ ul { } } -.promise-title { - display: flex; - justify-content: center; - text-align: center; +/* stylelint-disable docusaurus/copyright-header */ +.promise-svg { + height: 64px; + width: auto; } diff --git a/src/components/HomepageFeatures.module.css b/src/css/features.css similarity index 67% rename from src/components/HomepageFeatures.module.css rename to src/css/features.css index 69bf1ff..64686b8 100644 --- a/src/components/HomepageFeatures.module.css +++ b/src/css/features.css @@ -1,20 +1,12 @@ -@import url("../css/variables.css"); +/* FEATURES TABS */ -.featuresSubtitle { - padding-top: 26px; -} - -.tabsElement { +.tabs-element { width: 100%; margin-bottom: 48px; -} -.title { - font-weight: bold; - padding-bottom: 40px; } -.tabsElement>li { +.tabs-element>li { margin: auto; display: flex; justify-content: center; @@ -22,11 +14,11 @@ transition: 0.4s; } -.tabImages { +.tab-images { width: 360px; } -.rowDisplay { +.tab-row-display { display: flex; justify-content: center; align-items: center; @@ -34,7 +26,7 @@ flex-wrap: wrap; } -.textDisplay { +.tab-text-display { padding: 15px; width: 25%; font-size: 20px; @@ -42,7 +34,7 @@ } @media (max-width: 600px) { - .textDisplay { + .tab-text-display { width: 100%; text-align: center; } diff --git a/src/css/footer.css b/src/css/footer.css index 539ce63..7579e80 100644 --- a/src/css/footer.css +++ b/src/css/footer.css @@ -8,7 +8,7 @@ font-family: var(--ifm-font-family); } -.footer_container { +.footer-container { display: flex; justify-content: center; } @@ -21,7 +21,7 @@ color: var(--ifm-color-secondary); } -.footer_icons { +.footer-icons { margin-left: 12px; margin-right: 12px; width: 1.8rem; diff --git a/src/css/results.css b/src/css/results.css new file mode 100644 index 0000000..3da1630 --- /dev/null +++ b/src/css/results.css @@ -0,0 +1,11 @@ +/**** RESULTS ****/ + +.results-image { + width: 186px; + aspect-ratio: 1; +} + +.results-center { + display: flex; + justify-content: center; +} diff --git a/src/pages/dummy_page.mdx b/src/pages/dummy-page.mdx similarity index 95% rename from src/pages/dummy_page.mdx rename to src/pages/dummy-page.mdx index 935c321..75cd8cf 100644 --- a/src/pages/dummy_page.mdx +++ b/src/pages/dummy-page.mdx @@ -2,7 +2,7 @@ title: dummy description: "page factice" --- -import CarouselLibre from "@site/src/components/CarouselLibre"; +import CarouselLibre from "@site/src/components/Carousel/CarouselLibre"; # Page factice diff --git a/src/pages/faq.md b/src/pages/faq.md index 6cce8fd..ac706de 100644 --- a/src/pages/faq.md +++ b/src/pages/faq.md @@ -167,6 +167,6 @@ La communauté bénéficiera gratuitement des services suivants : Pour le moment nous sommes très pris par la bêta de **Froggit** mais nous espérons pouvoir lancer la communauté début 2022. -> Vous avez une question qui n’est pas dans la FAQ [écrivez-nous](/dummy_page). +> Vous avez une question qui n’est pas dans la FAQ [écrivez-nous](/dummy-page). [^SSO]: Single Sign On: authentification unique entre plusieurs services. diff --git a/src/pages/index.js b/src/pages/index.js index 02b73ad..9f37a81 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -3,18 +3,18 @@ import Layout from "@theme/Layout"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import styles from "./index.module.css"; import Link from "@docusaurus/Link"; -import HomepageResults from "@site/src/components/HomepageResults"; -import HomepagePromises from "@site/src/components/HomepagePromises"; -import HomepageFeatures from "@site/src/components/HomepageFeatures"; -import CarouselLibre from "@site/src/components/CarouselLibre"; +import HomepageResults from "@site/src/components/Results/HomepageResults"; +import HomepagePromises from "@site/src/components/Promises/HomepagePromises"; +import HomepageFeatures from "@site/src/components/Features/HomepageFeatures"; +import CarouselLibre from "@site/src/components/Carousel/CarouselLibre"; function HomepageHeader(){ return ( <header className={styles.heroBanner}> <div className="sections container"> - <h1 className="hero__title">Simplifiez-vous le code... <br />et faites plaisir à vos techs !</h1> - <p className="hero__subtitle">Collaborez autour du code sur la première plateforme intégrée DevOps <i>Made in France</i>. Avec Froggit, sécurisez vos données, améliorez vos performances et protégez enfin la planète.</p> + <h1 className="hero-title">Simplifiez-vous le code... <br />et faites plaisir à vos techs !</h1> + <p className="hero-subtitle">Collaborez autour du code sur la première plateforme intégrée DevOps <i>Made in France</i>. Avec Froggit, sécurisez vos données, améliorez vos performances et protégez enfin la planète.</p> <div className="button-frame"> <Link className="button button--beta button--lg" to="/tarifs"> Je m’abonne sans engagement<br /><div className="btn-little-txt">30 jours satisfaits ou remboursés !</div> diff --git a/src/pages/mentions_legales.md b/src/pages/mentions-legales.md similarity index 100% rename from src/pages/mentions_legales.md rename to src/pages/mentions-legales.md diff --git a/src/theme/Footer/index.js b/src/theme/Footer/index.js index 2e4bdec..ebcb2ea 100644 --- a/src/theme/Footer/index.js +++ b/src/theme/Footer/index.js @@ -29,26 +29,26 @@ function Footer() { <> <div className="footer"> - <div className="footer_container"> + <div className="footer-container"> <a href="https://lab.frogg.it/froggit" target="_blank" rel="noreferrer"> - <img className="footer_icons" src={Froggitblanc} alt="Logo Froggit blanc" /> + <img className="footer-icons" src={Froggitblanc} alt="Logo Froggit blanc" /> </a> <a href="https://gitlab.com/froggit" target="_blank" rel="noreferrer"> - <FaGitlab className="footer_icons" /> + <FaGitlab className="footer-icons" /> </a> <a href="https://www.youtube.com/channel/UCauIDghddUNu6Fto1nR9Bmg/?sub_confirmation=1" target="_blank" rel="noreferrer"> - <FaYoutube className="footer_icons" /> + <FaYoutube className="footer-icons" /> </a> <a href="https://www.linkedin.com/company/froggit" target="_blank" rel="noreferrer"> - <FaLinkedin className="footer_icons" /> + <FaLinkedin className="footer-icons" /> </a> <a href="https://twitter.com/art_devops" target="_blank" rel="noreferrer"> - <FaTwitter className="footer_icons" /> + <FaTwitter className="footer-icons" /> </a> </div> -- GitLab