Skip to content

Commit

Permalink
Create shared form components
Browse files Browse the repository at this point in the history
  • Loading branch information
utarwyn committed Dec 21, 2023
1 parent 056f76e commit 8b9ae50
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 183 deletions.
4 changes: 4 additions & 0 deletions src/assets/variables.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:root {
--color-primary: #355086;
--color-primary-lighter: hsl(220, 43%, 65%);
--color-primary-focus-ring: hsl(220, 43%, 37%, 20%);
--color-secondary: #57c18b;
--color-on-surface: #022826;
}
16 changes: 16 additions & 0 deletions src/components/Shared/Fieldset.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div class="app-fieldset">
<slot />
</div>
</template>

<style scoped lang="scss">
.app-fieldset {
display: grid;
gap: 1rem;
@media (min-width: 796px) {
grid-template-columns: repeat(2, 1fr);
}
}
</style>
75 changes: 75 additions & 0 deletions src/components/Shared/Selectfield.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<script setup lang="ts">
defineEmits(['update:modelValue'])
defineOptions({inheritAttrs: false})
defineProps<{ id: string; label: string; modelValue: string; items: string[] }>()
</script>

<template>
<div class="app-selectfield">
<label :for="id">{{ label }}</label>
<div class="container">
<select
:value="modelValue"
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
:id="id"
v-bind="$attrs"
>
<option v-for="item in items" :key="item">{{ item }}</option>
</select>
<svg viewBox="0 0 16 16" fill="currentColor">
<path
d="M12 6.5c0-.28-.22-.5-.5-.5h-7a.495.495 0 00-.37.83l3.5 4c.09.1.22.17.37.17s.28-.07.37-.17l3.5-4c.08-.09.13-.2.13-.33z"
fill-rule="evenodd"></path>
</svg>
</div>
</div>
</template>

<style scoped lang="scss">
.app-selectfield {
display: flex;
flex-direction: column;
gap: 0.5rem;
& > label {
color: var(--color-primary);
font-size: 18px;
font-weight: 900;
cursor: pointer;
}
& > .container {
position: relative;
height: 56px;
background-color: white;
border-radius: 0.25rem;
border: solid 1px #d8dae5;
transition: box-shadow .08s ease-in-out;
overflow: hidden;
& > select {
background: none;
appearance: none;
border: none;
outline: none;
width: 100%;
padding: 1rem 3rem 1rem 1rem;
font-size: 18px;
}
& > svg {
position: absolute;
right: 1rem;
top: 1rem;
width: 24px;
height: 24px;
color: var(--color-primary);
}
&:focus, &:focus-within {
border-color: var(--color-primary-lighter);
box-shadow: var(--color-primary-focus-ring) 0 0 0 3px;
}
}
}
</style>
72 changes: 72 additions & 0 deletions src/components/Shared/Textfield.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script setup lang="ts">
defineEmits(['update:modelValue'])
defineOptions({ inheritAttrs: false })
withDefaults(
defineProps<{ id: string; label: string; modelValue: string; type?: string; centered?: boolean }>(),
{ type: 'text', centered: false }
)
</script>

<template>
<div class="app-textfield">
<label :for="id" :class="centered ? 'centered' : ''">{{ label }}</label>
<input
v-if="type !== 'textarea'"
:value="modelValue"
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
:type="type"
:id="id"
v-bind="$attrs"
/>
<textarea
v-else
:value="modelValue"
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
:id="id"
v-bind="$attrs"
/>
</div>
</template>

<style lang="scss">
.app-textfield {
display: flex;
flex-direction: column;
gap: 0.5rem;
& > label {
color: var(--color-primary);
font-size: 18px;
font-weight: 900;
cursor: pointer;
&.centered {
text-align: center;
}
}
& > input,
& > textarea {
appearance: none;
height: 56px;
background-color: white;
padding: 1rem;
border-radius: 0.25rem;
border: solid 1px #d8dae5;
font-size: 18px;
font-weight: 500;
outline: none;
transition: box-shadow .08s ease-in-out;
&:focus, &:focus-within {
border-color: var(--color-primary-lighter);
box-shadow: var(--color-primary-focus-ring) 0 0 0 3px;
}
}
& > textarea {
height: 135px;
resize: none;
}
}
</style>
105 changes: 16 additions & 89 deletions src/components/company/CaseStudyForm.vue
Original file line number Diff line number Diff line change
@@ -1,46 +1,22 @@
<template>
<form @submit.prevent="submitForm" aria-label="Formulaire de contact">
<div class="form-fieldset">
<div class="form-field">
<label class="text-label" for="lastname">Nom :</label>
<input v-model="lastname" class="input" type="text" id="lastname" autocomplete="family-name"/>
</div>
<div class="form-field">
<label class="text-label" for="firstname">Prénom :</label>
<input v-model="firstname" class="input" type="text" id="firstname" autocomplete="given-name"/>
</div>
</div>

<div class="form-field">
<label class="text-label" for="company">Organisation :</label>
<input v-model="company" class="input" type="text" id="company" autocomplete="organization"/>
</div>
<Fieldset>
<Textfield id="lastname" v-model="lastname" label="Nom :" autocomplete="family-name"/>
<Textfield id="firstname" v-model="firstname" label="Prénom :" autocomplete="given-name"/>
</Fieldset>

<div class="form-field">
<label class="text-label" for="role">Rôle :</label>
<input v-model="role" class="input" type="text" id="role" autocomplete="organization-title"/>
</div>
<Textfield id="company" v-model="company" label="Organisation :" autocomplete="organization"/>
<Textfield id="role" v-model="role" label="Rôle :" autocomplete="organization-title"/>

<div class="form-fieldset">
<div class="form-field">
<label class="text-label" for="phone">Téléphone :</label>
<input v-model="phone" class="input" type="tel" id="phone" autocomplete="tel"/>
</div>
<div class="form-field">
<label class="text-label" for="email">E-mail * :</label>
<input v-model="email" required class="input" type="email" id="email" autocomplete="email"/>
</div>
</div>
<Fieldset>
<Textfield id="email" v-model="email" type="email" label="E-mail * :" autocomplete="email"/>
<Textfield id="phone" v-model="phone" type="tel" label="Téléphone :" autocomplete="tel"/>
</Fieldset>

<div class="form-field">
<label class="text-label" for="message">Votre besoin :</label>
<textarea v-model="message" id="message"></textarea>
</div>
<Textfield id="message" type="textarea" v-model="message" label="Votre besoin :"/>

<div class="hcaptcha">
<vue-hcaptcha @verify="getCaptcha" sitekey="359a430d-a0bf-4548-a583-959e93110b6d"
aria-label="Rendez vous sur https://www.hcaptcha.com/accessibility pour obtenir un passe-droit accessible"/>
</div>
<vue-hcaptcha @verify="getCaptcha" sitekey="359a430d-a0bf-4548-a583-959e93110b6d"
aria-label="Rendez vous sur https://www.hcaptcha.com/accessibility pour obtenir un passe-droit accessible"/>

<div class="form-submit">
<div class="error-message" v-if="error" aria-live="assertive">{{ error }}</div>
Expand All @@ -57,6 +33,8 @@ import { ref } from 'vue';
import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
import ButtonBlock from '@/components/global/Button.vue';
import { post } from '@/util/fetch';
import Textfield from "@/components/Shared/Textfield.vue";
import Fieldset from "@/components/Shared/Fieldset.vue";
/**
* Validates an email address to ensure it is not empty and follows a valid email format.
Expand Down Expand Up @@ -179,60 +157,9 @@ form {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.text-label {
color: #355086;
font-size: 18px;
font-weight: 900;
outline: none;
}
.form-field {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.form-fieldset {
display: grid;
gap: 1rem;
}
@media (min-width: 796px) {
form {
@media (min-width: 796px) {
width: 768px;
}
.form-fieldset {
grid-template-columns: repeat(2, 1fr);
}
}
.input {
height: 60px;
background-color: #ffffff;
padding: 1rem;
border-radius: 8px;
border: solid 1px rgba(0, 0, 0, 0.2);
color: #022826;
font-size: 18px;
font-weight: 500;
outline: none;
}
textarea {
width: 100%;
height: 135px;
background-color: #ffffff;
padding: 1rem;
border-radius: 8px;
border: solid 1px rgba(0, 0, 0, 0.2);
color: #022826;
font-size: 18px;
font-weight: 500;
outline: none;
resize: none;
}
</style>
33 changes: 5 additions & 28 deletions src/components/contributor/Newsletter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
<span class="title">Rejoins ecoCode !</span>
<span class="subtitle">Rejoins-nous et contribue à faire du numérique un domaine plus durable.</span>

<div class="form-field">
<label class="text-input" for="email">E-mail * :</label>
<input v-model="email" id="email" type="email" autocomplete="email"/>
<div class="text-field">
<Textfield id="email" v-model="email" type="email" label="E-mail * :" autocomplete="email" centered/>
</div>

<div style="margin-top: 15px;">
Expand All @@ -30,6 +29,7 @@ import { ref } from 'vue';
import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
import ButtonBlock from '@/components/global/Button.vue';
import { post } from '@/util/fetch';
import Textfield from "@/components/Shared/Textfield.vue";
const validateEmail = () => {
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
Expand Down Expand Up @@ -115,33 +115,10 @@ form {
max-width: 779px;
}
.form-field {
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 320px;
.text-field {
margin: 3rem 1rem 0;
width: 320px;
max-width: 100%;
label {
color: #355086;
font-size: 18px;
font-weight: 900;
outline: none;
text-align: center;
}
input {
height: 60px;
background-color: #ffffff;
padding: 1rem;
border-radius: 8px;
border: solid 1px rgba(0, 0, 0, 0.2);
color: #022826;
font-size: 18px;
font-weight: 500;
outline: none;
}
}
.join-us {
Expand Down
Loading

0 comments on commit 8b9ae50

Please sign in to comment.