Skip to content
This repository has been archived by the owner on May 28, 2023. It is now read-only.

Feat/create header component #192

Closed
18 changes: 14 additions & 4 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}

"presets": [
"next/babel"
],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"react-i18next": "^11.16.9",
"react-icons": "^4.3.1",
"react-router-dom": "^5.3.0",
"react-select": "^5.4.0",
"sass-loader": "^12.2.0",
"styled-components": "^5.3.5",
"web-vitals": "^1.0.1"
Expand Down Expand Up @@ -59,6 +60,7 @@
"@storybook/react": "^6.5.12",
"@storybook/testing-library": "^0.0.13",
"babel-loader": "^8.2.5",
"babel-plugin-styled-components": "^2.0.7",
"eslint": "8.16.0",
"eslint-config-next": "12.1.6",
"eslint-config-react-app": "^7.0.1"
Expand Down
Binary file added src/assets/img/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions src/components/BurgerMenu/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useEffect, useState } from "react";
import { Backdrop, Container, Sidebar } from "./styles";
import { GiHamburgerMenu } from "react-icons/gi";
import { AiOutlineClose } from "react-icons/ai";

export const BurgerMenu = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
window.addEventListener("keydown", (event) => {
if (event.key === "Escape") setIsOpen(false);
});

window.addEventListener("click", (event) => {
const origin = event.target.closest("a");
if (origin) setIsOpen(false);
});
}, []);

return (
<Container>
<button
onClick={() => {
setIsOpen(!isOpen);
}}
>
<GiHamburgerMenu />
</button>
{isOpen && (
<>
<Backdrop onClick={() => setIsOpen(false)} />
<Sidebar>
<button className="close" onClick={() => setIsOpen(false)}>
<AiOutlineClose />
</button>
{children}
</Sidebar>
</>
)}
</Container>
);
};
44 changes: 44 additions & 0 deletions src/components/BurgerMenu/styles.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import styled from "styled-components";

export const Container = styled.div`
padding: 0;
margin: 0;

button {
border: none;
background: none;

svg {
font-size: 3.5rem;
}
}
`

export const Sidebar = styled.div`
position: fixed;
right: 0;
top: 0;
height: 100vh;
width: 30vw;
background-color: white;
padding: 7rem 4rem;

.close {
position: absolute;
right: 1.5vw;
top: 2vh;

svg {
font-size: 2rem;
}
}
`;

export const Backdrop = styled.div`
position: fixed;
left: 0;
top: 0;
height: 100vh;
width: 70vw;
background-color: rgba(105,105,105,0.5);
`
95 changes: 95 additions & 0 deletions src/components/Header/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useCallback, useEffect, useState } from "react";
import i18n from "i18next";
import { useTranslation } from "react-i18next";
import { BsInstagram, BsGithub, BsDiscord } from "react-icons/bs";
import { SiOpencollective } from "react-icons/si";
import { Container, Navbar, AccessBar, CustomSelect } from "./styles";
import logo from "~/assets/img/RoadMapCCTypo.svg";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { BurgerMenu } from "../BurgerMenu";

const buildOption = (lang) => {
const namespace = i18n.options.defaultNS;
const language = i18n.getDataByLanguage(lang)[namespace];
return { value: lang, label: language.lang };
};

export const Header = () => {
const router = useRouter();
const { t } = useTranslation();
const [currentLang, setCurrentLang] = useState(buildOption(i18n.language));
const [availableLangs] = useState(Object.keys(i18n.options.resources).map(buildOption));
const [isSmallScreen, setIsSmallScreen] = useState(false);

const getClassActiveRoute = useCallback(
(routeName) => (router.pathname === routeName ? "nav-checked" : undefined),
[router.pathname]
);

const changeLang = useCallback((newLang) => {
i18n.changeLanguage(newLang.value);
setCurrentLang(newLang);
}, []);

useEffect(() => {
setIsSmallScreen(window.matchMedia("(max-width: 768px)").matches);
}, []);

const content = (
<>
<Navbar>
<Link href="/home">
<a className={getClassActiveRoute("/home")}>{t("nav.home")}</a>
</Link>
<Link href="/trails">
<a className={getClassActiveRoute("/trails")}>{t("nav.trails")}</a>
</Link>
<Link href="/about">
<a className={getClassActiveRoute("/about")}>{t("nav.about")}</a>
</Link>
</Navbar>
<AccessBar>
<Link href="https://www.instagram.com/opendevufcg/" prefetch={false}>
<a target="_blank">
<BsInstagram />
</a>
</Link>
<Link href="https://www.instagram.com/opendevufcg/" prefetch={false}>
franklingg marked this conversation as resolved.
Show resolved Hide resolved
<a target="_blank">
<SiOpencollective />
</a>
</Link>
<Link href="https://github.com/OpenDevUFCG/roadmap-cc" prefetch={false}>
<a target="_blank">
<BsGithub />
</a>
</Link>
<Link href="https://www.instagram.com/opendevufcg/" prefetch={false}>
franklingg marked this conversation as resolved.
Show resolved Hide resolved
<a target="_blank">
<BsDiscord />
</a>
</Link>
<CustomSelect
options={availableLangs}
value={currentLang}
onChange={changeLang}
classNamePrefix="Select"
isSearchable={false}
/>
</AccessBar>
</>
);

return (
<Container>
<Link href="/home">
<a className="header-logo">
<Image src={logo} />
</a>
</Link>
{isSmallScreen ? <BurgerMenu noOverlay width={280} >{content}</BurgerMenu> : <>{content}</>}
</Container>
);
};
127 changes: 127 additions & 0 deletions src/components/Header/styles.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import styled from "styled-components";
import Select from 'react-select';

export const Container = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding: 3.7rem 4.4rem;
background-color: rgba(252, 252, 252, 0.6);
`

export const Navbar = styled.div`
display: flex;
gap: 2.8rem;
& > * {
font-size: 2.3rem;
text-decoration: none;
color: var(--dark-blue);
font-weight: 700;
font-family: 'Rambla';
letter-spacing: 0.18rem;
transition: all 0.15s ease-out;
line-height: 3rem;

&:hover {
color: var(--light-orange);
}
&.nav-checked{
color: var(--light-orange);
text-decoration: underline;
}
}

@media (max-width: 768px){
flex-direction: column;
gap: 2vh;
& > * {
font-size: 1.8rem;
}
}
`

export const AccessBar = styled.div`
display: flex;
justify-content: space-between;
gap: 1.4rem;

& > a {
width: 3.5rem;
height: 3.5rem;
background-color: var(--dark-blue);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: var(--white);
transition: all 0.15s ease-in-out;

:hover {
transform: scale(1.08);
}
}

@media (max-width: 768px){
margin-top: 3vh;
display: grid;
grid-template-columns: 15vw 1fr;
column-gap: 0;
row-gap: 3vh;
}
`

export const CustomSelect = styled(Select)`
& .Select__control {
border: none;
box-shadow: none;

&:hover{
cursor: pointer;
}
}

& .Select__indicator-separator {
display: none;
}

& .Select__value-container {
padding: 0 0 0 0.5rem;
}

& .Select__single-value {
font-size: 2rem;
margin: 0;
color: var(--dark-blue);
font-weight: 700;
}

& .Select__indicator {
padding: 0;
& > svg {
fill: var(--dark-blue);
width: 3rem;
height: 2.5rem;
}
}

& .Select__menu-list {
padding: 0;
}

& .Select__option {
color: var(--dark-blue);
font-weight: 700;
font-size: 1.5rem;
border: 0.15rem solid var(--light-grey);
}

@media (max-width: 428px){
& .Select__control{
min-width: 24vw;
}

& .Select__single-value {
font-size: 1.6rem;
}
}
`
4 changes: 4 additions & 0 deletions src/i18n/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';

import translationsPTBR from './locales/pt-br.json';
import translationsENUS from './locales/en-us.json';
import translationsESES from './locales/es-es.json';
Copy link
Member

@LeandraOS LeandraOS Oct 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nessa linha, temos um pequeno detalhe de digitação do path do arquivo. Ele apresenta o seguinte erro:

Captura de tela de 2022-10-10 01-47-07

Para resolver, basta alterar o es-es.json para es-ES.json

import translationsESES from './locales/es-ES.json';


const i18nConfig = {
resources: {
'pt-BR': translationsPTBR,
'en-US': translationsENUS,
'es-ES': translationsESES
},
fallbackLng: 'pt-BR',
defaultNS: 'translations'
Expand Down
11 changes: 11 additions & 0 deletions src/i18n/locales/en-us.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"translations": {
"lang": "EN-US",
"lang_name": "English",
"nav": {
"home": "Home",
"trails": "Trails",
"about": "About Us"
}
}
}
11 changes: 11 additions & 0 deletions src/i18n/locales/es-ES.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"translations": {
"lang": "ES-ES",
"lang_name": "Español",
"nav": {
"home": "Inicio",
"trails": "Caminos",
"about": "Sobre Nosotros"
}
}
}
Loading