Compare commits
30 Commits
refactor/f
...
main
Author | SHA1 | Date | |
---|---|---|---|
e3c8395c0a | |||
ee3620c8d1 | |||
80a9bc862b | |||
adc50ceeed | |||
32ec2dbe5b | |||
84f70382c7 | |||
969b8ef5c3 | |||
2afdff5b59 | |||
33ae99810c | |||
eda5e00efa | |||
b3915ecafc | |||
9be5b1abf3 | |||
4a6664726b | |||
8710e7d333 | |||
1d0525d9ec | |||
a4590a4310 | |||
c5b8238466 | |||
cf11adba3b | |||
51bbe55cf1 | |||
1f49ed7bf1 | |||
6281bb98b2 | |||
2b0862dea3 | |||
97c46af125 | |||
7a72298d2a | |||
d903be8c81 | |||
b150a0bf61 | |||
d0f5df8fff | |||
c0edf709f7 | |||
5ccc4c9b2b | |||
2265768ee0 |
29142
package-lock.json
generated
@ -9,11 +9,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-text-mask": "^5.4.11",
|
||||
"formik": "^2.2.9",
|
||||
"proxyquire": "^2.1.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.6.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-text-mask": "^5.5.0",
|
||||
"rewire": "^6.0.0",
|
||||
"sass": "^1.57.1",
|
||||
"web-vitals": "^2.1.4",
|
||||
"yup": "^0.32.11"
|
||||
|
10
src/components/Atoms/CustomLink/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { AnchorHTMLAttributes, ReactNode } from 'react'
|
||||
import { LinkProps, To } from 'react-router-dom'
|
||||
|
||||
export interface CustomLinkProps
|
||||
extends AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
LinkProps {
|
||||
children: ReactNode | ReactNode[]
|
||||
href?: string
|
||||
to?: To | any
|
||||
}
|
18
src/components/Atoms/CustomLink/index.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { CustomLinkProps } from './@types'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
export function CustomLink({ children, href, to, ...props }: CustomLinkProps) {
|
||||
return (
|
||||
<>
|
||||
{href ? (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<Link to={to} {...props}>
|
||||
{children}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
7
src/components/Atoms/Icon/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { HTMLAttributes } from 'react'
|
||||
|
||||
export interface IconProps extends HTMLAttributes<HTMLImageElement> {
|
||||
src: any
|
||||
alt: string
|
||||
$container?: HTMLAttributes<HTMLSpanElement>
|
||||
}
|
10
src/components/Atoms/Icon/index.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
/* eslint-disable jsx-a11y/alt-text */
|
||||
import { IconProps } from './@types'
|
||||
|
||||
export function Icon({ $container, src, alt, ...props }: IconProps) {
|
||||
return (
|
||||
<span {...$container}>
|
||||
<img src={src} alt={alt} {...props} />
|
||||
</span>
|
||||
)
|
||||
}
|
5
src/components/Atoms/Item/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { HTMLAttributes, ReactNode } from 'react'
|
||||
|
||||
export interface ItemProps extends HTMLAttributes<HTMLLIElement> {
|
||||
children: ReactNode | ReactNode[]
|
||||
}
|
5
src/components/Atoms/Item/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { ItemProps } from './@types'
|
||||
|
||||
export function Item({ children, ...props }: ItemProps) {
|
||||
return <li {...props}>{children}</li>
|
||||
}
|
@ -2,14 +2,14 @@ import { useContext } from 'react'
|
||||
import { ContentProps, HeaderProps, MainProps } from './@types/index'
|
||||
import { AccordionContextItems } from './context/Items'
|
||||
|
||||
import './index.scss'
|
||||
import styles from './$Accordion.module.scss'
|
||||
|
||||
const Main = ({ customKey, children, className, ...props }: MainProps) => {
|
||||
const { current } = useContext(AccordionContextItems)
|
||||
|
||||
const isOpen = () => {
|
||||
if (current === customKey) {
|
||||
return 'active'
|
||||
return styles.active
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
@ -17,7 +17,7 @@ const Main = ({ customKey, children, className, ...props }: MainProps) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${className} accordion ${isOpen()}`}
|
||||
className={`${className} ${styles['accordion']} ${isOpen()}`}
|
||||
data-jsx="target"
|
||||
{...props}
|
||||
>
|
||||
@ -38,14 +38,14 @@ const Header = ({ customKey, children, className, ...props }: HeaderProps) => {
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<i className="accordion-icon" role={'presentation'}></i>
|
||||
<i className={styles['accordion-icon']} role={'presentation'}></i>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
const Content = ({ children, className, ...props }: ContentProps) => {
|
||||
return (
|
||||
<div className={`accordion-content ${className}`} {...props}>
|
||||
<div className={`${styles['accordion-content']} ${className}`} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
147
src/components/Molecules/Accordion/README.md
Normal file
@ -0,0 +1,147 @@
|
||||
# Componente Accordion
|
||||
|
||||
Esse componente foi criado sem nenhuma biblioteca externa, aqui deixo as maneiras de utilizar esse componente
|
||||
|
||||
## Primeiros Passos
|
||||
|
||||
Caso queira usar o componente, é recomendado, que estude sobre, `useContext`, `createContext`, e `useState`;
|
||||
Caso queira usar e não tem os conhecimentos, veja os exemplo a seguir.
|
||||
|
||||
```jsx
|
||||
import { createContext, useState } from 'react'
|
||||
|
||||
interface fooProps {
|
||||
current: string | number // O current(Atual) pode ser uma string ou number
|
||||
handleSetCurrent: (customkey) => void // O handleSetCurrent é uma função que vc pode criar para fazer as alterações que desejar no funcionamento
|
||||
// O paremetro passado chamado de customKey servi para identificar e 'setar' o Accordion Atual
|
||||
}
|
||||
|
||||
const foo = createContext({
|
||||
current: '', // Aqui demostra o componente que está aberto atualmente
|
||||
} as fooProps) // Aqui estamos o nosso contexto do nosso Accordion
|
||||
|
||||
// Provedor do Contexto
|
||||
interface AccordionProviderItemsProps {
|
||||
children: ReactNode | ReactNode[]
|
||||
value: fooProps
|
||||
}
|
||||
|
||||
export const AccordionProviderItems = ({
|
||||
children,
|
||||
value,
|
||||
}: AccordionProviderItemsProps) => {
|
||||
return (
|
||||
<>
|
||||
<AccordionContextItems.Provider value={value}>
|
||||
{children}
|
||||
</AccordionContextItems.Provider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// Estado que deve ser criado
|
||||
const [accordionCurrentIsOpen, setAccordionCurrentIsOpen] = useState<string | number | ''>('')
|
||||
|
||||
// Demostração da função handleSetCurrent
|
||||
function handleSetCurrent(customkey: string | number | '') {
|
||||
if (customkey === accordionCurrentIsOpen) {/*A verificação do customKey com o state*/
|
||||
// Essa veficação fica engarregada de verificar se o usario clicou no mesmo Accordion
|
||||
|
||||
// SE Clicou no mesmo Accordion 'setar' a customKey para 'vazio'
|
||||
// SENÃO 'setar' customKey
|
||||
|
||||
// A customKey é um identificador para cada Accordion da página caso queira, já que vc pode criar em qualquer lugar dá página
|
||||
|
||||
// Ok, se isso é um identificador se eu colocar outro igual ?
|
||||
// Simplemente ele íra abrir e fechar os identificadores iguais e fechar o mesmo quando clicado por um deles
|
||||
|
||||
setAccordionCurrentIsOpen('')
|
||||
} else {
|
||||
setAccordionCurrentIsOpen(customkey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Como usar ?
|
||||
import { Accordion } from "foo"
|
||||
|
||||
function Exemple() {
|
||||
const [accordionCurrentIsOpen, setAccordionCurrentIsOpen] = useState<string | number | ''>('')
|
||||
|
||||
|
||||
function handleSetCurrent(customkey: string | number | '') {
|
||||
if (customkey === accordionCurrentIsOpen) {
|
||||
setAccordionCurrentIsOpen('')
|
||||
} else {
|
||||
setAccordionCurrentIsOpen(customkey)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AccordionProviderItems
|
||||
value={{
|
||||
current: accordionCurrentIsOpen,
|
||||
handleSetCurrent: handleSetCurrentAccordion,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Accordion customKey={"Identificador"}>
|
||||
<Accordion.Header customKey={"Identificador"}>
|
||||
{/*Elemento escolhido para abrir*/}
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
{/*Qualquer Elemento que vai renderizar*/}
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
</div>
|
||||
<div>
|
||||
<Accordion customKey={"Identificador"}>
|
||||
<Accordion.Header customKey={"Identificador"}>
|
||||
{/*Elemento escolhido para abrir*/}
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
{/*Qualquer Elemento que vai renderizar*/}
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
</div>
|
||||
<div>
|
||||
<Accordion customKey={"Identificador"}>
|
||||
<Accordion.Header customKey={"Identificador"}>
|
||||
{/*Elemento escolhido para abrir*/}
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
{/*Qualquer Elemento que vai renderizar*/}
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
</div>
|
||||
</AccordionProviderItems>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
/*Como Estilizar*/
|
||||
.accordion {
|
||||
/*...*/
|
||||
}
|
||||
|
||||
.accordion.active {
|
||||
/*...*/
|
||||
}
|
||||
|
||||
.accordion-content {
|
||||
/*...*/
|
||||
}
|
||||
|
||||
.accordion-icon {
|
||||
/*...*/
|
||||
}
|
||||
|
||||
/*Alguns Components estão disponiveis para colocar classes HTML criadas por você*/
|
||||
```
|
||||
|
||||
Aviso Componente Criado em um desafio, pode ocorrer problemas com algumas coisas, então devido a colocação em que estão, esse componente não será atualizado
|
1
src/components/Molecules/Accordion/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Accordion } from './$Accordion'
|
@ -1,10 +1,12 @@
|
||||
import arrowRightIcon from '../../../assets/icons/arrow-right.svg'
|
||||
import initialHomeIcon from '../../../assets/icons/home.svg'
|
||||
|
||||
import css from './index.module.scss'
|
||||
|
||||
import { HTMLAttributes } from 'react'
|
||||
|
||||
import { ItemList } from '../ItemList'
|
||||
|
||||
import arrowRightIcon from './assets/arrow-right.svg'
|
||||
import initialHomeIcon from './assets/home.svg'
|
||||
|
||||
import styles from './$Breadcrumb.module.scss'
|
||||
|
||||
interface BreadcrumbProps extends HTMLAttributes<HTMLDivElement> {
|
||||
list: Array<{ name: string; href: string }>
|
||||
}
|
||||
@ -12,17 +14,15 @@ interface BreadcrumbProps extends HTMLAttributes<HTMLDivElement> {
|
||||
export function Breadcrumb({ list, ...props }: BreadcrumbProps) {
|
||||
return (
|
||||
<div {...props}>
|
||||
<ul className={css.list}>
|
||||
<li className={css.initial}>
|
||||
<a href="/">
|
||||
<img src={initialHomeIcon} alt="" />
|
||||
</a>
|
||||
</li>
|
||||
<ul className={styles.list}>
|
||||
<ItemList className={styles.initial} href="/">
|
||||
<img src={initialHomeIcon} alt="" />
|
||||
</ItemList>
|
||||
|
||||
{list.map(({ name, href }) => {
|
||||
return (
|
||||
<li key={name + '-breadcrumb-item'} className={css.item}>
|
||||
<div className={css.divider}>
|
||||
<li key={name + '-breadcrumb-item'} className={styles.item}>
|
||||
<div className={styles.divider}>
|
||||
<img src={arrowRightIcon} alt="ícone de divisão" />
|
||||
</div>
|
||||
<a href={href}>{name}</a>
|
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 689 B |
Before Width: | Height: | Size: 1007 B After Width: | Height: | Size: 1007 B |
1
src/components/Molecules/Breadcrumb/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Breadcrumb } from './$Breadcrumb'
|
15
src/components/Molecules/ButtonIcon/index.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { ButtonHTMLAttributes } from 'react'
|
||||
import { Icon } from '../../Atoms/Icon'
|
||||
|
||||
interface ButtonIconProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
src: any
|
||||
alt: string
|
||||
}
|
||||
|
||||
export function ButtonIcon({ src, alt, ...props }: ButtonIconProps) {
|
||||
return (
|
||||
<button {...props}>
|
||||
<Icon className="btn-icon icon" src={src} alt={alt} />
|
||||
</button>
|
||||
)
|
||||
}
|
12
src/components/Molecules/ItemList/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import { AnchorHTMLAttributes, ReactNode } from 'react'
|
||||
import { To } from 'react-router-dom'
|
||||
import { CustomLinkProps } from '../../Atoms/CustomLink/@types'
|
||||
import { ItemProps } from '../../Atoms/Item/@types'
|
||||
|
||||
export interface ItemListProps
|
||||
extends AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
CustomLinkProps {
|
||||
to?: To
|
||||
children?: ReactNode | ReactNode[]
|
||||
$container?: ItemProps
|
||||
}
|
11
src/components/Molecules/ItemList/index.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { Item } from '../../Atoms/Item'
|
||||
import { CustomLink } from '../../Atoms/CustomLink'
|
||||
import { ItemListProps } from './@types'
|
||||
|
||||
export function ItemList({ $container, children, ...props }: ItemListProps) {
|
||||
return (
|
||||
<Item {...$container}>
|
||||
<CustomLink {...props}>{children}</CustomLink>
|
||||
</Item>
|
||||
)
|
||||
}
|
599
src/components/Organisms/Footer/$Footer.module.scss
Normal file
@ -0,0 +1,599 @@
|
||||
@use '../../../styles/utils/helpers/functions' as function;
|
||||
|
||||
.footer {
|
||||
&__container--top,
|
||||
&__container--bottom {
|
||||
width: 100%;
|
||||
padding: 0 16px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
@media screen and (min-height: 1281px) {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer__content {
|
||||
border-top: 1px solid var(--clr-common-black);
|
||||
}
|
||||
|
||||
.newsletter {
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--clr-common-black);
|
||||
|
||||
&__container {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter {
|
||||
h3 {
|
||||
margin-bottom: 16px;
|
||||
font-weight: 500;
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
|
||||
color: var(--clr-gray-800);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-large);
|
||||
line-height: 21.09px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 42.19px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter__container {
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(474px, 1280px);
|
||||
padding: 16px 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(922px, 2500px);
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter__container {
|
||||
fieldset :global {
|
||||
border: none;
|
||||
|
||||
.form-group {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter__container :global {
|
||||
.form-input {
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(340px, 474px);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(668px, 922px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter__container :global {
|
||||
input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid var(--clr-gray-400);
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--clr-gray-400);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
height: 59px;
|
||||
}
|
||||
}
|
||||
|
||||
.form__success {
|
||||
display: none;
|
||||
transition: 200ms;
|
||||
color: var(--clr-common-green);
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
margin-top: 12px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 28.13px;
|
||||
}
|
||||
}
|
||||
|
||||
.form__success.form__success-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter__form {
|
||||
button[type='submit'] {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--clr-common-black);
|
||||
color: var(--clr-common-white);
|
||||
text-transform: uppercase;
|
||||
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
|
||||
transition: 200ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-common-black);
|
||||
background-color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(126px, 474px);
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(246px, 922px);
|
||||
line-height: 28.13px;
|
||||
height: 59px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.newsletter {
|
||||
@media screen and (min-width: 1025px) {
|
||||
&__container {
|
||||
fieldset :global {
|
||||
.form-group {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
.form-input {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer__container--top {
|
||||
padding-top: 17px;
|
||||
padding-bottom: 24px;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: function.fluid(1080px, 1280px);
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
|
||||
margin: 0 auto;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
gap: 0px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(2300px, 2500px);
|
||||
}
|
||||
}
|
||||
|
||||
.footer__container--bottom {
|
||||
background-color: var(--clr-common-black);
|
||||
|
||||
.footer__phrase {
|
||||
width: function.fluid(258px, 343px);
|
||||
|
||||
&::before {
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. .';
|
||||
}
|
||||
|
||||
text-overflow: ellipsis;
|
||||
text-transform: capitalize;
|
||||
overflow: hidden;
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: function.fluid(234px, 1080px);
|
||||
|
||||
&::before {
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor';
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(467px, 2300px);
|
||||
}
|
||||
}
|
||||
|
||||
* p,
|
||||
* li {
|
||||
color: var(--clr-common-white);
|
||||
}
|
||||
}
|
||||
|
||||
.footer__container--bottom {
|
||||
.footer__phrase::before,
|
||||
.footer__actions--bottom .footer__credits li p {
|
||||
font-size: var(--txt-xxs);
|
||||
}
|
||||
}
|
||||
|
||||
.footer__actions--bottom {
|
||||
.footer__credits {
|
||||
gap: 12.73px;
|
||||
|
||||
&,
|
||||
li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@each $index, $value in ('1': 12.12px, '2': 12.97px) {
|
||||
li:nth-child(#{$index}) {
|
||||
gap: #{$value};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
// moved container bottom actions footer for large, medium devices
|
||||
.footer__container--bottom {
|
||||
.footer__actions--bottom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 15px 0;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
|
||||
width: function.fluid(1080px, 1280px);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(2300px, 2500px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer__lists.lists {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.lists__content {
|
||||
&-list {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
li,
|
||||
a {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
|
||||
color: var(--clr-gray-800);
|
||||
transition: color 200ms ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 28.13px;
|
||||
}
|
||||
}
|
||||
|
||||
li:last-child {
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: function.fluid(707px, 1080px);
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
& > li {
|
||||
width: function.fluid(155px, 707px);
|
||||
}
|
||||
|
||||
.lists__content {
|
||||
height: auto;
|
||||
overflow: unset;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(1531px, 2300px);
|
||||
|
||||
& > li {
|
||||
width: function.fluid(315px, 1531px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lists__header {
|
||||
@media only screen and (min-width: 1025px) {
|
||||
margin-bottom: 12px;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: 500;
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
color: var(--clr-gray-800);
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payments {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: red;
|
||||
|
||||
&__divider {
|
||||
height: 20.36px;
|
||||
border-left: 1px solid var(--clr-gray-400);
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@each $index,
|
||||
$value
|
||||
in(
|
||||
'1': 11.33px,
|
||||
'2': 11.22px,
|
||||
'3': 11.22px,
|
||||
'4': 11.44px,
|
||||
'5': 11.22px,
|
||||
'6': 11.33px,
|
||||
'7': 10.33px
|
||||
)
|
||||
{
|
||||
&__item:nth-child(#{$index}) {
|
||||
margin-right: #{$value};
|
||||
}
|
||||
}
|
||||
|
||||
&__item:last-child {
|
||||
margin-left: 10.49px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(398.61px, 1080px);
|
||||
|
||||
gap: 12px;
|
||||
|
||||
&__item:nth-child(1),
|
||||
&__item:nth-child(2),
|
||||
&__item:nth-child(3),
|
||||
&__item:nth-child(4),
|
||||
&__item:nth-child(5),
|
||||
&__item:nth-child(6),
|
||||
&__item:nth-child(7) {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
width: function.fluid(36px, 398.61px);
|
||||
min-height: 20.2px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__item:last-child {
|
||||
width: function.fluid(54.61px, 398.61px);
|
||||
min-height: 34px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(692px, 2300px);
|
||||
|
||||
&__item {
|
||||
width: function.fluid(70px, 692px);
|
||||
min-height: 39.27px;
|
||||
}
|
||||
|
||||
&__item:last-child {
|
||||
width: function.fluid(106px, 692px);
|
||||
min-height: 66px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer__network {
|
||||
width: 100%;
|
||||
& > a {
|
||||
display: block;
|
||||
|
||||
margin-top: 12px;
|
||||
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
color: var(--clr-gray-800);
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: function.fluid(215px, 1080px);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(390px, 2300px);
|
||||
}
|
||||
}
|
||||
|
||||
.socials {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
li {
|
||||
width: function.fluid(35px, 215px);
|
||||
min-height: 35px;
|
||||
flex-grow: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer__credits {
|
||||
li:nth-child(1) {
|
||||
img {
|
||||
width: 44.92px;
|
||||
min-height: 16px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 84.22px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li:nth-child(2) {
|
||||
img {
|
||||
width: 28.66px;
|
||||
height: 15.65px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 54.95px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// control view order components
|
||||
.footer {
|
||||
&__phrase {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
&__payments {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
&__credits {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
&__phrase,
|
||||
&__payments,
|
||||
&__credits {
|
||||
order: initial;
|
||||
}
|
||||
}
|
||||
}
|
55
src/components/Organisms/Footer/$Footer.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import vtexIcon from './assets/imgs/svgs/Vtex.svg'
|
||||
import m3Icon from './assets/imgs/svgs/M3.svg'
|
||||
|
||||
import Containers from './containers'
|
||||
|
||||
import styles from './$Footer.module.scss'
|
||||
|
||||
export function Footer() {
|
||||
const [accordionCurrentIsOpen, setAccordionCurrentIsOpen] = useState<
|
||||
string | number | ''
|
||||
>('')
|
||||
|
||||
function handleSetCurrentAccordion(customkey: string | number | '') {
|
||||
if (window.innerWidth < 1024) {
|
||||
if (customkey === accordionCurrentIsOpen) {
|
||||
setAccordionCurrentIsOpen('')
|
||||
} else {
|
||||
setAccordionCurrentIsOpen(customkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<footer className={styles['footer']}>
|
||||
<Containers.Newsletter />
|
||||
<div className={styles['footer__content']}>
|
||||
<div className={styles['footer__container--top']}>
|
||||
<Containers.List
|
||||
accordionCurrentIsOpen={accordionCurrentIsOpen}
|
||||
handleSetCurrentAccordion={handleSetCurrentAccordion}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles['footer__container--bottom']}>
|
||||
<div className={styles['footer__actions--bottom']}>
|
||||
<p className={styles['footer__phrase']}></p>
|
||||
<Containers.PaymentsList />
|
||||
<ul className={styles['footer__credits']}>
|
||||
<li>
|
||||
<p>Powered by</p>
|
||||
<img src={vtexIcon} alt="" />
|
||||
</li>
|
||||
<li>
|
||||
<p>Developed by</p>
|
||||
<img src={m3Icon} alt="" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
15
src/components/Organisms/Footer/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
import { AccordionProps } from '../../../Molecules/Accordion/@types'
|
||||
|
||||
export interface InstitutionalListProps
|
||||
extends Omit<AccordionProps, 'setCurrentAccordion'> {}
|
||||
|
||||
export interface ContactListProps
|
||||
extends Omit<AccordionProps, 'setCurrentAccordion'> {}
|
||||
|
||||
export interface QuestionsListProps
|
||||
extends Omit<AccordionProps, 'setCurrentAccordion'> {}
|
||||
|
||||
export interface ListProps {
|
||||
accordionCurrentIsOpen: string | number | ''
|
||||
handleSetCurrentAccordion: (customKey: string | number | '') => void
|
||||
}
|
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 986 B After Width: | Height: | Size: 986 B |
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 817 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 885 B After Width: | Height: | Size: 885 B |
Before Width: | Height: | Size: 745 B After Width: | Height: | Size: 745 B |
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 1000 B After Width: | Height: | Size: 1000 B |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
46
src/components/Organisms/Footer/containers/_List.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { ListProps } from '../@types'
|
||||
|
||||
import { AccordionProviderItems } from '../../../Molecules/Accordion/context/Items'
|
||||
|
||||
import { Item } from '../../../Atoms/Item'
|
||||
import { CustomLink } from '../../../Atoms/CustomLink'
|
||||
|
||||
import { ContactList } from './__Contact'
|
||||
import { InstitutionalList } from './__Institutional'
|
||||
import { QuestionsList } from './__Question'
|
||||
import { Socials } from './__Socials'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
export function List({
|
||||
accordionCurrentIsOpen,
|
||||
handleSetCurrentAccordion,
|
||||
}: ListProps) {
|
||||
return (
|
||||
<>
|
||||
<AccordionProviderItems
|
||||
value={{
|
||||
current: accordionCurrentIsOpen,
|
||||
handleSetCurrent: handleSetCurrentAccordion,
|
||||
}}
|
||||
>
|
||||
<ul className={`${styles['footer__lists']} ${styles['lists']}`}>
|
||||
<Item>
|
||||
<InstitutionalList customKey={'institutional'} />
|
||||
</Item>
|
||||
<Item>
|
||||
<QuestionsList customKey={'question'} />
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ContactList customKey={'contact'} />
|
||||
</Item>
|
||||
</ul>
|
||||
<div className={styles['footer__network']}>
|
||||
<Socials />
|
||||
<CustomLink href="/">www.loremipsum.com</CustomLink>
|
||||
</div>
|
||||
</AccordionProviderItems>
|
||||
</>
|
||||
)
|
||||
}
|
60
src/components/Organisms/Footer/containers/_Newsletter.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import { useEffect, useState } from 'react'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
const schema = Yup.object({
|
||||
email: Yup.string().required('Campo Obrigratorio').email('Email ínvalido'),
|
||||
})
|
||||
|
||||
export function Newsletter() {
|
||||
const [isSubmiting, setIsSubmiting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (isSubmiting) {
|
||||
setTimeout(() => {
|
||||
setIsSubmiting(false)
|
||||
}, 2000)
|
||||
}
|
||||
}, [isSubmiting])
|
||||
|
||||
return (
|
||||
<section className={styles['newsletter']}>
|
||||
<div className={styles['newsletter__container']}>
|
||||
<div className={styles['newsletter__content']}>
|
||||
<h3>Assine nossa newsletter</h3>
|
||||
<Formik
|
||||
initialValues={{ email: '' }}
|
||||
onSubmit={(values, e) => {
|
||||
e.resetForm({
|
||||
isSubmitting: true,
|
||||
})
|
||||
|
||||
setIsSubmiting(true)
|
||||
}}
|
||||
validationSchema={schema}
|
||||
>
|
||||
<Form className={styles['newsletter__form']}>
|
||||
<fieldset className="form-container">
|
||||
<div className="form-group">
|
||||
<div className="form-input">
|
||||
<Field name="email" type="text" placeholder="E-mail" />
|
||||
</div>
|
||||
<button type="submit">Enviar</button>
|
||||
</div>
|
||||
<p
|
||||
className={`form__success ${
|
||||
isSubmiting ? 'form__success-active' : ''
|
||||
}`}
|
||||
>
|
||||
*Formulário enviado com sucesso!
|
||||
</p>
|
||||
</fieldset>
|
||||
</Form>
|
||||
</Formik>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
66
src/components/Organisms/Footer/containers/_Payment.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { Item } from '../../../Atoms/Item'
|
||||
|
||||
import BoletoImg from '../assets/imgs/Boleto.png'
|
||||
import DinersBrandImg from '../assets/imgs/Diners.png'
|
||||
import EloBrandImg from '../assets/imgs/Elo.png'
|
||||
import HiperBrandImg from '../assets/imgs/Hiper.png'
|
||||
import PaypalBrandImg from '../assets/imgs/Paypal.png'
|
||||
import MasterCardBrandImg from '../assets/imgs/Master.png'
|
||||
import VisaBrandImg from '../assets/imgs/Visa.png'
|
||||
import VtexPCIImg from '../assets/imgs/vtex-pci-200.png'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
const assetsImg = [
|
||||
{
|
||||
src: MasterCardBrandImg,
|
||||
alt: 'Pagamento com o mastercard',
|
||||
},
|
||||
{
|
||||
src: VisaBrandImg,
|
||||
alt: 'Pagamento com Visa',
|
||||
},
|
||||
{
|
||||
src: DinersBrandImg,
|
||||
alt: 'Pagamento com Diners',
|
||||
},
|
||||
{
|
||||
src: EloBrandImg,
|
||||
alt: 'Pagamento com a Elo',
|
||||
},
|
||||
|
||||
{
|
||||
src: HiperBrandImg,
|
||||
alt: 'Pagamento com o Hiper',
|
||||
},
|
||||
|
||||
{
|
||||
src: PaypalBrandImg,
|
||||
alt: 'Pagamento com o PayPal',
|
||||
},
|
||||
{
|
||||
src: BoletoImg,
|
||||
alt: 'Pagamento em Boleto',
|
||||
},
|
||||
]
|
||||
|
||||
export function PaymentsList() {
|
||||
return (
|
||||
<ul className={`${styles['footer__payments']} ${styles['payments']}`}>
|
||||
{assetsImg.map(({ src, alt }, index) => {
|
||||
return (
|
||||
<Item
|
||||
className={`${styles['payments__item']}`}
|
||||
key={alt.replace(' ', '-').toLowerCase()}
|
||||
>
|
||||
<img className="payments__image" src={src} alt={alt} />
|
||||
</Item>
|
||||
)
|
||||
})}
|
||||
<div className={`${styles['payments__divider']}`} role={'presentation'} />
|
||||
<Item className={`${styles['payments__item']}`}>
|
||||
<img src={VtexPCIImg} alt="" />
|
||||
</Item>
|
||||
</ul>
|
||||
)
|
||||
}
|
28
src/components/Organisms/Footer/containers/__Contact.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { ContactListProps } from '../@types'
|
||||
|
||||
import { Item } from '../../../Atoms/Item'
|
||||
import { Accordion } from '../../../Molecules/Accordion/$Accordion'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
export function ContactList({ customKey }: ContactListProps) {
|
||||
return (
|
||||
<Accordion className={styles.accordion} customKey={customKey}>
|
||||
<Accordion.Header
|
||||
customKey={customKey}
|
||||
className={`${styles['lists__header']}`}
|
||||
>
|
||||
<h4>Fale Conosco</h4>
|
||||
</Accordion.Header>
|
||||
|
||||
<Accordion.Content className={`${styles['lists__content']}`}>
|
||||
<ul className={styles['lists__content-list']}>
|
||||
<Item>Atendimento ao Consumidor</Item>
|
||||
<Item>(11) 4159 9504</Item>
|
||||
<Item>Atendimento Online</Item>
|
||||
<Item>(11) 99433-8825</Item>
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import { InstitutionalListProps } from '../@types'
|
||||
|
||||
import { Accordion } from '../../../Molecules/Accordion/$Accordion'
|
||||
|
||||
import { ItemList } from '../../../Molecules/ItemList'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
export function InstitutionalList({ customKey }: InstitutionalListProps) {
|
||||
return (
|
||||
<Accordion className={styles.accordion} customKey={customKey}>
|
||||
<Accordion.Header
|
||||
customKey={customKey}
|
||||
className={`${styles['lists__header']}`}
|
||||
>
|
||||
<h4>Institucional</h4>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content className={`${styles['lists__content']}`}>
|
||||
<ul className={styles['lists__content-list']}>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Quem somos nós
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Política de Privacidade
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Segurança
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Seja um Revendedor
|
||||
</ItemList>
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
)
|
||||
}
|
35
src/components/Organisms/Footer/containers/__Question.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { QuestionsListProps } from '../@types'
|
||||
|
||||
import { Accordion } from '../../../Molecules/Accordion/$Accordion'
|
||||
import { ItemList } from '../../../Molecules/ItemList'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
export function QuestionsList({ customKey }: QuestionsListProps) {
|
||||
return (
|
||||
<Accordion className={styles.accordion} customKey={customKey}>
|
||||
<Accordion.Header
|
||||
customKey={customKey}
|
||||
className={`${styles['lists__header']}`}
|
||||
>
|
||||
<h4>Dúvidas</h4>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content className={`${styles['lists__content']}`}>
|
||||
<ul className={`${styles['lists__content-list']}`}>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Entrega
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Pagamento
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Trocas e Devoluções
|
||||
</ItemList>
|
||||
<ItemList $container={{ className: '' }} href="/">
|
||||
Dúvidas Frequentes
|
||||
</ItemList>
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
)
|
||||
}
|
31
src/components/Organisms/Footer/containers/__Socials.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { ItemList } from '../../../Molecules/ItemList'
|
||||
|
||||
import facebookIcon from '../assets/icons/facebook.svg'
|
||||
import instagramIcon from '../assets/icons/instagram.svg'
|
||||
import linkedinIcon from '../assets/icons/linkedin.svg'
|
||||
import twitterIcon from '../assets/icons/twitter.svg'
|
||||
import youtubeIcon from '../assets/icons/youtube.svg'
|
||||
|
||||
import styles from '../$Footer.module.scss'
|
||||
|
||||
export function Socials() {
|
||||
return (
|
||||
<ul className={styles.socials}>
|
||||
<ItemList href="https://facebook.com">
|
||||
<img src={facebookIcon} alt="Facebook logo" />
|
||||
</ItemList>
|
||||
<ItemList href="https://instagram.com">
|
||||
<img src={instagramIcon} alt="Instagram logo" />
|
||||
</ItemList>
|
||||
<ItemList href="https://twitter.com">
|
||||
<img src={twitterIcon} alt="Twitter logo" />
|
||||
</ItemList>
|
||||
<ItemList href="https://youtube.com">
|
||||
<img src={youtubeIcon} alt="Youtube logo" />
|
||||
</ItemList>
|
||||
<ItemList href="https://linkedin.com">
|
||||
<img src={linkedinIcon} alt="Linkedin logo" />
|
||||
</ItemList>
|
||||
</ul>
|
||||
)
|
||||
}
|
13
src/components/Organisms/Footer/containers/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { List } from './_List'
|
||||
import { Newsletter } from './_Newsletter'
|
||||
import { PaymentsList } from './_Payment'
|
||||
|
||||
function Containers() {
|
||||
return {
|
||||
Newsletter,
|
||||
PaymentsList,
|
||||
List,
|
||||
}
|
||||
}
|
||||
|
||||
export default Containers()
|
1
src/components/Organisms/Footer/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Footer } from './$Footer'
|
@ -1,24 +1,22 @@
|
||||
@use '../../styles/utils/helpers/functions' as function;
|
||||
@use '../../../styles/utils/helpers/functions' as function;
|
||||
|
||||
$containers: (
|
||||
'xs': 339px,
|
||||
'sm': 988px,
|
||||
'md': 1080px,
|
||||
'xl': 2299.68px,
|
||||
'xl': 2300px,
|
||||
);
|
||||
|
||||
.header {
|
||||
.l-header {
|
||||
padding: 25px 0;
|
||||
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
position: sticky;
|
||||
|
||||
background-color: var(--clr-common-black);
|
||||
}
|
||||
|
||||
.header {
|
||||
@media only screen and (min-width: 1025px) {
|
||||
padding: 25px 0 0;
|
||||
}
|
||||
@ -28,16 +26,14 @@ $containers: (
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.l-header__top {
|
||||
padding: 0px 16px;
|
||||
margin-bottom: 27.14px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.content {
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: #{function.fluid(map-get($containers, 'md'), 1280px)};
|
||||
padding: 0;
|
||||
@ -49,27 +45,29 @@ $containers: (
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
$content: (
|
||||
'md': 136px,
|
||||
'xl': 265.62px,
|
||||
);
|
||||
.l-header__top :global {
|
||||
.top__logo {
|
||||
$content: (
|
||||
'md': 136px,
|
||||
'xl': 265.62px,
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
@media only screen and (min-width: 1025px) {
|
||||
// prettier-ignore
|
||||
@media only screen and (min-width: 1025px) {
|
||||
width: function.fluid(
|
||||
map-get($content, 'md'),
|
||||
map-get($containers, 'md')
|
||||
);
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
@media only screen and (min-width: 2500px) {
|
||||
// prettier-ignore
|
||||
@media only screen and (min-width: 2500px) {
|
||||
width: function.fluid(
|
||||
map-get($content, 'xl'),
|
||||
map-get($containers, 'xl')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
@ -77,12 +75,21 @@ $containers: (
|
||||
border: 2px solid var(--clr-gray-150);
|
||||
border-radius: 5px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--clr-common-white);
|
||||
|
||||
&,
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 36px;
|
||||
height: 100%;
|
||||
background-color: var(--clr-common-white);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 0 9px 0 16px;
|
||||
@ -90,19 +97,11 @@ $containers: (
|
||||
border-radius: 5px 0 0 5px;
|
||||
|
||||
font-size: var(--txt-normal);
|
||||
}
|
||||
}
|
||||
line-height: 16.41px;
|
||||
|
||||
.search {
|
||||
button {
|
||||
width: 36px;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--clr-common-white);
|
||||
@media only screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,36 +120,55 @@ $containers: (
|
||||
|
||||
button {
|
||||
width: 56.85px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 35.15px;
|
||||
height: 35.15px;
|
||||
}
|
||||
button img {
|
||||
width: 35.15px;
|
||||
height: 35.15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-top,
|
||||
.actions-bottom {
|
||||
.actions__top,
|
||||
.actions__bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-normal);
|
||||
text-transform: uppercase;
|
||||
line-height: 16.41px;
|
||||
|
||||
display: block;
|
||||
|
||||
color: var(--clr-common-white);
|
||||
transition: color 200ms linear;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-top {
|
||||
.actions__top {
|
||||
gap: 55px;
|
||||
|
||||
// remove action top link for small devices and added for large devices 1025 > x
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2500px) {
|
||||
img {
|
||||
width: 54.68px;
|
||||
@ -160,7 +178,7 @@ $containers: (
|
||||
}
|
||||
|
||||
// remove open menu mobile button for large devices 1025 > x
|
||||
.open {
|
||||
.button-open {
|
||||
display: flex;
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
@ -168,23 +186,26 @@ $containers: (
|
||||
}
|
||||
}
|
||||
|
||||
// remove action top link for small devices and added for large devices 1025 > x
|
||||
.actions-top {
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
.actions__bottom {
|
||||
width: 100%;
|
||||
height: 78px;
|
||||
padding: 0 16px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
background-color: var(--clr-common-black);
|
||||
|
||||
// remove actions bottom for large devices
|
||||
@media only screen and (min-width: 1025px) {
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
@media only screen and (max-width: 1024px) {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
position: fixed;
|
||||
left: -100%;
|
||||
@ -193,81 +214,67 @@ $containers: (
|
||||
background-color: transparent;
|
||||
transition: 300ms ease;
|
||||
|
||||
&-content {
|
||||
width: function.fluid(map-get($containers, 'sm'), 1024px);
|
||||
&,
|
||||
&__container {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
&-content {
|
||||
border-top: 1px solid var(--clr-common-white);
|
||||
&__container {
|
||||
width: function.fluid(map-get($containers, 'sm'), 1024px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
@media only screen and (max-width: 768px) {
|
||||
&-content {
|
||||
&__container {
|
||||
width: function.fluid(map-get($containers, 'xs'), 375px);
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
.actions-bottom {
|
||||
width: 100%;
|
||||
height: 78px;
|
||||
|
||||
background-color: var(--clr-common-black);
|
||||
@media screen and (min-width: 1025px) {
|
||||
&__container {
|
||||
border-top: 1px solid var(--clr-common-white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 0 16px;
|
||||
.menu {
|
||||
&__list {
|
||||
height: calc(100% - 78px);
|
||||
padding: 31px 16px 0;
|
||||
|
||||
background-color: var(--clr-common-white);
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
margin-bottom: 12px;
|
||||
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
|
||||
color: var(--clr-gray-400);
|
||||
transition: color 200ms linear;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
.list {
|
||||
height: calc(100% - 78px);
|
||||
padding-top: 31px;
|
||||
|
||||
background-color: var(--clr-common-white);
|
||||
|
||||
a {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-weight: 500;
|
||||
font-size: var(--txt-normal);
|
||||
|
||||
color: var(--clr-gray-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-bottom {
|
||||
padding: 0 16px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// styles for menu is active
|
||||
|
||||
.menu {
|
||||
&.active {
|
||||
&.menu--active {
|
||||
left: 0;
|
||||
background-color: #0004;
|
||||
}
|
||||
@ -280,7 +287,9 @@ $containers: (
|
||||
|
||||
display: block;
|
||||
|
||||
.list {
|
||||
background-color: var(--clr-common-black);
|
||||
|
||||
&__list {
|
||||
width: function.fluid(map-get($containers, 'md'), 1280px);
|
||||
padding: 14px 0;
|
||||
margin: 0 auto;
|
||||
@ -297,22 +306,16 @@ $containers: (
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
background-color: var(--clr-common-black);
|
||||
|
||||
.actions-bottom {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
.list {
|
||||
&__list {
|
||||
width: function.fluid(map-get($containers, 'xl'), 2500px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-top {
|
||||
.search--top {
|
||||
$content: (
|
||||
'md': 264px,
|
||||
'xl': 515.62px,
|
||||
@ -340,7 +343,7 @@ $containers: (
|
||||
\*|[O]o-o-o-o[X]|*/
|
||||
|
||||
//remove search top box for small, medium devices
|
||||
.search-top {
|
||||
.search--top {
|
||||
display: none;
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
@ -349,12 +352,12 @@ $containers: (
|
||||
}
|
||||
|
||||
// added search bottom box for small devices, medium devices
|
||||
.search-bottom {
|
||||
.search__bottom {
|
||||
padding: 0 16px;
|
||||
|
||||
display: flex;
|
||||
|
||||
&-content {
|
||||
&--content {
|
||||
width: 100%;
|
||||
}
|
||||
|
46
src/components/Organisms/Header/$Header.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import styles from './$Header.module.scss'
|
||||
|
||||
import Container from './containers'
|
||||
|
||||
export const Header = () => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
|
||||
const containerTopProps = {
|
||||
handleClickOpen: useMemo(
|
||||
() =>
|
||||
function () {
|
||||
if (window.innerWidth <= 1024) setIsMenuOpen(true)
|
||||
},
|
||||
[]
|
||||
),
|
||||
}
|
||||
|
||||
const containerBottomProps = {
|
||||
isMenuOpen,
|
||||
handleClickClose: useMemo(
|
||||
() =>
|
||||
function () {
|
||||
if (window.innerWidth <= 1024) setIsMenuOpen(false)
|
||||
},
|
||||
[]
|
||||
),
|
||||
}
|
||||
|
||||
return (
|
||||
<header className={styles['l-header']}>
|
||||
<nav>
|
||||
<Container.Top {...containerTopProps} />
|
||||
|
||||
<div className={`${styles['search__bottom']}`}>
|
||||
<Container.Search
|
||||
className={`${styles['search']} ${styles['search__bottom--content']}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Container.Bottom {...containerBottomProps} />
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 688 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 804 B After Width: | Height: | Size: 804 B |
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 638 B |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
19
src/components/Organisms/Header/containers/@types/index.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import { HTMLAttributes, ButtonHTMLAttributes } from 'react'
|
||||
|
||||
export type ISearchProps = HTMLAttributes<HTMLDivElement>
|
||||
|
||||
export interface ITopProps {
|
||||
handleClickOpen: () => void
|
||||
}
|
||||
|
||||
export interface IBottomProps {
|
||||
handleClickClose: () => void
|
||||
isMenuOpen: boolean
|
||||
}
|
||||
|
||||
export interface ActionsProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
$container?: HTMLAttributes<HTMLDivElement>
|
||||
handleClick: () => any
|
||||
src: any
|
||||
alt: string
|
||||
}
|
47
src/components/Organisms/Header/containers/_Bottom.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { IBottomProps } from './@types'
|
||||
|
||||
import { ItemList } from '../../../Molecules/ItemList'
|
||||
import { Actions } from './__Actions'
|
||||
|
||||
import closeIcon from '../assets/icons/x.svg'
|
||||
|
||||
import styles from '../$Header.module.scss'
|
||||
|
||||
export function Bottom({ isMenuOpen, handleClickClose }: IBottomProps) {
|
||||
function closeMenu(e: any) {
|
||||
if (e.target.classList.contains(styles.menu)) {
|
||||
if (e.target.children[0] !== e.target) {
|
||||
handleClickClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={(e) => closeMenu(e)}
|
||||
className={`${styles['menu']} ${
|
||||
isMenuOpen ? styles['menu--active'] : ''
|
||||
}`}
|
||||
>
|
||||
<div className={styles['menu__container']}>
|
||||
<Actions
|
||||
handleClick={handleClickClose}
|
||||
$container={{ className: styles['actions__bottom'] }}
|
||||
className={styles['button-close']}
|
||||
alt="ícone do botão para fechar o menu"
|
||||
src={closeIcon}
|
||||
/>
|
||||
|
||||
<ul className={styles['menu__list']}>
|
||||
{['Cursos', 'Saiba Mais', 'Institucionais'].map((item, index) => {
|
||||
return (
|
||||
<ItemList href="/" key={'header-bottom-list-' + index}>
|
||||
{item}
|
||||
</ItemList>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
33
src/components/Organisms/Header/containers/_Search.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import { ISearchProps } from './@types'
|
||||
|
||||
import { ButtonIcon } from '../../../Molecules/ButtonIcon'
|
||||
|
||||
import searchIcon from '../assets/icons/search.svg'
|
||||
|
||||
export function Search({ ...props }: ISearchProps) {
|
||||
const [searchData, setSearchData] = useState('')
|
||||
|
||||
const handleChangeValue = (e: any) => {
|
||||
setSearchData(e.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<input
|
||||
type="search"
|
||||
name="search"
|
||||
placeholder="Buscar..."
|
||||
value={searchData}
|
||||
onChange={handleChangeValue}
|
||||
/>
|
||||
<ButtonIcon
|
||||
type="button"
|
||||
onClick={() => setSearchData('')}
|
||||
src={searchIcon}
|
||||
alt="Search Icon"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
42
src/components/Organisms/Header/containers/_Top.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { ITopProps } from './@types'
|
||||
|
||||
import { ButtonIcon } from '../../../Molecules/ButtonIcon'
|
||||
import { Actions } from './__Actions'
|
||||
import { Search } from './_Search'
|
||||
|
||||
import cartIcon from '../assets/icons/minicart.svg'
|
||||
import openIcon from '../assets/icons/hamburger.svg'
|
||||
import logoImg from '../assets/m3-logo-small.png'
|
||||
import logoMediumImg from '../assets/m3-logo-medium.png'
|
||||
|
||||
import styles from '../$Header.module.scss'
|
||||
|
||||
export function Top({ handleClickOpen }: ITopProps) {
|
||||
return (
|
||||
<div className={`${styles['l-header__top']}`}>
|
||||
<ButtonIcon
|
||||
className={styles['button-open']}
|
||||
onClick={handleClickOpen}
|
||||
type="button"
|
||||
src={openIcon}
|
||||
alt="ícone do botão para abrir o menu"
|
||||
/>
|
||||
|
||||
<a className="top__logo" href="/">
|
||||
<picture>
|
||||
<source media="(min-width:1025px)" srcSet={logoMediumImg} />
|
||||
<img src={logoImg} alt="logo da M3 Academy" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<Search className={`${styles['search']} ${styles['search--top']}`} />
|
||||
|
||||
<Actions
|
||||
$container={{ className: styles['actions__top'] }}
|
||||
handleClick={() => console.log('Funcionando')}
|
||||
src={cartIcon}
|
||||
alt="ícone de carrinho"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
21
src/components/Organisms/Header/containers/__Actions.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { ActionsProps } from './@types'
|
||||
import { CustomLink } from '../../../Atoms/CustomLink'
|
||||
import { ButtonIcon } from '../../../Molecules/ButtonIcon'
|
||||
|
||||
export function Actions({
|
||||
handleClick,
|
||||
$container,
|
||||
src,
|
||||
alt,
|
||||
...props
|
||||
}: ActionsProps) {
|
||||
return (
|
||||
<div {...$container}>
|
||||
<CustomLink href="/">Entrar</CustomLink>
|
||||
{/* prettier-ignore */}
|
||||
<ButtonIcon onClick={handleClick} type="button" src={src}
|
||||
alt={alt} {...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
13
src/components/Organisms/Header/containers/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { Bottom } from './_Bottom'
|
||||
import { Search } from './_Search'
|
||||
import { Top } from './_Top'
|
||||
|
||||
function Containers() {
|
||||
return {
|
||||
Bottom,
|
||||
Search,
|
||||
Top,
|
||||
}
|
||||
}
|
||||
|
||||
export default Containers()
|
1
src/components/Organisms/Header/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Header } from './$Header'
|
47
src/components/Organisms/Sidebar/$Sidebar.module.scss
Normal file
@ -0,0 +1,47 @@
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 40px;
|
||||
|
||||
&__container {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
max-height: 285px;
|
||||
margin-top: 0;
|
||||
border-right: 1px solid var(--clr-common-black);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
max-height: 465px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar__list {
|
||||
a {
|
||||
display: inline-block;
|
||||
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-medium);
|
||||
line-height: 18.75px;
|
||||
|
||||
color: var(--clr-gray-600);
|
||||
|
||||
transition: background 700ms ease;
|
||||
|
||||
&.active {
|
||||
color: var(--clr-common-white);
|
||||
background: var(--clr-common-black);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 37.5px;
|
||||
}
|
||||
}
|
||||
}
|
38
src/components/Organisms/Sidebar/$Sidebar.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import { ItemList } from '../../Molecules/ItemList'
|
||||
|
||||
import styles from './$Sidebar.module.scss'
|
||||
|
||||
export function Sidebar() {
|
||||
const { pathname } = useLocation()
|
||||
|
||||
const paths = [
|
||||
{ name: 'Sobre', path: '/' },
|
||||
{ name: 'Forma de Pagamento', path: '/payments' },
|
||||
{ name: 'Entrega', path: '/shipping' },
|
||||
{ name: 'Troca e Devolução', path: '/exchange' },
|
||||
{ name: 'Segurança e Privacidade', path: '/privacity' },
|
||||
{ name: 'Contato', path: '/contact' },
|
||||
]
|
||||
|
||||
return (
|
||||
<nav className={styles['sidebar']}>
|
||||
<div className={styles['sidebar__container']}>
|
||||
<ul className={styles['sidebar__list']}>
|
||||
{paths.map(({ path, name }) => {
|
||||
return (
|
||||
<ItemList
|
||||
className={pathname === path ? styles['active'] : ''}
|
||||
key={name.replace(' ', '-').toLowerCase() + '-sidebar'}
|
||||
to={path}
|
||||
>
|
||||
{name}
|
||||
</ItemList>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
1
src/components/Organisms/Sidebar/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Sidebar } from './$Sidebar'
|
@ -1,14 +0,0 @@
|
||||
import { AnchorHTMLAttributes, HTMLAttributes, ReactNode } from 'react'
|
||||
|
||||
interface ItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
children: ReactNode | ReactNode[]
|
||||
$container?: HTMLAttributes<HTMLLIElement>
|
||||
}
|
||||
|
||||
export function Item({ children, $container, ...props }: ItemProps) {
|
||||
return (
|
||||
<li {...$container}>
|
||||
<a {...props}>{children}</a>
|
||||
</li>
|
||||
)
|
||||
}
|
30
src/pages/Institutional/About/$About.module.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.about {
|
||||
margin-bottom: 81px;
|
||||
&__descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import css from './index.module.scss'
|
||||
import styles from './$About.module.scss'
|
||||
|
||||
export function About() {
|
||||
return (
|
||||
<section className={css.about}>
|
||||
<div className={css.container}>
|
||||
<section className={styles['about']}>
|
||||
<div className={styles['about__container']}>
|
||||
<h2 className="title">Sobre</h2>
|
||||
|
||||
<div className={css.descriptions}>
|
||||
<div className={styles['about__descriptions']}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
@ -1,31 +0,0 @@
|
||||
.about {
|
||||
margin-bottom: 81px;
|
||||
}
|
||||
|
||||
.descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
1
src/pages/Institutional/About/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { About } from './$About'
|
207
src/pages/Institutional/Contact/$Contact.module.scss
Normal file
@ -0,0 +1,207 @@
|
||||
.contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
margin-bottom: 69.56px;
|
||||
|
||||
&__form {
|
||||
.form__container {
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form :global {
|
||||
.form__group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
display: block;
|
||||
padding: 0 15px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
|
||||
.form__content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.error-message {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
padding: 0 16px;
|
||||
|
||||
text-align: end;
|
||||
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translateY(-100%);
|
||||
color: red;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 28.13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form__input {
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 20px;
|
||||
|
||||
border: 1px solid var(--clr-gray-1000);
|
||||
border-radius: 25px;
|
||||
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
height: 63px;
|
||||
padding: 15px 20px;
|
||||
line-height: 32.81px;
|
||||
}
|
||||
|
||||
&::-webkit-input-placeholder,
|
||||
&::placeholder {
|
||||
color: var(--clr-gray-450);
|
||||
}
|
||||
}
|
||||
|
||||
.form-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4.28px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
text-align: center;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
font-size: 22px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: var(--txt-normal);
|
||||
line-height: 16.41px;
|
||||
|
||||
.form-icon-required {
|
||||
display: inline-block;
|
||||
|
||||
text-decoration: none;
|
||||
color: var(--clr-common-red);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: var(--clr-common-black);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 32.81px;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
input {
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
& ~ .custom-checkbox {
|
||||
width: 18.64px;
|
||||
height: 18px;
|
||||
margin-left: 4.28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--clr-common-black);
|
||||
border-radius: 3px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 36.4px;
|
||||
height: 35.15px;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
& ~ .custom-checkbox:after {
|
||||
content: '';
|
||||
width: 12.64px;
|
||||
height: 12px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--clr-primary-blue-500);
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 26.4px;
|
||||
height: 26.15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button[type='submit'] {
|
||||
width: 100%;
|
||||
height: 52.44px;
|
||||
border-radius: 25px;
|
||||
|
||||
font-weight: 400;
|
||||
|
||||
font-size: var(--txt-medium);
|
||||
line-height: 18.75px;
|
||||
letter-spacing: 0.05em;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--clr-common-black);
|
||||
color: var(--clr-common-white);
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
transition: 200ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-common-black);
|
||||
background-color: var(--clr-primary-blue-500);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
height: 71px;
|
||||
}
|
||||
}
|
||||
|
||||
.form__success {
|
||||
opacity: 0;
|
||||
transition: 200ms;
|
||||
color: var(--clr-common-green);
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
margin-top: 0px;
|
||||
height: 0;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 28.13px;
|
||||
}
|
||||
}
|
||||
|
||||
.form__success.form__success-active {
|
||||
opacity: 1;
|
||||
margin-top: 12px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
182
src/pages/Institutional/Contact/$Contact.tsx
Normal file
@ -0,0 +1,182 @@
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import validadeShema from './schema/FormSchema'
|
||||
|
||||
import { FormGroup } from './containers/_FormGroup'
|
||||
|
||||
import styles from './$Contact.module.scss'
|
||||
|
||||
export function Contact() {
|
||||
const [isSubmiting, setIsSubmiting] = useState(false)
|
||||
|
||||
const initialValues = useMemo(() => {
|
||||
return {
|
||||
fullname: '',
|
||||
email: '',
|
||||
cpf: '',
|
||||
date: '',
|
||||
tel: '',
|
||||
socials_instagram: '',
|
||||
terms: false,
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (isSubmiting) {
|
||||
setTimeout(() => {
|
||||
setIsSubmiting(false)
|
||||
}, 2000)
|
||||
}
|
||||
}, [isSubmiting])
|
||||
|
||||
return (
|
||||
<section className={styles['contact']}>
|
||||
<div>
|
||||
<h2 className="title">Preencha o formulário</h2>
|
||||
|
||||
<Formik
|
||||
onSubmit={(values, { resetForm }) => {
|
||||
resetForm({
|
||||
isSubmitting: true,
|
||||
})
|
||||
|
||||
setIsSubmiting(true)
|
||||
}}
|
||||
initialValues={initialValues}
|
||||
validationSchema={validadeShema}
|
||||
>
|
||||
{({ errors, touched }) => {
|
||||
return (
|
||||
<Form className={`${styles['contact__form']} ${styles['form']}`}>
|
||||
<fieldset className={styles['form__container']}>
|
||||
<FormGroup
|
||||
label="Nome"
|
||||
name="fullname"
|
||||
type="text"
|
||||
placeholder="Seu nome completo"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={false}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
label="Email"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Seu e-mail"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={false}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
mask={[
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
'.',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
'.',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
'-',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
]}
|
||||
label="CPF"
|
||||
type="text"
|
||||
name="cpf"
|
||||
placeholder="000.000.000-00"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={true}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
mask={[
|
||||
/[0-3]/,
|
||||
/[0-9]/,
|
||||
'.',
|
||||
/[0-1]/,
|
||||
/[0-9]/,
|
||||
'.',
|
||||
/[0-9]/,
|
||||
/[0-9]/,
|
||||
/[0-9]/,
|
||||
/[0-9]/,
|
||||
]}
|
||||
label="Data de Nascimento:"
|
||||
type="text"
|
||||
name="date"
|
||||
placeholder="00.00.0000"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={true}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
mask={[
|
||||
'(',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
')',
|
||||
' ',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
'-',
|
||||
/[0-9]/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
/\d/,
|
||||
]}
|
||||
label="Telefone:"
|
||||
type="tel"
|
||||
name="tel"
|
||||
placeholder="(00) 00000-0000"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={true}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
label="Instagram"
|
||||
type="text"
|
||||
name="socials_instagram"
|
||||
placeholder="@seuuser"
|
||||
error={errors && touched && 'touched'}
|
||||
masked={false}
|
||||
/>
|
||||
|
||||
<div className="form-check">
|
||||
<label htmlFor="terms">
|
||||
<span>
|
||||
<span className="form-icon-required">*</span>{' '}
|
||||
<a href="/">Declaro que li e aceito</a>
|
||||
</span>
|
||||
<Field id="terms" name="terms" type="checkbox" required />
|
||||
<span className="custom-checkbox"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button className={styles['submit']} type="submit">
|
||||
Cadastre-se
|
||||
</button>
|
||||
|
||||
<p
|
||||
className={`form__success ${
|
||||
isSubmiting ? 'form__success-active' : ''
|
||||
}`}
|
||||
>
|
||||
*Formulário enviado com sucesso!
|
||||
</p>
|
||||
</fieldset>
|
||||
</Form>
|
||||
)
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
53
src/pages/Institutional/Contact/containers/_FormGroup.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { ErrorMessage } from 'formik'
|
||||
import { InputHTMLAttributes } from 'react'
|
||||
|
||||
import { CustomInput, CustomMaskInput } from './__Input'
|
||||
|
||||
interface FormGroupProps extends InputHTMLAttributes<HTMLInputElement> {
|
||||
error: any
|
||||
name: string | any
|
||||
masked: boolean
|
||||
mask?: any
|
||||
label: string | any
|
||||
}
|
||||
|
||||
export function FormGroup({
|
||||
error,
|
||||
masked,
|
||||
mask,
|
||||
label,
|
||||
name,
|
||||
...props
|
||||
}: FormGroupProps) {
|
||||
return (
|
||||
<div className="form__group">
|
||||
<label className="form__label" htmlFor={name}>
|
||||
{label}
|
||||
</label>
|
||||
|
||||
<div className="form__content">
|
||||
<ErrorMessage
|
||||
className="error-message"
|
||||
component={'span'}
|
||||
name={name}
|
||||
/>
|
||||
|
||||
{masked ? (
|
||||
<CustomMaskInput
|
||||
mask={mask}
|
||||
id={name}
|
||||
name={name}
|
||||
className={`form__input ${error}`}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<CustomInput
|
||||
name={name}
|
||||
className={`form__input ${error}`}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
26
src/pages/Institutional/Contact/containers/__Input.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { Field } from 'formik'
|
||||
import { InputHTMLAttributes } from 'react'
|
||||
import MaskedInput, { MaskedInputProps } from 'react-text-mask'
|
||||
|
||||
interface CustomInputProps extends InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
export function CustomInput({ name, ...props }: CustomInputProps) {
|
||||
return <Field id={name} name={name} {...props} />
|
||||
}
|
||||
|
||||
interface CustomMaskInputProps
|
||||
extends InputHTMLAttributes<HTMLInputElement>,
|
||||
Omit<MaskedInputProps, 'mask'> {
|
||||
mask?: any
|
||||
name: string
|
||||
}
|
||||
|
||||
export function CustomMaskInput({ name, ...props }: CustomMaskInputProps) {
|
||||
return (
|
||||
<Field id={name} name={name}>
|
||||
{({ field }: any) => {
|
||||
return <MaskedInput {...field} {...props} id={name} name={name} />
|
||||
}}
|
||||
</Field>
|
||||
)
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { ErrorMessage, Field } from 'formik'
|
||||
import { InputHTMLAttributes } from 'react'
|
||||
|
||||
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
||||
name: string
|
||||
label: string
|
||||
error?: any
|
||||
}
|
||||
|
||||
export function Input({ label, name, error, ...props }: InputProps) {
|
||||
return (
|
||||
<div className="form-group">
|
||||
<div className="form-group-header">
|
||||
<label htmlFor={name}>{label}</label>
|
||||
<ErrorMessage
|
||||
className="error-message"
|
||||
component={'span'}
|
||||
name={name}
|
||||
/>
|
||||
</div>
|
||||
<Field
|
||||
id={name}
|
||||
name={name}
|
||||
className={`form-input ${error}`}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
.contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
margin-bottom: 69.56px;
|
||||
}
|
||||
|
||||
.form {
|
||||
fieldset {
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form :global {
|
||||
.form-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form-group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.form-input {
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 20px;
|
||||
|
||||
border: 1px solid var(--clr-gray-1000);
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.form-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4.28px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
text-align: center;
|
||||
|
||||
label {
|
||||
text-decoration: underline;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
|
||||
text-decoration: none;
|
||||
color: var(--clr-common-red);
|
||||
}
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
width: 18.64px;
|
||||
height: 18px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--clr-common-black);
|
||||
}
|
||||
}
|
||||
|
||||
button[type='submit'] {
|
||||
width: 100%;
|
||||
height: 52.44px;
|
||||
border-radius: 25px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--clr-common-black);
|
||||
color: var(--clr-common-white);
|
||||
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
1
src/pages/Institutional/Contact/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Contact } from './$Contact'
|
@ -1,107 +0,0 @@
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import { useMemo } from 'react'
|
||||
import { Input } from './fragments/Input'
|
||||
|
||||
import validadeShema from './schema/FormSchema'
|
||||
|
||||
import css from './index.module.scss'
|
||||
|
||||
export function Contact() {
|
||||
const initialValues = useMemo(() => {
|
||||
return {
|
||||
fullname: '',
|
||||
email: '',
|
||||
cpf: '',
|
||||
date: '',
|
||||
tel: '',
|
||||
socials_instagram: '',
|
||||
terms: false,
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section className={css.contact}>
|
||||
<div>
|
||||
<h2 className="title">Preencha o formulário</h2>
|
||||
|
||||
<Formik
|
||||
onSubmit={(values, e) => {
|
||||
e.validateField('email')
|
||||
|
||||
e.resetForm({
|
||||
isSubmitting: true,
|
||||
})
|
||||
}}
|
||||
initialValues={initialValues}
|
||||
validationSchema={validadeShema}
|
||||
>
|
||||
{({ errors, touched }) => {
|
||||
return (
|
||||
<Form className={css.form}>
|
||||
<fieldset className={css['form-container']}>
|
||||
<Input
|
||||
label="Nome"
|
||||
name="fullname"
|
||||
type="text"
|
||||
placeholder="Seu nome completo"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Email"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Seu e-mail"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="CPF"
|
||||
type="text"
|
||||
name="cpf"
|
||||
placeholder="000.000.000-00"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Data de Nascimento:"
|
||||
type="text"
|
||||
name="date"
|
||||
placeholder="00.00.0000"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone:"
|
||||
type="tel"
|
||||
name="tel"
|
||||
placeholder="(00) 00000-0000"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
<Input
|
||||
label="Instagram"
|
||||
type="text"
|
||||
name="socials_instagram"
|
||||
placeholder="@seuuser"
|
||||
error={errors && touched && 'touched'}
|
||||
/>
|
||||
|
||||
<div className="form-check">
|
||||
<label htmlFor="terms">
|
||||
<span>*</span>
|
||||
Declaro que li e aceito
|
||||
</label>
|
||||
<Field id="terms" name="terms" type="checkbox" />
|
||||
</div>
|
||||
|
||||
<button className={css.submit} type="submit">
|
||||
Cadastre-se
|
||||
</button>
|
||||
</fieldset>
|
||||
</Form>
|
||||
)
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
@ -4,12 +4,36 @@ const messages = {
|
||||
required: '*Campo Obrigatório',
|
||||
}
|
||||
|
||||
const emailRegexPattern = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/
|
||||
const cpfRegexPattern = /^([0-9]){3}\.([0-9]){3}\.([0-9]){3}-([0-9]){2}$/
|
||||
const telRegexPattern = /\(([0-9]{1,3})\) ([0-9]{5})-([0-9]{4})/
|
||||
const dateRegexPattern =
|
||||
/^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/
|
||||
|
||||
export default Yup.object().shape({
|
||||
fullname: Yup.string().required(messages.required),
|
||||
email: Yup.string().required(messages.required).email('Email ínvalido'),
|
||||
cpf: Yup.string().required(messages.required),
|
||||
tel: Yup.string().required(messages.required),
|
||||
date: Yup.string().required(messages.required),
|
||||
socials_instagram: Yup.string(),
|
||||
fullname: Yup.string()
|
||||
.trim()
|
||||
.min(7, 'Nome completo muito curto')
|
||||
.max(60, 'Nome completo muito grande')
|
||||
.required(messages.required),
|
||||
email: Yup.string()
|
||||
.matches(emailRegexPattern, { message: 'Email ínvalido' })
|
||||
.required(messages.required)
|
||||
.email('Email ínvalido'),
|
||||
cpf: Yup.string()
|
||||
.matches(cpfRegexPattern, { message: 'CPF ínvalido' })
|
||||
.required(messages.required),
|
||||
tel: Yup.string()
|
||||
.matches(telRegexPattern, { message: 'Número de Telefone ínvalido' })
|
||||
.required(messages.required),
|
||||
date: Yup.string()
|
||||
.matches(dateRegexPattern, { message: 'Data de Nascimento ínvalido' })
|
||||
.required(messages.required),
|
||||
socials_instagram: Yup.string().matches(
|
||||
/(?:^|[^\w])(?:@)([A-Za-z0-9_](?:(?:[A-Za-z0-9_]|(?:\.(?!\.))){0,28}(?:[A-Za-z0-9_]))?)/,
|
||||
{
|
||||
messages: 'Instagram ínvalido',
|
||||
}
|
||||
),
|
||||
terms: Yup.boolean().required('*'),
|
||||
})
|
||||
|
30
src/pages/Institutional/Exchange/$Exchange.module.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.exchange {
|
||||
margin-bottom: 81px;
|
||||
&__descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/pages/Institutional/Exchange/$Exchange.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import styles from './$Exchange.module.scss'
|
||||
|
||||
export function Exchange() {
|
||||
return (
|
||||
<section className={styles['exchange']}>
|
||||
<div className={styles['exchange__container']}>
|
||||
<h2 className="title">Troca e Devolução</h2>
|
||||
|
||||
<div className={styles['exchange__descriptions']}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
||||
culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
|
||||
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
|
||||
quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
|
||||
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
|
||||
eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit,
|
||||
sed quia non numquam eius modi tempora incidunt ut labore et dolore
|
||||
magnam aliquam quaerat voluptatem.
|
||||
</p>
|
||||
<p>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
|
||||
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis
|
||||
autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
|
||||
nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo
|
||||
voluptas nulla pariatur?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
1
src/pages/Institutional/Exchange/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Exchange } from './$Exchange'
|
30
src/pages/Institutional/Payments/$Payments.module.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.payements {
|
||||
margin-bottom: 81px;
|
||||
&__descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/pages/Institutional/Payments/$Payments.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import styles from './$Payments.module.scss'
|
||||
|
||||
export function Payments() {
|
||||
return (
|
||||
<section className={styles['payements']}>
|
||||
<div className={styles['payements__container']}>
|
||||
<h2 className="title">Formas de Pagamento</h2>
|
||||
|
||||
<div className={styles['payements__descriptions']}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
||||
culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
|
||||
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
|
||||
quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
|
||||
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
|
||||
eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit,
|
||||
sed quia non numquam eius modi tempora incidunt ut labore et dolore
|
||||
magnam aliquam quaerat voluptatem.
|
||||
</p>
|
||||
<p>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
|
||||
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis
|
||||
autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
|
||||
nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo
|
||||
voluptas nulla pariatur?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
1
src/pages/Institutional/Payments/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Payments } from './$Payments'
|
30
src/pages/Institutional/Privacity/$Privacity.module.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.privacity {
|
||||
margin-bottom: 81px;
|
||||
&__descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/pages/Institutional/Privacity/$Privacity.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import styles from './$Privacity.module.scss'
|
||||
|
||||
export function Privacity() {
|
||||
return (
|
||||
<section className={styles['privacity']}>
|
||||
<div className={styles['privacity__container']}>
|
||||
<h2 className="title">Segurança e Privacidade</h2>
|
||||
|
||||
<div className={styles['privacity__descriptions']}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
||||
culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
|
||||
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
|
||||
quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
|
||||
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
|
||||
eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit,
|
||||
sed quia non numquam eius modi tempora incidunt ut labore et dolore
|
||||
magnam aliquam quaerat voluptatem.
|
||||
</p>
|
||||
<p>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
|
||||
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis
|
||||
autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
|
||||
nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo
|
||||
voluptas nulla pariatur?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
1
src/pages/Institutional/Privacity/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Privacity } from './$Privacity'
|
30
src/pages/Institutional/Shipping/$Shipping.module.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.shipping {
|
||||
margin-bottom: 81px;
|
||||
&__descriptions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 18.2px;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
color: var(--clr-gray-700);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
font-size: var(--txt-small);
|
||||
line-height: 15.23px;
|
||||
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 30.47px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/pages/Institutional/Shipping/$Shipping.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import styles from './$Shipping.module.scss'
|
||||
|
||||
export function Shipping() {
|
||||
return (
|
||||
<section className={styles['shipping']}>
|
||||
<div className={styles['shipping__container']}>
|
||||
<h2 className="title">Entrega</h2>
|
||||
|
||||
<div className={styles['shipping__descriptions']}>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
||||
culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
|
||||
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
|
||||
quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
|
||||
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
|
||||
eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit,
|
||||
sed quia non numquam eius modi tempora incidunt ut labore et dolore
|
||||
magnam aliquam quaerat voluptatem.
|
||||
</p>
|
||||
<p>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
|
||||
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis
|
||||
autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
|
||||
nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo
|
||||
voluptas nulla pariatur?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
1
src/pages/Institutional/Shipping/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Shipping } from './$Shipping'
|
19
src/pages/Institutional/index.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { About } from './About'
|
||||
import { Contact } from './Contact'
|
||||
import { Exchange } from './Exchange'
|
||||
import { Payments } from './Payments'
|
||||
import { Privacity } from './Privacity'
|
||||
import { Shipping } from './Shipping'
|
||||
|
||||
function Institutional() {
|
||||
return {
|
||||
About,
|
||||
Contact,
|
||||
Exchange,
|
||||
Privacity,
|
||||
Payments,
|
||||
Shipping,
|
||||
}
|
||||
}
|
||||
|
||||
export default Institutional()
|
162
src/routes/$Routes.module.scss
Normal file
@ -0,0 +1,162 @@
|
||||
@use '../styles/utils/helpers/functions' as function;
|
||||
|
||||
main :global {
|
||||
.main-container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb :global {
|
||||
a {
|
||||
font-size: var(--txt-xs);
|
||||
line-height: 14.06px;
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
line-height: 28.13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
width: 100%;
|
||||
padding: 0 16px;
|
||||
margin-top: 29px;
|
||||
margin-bottom: 81px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(1080px, 1280px);
|
||||
margin: 29px auto 81px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(2300px, 2500px);
|
||||
}
|
||||
}
|
||||
|
||||
.scroll__fixed {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
bottom: 168px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
bottom: 229.24px;
|
||||
}
|
||||
|
||||
&-whatsapp,
|
||||
&-top {
|
||||
display: block;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 66px;
|
||||
height: 66px;
|
||||
}
|
||||
}
|
||||
|
||||
&-whatsapp {
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--clr-gray-400);
|
||||
border-radius: 100%;
|
||||
|
||||
img {
|
||||
width: 12px;
|
||||
height: 6.46px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: 13px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: 24.24px;
|
||||
height: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-content :global {
|
||||
width: 100%;
|
||||
padding: 0 16px;
|
||||
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-weight: 700;
|
||||
font-size: var(--txt-xl);
|
||||
|
||||
text-align: center;
|
||||
|
||||
color: var(--clr-gray-900);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
text-align: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
width: function.fluid(1080px, 1280px);
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media screen and (min-width: 2500px) {
|
||||
width: function.fluid(2300px, 2500px);
|
||||
}
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-weight: 400;
|
||||
font-size: var(--txt-xl);
|
||||
font-family: var(--font-family-100);
|
||||
letter-spacing: 0.1em;
|
||||
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
|
||||
color: var(--clr-gray-900);
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
margin-bottom: 82px;
|
||||
}
|
||||
}
|
||||
|
||||
.window-initial {
|
||||
min-height: 60vh;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 30px;
|
||||
|
||||
@media screen and (min-width: 1025px) {
|
||||
grid-template-columns:
|
||||
function.fluid(302px, 1080px)
|
||||
function.fluid(748px, 1080px);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
grid-template-columns:
|
||||
function.fluid(590px, 2300px)
|
||||
function.fluid(1680px, 2300px);
|
||||
}
|
||||
}
|
46
src/routes/$Routes.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { Outlet, Route, Routes } from 'react-router-dom'
|
||||
|
||||
import { Header } from '../components/Organisms/Header/$Header'
|
||||
import { Sidebar } from '../components/Organisms/Sidebar'
|
||||
import { Footer } from '../components/Organisms/Footer/$Footer'
|
||||
import { Breadcrumb } from './containers/_BreadCrumb'
|
||||
import { ScrollFixed } from './containers/_ScrollFixed'
|
||||
|
||||
import Institutional from '../pages/Institutional'
|
||||
|
||||
import styles from './$Routes.module.scss'
|
||||
|
||||
export function Router() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<>
|
||||
<Header />
|
||||
<Breadcrumb />
|
||||
|
||||
<main className={styles['window-content']}>
|
||||
<h1 className={styles['main-title']}>Institutional</h1>
|
||||
<div className={styles['window-initial']}>
|
||||
<Sidebar />
|
||||
<div className={styles['main-container']}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
<ScrollFixed />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Route index element={<Institutional.About />} />
|
||||
<Route path="/contact" element={<Institutional.Contact />} />
|
||||
<Route path="/payments" element={<Institutional.Payments />} />
|
||||
<Route path="/exchange" element={<Institutional.Exchange />} />
|
||||
<Route path="/privacity" element={<Institutional.Privacity />} />
|
||||
<Route path="/shipping" element={<Institutional.Shipping />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
)
|
||||
}
|
3
src/routes/assets/icons/scroll-top.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="25" height="13" viewBox="0 0 25 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.7428 11.3959C23.741 11.6959 23.6177 11.9953 23.373 12.226L23.3728 12.2261C22.8668 12.7035 22.037 12.7035 21.5311 12.2261L21.5232 12.2345L21.5311 12.2261L12.3457 3.5599L12.0712 3.30091L11.7967 3.5599L2.61178 12.2258C2.10549 12.7033 1.27571 12.7032 0.769767 12.2259L0.769708 12.2258C0.525704 11.9957 0.402467 11.6972 0.400037 11.398C0.401876 11.0981 0.525111 10.7986 0.769782 10.5678L0.769785 10.5678L11.1506 0.773762C11.4013 0.537307 11.7333 0.415846 12.0712 0.415846C12.4093 0.415846 12.7415 0.537566 12.9922 0.773969L23.3728 10.568L23.3729 10.5681C23.6171 10.7983 23.7403 11.0968 23.7428 11.3959Z" fill="white" stroke="white" stroke-width="0.8"/>
|
||||
</svg>
|
After Width: | Height: | Size: 764 B |
11
src/routes/assets/icons/whatsapp.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="66" height="66" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3751_658)">
|
||||
<path d="M33.0083 0H32.9917C14.7964 0 0 14.8005 0 33C0 40.2188 2.3265 46.9095 6.28237 52.3421L2.16975 64.6016L14.8541 60.5468C20.0723 64.0035 26.2969 66 33.0083 66C51.2036 66 66 51.1954 66 33C66 14.8046 51.2036 0 33.0083 0Z" fill="#4CAF50"/>
|
||||
<path d="M52.21 46.6001C51.4139 48.8483 48.2542 50.7128 45.7338 51.2573C44.0095 51.6244 41.7573 51.9173 34.1755 48.774C24.4777 44.7563 18.2324 34.9016 17.7457 34.2623C17.2795 33.6229 13.8269 29.0441 13.8269 24.3086C13.8269 19.5731 16.2318 17.2673 17.2012 16.2773C17.9973 15.4646 19.3132 15.0934 20.5754 15.0934C20.9838 15.0934 21.3509 15.114 21.6809 15.1305C22.6503 15.1718 23.137 15.2295 23.7764 16.7599C24.5725 18.678 26.5113 23.4135 26.7423 23.9003C26.9774 24.387 27.2125 25.047 26.8825 25.6864C26.5732 26.3464 26.3009 26.6393 25.8142 27.2003C25.3274 27.7613 24.8654 28.1903 24.3787 28.7925C23.9332 29.3164 23.4299 29.8774 23.9909 30.8468C24.5519 31.7955 26.4907 34.9594 29.3452 37.5004C33.0288 40.7798 36.0153 41.8275 37.0837 42.273C37.8798 42.603 38.8285 42.5246 39.4102 41.9059C40.1485 41.1098 41.0602 39.7898 41.9883 38.4904C42.6483 37.5581 43.4815 37.4426 44.356 37.7726C45.247 38.082 49.9619 40.4126 50.9313 40.8953C51.9007 41.382 52.54 41.613 52.7752 42.0214C53.0062 42.4298 53.0062 44.3479 52.21 46.6001Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3751_658">
|
||||
<rect width="66" height="66" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
14
src/routes/containers/_BreadCrumb.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { useMemo } from 'react'
|
||||
import { Breadcrumb as BreadcrumbMolecules } from '../../components/Molecules/Breadcrumb'
|
||||
|
||||
import styles from '../$Routes.module.scss'
|
||||
|
||||
export function Breadcrumb() {
|
||||
let list = useMemo(() => [{ name: 'Introduction', href: '/' }], [])
|
||||
|
||||
return (
|
||||
<nav className={styles['breadcrumb-container']}>
|
||||
<BreadcrumbMolecules className={styles['breadcrumb']} list={list} />
|
||||
</nav>
|
||||
)
|
||||
}
|
39
src/routes/containers/_ScrollFixed.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ItemList } from '../../components/Molecules/ItemList'
|
||||
|
||||
import whatsappImg from '../assets/icons/whatsapp.svg'
|
||||
import scrollTopImg from '../assets/icons/scroll-top.svg'
|
||||
|
||||
import styles from '../$Routes.module.scss'
|
||||
|
||||
export function ScrollFixed() {
|
||||
const [isScrollTop, setIsScrollTop] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', () => {
|
||||
if (window.scrollY > 100) {
|
||||
setIsScrollTop(true)
|
||||
} else {
|
||||
setIsScrollTop(false)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ul className={styles['scroll__fixed']}>
|
||||
<ItemList
|
||||
className={styles['scroll__fixed-whatsapp']}
|
||||
href="https://wa.me/254777123456"
|
||||
>
|
||||
<img src={whatsappImg} alt="" />
|
||||
</ItemList>
|
||||
{isScrollTop && (
|
||||
<ItemList className={styles['scroll__fixed-top']} href={'#root'}>
|
||||
<img src={scrollTopImg} alt="" />
|
||||
</ItemList>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|