Merge pull request #4762 from betagouv/form-stylesheet

Usager : amélioration de la clarté et de l'accessibilité des formulaires
This commit is contained in:
Pierre de La Morinerie 2020-02-11 17:38:26 +01:00 committed by GitHub
commit d5fcaf7073
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 152 additions and 66 deletions

View file

@ -3,6 +3,7 @@ $small-page-width: 840px;
$default-spacer: 8px;
$default-padding: 2 * $default-spacer;
$default-fields-spacer: 5 * $default-spacer;
// layouts
$two-columns-padding: 60px;

View file

@ -20,7 +20,7 @@
}
%outline {
&:active,
&:active:not(:disabled),
&:focus {
outline: 3px solid $blue;
}

View file

@ -16,13 +16,13 @@
width: 100%;
height: 0;
margin-top: $default-padding;
margin-bottom: 2 * $default-padding;
margin-bottom: $default-fields-spacer;
border: none;
border-bottom: 1px solid $border-grey;
border-bottom: 2px solid $border-grey;
}
@mixin notice-text-style {
font-size: 14px;
font-size: 16px;
color: $grey;
}
@ -31,6 +31,7 @@
}
label {
font-size: 18px;
margin-bottom: $default-padding;
display: block;
font-weight: bold;
@ -45,7 +46,6 @@
.notice {
@include notice-text-style;
font-weight: bold;
margin-top: - $default-spacer;
margin-bottom: $default-padding;
@ -70,32 +70,80 @@
visibility: visible;
}
// Align checkboxes on the top-left side of the label
// Move checkbox to the top-left side of the label
&.editable-champ-checkbox,
&.editable-champ-radio.vertical,
&.editable-champ-engagement {
p,
label {
padding-left: 28px;
}
input[type=checkbox],
input[type=radio] {
input[type=checkbox] {
position: absolute;
top: 1px;
top: 3px;
left: 0px;
}
// When an (eventual) notice is displayed after the input, give it some bottom margin.
.notice {
margin-bottom: $default-fields-spacer;
}
}
}
.radios {
display: flex;
// Horizontal layout (default)
flex-direction: row;
align-items: flex-start;
label {
display: inline;
margin-left: $default-padding;
margin-right: $default-padding;
}
// Vertical layout
&.vertical {
flex-direction: column;
align-items: stretch;
label {
margin-right: 0;
}
}
label {
padding: $default-padding $default-padding $default-padding $default-spacer;
border: 1px solid $border-grey;
border-radius: 4px;
font-weight: normal;
background: $white;
user-select: none;
&:last-of-type {
margin-bottom: $default-fields-spacer;
}
&:hover {
background: $light-grey;
cursor: pointer;
}
&:active {
border-color: darken($border-grey, 10);
}
&:first-child {
margin-left: 0;
}
input[type=radio] {
margin-bottom: 0;
}
.notice {
margin: 4px 0 0 27px;
}
}
}
@ -109,7 +157,7 @@
select,
.attachment {
display: block;
margin-bottom: 2 * $default-padding;
margin-bottom: $default-fields-spacer;
&.small-margin {
margin-bottom: $default-padding / 2;
@ -117,7 +165,7 @@
}
.add-row {
margin-bottom: 2 * $default-padding;
margin-bottom: $default-fields-spacer;
}
input[type=checkbox] {
@ -182,16 +230,14 @@
input[type=radio] {
@extend %outline;
margin-left: 5px;
margin-right: 4px;
margin-bottom: 2 * $default-padding;
}
input[type=checkbox] {
// Firefox tends to display checkbox controls smaller than other browsers.
// Firefox tends to display some controls smaller than other browsers.
// Ensure a consistency of size between browsers.
width: 16px;
height: 16px;
margin-left: 5px;
margin-right: 4px;
margin-bottom: $default-fields-spacer;
}
input[type=date] {
@ -234,7 +280,7 @@
.select2-container {
display: block;
margin-bottom: 2 * $default-padding;
margin-bottom: $default-fields-spacer;
&.select2-container--focus {
.select2-selection {
@ -304,10 +350,17 @@
}
.header-section {
display: inline-block;
color: $blue;
font-weight: bold;
font-size: 20px;
margin-bottom: 2 * $default-padding;
font-size: 30px;
margin-bottom: 3 * $default-padding;
border-bottom: 3px solid $blue;
}
.header-subsection {
font-size: 22px;
color: $blue;
margin-bottom: $default-padding;
}
.explication-libelle {
@ -317,7 +370,7 @@
}
.explication {
margin-bottom: $default-padding;
margin-bottom: $default-fields-spacer;
padding: $default-padding / 2;
background-color: $light-grey;
@ -326,6 +379,13 @@
}
}
.siret-info {
margin-top: -$default-fields-spacer;
margin-bottom: $default-fields-spacer;
// Ensure the bottom-margin is not collapsed when the element is empty
min-height: 1px;
}
.send-wrapper {
display: flex;
width: 100%;
@ -388,15 +448,4 @@
margin-right: 0;
}
}
.pj-input {
input[type=file] {
margin: $default-padding 0 (2 * $default-padding);
padding: 2px;
}
.piece-description {
margin-bottom: $default-padding;
}
}
}

View file

@ -2,4 +2,11 @@ class Champs::HeaderSectionChamp < Champ
def search_terms
# The user cannot enter any information here so it doesnt make much sense to search
end
def section_index
dossier
.champs
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:header_section) }
.index(self) + 1
end
end

View file

@ -7,5 +7,6 @@
= render partial: "shared/dossiers/editable_champs/editable_champ", locals: { champ: champ, form: form }
= form.hidden_field :id
= form.hidden_field :_destroy, disabled: true
%button.button.danger.remove-row
Supprimer
.flex.row-reverse
%button.button.danger.remove-row
Supprimer lélément

View file

@ -78,18 +78,17 @@
- if !@procedure.locked?
%h2.header-section À qui sadresse ma démarche ?
.editable-champ.editable-champ-radio.vertical
.radios.vertical
= f.label :for_individual, value: true do
= f.radio_button :for_individual, true
Ma démarche sadresse à un particulier
%p.notice En choisissant cette option, lusager devra renseigner son nom et prénom avant daccéder au formulaire
= f.radio_button :for_individual, true
%p.notice En choisissant cette option, lusager devra renseigner son nom et prénom avant daccéder au formulaire
.editable-champ.editable-champ-radio.vertical
= f.label :for_individual, value: false do
= f.radio_button :for_individual, false
Ma démarche sadresse à une personne morale
%p.notice
En choisissant cette option, lusager devra renseigner son n° SIRET.<br>Grâce à lAPI Entreprise, les informations sur la personne morale (raison sociale, adresse du siège, etc.) seront automatiquement renseignées.
= f.radio_button :for_individual, false
%p.notice
En choisissant cette option, lusager devra renseigner son n° SIRET.<br>Grâce à lAPI Entreprise, les informations sur la personne morale (raison sociale, adresse du siège, etc.) seront automatiquement renseignées.
%p.explication
Si votre démarche sadresse indifféremment à une personne morale ou un particulier, choisissez l'option « Particuliers ». Vous pourrez ajouter un champ SIRET directement dans le formulaire.

View file

@ -52,16 +52,16 @@
%label Mot de passe
%input{ type: "password", value: "12345678" }
%h2.header-section Bouton radio verticaux
.editable-champ.editable-champ-radio.vertical
= f.label :archived, 'Option A', value: true
%p.notice Une option tout à fait valable.
= f.radio_button :archived, true
.editable-champ.editable-champ-radio.vertical
= f.label :archived, 'Option B', value: false
%p.notice Une autre option, pas mal non plus.
= f.radio_button :archived, false
%h3.header-subsection Bouton radio verticaux
.radios.vertical
= f.label :archived, value: true do
= f.radio_button :archived, true
Option A
%p.notice Une option tout à fait valable.
= f.label :archived, value: false do
= f.radio_button :archived, false
Option B
%p.notice Une autre option, pas mal non plus.
.send-wrapper
= f.submit 'Enregistrer un brouillon (formnovalidate)', formnovalidate: true, class: 'button send'

View file

@ -1,9 +1,9 @@
.editable-champ{ class: "editable-champ-#{champ.type_champ}" }
- if champ.repetition?
= render partial: 'shared/dossiers/editable_champs/header_section', locals: { champ: champ }
%h3.header-subsection= champ.libelle
- if champ.description.present?
%p.notice= string_to_html(champ.description, false)
- elsif has_label?(champ)
= render partial: 'shared/dossiers/editable_champs/champ_label', locals: { form: form, champ: champ, seen_at: defined?(seen_at) ? seen_at : nil }

View file

@ -1,2 +1,6 @@
- section_index = champ.section_index
%h2.header-section
- if section_index
= "#{section_index}."
= champ.libelle

View file

@ -8,16 +8,16 @@
.flex.row-reverse
- if champ.persisted?
%button.button.danger.remove-row{ type: :button }
Supprimer
Supprimer lélément
- else
%button.button.danger{ type: :button }
Supprimer
Supprimer lélément
- if champ.persisted?
= link_to champs_repetition_path(form.index), class: 'button add-row', data: { remote: true, method: 'POST', params: { champ_id: champ&.id }.to_query } do
%span.icon.add
Ajouter une ligne pour « #{champ.libelle} »
Ajouter un élément pour « #{champ.libelle} »
- else
%a.button.add-row
%span.icon.add
Ajouter une ligne pour « #{champ.libelle} »
Ajouter un élément pour « #{champ.libelle} »

View file

@ -1,11 +1,10 @@
= form.text_field :value,
placeholder: champ.libelle,
class: 'small-margin',
data: { remote: true, debounce: true, url: champs_siret_path(form.index), params: { champ_id: champ&.id }.to_query, spinner: true },
required: champ.mandatory?,
pattern: "[0-9]{14}",
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
.spinner.right.hidden
%div{ class: "siret-info-#{form.index}" }
.siret-info{ class: "siret-info-#{form.index}" }
- if champ.etablissement.present?
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement }

View file

@ -107,7 +107,7 @@ feature 'The user' do
fill_in('text', with: 'super texte')
expect(page).to have_field('text', with: 'super texte')
click_on 'Ajouter une ligne pour'
click_on 'Ajouter un élément pour'
within '.row-1' do
fill_in('text', with: 'un autre texte')
@ -120,7 +120,7 @@ feature 'The user' do
expect(page).to have_content('Supprimer', count: 2)
within '.row-1' do
click_on 'Supprimer'
click_on 'Supprimer lélément'
end
click_on 'Enregistrer le brouillon'

View file

@ -0,0 +1,26 @@
require 'spec_helper'
describe Champs::CheckboxChamp do
let(:types_de_champ) do
[
create(:type_de_champ_header_section),
create(:type_de_champ_civilite),
create(:type_de_champ_text),
create(:type_de_champ_header_section),
create(:type_de_champ_email)
]
end
let(:procedure) { create(:procedure, types_de_champ: types_de_champ) }
let(:dossier) { create(:dossier, procedure: procedure) }
describe '#section_index' do
let(:first_header) { dossier.champs[0] }
let(:second_header) { dossier.champs[3] }
it 'returns the index of the section (starting from 1)' do
expect(first_header.section_index).to eq 1
expect(second_header.section_index).to eq 2
end
end
end