feat(form, newsletter, scrollfixed,etc): added final step in styles and features

This commit is contained in:
Henrique Santos Santana 2023-01-09 15:58:44 -03:00
parent 9be5b1abf3
commit b3915ecafc
12 changed files with 285 additions and 40 deletions

View 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

View File

@ -91,25 +91,65 @@
text-align: center;
label {
text-decoration: underline;
display: flex;
cursor: pointer;
font-size: 22px;
margin: 0;
padding: 0;
font-size: var(--txt-normal);
line-height: 16.41px;
span {
.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;
}
}
input[type='checkbox'] {
width: 18.64px;
height: 18px;
label {
input {
width: 0;
height: 0;
&:checked {
border-radius: 3px;
border: 1px solid var(--clr-common-black);
& ~ .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;
}
}
}
}
}
}
@ -151,7 +191,8 @@
color: var(--clr-common-green);
font-size: var(--txt-xs);
line-height: 14.06px;
margin-top: 12px;
margin-top: 0px;
height: 0;
@media screen and (min-width: 2500px) {
line-height: 28.13px;
@ -160,5 +201,7 @@
.form__success.form__success-active {
opacity: 1;
margin-top: 12px;
height: auto;
}
}

View File

@ -152,10 +152,13 @@ export function Contact() {
<div className="form-check">
<label htmlFor="terms">
<span>*</span>
Declaro que li e aceito
<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>
<Field id="terms" name="terms" type="checkbox" required />
</div>
<button className={styles['submit']} type="submit">

View File

@ -11,7 +11,11 @@ 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().trim().min(7).max(60).required(messages.required),
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)

View File

@ -6,8 +6,8 @@ export function RouterBreadcrumb() {
let list = useMemo(() => [{ name: 'Introduction', href: '/' }], [])
return (
<div className={styles['breadcrumb-container']}>
<nav className={styles['breadcrumb-container']}>
<Breadcrumb className={styles['breadcrumb']} list={list} />
</div>
</nav>
)
}

View File

@ -20,18 +20,20 @@ export function ScrollFixed() {
}, [])
return (
<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="" />
<ul>
<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>
</ul>
)
}

View File

@ -17,8 +17,8 @@ export function Router() {
element={
<>
<Header />
<RouterBreadcrumb />
<div className="window-routes">
<RouterBreadcrumb />
<Outlet />
</div>
<Footer />
@ -34,10 +34,8 @@ export function Router() {
<h1 className="main-title">Institutional</h1>
<div className="window-initial">
<Sidebar />
<div>
<div className="main-container">
<Outlet />
</div>
<div className="main-container">
<Outlet />
</div>
</div>
</main>

View File

@ -106,7 +106,7 @@ textarea {
@media screen and (min-width: 1025px) {
grid-template-columns:
function.fluid(332px, 1080px)
function.fluid(302px, 1080px)
function.fluid(748px, 1080px);
}

View File

@ -1,4 +1,5 @@
import { Field, Form, Formik } from 'formik'
import { useEffect, useState } from 'react'
import * as Yup from 'yup'
import styles from '../index.module.scss'
@ -8,6 +9,16 @@ const schema = Yup.object({
})
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']}>
@ -15,7 +26,13 @@ export function Newsletter() {
<h3>Assine nossa newsletter</h3>
<Formik
initialValues={{ email: '' }}
onSubmit={(e) => console.log(e)}
onSubmit={(values, e) => {
e.resetForm({
isSubmitting: true,
})
setIsSubmiting(true)
}}
validationSchema={schema}
>
<Form className={styles['newsletter__form']}>
@ -26,6 +43,13 @@ export function Newsletter() {
</div>
<button type="submit">Enviar</button>
</div>
<p
className={`form__success ${
isSubmiting ? 'form__success-active' : ''
}`}
>
*Formulário enviado com sucesso!
</p>
</fieldset>
</Form>
</Formik>

View File

@ -11,19 +11,19 @@ import css from '../index.module.scss'
export function Socials() {
return (
<ul className={css.socials}>
<ItemList href="/">
<ItemList href="https://facebook.com">
<img src={facebookIcon} alt="" />
</ItemList>
<ItemList href="/">
<ItemList href="https://instagram.com">
<img src={instagramIcon} alt="" />
</ItemList>
<ItemList href="/">
<ItemList href="https://twitter.com">
<img src={twitterIcon} alt="" />
</ItemList>
<ItemList href="/">
<ItemList href="https://youtube.com">
<img src={youtubeIcon} alt="" />
</ItemList>
<ItemList href="/">
<ItemList href="https://linkedin.com">
<img src={linkedinIcon} alt="" />
</ItemList>
</ul>

View File

@ -114,6 +114,23 @@
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 {
@ -132,6 +149,13 @@
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);

View File

@ -17,7 +17,7 @@ export function Sidebar() {
]
return (
<aside className={styles['sidebar']}>
<nav className={styles['sidebar']}>
<div className={styles['sidebar__container']}>
<ul className={styles['sidebar__list']}>
{paths.map(({ path, name }) => {
@ -33,6 +33,6 @@ export function Sidebar() {
})}
</ul>
</div>
</aside>
</nav>
)
}