diff --git a/src/App.tsx b/src/App.tsx index 49cf0b4..4a416eb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,6 @@ -import { Introduction } from './pages/Introduction' +import { Footer } from './template/Footer' import { Header } from './template/Header' +import { Introduction } from './pages/Introduction' import './settings/styles/index.scss' @@ -11,6 +12,8 @@ export function App() { + + > ) } diff --git a/src/assets/brands/Boleto.png b/src/assets/brands/Boleto.png new file mode 100644 index 0000000..da88e63 Binary files /dev/null and b/src/assets/brands/Boleto.png differ diff --git a/src/assets/brands/Diners.png b/src/assets/brands/Diners.png new file mode 100644 index 0000000..56edfee Binary files /dev/null and b/src/assets/brands/Diners.png differ diff --git a/src/assets/brands/Elo.png b/src/assets/brands/Elo.png new file mode 100644 index 0000000..a887e53 Binary files /dev/null and b/src/assets/brands/Elo.png differ diff --git a/src/assets/brands/Hiper.png b/src/assets/brands/Hiper.png new file mode 100644 index 0000000..094a571 Binary files /dev/null and b/src/assets/brands/Hiper.png differ diff --git a/src/assets/brands/Master.png b/src/assets/brands/Master.png new file mode 100644 index 0000000..776953e Binary files /dev/null and b/src/assets/brands/Master.png differ diff --git a/src/assets/brands/Paypal.png b/src/assets/brands/Paypal.png new file mode 100644 index 0000000..fc18c89 Binary files /dev/null and b/src/assets/brands/Paypal.png differ diff --git a/src/assets/brands/Visa.png b/src/assets/brands/Visa.png new file mode 100644 index 0000000..ba0cc36 Binary files /dev/null and b/src/assets/brands/Visa.png differ diff --git a/src/assets/brands/svgs/M3.svg b/src/assets/brands/svgs/M3.svg new file mode 100644 index 0000000..d05ea09 --- /dev/null +++ b/src/assets/brands/svgs/M3.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/brands/svgs/Vtex.svg b/src/assets/brands/svgs/Vtex.svg new file mode 100644 index 0000000..8d67613 --- /dev/null +++ b/src/assets/brands/svgs/Vtex.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/brands/vtex-pci-200.png b/src/assets/brands/vtex-pci-200.png new file mode 100644 index 0000000..bccc61e Binary files /dev/null and b/src/assets/brands/vtex-pci-200.png differ diff --git a/src/components/Accordion/@types/index.d.ts b/src/components/Accordion/@types/index.d.ts new file mode 100644 index 0000000..9693bd9 --- /dev/null +++ b/src/components/Accordion/@types/index.d.ts @@ -0,0 +1,22 @@ +import { HTMLAttributes, ReactNode } from 'react' + +export interface MainProps + extends Omit, + HTMLAttributes { + children: ReactNode | ReactNode[] +} + +export interface HeaderProps + extends AccordionProps, + HTMLAttributes { + children: ReactNode | ReactNode[] +} + +export interface ContentProps extends HTMLAttributes { + children: ReactNode | ReactNode[] +} + +export interface AccordionProps { + customKey: string | number + setCurrentAccordion: (customKey) => void +} diff --git a/src/components/Accordion/context/Items.tsx b/src/components/Accordion/context/Items.tsx new file mode 100644 index 0000000..7e3c4a8 --- /dev/null +++ b/src/components/Accordion/context/Items.tsx @@ -0,0 +1,27 @@ +import { createContext, ReactNode } from 'react' + +interface IAccordionItemsValues { + current: string | number | '' +} + +export let AccordionContextItems = createContext({ + current: '', +}) + +interface AccordionProviderItemsProps { + children: ReactNode | ReactNode[] + current: string | number | '' +} + +export const AccordionProviderItems = ({ + children, + current, +}: AccordionProviderItemsProps) => { + return ( + <> + + {children} + + > + ) +} diff --git a/src/components/Accordion/index.scss b/src/components/Accordion/index.scss new file mode 100644 index 0000000..701194b --- /dev/null +++ b/src/components/Accordion/index.scss @@ -0,0 +1,66 @@ +.accordion { + position: relative; + overflow: hidden; + z-index: 10; + + &-content { + height: 0; + transform: translateY(-5%); + transition: 180ms ease-in; + } +} + +.accordion.active { + overflow: unset; + .accordion-content { + height: auto; + transform: translateY(0%); + } +} + +.accordion { + header { + width: 100%; + display: inline-flex; + align-items: center; + justify-content: space-between; + } + + &-icon { + position: relative; + + width: 7.8px; + height: 8.28px; + + &::before, + &::after { + content: ''; + position: absolute; + width: 100%; + background-color: var(--clr-gray-800); + } + + &::before { + top: 50%; + right: 0; + transform: translateY(-50%); + height: 2px; + } + + &::after { + right: 50%; + transform: translateX(50%); + height: 100%; + width: 2px; + transition: 200ms linear; + } + } +} + +.accordion.active { + .accordion-icon { + &::after { + height: 0; + } + } +} diff --git a/src/components/Accordion/index.tsx b/src/components/Accordion/index.tsx new file mode 100644 index 0000000..4fbd82e --- /dev/null +++ b/src/components/Accordion/index.tsx @@ -0,0 +1,64 @@ +import { useContext } from 'react' +import { ContentProps, HeaderProps, MainProps } from './@types/index' +import { AccordionContextItems } from './context/Items' + +import './index.scss' + +const Main = ({ customKey, children, className, ...props }: MainProps) => { + const currentTargetItem = useContext(AccordionContextItems) + + const isOpen = () => { + if (currentTargetItem.current === customKey) { + return 'active' + } else { + return '' + } + } + + return ( + + {children} + + ) +} + +const Header = ({ + setCurrentAccordion, + customKey, + children, + className, + ...props +}: HeaderProps) => { + const currentTargetItem = useContext(AccordionContextItems) + + function handleEvent() { + if (customKey === currentTargetItem.current) { + setCurrentAccordion('') + } else { + setCurrentAccordion(customKey) + } + } + + return ( + + {children} + + + ) +} + +const Content = ({ children, className, ...props }: ContentProps) => { + return ( + + {children} + + ) +} + +export const Accordion = Object.assign(Main, { Header, Content }) diff --git a/src/settings/styles/global/_reset.scss b/src/settings/styles/global/_reset.scss index b7ae335..c323577 100644 --- a/src/settings/styles/global/_reset.scss +++ b/src/settings/styles/global/_reset.scss @@ -27,6 +27,7 @@ button { background-color: transparent; } +[role='button'], .btn-ref, button { cursor: pointer; diff --git a/src/template/Footer/fragments/Lists.tsx b/src/template/Footer/fragments/Lists.tsx new file mode 100644 index 0000000..b0d56ac --- /dev/null +++ b/src/template/Footer/fragments/Lists.tsx @@ -0,0 +1,163 @@ +import { AnchorHTMLAttributes, HTMLAttributes, ReactNode } from 'react' +import { Accordion } from '../../../components/Accordion' +import { AccordionProps } from '../../../components/Accordion/@types' + +import BoletoImg from '../../../assets/brands/Boleto.png' +import DinersBrandImg from '../../../assets/brands/Diners.png' +import EloBrandImg from '../../../assets/brands/Elo.png' +import HiperBrandImg from '../../../assets/brands/Hiper.png' +import PaypalBrandImg from '../../../assets/brands/Paypal.png' +import MasterCardBrandImg from '../../../assets/brands/Master.png' +import VisaBrandImg from '../../../assets/brands/Visa.png' +import VtexPCIImg from '../../../assets/brands/vtex-pci-200.png' + +import css from '../index.module.scss' + +export function PaymentsList() { + let images = [ + MasterCardBrandImg, + VisaBrandImg, + DinersBrandImg, + EloBrandImg, + HiperBrandImg, + PaypalBrandImg, + BoletoImg, + ] + + return ( + + {images.map((image, index) => { + return ( + + + + ) + })} + + + + + + + + ) +} + +interface InstitutionalListProps extends AccordionProps {} + +export function InstitutionalList({ + setCurrentAccordion, + customKey, +}: InstitutionalListProps) { + return ( + + + Institucional + + + + + Quem somos nós + + + Política de Privacidade + + + Segurança + + + Seja um Revendedor + + + + + ) +} + +interface QuestionsListProps extends AccordionProps {} + +export function QuestionsList({ + setCurrentAccordion, + customKey, +}: QuestionsListProps) { + return ( + + + Dúvidas + + + + + Entrega + + + Pagamento + + + Trocas e Devoluções + + + Dúvidas Frequentes + + + + + ) +} + +interface ContactListProps extends AccordionProps {} + +export function ContactList({ + setCurrentAccordion, + customKey, +}: ContactListProps) { + return ( + + + Fale Conosco + + + + + + Atendimento ao Consumidor + + + (11) 4159 9504 + + + Atendimento Online + + + (11) 99433-8825 + + + + + ) +} + +interface ItemProps extends AnchorHTMLAttributes { + children: ReactNode | ReactNode[] + $container?: HTMLAttributes +} + +function Item({ children, $container, ...props }: ItemProps) { + return ( + + {children} + + ) +} diff --git a/src/template/Footer/index.module.scss b/src/template/Footer/index.module.scss new file mode 100644 index 0000000..f8498ae --- /dev/null +++ b/src/template/Footer/index.module.scss @@ -0,0 +1,203 @@ +@use '../../settings/styles/utils/helpers/functions' as function; + +.footer { + border-top: 1px solid var(--clr-common-black); +} + +.container-top, +.container-bottom { + padding: 0 16px; + + @media screen and (min-width: 1025px) { + padding: 0; + } +} + +.container-top { + padding-top: 17px; + padding-bottom: 24px; + + @media screen and (min-width: 1025px) { + width: function.fluid(1080px, 1280px); + margin: 0 auto; + } +} + +.container-bottom { + width: 100%; + padding-top: 15px; + padding-bottom: 15px; + + background-color: var(--clr-common-black); + + .phrase { + font-size: var(--txt-xxs); + } + + * p, + * li { + color: var(--clr-common-white); + } +} + +.container-bottom { + .phrase, + .actions-bottom .credits li p { + font-size: var(--txt-xxs); + } +} + +.actions-bottom { + .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}; + } + } + } +} + +// moved container bottom actions footer for large, medium devices +.container-bottom { + .actions-bottom { + width: 100%; + height: 100%; + display: flex; + align-items: flex-start; + justify-content: center; + flex-direction: column; + gap: 15px; + + @media screen and (min-width: 1025px) { + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 0; + + width: function.fluid(1080px, 1280px); + padding: 15px 0; + margin: 0 auto; + } + } +} + +.lists { + display: flex; + align-items: stretch; + flex-direction: column; + gap: 5px; + + @media screen and (min-width: 1025px) { + flex-direction: row; + + .content { + height: auto; + overflow: unset; + transform: translate(0, 0); + } + } + + .content { + margin-top: 7px; + + ul { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: 12px; + } + + li, + a { + font-weight: 400; + font-size: var(--txt-xs); + + color: var(--clr-gray-800); + } + } +} + +.list-header { + padding: 7px 0; + + @media screen and (min-width: 1025px) { + i { + display: none; + } + } + + h4 { + font-weight: 500; + font-size: var(--txt-normal); + text-transform: uppercase; + + color: var(--clr-gray-800); + } +} + +.payments { + display: flex; + align-items: center; + + .divider { + border-left: 1px solid var(--clr-gray-400); + height: 20.36px; + } + + @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 + ) + { + li:nth-child(#{$index}) { + margin-right: #{$value}; + } + } + + li:last-child { + margin-left: 10.49px; + } +} + +.container-bottom { + .phrase { + order: 2; + } + + .payments { + order: 1; + } + + .credits { + order: 3; + } + + @media screen and (min-width: 1025px) { + .phrase { + order: initial; + } + + .payments { + order: initial; + } + + .credits { + order: initial; + } + } +} diff --git a/src/template/Footer/index.tsx b/src/template/Footer/index.tsx new file mode 100644 index 0000000..a123473 --- /dev/null +++ b/src/template/Footer/index.tsx @@ -0,0 +1,75 @@ +import vtexIcon from '../../assets/brands/svgs/Vtex.svg' +import m3Icon from '../../assets/brands/svgs/M3.svg' + +import { AccordionProviderItems } from '../../components/Accordion/context/Items' + +import { + ContactList, + InstitutionalList, + PaymentsList, + QuestionsList, +} from './fragments/Lists' + +import css from './index.module.scss' +import { useState } from 'react' + +export function Footer() { + const [AccordionCurrentIsOpen, setAccordionCurrentIsOpen] = useState< + string | number | '' + >('') + + function handleSetCurrentAccordion(customkey: string | number | '') { + if (window.innerWidth < 1024) setAccordionCurrentIsOpen(customkey) + } + + return ( + + ) +} diff --git a/src/template/Header/index.module.scss b/src/template/Header/index.module.scss index 7442845..b362409 100644 --- a/src/template/Header/index.module.scss +++ b/src/template/Header/index.module.scss @@ -4,6 +4,7 @@ position: sticky; top: 0; left: 0; + z-index: 1000; padding: 25px 0;