ajout de la page formulaire
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 22s
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 22s
This commit is contained in:
parent
4926fa8ead
commit
ebe6bb6401
10 changed files with 476 additions and 8 deletions
|
|
@ -64,6 +64,9 @@ Popups expose imperatively (defineExpose: open/close/visible/handleClick); App w
|
|||
- `FigureSettingsPopup.vue` (thin view) + `useFigureSettings.js` (composable) — per-figure width/height/margin/position editor for block-image & block-carte. prop `kind`('image'|'carte') selects baseClass + selector derivation + defaults store. Composable logic in named helpers: read{Width,Height,Margins,Position}FromCss (store→data), apply*, loadFromCss/restoreFromStored, parse*FromText/persistStateAsCss (manual edits). exposes handleClick(figure,event). (Merged from former ImagePopup/CartePopup.)
|
||||
- `editor/FigureDefaultsSettings.vue` — default width/height panel for images & cartes. prop `kind`; image targets [.block-image,.geoformat-cover-image], carte targets [.block-carte]; writes ⊙image/carteDefaults. (Merged from former ImageSettings/CarteSettings.)
|
||||
|
||||
## PHP templates (public/site/templates/) — notable additions
|
||||
- `form.php` — Page avec deux formulaires de contact (autonome / partenaire). POST handling natif Kirby : CSRF (`csrf()`), honeypot, `kirby()->email()`, Post/Redirect/Get (`go()`). Blueprint : `blueprints/pages/form.yml` (writer `text` + `email_to` text). CSS : `assets/css/form.css` (chargé conditionnellement dans `header-web.php`). Pas de plugin tiers.
|
||||
|
||||
## PHP snippets (public/site/snippets/)
|
||||
- `cover-img.php` — snippet réutilisable pour les images de couverture responsives.
|
||||
- `blocks/gallery.php` — rendu du bloc galerie : grille CSS avec `--gallery-cols` (1–4 colonnes), srcset 2 tailles, liens `class="glightbox"`. Blueprint : `blueprints/blocks/gallery.yml`. Preview panel : composant natif Kirby (`preview: gallery` dans le blueprint — ne pas créer de plugin `k-gallery-block-preview` car Kirby en fournit un). Génère un `<img>` avec 3 breakpoints `w` srcset, crop Kirby (ratio configurable via `$imgW`/`$imgH`, défaut 900×600 = 3:2), point focus panel → position nommée (crop) + `object-position` CSS. Variables : `$file`, `$alt`, `$lazy` (bool, défaut true), `$sizes` (string), `$imgW`, `$imgH`. Utilisé par home.php, projects.php, actus.php, actu.php.
|
||||
|
|
|
|||
159
public/assets/css/form.css
Normal file
159
public/assets/css/form.css
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* ── FORMULAIRES DE DEMANDE D'ACCOMPAGNEMENT ──────────── */
|
||||
|
||||
.form-intro {
|
||||
max-width: 680px;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.form-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
border-bottom: 1px solid currentColor;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.form-tab {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: none;
|
||||
cursor: pointer;
|
||||
padding: 0.6rem 1.25rem;
|
||||
font: inherit;
|
||||
font-size: 1em;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.15s ease;
|
||||
margin-bottom: -1px;
|
||||
color: var(--nw-accent);
|
||||
}
|
||||
|
||||
.form-tab:hover { opacity: 1; }
|
||||
|
||||
.form-tab.is-active {
|
||||
opacity: 1;
|
||||
border-color: #FFF;
|
||||
background: var(--nw-accent);
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
/* Panels */
|
||||
.form-panel[hidden] { display: none; }
|
||||
|
||||
/* Notices */
|
||||
.form-notice {
|
||||
padding: 0.9rem 1.1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
border-left: 3px solid;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.form-notice--success { border-color: #2a9d5c; background: #f0fdf4; }
|
||||
.form-notice--error { border-color: #c0392b; background: #fef2f2; }
|
||||
|
||||
/* Fields */
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.form-field label abbr,
|
||||
.form-required-note abbr {
|
||||
text-decoration: none;
|
||||
color: #c0392b;
|
||||
margin-left: 0.1em;
|
||||
}
|
||||
|
||||
.form-field small {
|
||||
font-size: 0.85em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.form-field input,
|
||||
.form-field select,
|
||||
.form-field textarea {
|
||||
font: inherit;
|
||||
font-size: 1rem;
|
||||
padding: 1rem 0.75rem;
|
||||
border: 1px solid currentColor;
|
||||
background: #FFF;
|
||||
color: inherit;
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.form-field select {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='currentColor' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
padding-right: 2.25rem;
|
||||
padding-top: 0.8rem;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.form-field textarea {
|
||||
resize: vertical;
|
||||
min-height: 8rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.form-field input:focus,
|
||||
.form-field select:focus,
|
||||
.form-field textarea:focus {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
/* Honeypot — caché visuellement et pour l'accessibilité */
|
||||
.form-hp {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
tab-index: -1;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
.form-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-top: 1.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.form-required-note {
|
||||
font-size: 0.85em;
|
||||
opacity: 0.65;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form-submit {
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
padding: 0.6rem 2.25rem;
|
||||
background: transparent;
|
||||
border: 1px solid currentColor;
|
||||
color: inherit;
|
||||
letter-spacing: 0.02em;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.form-submit:hover,
|
||||
.form-submit:focus-visible {
|
||||
background: var(--nw-accent);
|
||||
color: #FFF;
|
||||
}
|
||||
|
|
@ -192,13 +192,15 @@ body[data-template="actus"] .hp-section {
|
|||
}
|
||||
|
||||
/* Page about */
|
||||
body[data-template="about"] .hp-section {
|
||||
body[data-template="about"] .hp-section,
|
||||
body[data-template="form"] .hp-section {
|
||||
margin-top: 100px;
|
||||
border: none;
|
||||
min-height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
body[data-template="about"] .hp-section .hp-container {
|
||||
body[data-template="about"] .hp-section .hp-container,
|
||||
body[data-template="form"] .hp-section .hp-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
body[data-template='tutos'],
|
||||
body[data-template='actus'],
|
||||
body[data-template='actu'],
|
||||
body[data-template='tuto'] {
|
||||
body[data-template='tuto'],
|
||||
body[data-template='form'] {
|
||||
background: var(--w-bg);
|
||||
}
|
||||
|
||||
|
|
@ -740,7 +741,8 @@
|
|||
body[data-template="tutos"] .btn-connect,
|
||||
body[data-template="tuto"] .btn-connect,
|
||||
body[data-template="actus"] .btn-connect,
|
||||
body[data-template="actu"] .btn-connect{
|
||||
body[data-template="actu"] .btn-connect,
|
||||
body[data-template="form"] .btn-connect{
|
||||
position: relative;
|
||||
top: -3px;
|
||||
right: 0;
|
||||
|
|
@ -1723,7 +1725,6 @@
|
|||
|
||||
.nw-geoformat-toggle:hover {
|
||||
background: var(--nw-accent);
|
||||
/*border-color: #fff;*/
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
|
|
|
|||
12
public/site/blueprints/pages/form.yml
Normal file
12
public/site/blueprints/pages/form.yml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
title: Formulaire
|
||||
|
||||
columns:
|
||||
main:
|
||||
width: 2/3
|
||||
sections:
|
||||
fields:
|
||||
type: fields
|
||||
fields:
|
||||
text:
|
||||
label: Texte
|
||||
type: writer
|
||||
|
|
@ -26,6 +26,7 @@ tabs:
|
|||
- projects
|
||||
- actus
|
||||
- tutos
|
||||
- form
|
||||
- error
|
||||
settings:
|
||||
label: Paramètres
|
||||
|
|
|
|||
|
|
@ -29,5 +29,18 @@ return [
|
|||
],
|
||||
'panel' => [
|
||||
'css' => 'assets/css/panel.css'
|
||||
],
|
||||
'email' => [
|
||||
'transport' => [
|
||||
'type' => 'smtp',
|
||||
'host' => 'ssl0.ovh.net',
|
||||
'port' => 465,
|
||||
'security' => true,
|
||||
'auth' => true,
|
||||
// 'username' => 'newsletter@ballet-de-lorraine.eu',
|
||||
// 'password' => 'Tusia7p!?2026',
|
||||
'username' => 'contact@sarahgarcin.com',
|
||||
'password' => 'saracroche2804',
|
||||
]
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,11 +43,16 @@
|
|||
<link rel="stylesheet" href="<?= url('assets/css/projet.css') ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Styles pour site vitrine (home, projects, about, tutos, tuto, actus, actu) -->
|
||||
<?php if(in_array($page->template()->name(), ['home', 'projects', 'about', 'tutos', 'tuto', 'actus', 'actu'])):?>
|
||||
<!-- Styles pour site vitrine (home, projects, about, tutos, tuto, actus, actu, form) -->
|
||||
<?php if(in_array($page->template()->name(), ['home', 'projects', 'about', 'tutos', 'tuto', 'actus', 'actu', 'form'])):?>
|
||||
<link rel="stylesheet" href="<?= url('assets/css/home.css') ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Styles formulaires -->
|
||||
<?php if($page->template() == "form"):?>
|
||||
<link rel="stylesheet" href="<?= url('assets/css/form.css') ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<!-- MapLibre GL (récit web + vue carte projet) -->
|
||||
<?php if($page->template() == "narrative-web" || ($page->template() == "project" && kirby()->request()->get('view') === 'map')): ?>
|
||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<nav class="hp-header__nav" id="hp-nav" aria-label="Navigation principale">
|
||||
<?php
|
||||
$navPages = $site->children()->listed()
|
||||
->filterBy('intendedTemplate', 'in', ['actus', 'tutos', 'projects', 'about']);
|
||||
->filterBy('intendedTemplate', 'in', ['actus', 'tutos', 'projects', 'about', 'form']);
|
||||
?>
|
||||
<?php foreach ($navPages as $navPage): ?>
|
||||
<a
|
||||
|
|
|
|||
272
public/site/templates/form.php
Normal file
272
public/site/templates/form.php
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
/**
|
||||
* Template: form.php — Formulaires de demande d'accompagnement
|
||||
* Protection : CSRF (Kirby natif) + honeypot
|
||||
* Envoi : kirby()->email() (PHP mail par défaut, configurable SMTP dans config.php)
|
||||
*/
|
||||
|
||||
$success = false;
|
||||
$error = null;
|
||||
$activeTab = 'autonome';
|
||||
$old = [];
|
||||
|
||||
$emailTo = 'garcinsarah@gmail.com';
|
||||
|
||||
// Post/Redirect/Get — succès après redirection pour éviter la re-soumission
|
||||
$sent = get('sent');
|
||||
if (in_array($sent, ['autonome', 'partenaire'], true)) {
|
||||
$success = true;
|
||||
$activeTab = $sent;
|
||||
}
|
||||
|
||||
if (!$success && kirby()->request()->is('POST')) {
|
||||
$data = kirby()->request()->data();
|
||||
$formType = in_array($data['form_type'] ?? '', ['autonome', 'partenaire'], true)
|
||||
? $data['form_type'] : 'autonome';
|
||||
$activeTab = $formType;
|
||||
|
||||
if (!csrf($data['csrf_token'] ?? '')) {
|
||||
$error = 'Formulaire expiré. Rafraîchissez la page et réessayez.';
|
||||
} elseif (!empty($data['website'])) {
|
||||
// Honeypot rempli — bot silencieusement ignoré
|
||||
go($page->url() . '?sent=' . $formType);
|
||||
} else {
|
||||
$required = ['structure', 'nom', 'localisation', 'email', 'nature', 'titre', 'presentation'];
|
||||
if ($formType === 'partenaire') {
|
||||
$required[] = 'partenariat';
|
||||
}
|
||||
|
||||
$missing = array_filter($required, fn($f) => trim($data[$f] ?? '') === '');
|
||||
|
||||
if (!empty($missing)) {
|
||||
$error = 'Veuillez remplir tous les champs obligatoires.';
|
||||
$old = $data;
|
||||
} elseif (!filter_var(trim($data['email']), FILTER_VALIDATE_EMAIL)) {
|
||||
$error = 'L\'adresse email n\'est pas valide.';
|
||||
$old = $data;
|
||||
} else {
|
||||
$label = $formType === 'partenaire' ? 'Partenaire' : 'Autonome';
|
||||
$lines = [
|
||||
'Demande d\'accompagnement (' . $label . ')',
|
||||
str_repeat('─', 40),
|
||||
'Nom de la structure : ' . $data['structure'],
|
||||
'Nom et prénom : ' . $data['nom'],
|
||||
'Lieu : ' . $data['localisation'],
|
||||
'Email : ' . $data['email'],
|
||||
'Nature du projet : ' . $data['nature'],
|
||||
'Titre provisoire : ' . $data['titre'],
|
||||
'',
|
||||
'Présentation :',
|
||||
$data['presentation'],
|
||||
];
|
||||
if ($formType === 'partenaire') {
|
||||
$lines[] = '';
|
||||
$lines[] = 'Demande de partenariat :';
|
||||
$lines[] = $data['partenariat'];
|
||||
}
|
||||
|
||||
try {
|
||||
kirby()->email([
|
||||
'from' => 'noreply@' . parse_url(site()->url(), PHP_URL_HOST),
|
||||
'replyTo' => trim($data['email']),
|
||||
'to' => $emailTo,
|
||||
'subject' => 'Demande d\'accompagnement (' . $label . ') — ' . $data['titre'],
|
||||
'body' => implode("\n", $lines),
|
||||
]);
|
||||
go($page->url() . '?sent=' . $formType);
|
||||
} catch (Exception $e) {
|
||||
$error = 'Une erreur est survenue lors de l\'envoi. Veuillez réessayer ou nous contacter directement.';
|
||||
$old = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$natures = [
|
||||
'médiation',
|
||||
'création fictionnelle',
|
||||
'création documentaire',
|
||||
'création poétique',
|
||||
'recherche',
|
||||
'projet éducatif',
|
||||
'projet d\'inclusion',
|
||||
'projet économie social et solidaire',
|
||||
'projet journalistique',
|
||||
'projet de voyage',
|
||||
'projet de valorisation patrimoniale',
|
||||
];
|
||||
?>
|
||||
<?php snippet('header-web') ?>
|
||||
|
||||
<div class="hp-wrapper">
|
||||
<?php snippet('nav-web') ?>
|
||||
|
||||
<section class="hp-section">
|
||||
<div class="hp-container">
|
||||
|
||||
<?php if ($page->text()->isNotEmpty()): ?>
|
||||
<div class="form-intro">
|
||||
<?= $page->text()->kt() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="form-notice form-notice--success" role="alert">
|
||||
<p>Votre demande a bien été envoyée. Nous vous contacterons dans les meilleurs délais.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
|
||||
<div class="form-tabs" role="tablist" aria-label="Type de demande">
|
||||
<?php foreach (['autonome' => 'Demande d\'accompagnement autonome', 'partenaire' => 'Demande d\'accompagnement partenaire'] as $type => $label): ?>
|
||||
<button
|
||||
class="form-tab<?= $activeTab === $type ? ' is-active' : '' ?>"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="<?= $activeTab === $type ? 'true' : 'false' ?>"
|
||||
aria-controls="form-panel-<?= $type ?>"
|
||||
data-tab="<?= $type ?>"
|
||||
><?= $label ?></button>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
|
||||
<?php foreach (['autonome', 'partenaire'] as $type): ?>
|
||||
<div
|
||||
id="form-panel-<?= $type ?>"
|
||||
class="form-panel"
|
||||
role="tabpanel"
|
||||
<?= $activeTab !== $type ? 'hidden' : '' ?>
|
||||
>
|
||||
<?php if ($error && $activeTab === $type): ?>
|
||||
<div class="form-notice form-notice--error" role="alert"><?= html($error) ?></div>
|
||||
<?php endif ?>
|
||||
|
||||
<form method="post" action="<?= $page->url() ?>#form-panel-<?= $type ?>" novalidate>
|
||||
<input type="hidden" name="csrf_token" value="<?= csrf() ?>">
|
||||
<input type="hidden" name="form_type" value="<?= $type ?>">
|
||||
|
||||
<!-- Honeypot : invisible pour les humains, les bots le remplissent -->
|
||||
<div class="form-hp" aria-hidden="true">
|
||||
<label for="hp-website-<?= $type ?>">Site web</label>
|
||||
<input type="text" id="hp-website-<?= $type ?>" name="website" tabindex="-1" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<?php $v = ($activeTab === $type && !empty($old)) ? $old : []; ?>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="structure-<?= $type ?>">
|
||||
Nom de la structure <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<input type="text" id="structure-<?= $type ?>" name="structure"
|
||||
value="<?= html($v['structure'] ?? '') ?>"
|
||||
required maxlength="400" autocomplete="organization">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="nom-<?= $type ?>">
|
||||
Nom et prénom de l'acteur du projet <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<input type="text" id="nom-<?= $type ?>" name="nom"
|
||||
value="<?= html($v['nom'] ?? '') ?>"
|
||||
required maxlength="400" autocomplete="name">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="localisation-<?= $type ?>">
|
||||
Lieu du demandeur <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<input type="text" id="localisation-<?= $type ?>" name="localisation"
|
||||
value="<?= html($v['localisation'] ?? '') ?>"
|
||||
required maxlength="400">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="email-<?= $type ?>">
|
||||
Adresse de messagerie <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<input type="email" id="email-<?= $type ?>" name="email"
|
||||
value="<?= html($v['email'] ?? '') ?>"
|
||||
required maxlength="400" autocomplete="email">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="nature-<?= $type ?>">
|
||||
Nature du projet cartographique <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<select id="nature-<?= $type ?>" name="nature" required>
|
||||
<option value="" disabled <?= empty($v['nature']) ? 'selected' : '' ?>>— Choisir —</option>
|
||||
<?php foreach ($natures as $n): ?>
|
||||
<option value="<?= html($n) ?>"<?= ($v['nature'] ?? '') === $n ? ' selected' : '' ?>><?= html($n) ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="titre-<?= $type ?>">
|
||||
Titre provisoire du projet <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<input type="text" id="titre-<?= $type ?>" name="titre"
|
||||
value="<?= html($v['titre'] ?? '') ?>"
|
||||
required maxlength="400">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="presentation-<?= $type ?>">
|
||||
Présentation et objectifs du projet <small>(100 mots)</small>
|
||||
<abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<textarea id="presentation-<?= $type ?>" name="presentation"
|
||||
rows="8" maxlength="2000" required><?= html($v['presentation'] ?? '') ?></textarea>
|
||||
</div>
|
||||
|
||||
<?php if ($type === 'partenaire'): ?>
|
||||
<div class="form-field">
|
||||
<label for="partenariat-<?= $type ?>">
|
||||
Pistes et/ou demandes de partenariats envisagés avec la bibliothèque
|
||||
<small>(100 mots minimum)</small> <abbr title="Obligatoire">*</abbr>
|
||||
</label>
|
||||
<textarea id="partenariat-<?= $type ?>" name="partenariat"
|
||||
rows="8" maxlength="2000" required><?= html($v['partenariat'] ?? '') ?></textarea>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<p class="form-required-note"><abbr title="Obligatoire">*</abbr> Champs obligatoires</p>
|
||||
<button type="submit" class="form-submit">Envoyer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php snippet('footer-web') ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var tabs = document.querySelectorAll('.form-tab');
|
||||
var panels = document.querySelectorAll('.form-panel');
|
||||
tabs.forEach(function (tab) {
|
||||
tab.addEventListener('click', function () {
|
||||
var target = tab.dataset.tab;
|
||||
tabs.forEach(function (t) {
|
||||
var on = t.dataset.tab === target;
|
||||
t.classList.toggle('is-active', on);
|
||||
t.setAttribute('aria-selected', on ? 'true' : 'false');
|
||||
});
|
||||
panels.forEach(function (p) {
|
||||
var on = p.id === 'form-panel-' + target;
|
||||
p.classList.toggle('is-active', on);
|
||||
if (on) p.removeAttribute('hidden');
|
||||
else p.setAttribute('hidden', '');
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue