10 Commits

Author SHA1 Message Date
Stage1 d7b5df74be simulateur de devis 2026-06-18 15:09:33 +02:00
Stage1 bb2b789d3f simulateur de devis 2026-06-18 15:09:14 +02:00
Stage1 397272429d corrections 2026-06-18 12:05:02 +02:00
matthieu 5314db52a0 Guide services: relecture form, redimensionnement borne textarea (min/max), icone bouton Envoyer
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:44:33 +02:00
Stage1 be6c852045 update style formulaire 2026-06-18 10:55:11 +02:00
Stage1 d14cce5731 update formulaire + footer 2026-06-18 10:22:29 +02:00
Stage1 8910b77294 début formulaire 2026-06-17 16:54:23 +02:00
Stage1 f630bbf649 add style table 2026-06-17 16:04:44 +02:00
Stage1 2aade91105 update table + nav barre 2026-06-17 16:03:56 +02:00
Stage1 bebc535cae new style for the same page 2026-06-17 15:07:13 +02:00
5 changed files with 799 additions and 0 deletions
+416
View File
@@ -0,0 +1,416 @@
# 🛠️ Page Services — relecture & prochaine étape
Salut Guillaume ! 👋
Ta page services avance super bien : le tableau des prestations est clair, les boutons de navigation sont stylés, et tu as même ajouté une petite icône SVG sur le bouton « retour ». Bravo, c'est du bon travail ! 🎉
Ce guide a deux objectifs :
1. Te montrer **3 bugs** à corriger (avec l'explication, pas juste la solution).
2. T'apprendre à **définir et limiter une `<textarea>`** proprement.
3. Te lancer sur ta **première mission JavaScript** 🚀 (un vrai morceau de programmation, dans le thème FleetZen).
---
## 🐛 Bug 1 — Ton formulaire ne contient (presque) aucun champ
Regarde bien comment tu as écrit ton formulaire :
```html
<form action="" method="post">Si vous avez des suggestions :</form> <!-- ❌ le </form> ferme ICI -->
<ul>
<li><input type="text" ... /></li> <!-- ces champs sont DEHORS du <form> ! -->
<li><textarea ...></textarea></li>
<button type="submit">Envoyer le message</button>
</ul>
```
Le problème : tu **ouvres** `<form>` puis tu le **refermes** (`</form>`) tout de suite, juste après la phrase d'intro. Du coup, tous tes champs (`<input>`, `<textarea>`, le bouton « Envoyer ») se retrouvent **à l'extérieur** du formulaire.
👉 Conséquence : le jour où le formulaire enverra vraiment les données, **rien ne partira**, parce que le navigateur n'envoie que ce qui est **à l'intérieur** des balises `<form>…</form>`.
### ✅ La correction : le `<form>` doit englober TOUS les champs
```html
<form action="" method="post">
<p>Si vous avez des suggestions :</p>
<ul>
<li>
<label for="name">Nom&nbsp;:</label>
<input type="text" id="name" name="user_name" placeholder="Dupond" />
</li>
<li>
<label for="mail">E-mail&nbsp;:</label>
<input type="email" id="mail" name="user_mail" placeholder="dupond@gmail.com" />
</li>
<li>
<label for="msg">Message&nbsp;:</label>
<textarea id="msg" name="user_message" placeholder="Je pense qu'il faudrait..."></textarea>
</li>
</ul>
<div id="boutton_formulaire">
<button type="submit">Envoyer le message</button>
</div>
</form>
```
> 💡 **À retenir :** un `<form>` est une **boîte**. Tout ce qu'on veut envoyer (champs + bouton « Envoyer ») doit être **dedans**, entre `<form>` et `</form>`.
---
## 🐛 Bug 2 — Un dégradé qui ne s'affiche pas (parenthèses oubliées)
Dans `style_services.css`, ton bouton de la page courante `.x_to_x` :
```css
.x_to_x {
background-image:
linear-gradient to top left, /* ❌ il manque les parenthèses */
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent;
}
```
`linear-gradient` est une **fonction** : comme en maths, ses arguments vont **entre parenthèses**. Sans elles, le navigateur ne comprend pas la ligne et **ignore tout le dégradé**. C'est pour ça que ce bouton n'a pas le même rendu que les autres.
### ✅ Correction (compare avec ta classe `.styled` qui, elle, est correcte)
```css
.x_to_x {
background-image: linear-gradient(
to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent
);
}
```
> 💡 **À retenir :** `linear-gradient( … )`, `rgb( … )`, `calc( … )` … toutes les **fonctions** CSS prennent leurs arguments **entre parenthèses**. Une fonction sans parenthèses = ligne ignorée.
---
## 🎯 Bug 3 — L'icône SVG n'est pas centrée dans le bouton « retour »
Ton bouton mélange une **image** (le SVG) et du **texte** côte à côte :
```html
<button class="retour"><svg ...></svg>retour</button>
```
Le souci : par défaut, une icône SVG se pose **sur la ligne du texte** (sur la « ligne de base », comme une lettre). Du coup elle paraît trop haute ou trop basse, et ton `line-height: 2.5` accentue le décalage. L'icône et le mot « retour » ne sont pas alignés sur leur **milieu**.
### ✅ La solution : transformer le bouton en boîte flex
```css
.retour {
display: inline-flex; /* le bouton range ses enfants (icône + texte) */
align-items: center; /* ↕ les centre verticalement, sur le même milieu */
justify-content: center; /* ↔ les centre horizontalement */
gap: 6px; /* un petit espace entre l'icône et le mot */
line-height: normal; /* on enlève le 2.5 qui déréglait l'alignement */
/* ...garde le reste de tes styles (couleur, border-radius, etc.) */
}
```
`align-items: center`, c'est **exactement** le `flex` que tu connais déjà (tu l'utilises sur `#buttons` et `.align_x`). Ici on l'applique **au bouton lui-même**, parce que c'est lui le parent qui contient l'icône **et** le texte.
> 💡 **À retenir :** dès qu'un bouton (ou n'importe quelle boîte) contient **une icône + du texte** à aligner, passe-le en `display: inline-flex; align-items: center;`. C'est le réflexe pro pour centrer proprement une icône avec du texte.
> ⚠️ **Ça vaut aussi pour ton nouveau bouton « Envoyer le message »** : tu viens d'y ajouter l'icône SVG « avion en papier », il a donc exactement le même décalage. Applique-lui la même recette flex (par ex. une classe commune `.btn-icone` que tu mets sur les deux boutons, plutôt que de répéter le CSS).
---
## 📐 La leçon du jour : définir et **limiter** une `<textarea>`
Pour l'instant ta `<textarea>` est « brute » :
```html
<textarea id="msg" name="user_message"></textarea>
```
Par défaut elle est petite, et surtout l'utilisateur peut écrire **un roman de 10 000 mots** sans aucune limite. On va apprendre à la **cadrer**.
### 1️⃣ Lui donner une taille de départ : `rows` et `cols`
```html
<textarea id="msg" name="user_message"
rows="6" cols="40"></textarea>
```
- `rows` = nombre de **lignes** visibles (la hauteur).
- `cols` = nombre de **colonnes** = caractères en largeur.
> 🔎 `rows`/`cols` ne sont **pas** des pixels : c'est « combien de lignes/caractères je vois ». C'est la taille **de départ**.
### 2️⃣ Limiter le nombre de caractères : `maxlength`
```html
<textarea id="msg" name="user_message"
rows="6" cols="40"
maxlength="500"></textarea>
```
`maxlength="500"` = l'utilisateur **ne peut pas** taper plus de 500 caractères. C'est le navigateur qui bloque tout seul, sans JavaScript. 👍
### 3️⃣ Empêcher (ou cadrer) le redimensionnement : `resize` en CSS
Tu as remarqué la petite poignée en bas à droite d'une textarea ? L'utilisateur peut l'étirer et **casser ta mise en page**. On contrôle ça en CSS :
```css
#msg {
resize: vertical; /* il peut agrandir en hauteur seulement (recommandé) */
/* resize: none; pour interdire complètement le redimensionnement */
width: 100%; /* la largeur, on la pilote en CSS, pas avec cols */
min-height: 120px;
}
```
> 💡 **À retenir :**
> - `rows` / `cols` → **taille de départ** (lignes / caractères).
> - `maxlength` → **limite** le nombre de caractères (le navigateur bloque tout seul).
> - `resize` (CSS) → contrôle la **poignée** d'étirement (`vertical`, `horizontal`, `none`, `both`).
> - Astuce de pro : on règle souvent la **largeur en CSS** (`width`) et on garde `rows` pour la hauteur de départ.
### 4️⃣ 👉 Votre question : laisser l'utilisateur redimensionner, mais **entre un min et un max**
Tu as choisi pour l'instant :
```css
#msg {
resize: none; /* la poignée est désactivée : l'utilisateur ne peut RIEN étirer */
width: 200px;
}
```
`resize: none` est un **choix valable** (la zone est verrouillée). Mais vous m'avez demandé l'inverse : **autoriser** l'agrandissement, tout en **empêchant que ça parte trop grand ou trop petit**. La recette tient en 2 idées qui se combinent :
1. **`resize`** dit *dans quelle direction* on peut étirer.
2. **`min-*` / `max-*`** disent *jusqu'où* on peut aller.
```css
#msg {
resize: vertical; /* on autorise l'étirement, mais en HAUTEUR seulement */
min-height: 80px; /* impossible de la réduire en dessous de 80px */
max-height: 300px; /* impossible de l'agrandir au-delà de 300px */
width: 100%; /* largeur pilotée en CSS, pas par l'utilisateur */
}
```
Avec ça : l'utilisateur attrape la poignée, tire vers le bas pour avoir plus de place… mais **la zone refuse de dépasser 300px** et **de descendre sous 80px**. Ta mise en page reste protégée. 🎉
#### Et si on veut autoriser les **deux** sens (vertical **et** horizontal) ?
Même principe, mais avec **4 bornes** : 2 pour la hauteur, 2 pour la largeur. On passe `resize` à `both` :
```css
#msg {
resize: both; /* la poignée étire en hauteur ET en largeur */
min-height: 80px; /* bornes verticales */
max-height: 300px;
min-width: 200px; /* bornes horizontales */
max-width: 100%; /* ne dépasse jamais la largeur du parent → pas de scroll */
}
```
Chaque direction a sa paire `min`/`max` :
- **hauteur** → `min-height` / `max-height`
- **largeur** → `min-width` / `max-width`
L'utilisateur peut alors étirer dans tous les sens, mais **jamais au-delà** de ces 4 limites.
> ⚠️ Le piège classique en horizontal : mets `max-width: 100%` (et pas une grande valeur en `px`), sinon l'utilisateur peut élargir la zone **plus que l'écran** et faire réapparaître la barre de défilement horizontale (souviens-toi du bug du scroll 😉).
Récap des valeurs de `resize` :
| `resize` | Ce que l'utilisateur peut étirer |
|---|---|
| `none` | rien (verrouillé) — ton choix actuel |
| `vertical` | la hauteur seulement (le plus confortable pour un message) |
| `horizontal` | la largeur seulement |
| `both` | les deux |
> 💡 **À retenir :** `resize` = **la direction** autorisée. `min-height`/`max-height` (et `min-width`/`max-width`) = **les bornes**. Les deux ensemble = un redimensionnement libre **mais encadré**.
---
## 🚀 Ta première mission JavaScript : le **simulateur de devis FleetZen**
Jusqu'ici tu as fait du HTML (la **structure**) et du CSS (l'**apparence**). Le JavaScript, c'est la **3ᵉ couche** : le **comportement**, ce qui réagit quand on clique. 🧠
On va le faire **en mode tuto** : tu construis petit bout par petit bout, et **tu testes à chaque étape**. Ne copie pas tout d'un coup — avance palier par palier, c'est comme ça qu'on comprend. 🙂
**Objectif final :** un petit **simulateur** où le client choisit **combien de véhicules** il a, et le prix total se met à jour **tout seul**, sans recharger la page.
---
### 🪜 Étape 0 — Découvrir la console (ton meilleur ami)
Avant tout : ouvre ta page dans le navigateur, puis appuie sur **F12** → onglet **Console**. C'est là que le JS « parle ».
Crée un fichier `css/devis.js` avec une seule ligne :
```js
console.log("Mon fichier JS est bien chargé !");
```
Et branche-le en bas du `<body>`, **juste avant** `</body>` :
```html
<script src="css/devis.js"></script>
```
> 🔎 Pourquoi à la fin du body ? Parce que le JS s'exécute de haut en bas. S'il se lance **avant** que le HTML existe, il ne trouve rien à manipuler. À la fin, tout le HTML est déjà là. 👍
**✅ Teste maintenant :** recharge la page. Tu dois voir ton message dans la Console. Si oui, ton JS est branché. Sinon, vérifie le chemin du `src`.
---
### 🪜 Étape 1 — Ajouter le HTML du simulateur
Sous ton tableau, ajoute :
```html
<section class="simulateur">
<h2>Estimez votre devis</h2>
<p>Nombre de véhicules dans votre flotte :</p>
<button id="moins" type="button"></button>
<span id="nb_vehicules">1</span>
<button id="plus" type="button">+</button>
<p>Total géolocalisation : <strong id="total">30</strong> €/mois</p>
</section>
```
**✅ Teste maintenant :** tu dois voir les boutons `` et `+` et le chiffre `1`. Pour l'instant ils ne font rien, c'est normal : on n'a pas encore écrit le comportement.
> 🔎 Remarque les **`id`** (`moins`, `plus`, `nb_vehicules`, `total`). Un `id` est une **étiquette unique** : c'est par là que le JS va « attraper » chaque élément à l'étape suivante.
---
### 🪜 Étape 2 — Attraper les éléments depuis le JS
Dans `devis.js`, remplace ton `console.log` de test par :
```js
// "Attraper" un élément du HTML grâce à son id
const boutonPlus = document.getElementById("plus");
console.log(boutonPlus); // pour vérifier qu'on l'a bien trouvé
```
**✅ Teste maintenant :** dans la Console tu dois voir s'afficher ton `<button id="plus">`. Si tu vois `null`, c'est que l'id ne correspond pas → vérifie l'orthographe.
> 🧩 **Idée clé n°1 — SÉLECTIONNER.** `document.getElementById("plus")` veut dire : « dans le document, va me chercher l'élément dont l'id est *plus* ». On le range dans une variable pour s'en servir après.
---
### 🪜 Étape 3 — Réagir à un clic
Ajoute en dessous :
```js
boutonPlus.addEventListener("click", function () {
console.log("Clic sur + détecté !");
});
```
**✅ Teste maintenant :** clique sur le bouton `+`. À **chaque** clic, un message apparaît dans la Console. 🎉
> 🧩 **Idée clé n°2 — RÉAGIR.** `addEventListener("click", … )` se lit : « écoute les clics sur ce bouton, et quand il y en a un, exécute cette fonction ». La fonction entre `{ }` est le « que faire quand ça arrive ».
---
### 🪜 Étape 4 — Faire vraiment changer le compteur
Maintenant on remplace le `console.log` par une vraie logique. Voici le fichier complet :
```js
// 1. On attrape tous les éléments dont on a besoin
const affichageNb = document.getElementById("nb_vehicules");
const affichageTotal = document.getElementById("total");
const boutonPlus = document.getElementById("plus");
const boutonMoins = document.getElementById("moins");
const PRIX_PAR_VEHICULE = 30; // 30 €/véhicule/mois (cf. ton tableau)
let nbVehicules = 1; // "let" = une variable qui va CHANGER
// 2. Une fonction qui réécrit l'affichage à partir de nbVehicules
function mettreAJour() {
affichageNb.textContent = nbVehicules;
affichageTotal.textContent = nbVehicules * PRIX_PAR_VEHICULE;
}
// 3. Au clic sur "+", on augmente puis on réaffiche
boutonPlus.addEventListener("click", function () {
nbVehicules = nbVehicules + 1;
mettreAJour();
});
// 4. Au clic sur "", on diminue (mais jamais en dessous de 1)
boutonMoins.addEventListener("click", function () {
if (nbVehicules > 1) {
nbVehicules = nbVehicules - 1;
}
mettreAJour();
});
```
> 🧩 **Idée clé n°3 — MODIFIER.** `element.textContent = …` réécrit le texte affiché **en direct**, sans recharger la page. C'est ça, la magie du JS.
>
> 🔎 Pourquoi une fonction `mettreAJour()` ? Pour ne pas se répéter : le `+` et le `` ont tous les deux besoin de réafficher. On écrit le « comment afficher » **une seule fois** et on l'appelle aux deux endroits (c'est le même esprit que le composant réutilisable, juste après 👇).
**✅ Teste maintenant :** clique 3 fois sur `+` → tu dois lire **4 véhicules** et **120 €**. Clique sur `` jusqu'en bas → ça doit **bloquer à 1**. Si oui : bravo, tu viens d'écrire ta première vraie logique en JavaScript ! 🎉
> 🎯 **Défis bonus** (dans l'ordre de difficulté) :
> 1. Empêcher aussi de dépasser 100 véhicules.
> 2. Afficher le total avec un séparateur de milliers.
> 3. Ajouter un 2ᵉ service (ex. consommation à 15 €) et calculer un total combiné.
---
## ♻️ Bonus — La notion de **composant réutilisable** (la navbar)
Regarde : la barre du haut (`#nav_barre`) est **recopiée à l'identique** dans `index.html`, `services.html` et `contact.html`. Le jour où tu changes un lien, tu dois le changer **dans 3 fichiers** → source d'erreurs (d'ailleurs, vérifie tes liens entre pages 😉).
C'est **le** problème que résolvent les **composants** : on écrit la navbar **une seule fois**, et on la réutilise partout.
Première approche très simple en JavaScript : une fonction qui **génère** la navbar.
```js
function creerNavbar() {
return `
<div id="nav_barre" class="shadow">
<h1>FleetZen</h1>
<div id="buttons">
<a href="contact.html"><button class="styled">contact</button></a>
<a href="services.html"><button class="styled">services</button></a>
<a href="../index.html"><button class="retour">retour</button></a>
</div>
</div>`;
}
// On l'injecte tout en haut du body :
document.body.insertAdjacentHTML("afterbegin", creerNavbar());
```
**✅ Teste :** enlève la navbar écrite « en dur » dans le HTML, garde ce JS, recharge → la navbar réapparaît, générée par la fonction. Maintenant le jour où tu changes un lien, tu le changes **à un seul endroit** pour **toutes** les pages.
> 💡 **À retenir :** un **composant** = un bout d'interface écrit **une fois** et **réutilisé** partout. C'est l'idée centrale derrière React, Vue, etc. — mais ça commence par une simple fonction comme celle-ci.
---
## ✅ Ta checklist
- [ ] Remettre tous les champs **dans** le `<form>` (Bug 1)
- [ ] Réparer le dégradé de `.x_to_x` avec les parenthèses (Bug 2)
- [ ] Centrer l'icône SVG des boutons « retour » **et** « Envoyer » avec `inline-flex` (Bug 3)
- [ ] Ajouter `rows`, `maxlength` + redimensionnement borné (`resize: vertical` + `min/max-height`)
- [ ] Faire marcher le **simulateur de devis** en JavaScript
- [ ] (Bonus) Transformer la navbar en composant réutilisable
- [ ] Commits petits et clairs, puis `git push`
Pose-moi toutes tes questions. Tu gères ! 🚗💨
+46
View File
@@ -81,7 +81,53 @@ h1 {
inset -2px -2px 3px rgb(255 255 255 / 0.6),
inset 2px 2px 3px rgb(0 0 0 / 0.6);
}
.x_to_x {
border: 0;
height: 70px;
width: 130px;
line-height: 2.5;
padding: 0 20px;
font-size: 1rem;
text-align: center;
color: white;
text-shadow: 1px 1px 1px black;
border-radius: 10px;
background-color: midnightblue;
background-image:
linear-gradient to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent;
}
.styled {
border: 0;
height: 70px;
width: 130px;
line-height: 2.5;
padding: 0 20px;
font-size: 1rem;
text-align: center;
color: white;
text-shadow: 1px 1px 1px black;
border-radius: 10px;
background-color: royalblue;
background-image: linear-gradient(
to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent
);
}
.styled:hover {
background-color: midnightblue;
}
.styled:active {
box-shadow:
inset -2px -2px 3px rgb(255 255 255 / 0.6),
inset 2px 2px 3px rgb(0 0 0 / 0.6);
}
#buttons {
height: 100%;
width: 25%;
+34
View File
@@ -0,0 +1,34 @@
const affichageNb = document.getElementById("nb_vehicules");
const affichageGéo = document.getElementById("géolocalisation");
const affichageConso = document.getElementById("consommation");
const boutonPlus = document.getElementById("plus");
const boutonMoins = document.getElementById("moins");
const PRIX_GPS = 30;
const PRIX_CONSOMMATION = 15;
let nbVehicules = 1;
let totalargent = 0;
function mettreAJourGPS() {
affichageNb.textContent = nbVehicules;
affichageGéo.textContent = nbVehicules * PRIX_GPS;
}
function mettreAJourCONSO() {
affichageNb.textContent = nbVehicules;
affichageConso.textContent = nbVehicules * PRIX_CONSOMMATION;
}
function mettreAJourTOTAL() {
affichageNb.textContent = totalargent;
affichageGéo.textContent = totalargent + PRIX_GPS + PRIX_CONSOMMATION;
}
boutonPlus.addEventListener("click", function () {
nbVehicules = nbVehicules + 1;
(mettreAJourGPS(), mettreAJourCONSO());
if (nbVehicules > 99) {
nbVehicules = nbVehicules - 1;
}
});
boutonMoins.addEventListener("click", function () {
if (nbVehicules > 1) {
nbVehicules = nbVehicules - 1;
}
(mettreAJourGPS(), mettreAJourCONSO());
});
+213
View File
@@ -0,0 +1,213 @@
* {
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
background-color: rgb(190, 255, 255);
margin: 0;
padding-bottom: 60px;
}
#img_1 {
width: 20%;
height: auto;
}
.image_footer {
display: flex;
width: 30%;
height: auto;
}
.align_x {
display: flex;
width: 100%;
height: 100%;
flex-direction: row;
justify-content: space-between;
padding-top: 20px;
padding-left: 10px;
padding-right: 10px;
}
#text_1 {
width: 65%;
font-size: 200%;
}
h1 {
background-color: steelblue;
font-size: 40px;
}
.footer {
text-align: center;
background-color: cadetblue;
font-size: 25px;
position: fixed;
bottom: 0;
width: 100%;
}
#nav_barre {
display: flex;
width: 100%;
height: 100px;
background-color: steelblue;
padding-left: 10px;
padding-right: 10px;
}
.styled {
border: 0;
height: 70px;
width: 130px;
line-height: 2.5;
padding: 0 20px;
font-size: 1rem;
text-align: center;
color: white;
text-shadow: 1px 1px 1px black;
border-radius: 10px;
background-color: royalblue;
background-image: linear-gradient(
to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent
);
}
.styled:hover {
background-color: midnightblue;
}
.styled:active {
box-shadow:
inset -2px -2px 3px rgb(255 255 255 / 0.6),
inset 2px 2px 3px rgb(0 0 0 / 0.6);
}
.x_to_x {
border: 0;
height: 70px;
width: 130px;
line-height: 2.5;
padding: 0 20px;
font-size: 1rem;
text-align: center;
color: white;
text-shadow: 1px 1px 1px black;
border-radius: 10px;
background-color: midnightblue;
background-image: linear-gradient(
to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent
);
}
.retour {
border: 0;
height: 50px;
width: 130px;
line-height: 2.5;
padding: 0 20px;
font-size: 1rem;
text-align: center;
color: black;
border-radius: 10px;
background-color: white;
background-image: linear-gradient(
to top left,
rgb(0 0 0 / 0.2),
rgb(0 0 0 / 0.2) 30%,
transparent
);
}
.retour:hover {
background-color: gray;
}
.retour:active {
box-shadow:
inset -2px -2px 3px rgb(255 255 255 / 0.6),
inset 2px 2px 3px rgb(0 0 0 / 0.6);
}
#buttons {
height: 100%;
width: 37%;
display: flex;
justify-content: space-around;
flex-direction: row-reverse;
margin-left: auto;
align-items: center;
}
.shadow {
box-shadow: 0px 10px 5px gray;
}
p {
font-family: cursive;
}
.sous-titre {
font-size: 25px;
}
.table {
margin-bottom: 30px;
width: 70%;
height: auto;
background-color: dodgerblue;
border-collapse: collapse;
font-size: 25px;
table-layout: auto;
border: 2px solid;
th,
td {
padding: 10px;
text-align: center;
}
td {
background-color: lightskyblue;
}
}
.padding_left {
padding-left: 10px;
}
#boutton_formulaire {
width: 200px;
height: 50px;
display: flex;
justify-content: space-around;
flex-direction: row;
margin-left: auto;
align-items: center;
padding: 2px;
text-align: center;
}
.formulaire {
background-color: lightskyblue;
padding: 10px;
width: 40%;
height: 300px;
border: solid;
display: flex;
font-size: 20px;
li {
padding: 15px;
}
ul {
list-style-type: none;
}
}
.center {
width: 100%;
display: flex;
justify-content: center;
}
#msg {
resize: horizontal;
min-width: 50px;
max-width: 300px;
}
.btn_icone {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
line-height: normal;
}
+90
View File
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/style_services.css" />
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width", initial-scame="1"/>
<title>FleetZen/services</title>
<html lang="fr">
</head>
<body>
<div id="nav_barre" class="shadow">
<h1>FleetZen</h1>
<div id="buttons">
<a href="../pages/contact.html"><button class="styled">contact</button></a>
<a href="../pages/services.html"><button class="x_to_x">services</button></a>
<a href="../index.html"><button class="retour btn_icone"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-undo2-icon lucide-undo-2"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11"/></svg>retour</button></a>
</div>
</div>
<div class="padding_left">
<p class="sous-titre">Découvrez nos services tous plus utiles les uns que les autres !</p>
<table border="1" class="table">
<thead>
<tr>
<th>Nom</th>
<th>Description</th>
<th>Prix</th>
</tr>
</thead>
<tr>
<td>Géolocalisation</td>
<td>Afin de retrouver l'ensemble de vos véhicules sur une carte en temps réel !</td>
<td>30€/véhicule/mois</td>
</tr>
<tr>
<td>Odomètre</td>
<td>Ayez accès à un killomètrage précis.</td>
<td>200€</td>
</tr>
<tr>
<td>Consommation</td>
<td>Le carburant consommé par votre flotte.</td>
<td>15£/véhicule/mois</td>
</tr>
<tr>
<td>Impact Carbonne</td>
<td>Ayez sous les yeux tous les chiffres concernant le CO2 rejeté par votre flotte</td>
<td>30€/véhicule/mois</td>
</tr>
</table>
</div>
<section class="simulateur">
<h2>Estimez votre devis</h2>
<p>Nombre de véhicules dans votre flotte :</p>
<button id="moins" type="button"></button>
<span id="nb_vehicules">1</span>
<button id="plus" type="button">+</button>
<p>Total géolocalisation : <strong id="géolocalisation">30</strong> €/mois</p>
<p>Total consommation : <strong id="consommation">15</strong> €/mois</p>
</section>
<div class="center">
<div class="formulaire">
<form action="" method="post">
<p> Si vous avez des suggestions :</p>
<ul>
<li>
<label for="name">Nom&nbsp;:</label>
<input type="text" placeholder="Dupond" id="name" name="user_name" />
</li>
<li>
<label for="mail">E-mail&nbsp;:</label>
<input type="email" placeholder="dupondrichard@gmail.com" id="mail" name="user_mail" />
</li>
<li>
<label for="msg">Message&nbsp;:</label>
<textarea id="msg" placeholder="Je pense qu'il faudrait..." name="user_message"
row="6" cols="40" maxlength="500"></textarea>
</li>
<div id="boutton_formulaire">
<button type="submit"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-send-icon lucide-send"><path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"/><path d="m21.854 2.147-10.94 10.939"/></svg>Envoyer le message</button>
</div>
</ul>
</form>
</div>
</div>
<footer class="footer">
stagiaires rpz echoes
</footer>
<script src="css/devis.js"></script>
</body>
</html>